Learn Filament

Tutorials, Tips, and Courses on FilamentPHP

How to Test Repeaters and Builders Form Fields in FilamentPHP 4

person holding pink sticky note

Not many people know that, apart from being an amazing tool for building admin panels, FilamentPHP also exposes a robust testing framework, enabling you to interact with your forms and test advanced scenarios with ease.

The Filament docs share tons of valuable examples on how to test various components, and it’s fairly easy to write a test like the one below.

livewire(EditCollection::class, ['record' => $collection])
    ->assertSchemaStateSet([
        'fields' => [
            [
                'type' => 'input',
                'data' => [
                    'label' => 'Invoice',
                    'required' => true,
                ],
            ],
            [
                'type' => 'select',
                'data' => [
                    'label' => 'Customer',
                ],
            ],
        ],
        // ...
    ]);

Its content is not really important. What’s important is the fact that it doesn’t work.

How to make tests work?

That is happening because the form we are testing has a builder form field. This, alongside the repeater field, requires some additional code to make them work, even though it may appear to be a correct test at first glance.

The solution is simple: before running the test, you should “fake” the builder, or repeater, or both if you are testing both of them.

$undoBuilderFake = Builder::fake();

livewire(EditCollection::class, ['record' => $collection])
    ->assertSchemaStateSet([
        'fields' => [
            [
                'type' => 'input',
                'data' => [
                    'label' => 'Invoice',
                    'required' => true,
                ],
            ],
            [
                'type' => 'select',
                'data' => [
                    'label' => 'Customer',
                ],
            ],
        ],
        // ...
    ]);

$undoBuilderFake();

By adding that extra line of code Builder::fake(); you can fake the builder and run the test successfully. The same would go with a repeater, except that you would use Repeater::fake().

As you can see from the example above, the fake() method returns a Closure, so you can save it in a variable and call it later to undo the effect of the fake() method.

Why is this happening?

When using a builder, Livewire assigns a UUID for each row you add (the same thing happens with the repeater). It can then use that UUID to identify that row when it re-renders something, so it doesn’t mix up the data you saved there.

That works great when interacting with repeaters or builders inside the browser, but with automated tests, you simulate the filling of the form by passing actual arrays instead of filling up the form, thus you lose that UUID.

However, we don’t care about keeping track of UUIDs in tests, and thus, we can disable the UUID generation and instead use numeric keys (which is what arrays in PHP use by default).

Leave a Reply

Your email address will not be published. Required fields are marked *