Testing Filament with Pest: Resources &amp; Actions | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Testing Filament Resources, Actions, and Form Assertions with Pest

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

 A practical guide to writing reliable Pest tests for Filament v3/v4 resources, covering table actions, form submissions, and infolist assertions without brittle CSS selectors.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 27 Jun 2026 · Updated 27 Jun 2026 · 3 min read

ShareCopy linkCopied

 ![Testing Filament Resources, Actions, and Form Assertions with Pest](https://cdn.msaied.com/304/2d16aec8179bbaae9647506470a85e40.png) 

  On this page +1. [Testing Filament Resources, Actions, and Form Assertions with Pest](#testing-filament-resources-actions-and-form-assertions-with-pest)
2. [Setting Up the Test Environment](#setting-up-the-test-environment)
3. [Testing the List Page](#testing-the-list-page)
4. [Asserting Table Actions](#asserting-table-actions)
5. [Testing Create and Edit Forms](#testing-create-and-edit-forms)
6. [Testing Header Actions and Modals](#testing-header-actions-and-modals)
7. [Infolist Assertions (Filament v4)](#infolist-assertions-filament-v4)
8. [Key Takeaways](#key-takeaways)

 Testing Filament Resources, Actions, and Form Assertions with Pest
------------------------------------------------------------------

Filament ships with a first-class testing API built on top of Livewire's test utilities. Yet most teams either skip tests entirely or write fragile assertions against rendered HTML. This article shows you how to write meaningful, maintainable Pest tests for Filament resources — covering list pages, table actions, create/edit forms, and infolist assertions.

### Setting Up the Test Environment

Filament tests need an authenticated user and an active panel. Use the `actingAs` helper combined with `filament()->setCurrentPanel()`:

```php
use App\Models\User;
use function Pest\Laravel\actingAs;

beforeEach(function () {
    actingAs(User::factory()->create());
});

```

For multi-panel setups, resolve the panel explicitly:

```php
use Filament\Facades\Filament;

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

```

### Testing the List Page

Filament exposes `livewire()` helpers that understand resource routing. Use `Livewire::test()` with the resource's list page class:

```php
use App\Filament\Resources\OrderResource\Pages\ListOrders;
use Livewire\Livewire;

it('renders the orders list', function () {
    Order::factory()->count(3)->create();

    Livewire::test(ListOrders::class)
        ->assertCanSeeTableRecords(Order::all());
});

```

`assertCanSeeTableRecords` checks that the Eloquent models are present in the rendered table — no CSS selectors required.

### Asserting Table Actions

Table row actions are tested by passing the action name and the target record:

```php
it('soft-deletes an order via table action', function () {
    $order = Order::factory()->create();

    Livewire::test(ListOrders::class)
        ->callTableAction('delete', $order)
        ->assertHasNoTableActionErrors();

    expect($order->fresh()->deleted_at)->not->toBeNull();
});

```

For bulk actions, use `callTableBulkAction`:

```php
it('exports selected orders', function () {
    $orders = Order::factory()->count(5)->create();

    Livewire::test(ListOrders::class)
        ->callTableBulkAction('export', $orders)
        ->assertHasNoTableActionErrors();
});

```

### Testing Create and Edit Forms

Form assertions use `fillForm` and `assertHasNoFormErrors`. Target the specific form by name when a page has multiple:

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

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

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

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

```

Validation failures are equally straightforward:

```php
it('requires a customer', function () {
    Livewire::test(CreateOrder::class)
        ->fillForm(['status' => 'pending'])
        ->call('create')
        ->assertHasFormErrors(['customer_id' => 'required']);
});

```

### Testing Header Actions and Modals

Header actions (e.g., a custom "Approve" action with a confirmation modal) are called via `callAction`:

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

it('approves an order through the header action', function () {
    $order = Order::factory()->state(['status' => 'pending'])->create();

    Livewire::test(EditOrder::class, ['record' => $order->getRouteKey()])
        ->callAction('approve')
        ->assertHasNoActionErrors();

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

```

If the action opens a modal with its own form, chain `fillActionForm` before `callAction`:

```php
->fillActionForm(['reason' => 'Verified by finance'])
->callAction('approve')

```

### Infolist Assertions (Filament v4)

Filament v4 infolists expose `assertSeeInInfolist`:

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

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

    Livewire::test(ViewOrder::class, ['record' => $order->getRouteKey()])
        ->assertSeeInInfolist('order_details', '250');
});

```

### Key Takeaways

- Use `assertCanSeeTableRecords` and `assertCanNotSeeTableRecords` instead of asserting raw HTML.
- `callTableAction` / `callTableBulkAction` are the stable API for row and bulk actions.
- `fillForm` + `assertHasNoFormErrors` / `assertHasFormErrors` covers the full validation surface.
- Always set the active panel in `beforeEach` for multi-panel apps to avoid resolver exceptions.
- Test the database state after actions — Livewire assertions confirm UI, not persistence.

- [filament](https://www.msaied.com/public/articles?search=filament)
- [pest](https://www.msaied.com/public/articles?search=pest)
- [testing](https://www.msaied.com/public/articles?search=testing)
- [laravel](https://www.msaied.com/public/articles?search=laravel)

 Frequently asked questions 
---------------------------

  Do Filament tests require a real database or can I use mocks?Filament's testing API resolves Eloquent models directly, so you need a real (or in-memory SQLite) database. Use RefreshDatabase in your Pest test suite and factories to seed state. Mocking Eloquent at this layer adds more complexity than it saves.

   How do I test a table filter in Filament?Use `filterTable('filter\_name', \['value' =&gt; 'x'\])` on the Livewire test instance, then follow up with `assertCanSeeTableRecords` or `assertCanNotSeeTableRecords` to verify the filtered result set.

   Can I test custom Filament actions that dispatch jobs or events?Yes. Wrap the `callAction` call between `Queue::fake()` / `Event::fake()` and then assert with `Queue::assertPushed()` or `Event::assertDispatched()` as you would in any Laravel feature test.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

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

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articlePostgreSQL CTEs, Window Functions, and Lateral Joins in Laravel](https://www.msaied.com/public/articles/postgresql-ctes-window-functions-and-lateral-joins-in-laravel-1) [Next articleLivewire v3 Performance: Optimistic UI, Wire:model.live Debouncing, and Dirty State](https://www.msaied.com/public/articles/livewire-v3-performance-optimistic-ui-wiremodellive-debouncing-and-dirty-state)  

   On this page
-------------

1. [Testing Filament Resources, Actions, and Form Assertions with Pest](#testing-filament-resources-actions-and-form-assertions-with-pest)
2. [Setting Up the Test Environment](#setting-up-the-test-environment)
3. [Testing the List Page](#testing-the-list-page)
4. [Asserting Table Actions](#asserting-table-actions)
5. [Testing Create and Edit Forms](#testing-create-and-edit-forms)
6. [Testing Header Actions and Modals](#testing-header-actions-and-modals)
7. [Infolist Assertions (Filament v4)](#infolist-assertions-filament-v4)
8. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/743/8998fac3a41451ab3fe1588194e17a43.png) Filament · 3 min read### Securing Filament Plugins with Plumb: Automated Security Scoring for PHP Packages

5 Oct 2026 ](https://www.msaied.com/public/articles/securing-filament-plugins-with-plumb-automated-security-scoring-for-php-packages) [ ![](https://cdn.msaied.com/742/2d02018669cdeedccb5de2efb898f0ee.png) Filament · 3 min read### Filament v3.3.56 Released: File Hash Names and Livewire Upload Fix

5 Oct 2026 ](https://www.msaied.com/public/articles/filament-v3356-released-file-hash-names-and-livewire-upload-fix) [ ![](https://cdn.msaied.com/741/5b55c123ad08e4d34e1f4b99ad6a428b.png)  · 3 min read### Filament v4 Schema-Based Forms, Infolists, and the Unified Schema API

5 Oct 2026 ](https://www.msaied.com/public/articles/filament-v4-schema-based-forms-infolists-and-the-unified-schema-api-5) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
