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

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

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

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Testing Filament Resources, Actions, and Form Assertions with Pest        On this page       1. [  Why Filament Testing Deserves Its Own Strategy ](#why-filament-testing-deserves-its-own-strategy)
2. [  Setting Up the Test Environment ](#setting-up-the-test-environment)
3. [  Testing a List Resource ](#testing-a-list-resource)
4. [  Testing Table Actions ](#testing-table-actions)
5. [  Testing Create and Edit Forms ](#testing-create-and-edit-forms)
6. [  v4 Schema API Note ](#v4-schema-api-note)
7. [  Testing Header Actions ](#testing-header-actions)
8. [  Asserting Authorization ](#asserting-authorization)
9. [  Key Takeaways ](#key-takeaways)

  ![Testing Filament Resources, Actions, and Form Assertions with Pest](https://cdn.msaied.com/242/848ced5bf306218276c019bd150c25d7.png)

  #filament   #pest   #testing   #laravel  

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

     19 Jun 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

  9 sections  

1. [  01   Why Filament Testing Deserves Its Own Strategy  ](#why-filament-testing-deserves-its-own-strategy)
2. [  02   Setting Up the Test Environment  ](#setting-up-the-test-environment)
3. [  03   Testing a List Resource  ](#testing-a-list-resource)
4. [  04   Testing Table Actions  ](#testing-table-actions)
5. [  05   Testing Create and Edit Forms  ](#testing-create-and-edit-forms)
6. [  06   v4 Schema API Note  ](#v4-schema-api-note)
7. [  07   Testing Header Actions  ](#testing-header-actions)
8. [  08   Asserting Authorization  ](#asserting-authorization)
9. [  09   Key Takeaways  ](#key-takeaways)

       Why Filament Testing Deserves Its Own Strategy
----------------------------------------------

Filament ships a first-class testing API built on top of Livewire's test utilities. Yet most teams either skip tests entirely or write fragile browser-level assertions. The sweet spot is the middle ground: use Filament's own assertion helpers to test intent, not implementation.

This article targets Filament v3 and v4. The core testing API is stable across both; v4 schema-based forms add a few nuances noted below.

---

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

Install the Filament test helpers (already bundled) and make sure your `TestCase` boots the panel:

```php
// tests/TestCase.php
use Filament\FilamentServiceProvider;

protected function getPackageProviders($app): array
{
    return [FilamentServiceProvider::class];
}

```

For panel-specific tests, authenticate as a user that satisfies your panel's `authGuard` and `canAccess` checks:

```php
beforeEach(function () {
    $this->actingAs(User::factory()->admin()->create());
});

```

---

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

Filament exposes `livewire(ListRecords::class)` style helpers. Use `assertCanSeeTableRecords` to verify rows without touching the DOM:

```php
use App\Filament\Resources\OrderResource\Pages\ListOrders;
use App\Models\Order;

it('lists only the authenticated tenant orders', function () {
    $visible = Order::factory()->count(3)->create(['tenant_id' => auth()->id()]);
    $hidden  = Order::factory()->count(2)->create(['tenant_id' => 99]);

    livewire(ListOrders::class)
        ->assertCanSeeTableRecords($visible)
        ->assertCanNotSeeTableRecords($hidden);
});

```

`assertCanSeeTableRecords` compares model keys against the rendered table query — it will catch broken global scopes immediately.

---

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

Table row actions are tested by calling `callTableAction` with the action name and the target record:

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

it('marks an order as shipped', function () {
    $order = Order::factory()->pending()->create();

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

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

```

For actions that open a modal form, pass the form data as the third argument:

```php
livewire(ListOrders::class)
    ->callTableAction('refund', $order, data: [
        'reason' => 'damaged_goods',
        'amount' => 49.99,
    ])
    ->assertHasNoTableActionErrors();

```

`assertHasNoTableActionErrors` checks Livewire validation state — far more reliable than asserting a flash message.

---

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

For `CreateRecord` and `EditRecord` pages, use `fillForm` + `call('create')` or `call('save')`:

```php
use App\Filament\Resources\ProductResource\Pages\CreateProduct;

it('creates a product with valid data', function () {
    livewire(CreateProduct::class)
        ->fillForm([
            'name'  => 'Ergonomic Chair',
            'price' => 299,
            'sku'   => 'CHAIR-001',
        ])
        ->call('create')
        ->assertHasNoFormErrors();

    $this->assertDatabaseHas('products', ['sku' => 'CHAIR-001']);
});

it('requires a unique sku', function () {
    Product::factory()->create(['sku' => 'CHAIR-001']);

    livewire(CreateProduct::class)
        ->fillForm(['sku' => 'CHAIR-001', 'name' => 'Dupe', 'price' => 10])
        ->call('create')
        ->assertHasFormErrors(['sku' => 'unique']);
});

```

### v4 Schema API Note

In Filament v4, forms are defined via `Schema::make()` rather than `Form::make()`. The `fillForm` / `assertHasFormErrors` helpers remain unchanged — the schema change is internal to the component, not to the test surface.

---

Testing Header Actions
----------------------

Page-level header actions (e.g., an "Export" button on a list page) use `callAction`:

```php
livewire(ListOrders::class)
    ->callAction('export', data: ['format' => 'csv'])
    ->assertDispatched('download-ready');

```

---

Asserting Authorization
-----------------------

Filament respects policy methods. Test that unauthorized users cannot reach an action:

```php
it('prevents non-admins from deleting orders', function () {
    $this->actingAs(User::factory()->create()); // no admin role
    $order = Order::factory()->create();

    livewire(ListOrders::class)
        ->assertTableActionHidden('delete', $order);
});

```

`assertTableActionHidden` checks the action's `visible` / `authorize` callback — it does not make an HTTP request.

---

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

- Use `assertCanSeeTableRecords` / `assertCanNotSeeTableRecords` to validate query scopes, not rendered HTML.
- `callTableAction` with a data array covers modal-form actions in a single assertion chain.
- `assertHasNoFormErrors` / `assertHasFormErrors` map directly to Laravel validation rule names.
- `assertTableActionHidden` tests policy-driven visibility without mocking the gate.
- The Filament testing API is stable across v3 and v4; schema internals do not affect test syntax.
- Keep tests focused on one behavior per `it()` block — Filament components carry a lot of state.

 Found this useful?

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

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

  3 questions  

     Q01  Do I need a real database for Filament Pest tests?        Yes. Filament's testing helpers execute real Eloquent queries through Livewire, so you need either an in-memory SQLite database or a dedicated test database. Use the `RefreshDatabase` or `LazilyRefreshDatabase` trait in your base test case. 

      Q02  How do I test a Filament action that dispatches a queued job?        Fake the queue before calling the action: `Queue::fake()`. After `callTableAction`, assert with `Queue::assertPushed(MyJob::class)`. Because Filament actions run synchronously in tests, the job is dispatched but not executed, letting you assert dispatch intent cleanly. 

      Q03  Can I test custom Filament widgets with the same helpers?        Widgets are standard Livewire components, so you use `livewire(MyWidget::class)` directly. Filament does not add extra assertion helpers for widgets, but Livewire's `assertSee`, `assertSet`, and `assertDispatched` cover most widget testing needs. 

  Continue reading

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

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

 [ ![Laravel AI SDK: Tool-Calling Agents and Conversation Persistence](https://cdn.msaied.com/260/8c84f424e42da01993c9ba4b8eb19655.png) laravel ai agents 

### Laravel AI SDK: Tool-Calling Agents and Conversation Persistence

Build reliable tool-calling AI agents in Laravel using the Prism package. Learn how to wire tools, persist con...

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

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-ai-sdk-tool-calling-agents-and-conversation-persistence) [ ![Laravel Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration](https://cdn.msaied.com/259/e8ce445f021c2b26ebe4dd5da50014f8.png) livewire laravel alpine 

### Laravel Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration

Go beyond the docs: understand how Livewire v3 diffs the DOM with morph markers, intercept the lifecycle with...

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

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-livewire-v3-internals-morph-markers-js-hooks-and-alpine-integration) [ ![Laravel Package Development: Service Providers, Auto-Discovery, and Config Merging](https://cdn.msaied.com/258/673a80fa8e42ae375a4bba21bdcd92ea.png) laravel packages service-providers 

### Laravel Package Development: Service Providers, Auto-Discovery, and Config Merging

Build a production-ready Laravel package from scratch — covering service provider design, auto-discovery via c...

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

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-package-development-service-providers-auto-discovery-and-config-merging-1) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://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://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://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)
