Testing Filament v4 with Pest: Forms &amp; Actions | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com) [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles  ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

  [ home ](https://www.msaied.com)    [ articles ](https://www.msaied.com/articles)    Filament v4 Testing with Pest: Resources, Actions, and Form Assertions        On this page       1. [  Why Testing Filament Panels Is Different ](#why-testing-filament-panels-is-different)
2. [  Setting Up the Test Environment ](#setting-up-the-test-environment)
3. [  Testing a List Resource Page ](#testing-a-list-resource-page)
4. [  Testing Create and Edit Forms ](#testing-create-and-edit-forms)
5. [  Nested Repeater Fields ](#nested-repeater-fields)
6. [  Testing Custom Table Actions ](#testing-custom-table-actions)
7. [  Testing Infolists ](#testing-infolists)
8. [  Key Takeaways ](#key-takeaways)

  ![Filament v4 Testing with Pest: Resources, Actions, and Form Assertions](https://cdn.msaied.com/426/a81430a378b2849b6fbecb8235b9119f.png)

  #filament   #pest   #testing   #laravel   #livewire  

 Filament v4 Testing with Pest: Resources, Actions, and Form Assertions 
========================================================================

     15 Jul 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Why Testing Filament Panels Is Different  ](#why-testing-filament-panels-is-different)
2. [  02   Setting Up the Test Environment  ](#setting-up-the-test-environment)
3. [  03   Testing a List Resource Page  ](#testing-a-list-resource-page)
4. [  04   Testing Create and Edit Forms  ](#testing-create-and-edit-forms)
5. [  05   Nested Repeater Fields  ](#nested-repeater-fields)
6. [  06   Testing Custom Table Actions  ](#testing-custom-table-actions)
7. [  07   Testing Infolists  ](#testing-infolists)
8. [  08   Key Takeaways  ](#key-takeaways)

 Why Testing Filament Panels Is Different
----------------------------------------

Filament v4 renders UI through Livewire components. That means your test suite can drive the full resource lifecycle — list, create, edit, delete — without a browser, using `Livewire::test()` and Filament's own test helpers. The trick is knowing *which layer* to assert against.

---

Setting Up the Test Environment
-------------------------------

Install the Filament testing utilities alongside Pest:

```bash
composer require --dev pestphp/pest pestphp/pest-plugin-livewire

```

In `TestCase.php`, authenticate as a panel user before each test:

```php
use App\Models\User;
use Filament\Facades\Filament;

beforeEach(function () {
    $user = User::factory()->create();
    $this->actingAs($user);
    Filament::setCurrentPanel(Filament::getPanel('admin'));
});

```

Setting the current panel is essential — without it, policy checks and navigation guards resolve against the wrong context.

---

Testing a List Resource Page
----------------------------

```php
use App\Filament\Resources\OrderResource\Pages\ListOrders;
use Filament\Tables\Actions\DeleteAction;

it('renders the orders list', function () {
    livewire(ListOrders::class)
        ->assertSuccessful()
        ->assertCountTableRecords(5);
});

it('can delete an order from the table', function () {
    $order = Order::factory()->create();

    livewire(ListOrders::class)
        ->callTableAction(DeleteAction::class, $order)
        ->assertHasNoTableActionErrors();

    expect(Order::find($order->id))->toBeNull();
});

```

`assertCountTableRecords` counts rows *after* applying the default query, so it respects global scopes and any `modifyQueryUsing` you have on the table.

---

Testing Create and Edit Forms
-----------------------------

Filament v4 uses the unified Schema API. Form fields are still addressable by their `name` attribute:

```php
use App\Filament\Resources\OrderResource\Pages\CreateOrder;

it('validates required fields on create', function () {
    livewire(CreateOrder::class)
        ->fillForm([
            'customer_id' => null,
            'total' => -10,
        ])
        ->call('create')
        ->assertHasFormErrors([
            'customer_id' => 'required',
            'total' => 'min',
        ]);
});

it('creates an order with valid data', function () {
    $customer = Customer::factory()->create();

    livewire(CreateOrder::class)
        ->fillForm([
            'customer_id' => $customer->id,
            'total' => 150.00,
            'status' => 'pending',
        ])
        ->call('create')
        ->assertHasNoFormErrors();

    expect(Order::where('customer_id', $customer->id)->exists())->toBeTrue();
});

```

### Nested Repeater Fields

Repeater state is passed as an indexed array:

```php
->fillForm([
    'line_items' => [
        ['product_id' => 1, 'qty' => 2],
        ['product_id' => 3, 'qty' => 1],
    ],
])

```

---

Testing Custom Table Actions
----------------------------

Custom actions registered with `Action::make('approve')` are callable by name:

```php
it('approves an order', function () {
    $order = Order::factory()->pending()->create();

    livewire(ListOrders::class)
        ->callTableAction('approve', $order, data: [
            'note' => 'Looks good',
        ])
        ->assertNotified();

    expect($order->fresh()->status)->toBe('approved');
});

```

`assertNotified()` checks that a Filament notification was dispatched — a clean proxy for "the action completed without throwing".

---

Testing Infolists
-----------------

Filament v4 infolists are also Livewire-driven. Assert entry state on the view page:

```php
use App\Filament\Resources\OrderResource\Pages\ViewOrder;

it('displays the order total in the infolist', function () {
    $order = Order::factory()->create(['total' => 299.99]);

    livewire(ViewOrder::class, ['record' => $order->getRouteKey()])
        ->assertSuccessful()
        ->assertInfolists()
        ->assertInfolists(fn ($infolist) =>
            $infolist->has('total')
        );
});

```

> **Note:** `assertInfolists` with a closure is available in Filament v4's test helpers. For entry *values*, read the component state directly via `->get('infolist.total')` if the helper isn't available yet in your build.

---

Key Takeaways
-------------

- Always call `Filament::setCurrentPanel()` in `beforeEach` — panel context affects auth, navigation, and policies.
- Use `assertHasFormErrors` with field-rule pairs for precise validation assertions.
- `callTableAction` accepts a `data` array for modal-based actions.
- `assertCountTableRecords` respects your resource's base query, including global scopes.
- Test infolist entries via the view page Livewire component, not a separate render path.
- Keep one assertion per test; Filament's Livewire layer is fast enough that granular tests don't slow CI meaningfully.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v4-testing-with-pest-resources-actions-and-form-assertions&text=Filament+v4+Testing+with+Pest%3A+Resources%2C+Actions%2C+and+Form+Assertions) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fwww.msaied.com%2Farticles%2Ffilament-v4-testing-with-pest-resources-actions-and-form-assertions) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Do I need a real database to test Filament resources with Pest?        Yes. Filament's test helpers drive actual Livewire components that query Eloquent models, so you need a database. Use RefreshDatabase or a SQLite in-memory connection in phpunit.xml for fast, isolated runs. 

      Q02  How do I test a Filament action that opens a modal with a form?        Use `callTableAction('actionName', $record, data: [...])` and pass the modal form values in the `data` array. Follow up with `assertHasNoTableActionErrors()` to confirm the form passed validation. 

      Q03  Can I test Filament pages that require specific permissions?        Yes. Create a user with the required roles or permissions before the test, authenticate with `actingAs`, and set the panel context. Filament resolves policies against the authenticated user, so your permission checks run as normal. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://www.msaied.com/articles) 

 [ ![Laravel queue:work Now Prints Why the Worker Stopped](https://cdn.msaied.com/629/bed93940d17b932032d64cee2e32d333.png) Laravel Queue Laravel 13.30 

### Laravel queue:work Now Prints Why the Worker Stopped

Laravel 13.30 adds a stop-reason line to queue:work output. Workers now print why they exited—memory limit, re...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 3 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-queuework-now-prints-why-the-worker-stopped) [ ![The Laracon Archive: 626 Talks, 287 Speakers, and 14 Years of Laravel History](https://cdn.msaied.com/628/13d8d0cef5fb083813df134cc253bb1b.png) laracon laravel community 

### The Laracon Archive: 626 Talks, 287 Speakers, and 14 Years of Laravel History

The Laracon Archive is a community-built, searchable index of every recorded Laracon talk — 626 talks from 287...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 3 Sep 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/the-laracon-archive-626-talks-287-speakers-and-14-years-of-laravel-history) [ ![Semantic Memory or Just Markdown? How Laravel Boost Manages AI Agent Project Rules](https://cdn.msaied.com/627/b162933f96fd615f3165bfe167816018.png) Laravel Boost AI Agents Context Engineering 

### Semantic Memory or Just Markdown? How Laravel Boost Manages AI Agent Project Rules

Laravel Boost tried semantic search with embeddings and a vector index to give AI coding agents project memory...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 3 Sep 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/semantic-memory-or-just-markdown-how-laravel-boost-manages-ai-agent-project-rules) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
