Testing related fields in filament and livewire

260 Views Asked by At

I'm trying to test a form that when I select a brand it should prefill the related suppliers in the next select. In my form I user the ->live() method to make the fields dependent on each other. In my test i have:

$brand = Brand::factory()->create();
$suppliers = Supplier::factory()
    ->count(2)
    ->hasAttached($brand)
    ->create();

$this->get(OrderResource::getUrl('create'));
livewire(CreateOrder::class)
    ->assertFormFieldExists('brand_id')
    ->fillForm([
        'brand_id' => $brand->id,
    ])
    ->assertFormSet(['supplier_id' => $suppliers->pluck('id')->toArray()]);

However this doesn't work, I get the error:

Failed asserting that null matches expected 1.

  at vendor/livewire/livewire/src/Features/SupportTesting/MakesAssertions.php:93
     89▕
     90▕         if (! is_string($value) && is_callable($value)) {
     91▕             PHPUnit::assertTrue($value($actual));
     92▕         } else {
  ➜  93▕             $strict ? PHPUnit::assertSame($value, $actual) : PHPUnit::assertEquals($value, $actual);
     94▕         }
     95▕
     96▕         return $this;
     97▕     }

I have tried to log what the value is of the suppliers. And I have confirmed that the options are empty. How Can I solve this, or where can I read about testing these dependent fields. Thanks.

1

There are 1 best solutions below

0
suxgri On BEST ANSWER

You didn t show the form but it must be similar to the one below (the example form below is the one shown here:

class CreateOrder extends Component implements HasForms
{
use InteractsWithForms;

public $brandId;
public $supplierId;

public function getFormSchema(): array
{
  return [

    Select::make('brandId')
    ->label('Brands')
    ->options(Brand::all()->pluck('name','id')->toArray())
    ->reactive(),
 
    Select::make('supplierId')
    ->label('Suppliers')
    ->options(function(callable $get){
        $brand = Brand::find($get('brandId'));
     
        if(!$brand){
          return Supplier::all()->pluck('title','id');
        }
        return $brand->suppliers->pluck('title','id');
    })

  ];
}


public function render():View
{
    return view('livewire.createorder');
}
}

The form has 2 dependant selects, the second one lists all suppliers in the database if no brand is chosen in the first select, but if a brand is chosen it re-renders to list only the suppliers that belongs to the chosen brand.

Below is the test:

it('has dependant fields with logic ok', function () {

$brand = Brand::factory()->create();
$brand2 = Brand::factory()->create();

$suppliersVisible = Supplier::factory()
    ->count(2)->create(['user_id' => $brand->id, 'title'=>fake()->sentence()]);

$suppliersHidden = Supplier::factory()
    ->count(2)->create(['user_id' => $brand2->id,'title'=>fake()->sentence()]);

livewire(CreateOrder::class)
    ->fillForm([
        'brandId' => $brand->id,
    ])
    ->assertSee($suppliersVisible[0]->title)
    ->assertSee($suppliersVisible[1]->title)
    ->assertDontSee($suppliersHidden[0]->title)
    ->assertDontSee($suppliersHidden[1]->title);
});

The test populate the db with 2 brands and each brand has 2 suppliers.

The test passes if only the suppliers for the selected brand are shown after the re-render.

The assertFormSet method is to test state of the form, but in this case there is no state, we have to test what the page shows.