Testing Filament v3 with Pest: Resources &amp; Forms | 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. Filament v3 Testing with Pest: Resources, Actions, and Form Assertions

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

 Learn how to write confident, maintainable Pest tests for Filament v3 resources, table actions, and form submissions — covering auth context, livewire assertions, and common pitfalls.

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

ShareCopy linkCopied

 ![Filament v3 Testing with Pest: Resources, Actions, and Form Assertions](https://cdn.msaied.com/177/7c53cf56fda3d488b9f618ccf3998a78.png) 

  On this page +1. [Why Filament Testing Deserves Its Own Strategy](#why-filament-testing-deserves-its-own-strategy)
2. [Setting the Auth Context](#setting-the-auth-context)
3. [Asserting Table Columns and Records](#asserting-table-columns-and-records)
4. [Testing Table Actions](#testing-table-actions)
5. [Form Submission on Create/Edit Pages](#form-submission-on-createedit-pages)
6. [Testing Authorization Inside Resources](#testing-authorization-inside-resources)
7. [Practical Takeaways](#practical-takeaways)

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

Filament panels are Livewire components under the hood. That means standard HTTP tests miss most of what matters — form validation, action modals, bulk operations, and authorization checks all live inside component state. Pest's Livewire integration, combined with Filament's own test helpers, gives you a clean path to full coverage without brittle browser tests.

---

Setting the Auth Context
------------------------

Every Filament resource test needs an authenticated panel user. Use `actingAs` before mounting the component, and make sure the user satisfies your panel's `auth()->check()` guard.

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

it('renders the orders list for an admin', function () {
    $admin = User::factory()->admin()->create();

    livewire(ListOrders::class)
        ->actingAs($admin)
        ->assertSuccessful();
});

```

If your panel uses a custom guard, pass it explicitly: `actingAs($admin, 'admin')`.

---

Asserting Table Columns and Records
-----------------------------------

Filament's `InteractsWithTable` trait exposes helpers that map directly to what the user sees.

```php
it('shows pending orders in the table', function () {
    $admin = User::factory()->admin()->create();
    Order::factory()->pending()->count(3)->create();
    Order::factory()->completed()->count(2)->create();

    livewire(ListOrders::class)
        ->actingAs($admin)
        ->assertCountTableRecords(3); // default filter: pending
});

```

Use `->assertCanSeeTableRecords($records)` when you need to assert specific model instances appear, and `->assertCanNotSeeTableRecords($records)` for scoping and authorization checks.

---

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

Row actions and bulk actions are where most bugs hide. Filament provides `callTableAction` and `callTableBulkAction`.

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

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

    expect($order->fresh()->status)->toBe(OrderStatus::Shipped);
});

```

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

```php
->callTableAction('reassign', $order, data: [
    'assignee_id' => $agent->id,
])
->assertHasNoTableActionErrors();

```

---

Form Submission on Create/Edit Pages
------------------------------------

Mount the `CreateOrder` or `EditOrder` page directly and use `fillForm` + `call('create')` or `call('save')`.

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

it('validates required fields on create', function () {
    $admin = User::factory()->admin()->create();

    livewire(CreateOrder::class)
        ->actingAs($admin)
        ->fillForm([
            'customer_id' => null,
            'total' => -10,
        ])
        ->call('create')
        ->assertHasFormErrors([
            'customer_id' => 'required',
            'total' => 'min',
        ]);
});

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

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

    $this->assertDatabaseHas('orders', [
        'customer_id' => $customer->id,
        'total' => 150.00,
    ]);
});

```

---

Testing Authorization Inside Resources
--------------------------------------

Filament respects policies. Test that unauthorized users are blocked at the component level, not just the route.

```php
it('prevents non-admins from deleting orders', function () {
    $viewer = User::factory()->viewer()->create();
    $order = Order::factory()->create();

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

```

`assertTableActionHidden` checks that the action is not rendered for that record — a stronger guarantee than checking HTTP status codes.

---

Practical Takeaways
-------------------

- Always call `actingAs` before mounting; Filament panels enforce auth at the component level.
- Use `assertCountTableRecords` for scope/filter tests — it respects the component's default filters.
- `callTableAction` with a `data` array covers modal-based actions without browser overhead.
- `assertHasFormErrors` accepts field-rule pairs for precise validation assertions.
- Test authorization with `assertTableActionHidden` / `assertTableActionVisible` rather than policy unit tests alone.
- Keep each test focused on one behavior; Filament component state resets between Pest tests automatically.

- [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)
- [livewire](https://www.msaied.com/public/articles?search=livewire)

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

  Do I need to register the Filament panel in tests?Yes. Filament resolves resources through the panel registry, so your test environment must boot the panel. Typically this happens automatically via your AppServiceProvider or a dedicated test service provider. If resources are not found, ensure the panel's `boot` method runs during the test suite.

   How do I test a custom Filament action that dispatches a job?Fake the queue with `Queue::fake()` before calling `callTableAction`, then assert the job was pushed with `Queue::assertPushed(MyJob::class)`. The action executes synchronously inside the Livewire test, so the fake captures the dispatch correctly.

   Can I test Filament notifications triggered by actions?Yes. After calling an action, chain `-&gt;assertNotified()` or `-&gt;assertNotified('Order shipped')` to assert that a Filament notification was dispatched to the current session. This works for both success and error notifications defined inside your action's `action()` closure.

   ![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 articleRecursive Queries in MySQL 8 with Laravel: CTEs, Hierarchies, and Adjacency Lists](https://www.msaied.com/public/articles/recursive-queries-in-mysql-8-with-laravel-ctes-hierarchies-and-adjacency-lists) [Next articleLaravel Octane Worker Lifecycle, State Leakage, and Memory Management](https://www.msaied.com/public/articles/laravel-octane-worker-lifecycle-state-leakage-and-memory-management)  

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

1. [Why Filament Testing Deserves Its Own Strategy](#why-filament-testing-deserves-its-own-strategy)
2. [Setting the Auth Context](#setting-the-auth-context)
3. [Asserting Table Columns and Records](#asserting-table-columns-and-records)
4. [Testing Table Actions](#testing-table-actions)
5. [Form Submission on Create/Edit Pages](#form-submission-on-createedit-pages)
6. [Testing Authorization Inside Resources](#testing-authorization-inside-resources)
7. [Practical Takeaways](#practical-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)
