Accept the option picked in selects of translatable records
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / test-postgres (push) Has been cancelled
Tests / mcp (push) Has been cancelled

Saving a page with a category failed with "El campo categoría no está
en la lista de valores permitidos" — for every category, not only the
one being tried. Filament builds such a list through a query, which
handles `->relationship('category', 'name->es')`, but validates a choice
by reading the title back off the record as a property,
`$record->{'name->es'}`, which does not exist. No label, so every
option was refused.

The same pattern was in seven more places: a call's, a testimonial's,
a talk's and a repository's project, a testimonial's service, and the
page and application filters. TranslatedOptionLabel gives Filament the
record's own translation instead, in the language of whoever uses the
panel; the JSON path stays for search and ordering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 21:21:43 +02:00
parent 82ef2b38dd
commit 3daa40570b
9 changed files with 138 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Tests\Feature\Panel;
use App\Filament\Resources\Calls\Pages\CreateCall;
use App\Filament\Resources\Pages\Pages\CreatePage;
use App\Filament\Resources\Repositories\Pages\CreateRepository;
use App\Filament\Resources\Talks\Pages\CreateTalk;
use App\Filament\Resources\Testimonials\Pages\CreateTestimonial;
use App\Models\Category;
use App\Models\Project;
use App\Models\Service;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Tests\FakesPireon;
use Tests\TestCase;
/**
* A select whose options are records with a translatable title — a page's
* category, the project a call belongs to — must accept the option picked.
*
* It did not: every choice was refused as "not in the list of allowed
* values", because Filament validated it by reading `name->es` off the record
* as a property. See App\Filament\Support\TranslatedOptionLabel.
*/
class TranslatedRelationshipSelectsTest extends TestCase
{
use FakesPireon, RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->seed(RolePermissionSeeder::class);
Queue::fake();
$this->actingAs($this->userWithRoles('super_admin'));
}
/**
* @return array<string, array{0: class-string, 1: string, 2: string}>
*/
public static function selects(): array
{
return [
"a page's category" => [CreatePage::class, 'category_id', Category::class],
"a call's project" => [CreateCall::class, 'project_id', Project::class],
"a testimonial's project" => [CreateTestimonial::class, 'project_id', Project::class],
"a testimonial's service" => [CreateTestimonial::class, 'service_id', Service::class],
"a talk's project" => [CreateTalk::class, 'project_id', Project::class],
"a repository's project" => [CreateRepository::class, 'project_id', Project::class],
];
}
/**
* @param class-string $page
* @param class-string<Model> $model
*/
#[Test]
#[DataProvider('selects')]
public function the_option_picked_is_accepted(string $page, string $field, string $model): void
{
$record = $model::factory()->create();
// Only this field is asserted: the rest of each form is left empty on
// purpose, and its own errors are not what this is about.
Livewire::test($page)
->fillForm([$field => $record->getKey()])
->call('create')
->assertHasNoFormErrors([$field]);
}
#[Test]
public function the_option_reads_in_the_language_of_whoever_uses_the_panel(): void
{
$category = Category::factory()->create(['name' => ['es' => 'Novedades', 'en' => 'News']]);
app()->setLocale('en');
$select = collect(Livewire::test(CreatePage::class)->instance()->form->getFlatComponents())
->first(fn ($component) => method_exists($component, 'getName') && $component->getName() === 'category_id');
$label = $select->getOptionLabelFromRecord($category);
$this->assertSame('News', $label);
}
}