Testing Filament v3 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 resources — covering table actions, form submissions, and infolist assertions without reaching for a browser.

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

ShareCopy linkCopied

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

  On this page +1. [Why Testing Filament Deserves Its Own Strategy](#why-testing-filament-deserves-its-own-strategy)
2. [Project Setup](#project-setup)
3. [Testing a List Page](#testing-a-list-page)
4. [Filtering and Searching](#filtering-and-searching)
5. [Testing Table Actions](#testing-table-actions)
6. [Testing Create and Edit Forms](#testing-create-and-edit-forms)
7. [Edit Page — Pre-filled State](#edit-page-pre-filled-state)
8. [Authorization Inside Tests](#authorization-inside-tests)
9. [Key Takeaways](#key-takeaways)

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

Filament ships a first-class testing API built on top of Livewire's testing utilities. Most teams either skip it entirely or write brittle browser tests. Neither is acceptable when a resource manages production data. The goal here is fast, deterministic Pest tests that cover the paths users actually hit.

### Project Setup

Install the Filament testing package alongside Pest:

```bash
composer require --dev filament/filament pestphp/pest-plugin-laravel

```

Filament's helpers live in `Filament\Tests` and are pulled in automatically when you use `livewire()` inside a test. No extra trait is needed beyond `RefreshDatabase`.

---

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

The list page is the most common entry point. Assert that the table renders and that records appear:

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

it('renders the order list page', function () {
    $this->actingAs(User::factory()->admin()->create());

    $orders = Order::factory(3)->create();

    livewire(OrderResource\Pages\ListOrders::class)
        ->assertCanSeeTableRecords($orders);
});

```

`assertCanSeeTableRecords` checks that the Livewire component's rendered HTML contains each model's row — it does **not** fire a real browser.

### Filtering and Searching

```php
it('filters orders by status', function () {
    $pending = Order::factory()->pending()->create();
    $shipped = Order::factory()->shipped()->create();

    livewire(OrderResource\Pages\ListOrders::class)
        ->filterTable('status', 'pending')
        ->assertCanSeeTableRecords([$pending])
        ->assertCanNotSeeTableRecords([$shipped]);
});

```

The `filterTable($filterName, $value)` helper maps directly to the filter key you registered on the table.

---

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

Bulk actions and row actions are where bugs hide. Test them explicitly:

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

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

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

```

For actions that open a modal with a form, fill the fields before calling:

```php
it('assigns a courier via action modal', function () {
    $order = Order::factory()->create();
    $courier = Courier::factory()->create();

    livewire(OrderResource\Pages\ListOrders::class)
        ->mountTableAction('assign_courier', $order)
        ->setTableActionData(['courier_id' => $courier->id])
        ->callMountedTableAction()
        ->assertHasNoTableActionErrors();

    expect($order->fresh()->courier_id)->toBe($courier->id);
});

```

---

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

Form assertions validate that Filament's schema maps correctly to your model:

```php
it('creates an order with valid data', function () {
    livewire(OrderResource\Pages\CreateOrder::class)
        ->fillForm([
            'customer_id' => Customer::factory()->create()->id,
            'notes'       => 'Rush delivery',
            'status'      => 'pending',
        ])
        ->call('create')
        ->assertHasNoFormErrors();

    $this->assertDatabaseHas('orders', ['notes' => 'Rush delivery']);
});

it('fails validation when customer is missing', function () {
    livewire(OrderResource\Pages\CreateOrder::class)
        ->fillForm(['notes' => 'No customer'])
        ->call('create')
        ->assertHasFormErrors(['customer_id' => 'required']);
});

```

### Edit Page — Pre-filled State

```php
it('pre-fills the edit form with existing data', function () {
    $order = Order::factory()->create(['notes' => 'Original note']);

    livewire(OrderResource\Pages\EditOrder::class, ['record' => $order->getRouteKey()])
        ->assertFormSet(['notes' => 'Original note']);
});

```

`assertFormSet` is the quickest way to verify that `fill()` inside `mount()` works correctly.

---

Authorization Inside Tests
--------------------------

Don't forget to test that unauthorized users are blocked:

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

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

```

`assertTableActionHidden` confirms the action is not rendered for that record — no need to call it and catch an exception.

---

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

- Use `livewire(PageClass::class)` — Filament pages are Livewire components and test identically.
- `filterTable`, `callTableAction`, and `fillForm` cover 90% of real user paths.
- Always assert the **database state** after mutations, not just the absence of errors.
- Test authorization with `assertTableActionHidden` / `assertTableActionVisible` rather than role-checking in isolation.
- Keep each test focused on one behavior; share fixture setup via Pest `beforeEach` or dataset factories.

- [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 to publish Filament's test helpers or install a separate package?No. Filament's testing helpers are bundled with the main `filament/filament` package. As long as you have Pest and the Laravel plugin installed, you can call `livewire()` directly on any Filament page class inside your tests.

   How do I test a custom action that dispatches a job or fires an event?Wrap the action call with `Bus::fake()` or `Event::fake()` before mounting the Livewire component, then call `callTableAction()` or `callMountedTableAction()` as normal. Assert the job or event was dispatched after the call completes.

   Can these tests run in CI without a database?They require a database because Filament queries Eloquent models. Use SQLite in-memory (`:memory:`) in your `phpunit.xml` for fast CI runs, combined with `RefreshDatabase` to keep each test isolated.

   ![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 articlePayZephyr: One Payment API for Stripe, Paystack, and PayPal in Laravel](https://www.msaied.com/public/articles/payzephyr-one-payment-api-for-stripe-paystack-and-paypal-in-laravel) [Next articleA Better Way to Build MCP Servers with Laravel: Searchable Tool Catalogs](https://www.msaied.com/public/articles/a-better-way-to-build-mcp-servers-with-laravel-searchable-tool-catalogs)  

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

1. [Why Testing Filament Deserves Its Own Strategy](#why-testing-filament-deserves-its-own-strategy)
2. [Project Setup](#project-setup)
3. [Testing a List Page](#testing-a-list-page)
4. [Filtering and Searching](#filtering-and-searching)
5. [Testing Table Actions](#testing-table-actions)
6. [Testing Create and Edit Forms](#testing-create-and-edit-forms)
7. [Edit Page — Pre-filled State](#edit-page-pre-filled-state)
8. [Authorization Inside Tests](#authorization-inside-tests)
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)
