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 selectors.

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

ShareCopy linkCopied

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

  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)

 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.

- [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 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.

   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.

   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.

   ![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, Recursive Queries, and Lateral Joins in Laravel](https://www.msaied.com/public/articles/postgresql-ctes-recursive-queries-and-lateral-joins-in-laravel) [Next articleOctane Worker Lifecycle, State Leakage, and Memory Management in Production](https://www.msaied.com/public/articles/octane-worker-lifecycle-state-leakage-and-memory-management-in-production)  

   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)

 ###  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/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  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)
