Skip to content

Testing PowerGrid Tables โ€‹

PowerGrid mixes TestActions into Livewire's Testable. Use the same Livewire testing flow, then the helpers below.

Pest Browser Testing โ€‹

Pest Browser Testing drives the real UI. Example: type into the search field and assert which rows remain.

phptests/Browser/ProductTableTest.php
it('can filter products', function () {
    $this->withVite();

    $searchField = '[wire\:model\.live\.debounce\.700ms="search"]';

    visit('/products')
        ->assertSee('Arkansas Possum Pie')
        ->assertSee('Bacalhau')
        ->fill($searchField, 'Bacalhau')
        ->assertDontSee('Arkansas Possum Pie')
        ->assertSee('Bacalhau');
});

Livewire Testing โ€‹

Disable partials in tests

Search, sort, pagination, resetPage(), and filter changes send only the changed hot zones and skip the full render. Livewire::test() keeps the last full render, so assertSee() / assertDontSee() check stale rows after those updates. Turn partials off for the test suite:

xml
<env name="POWERGRID_PARTIALS_ENABLED" value="false"/>

Testing Actions Buttons โ€‹

See action button. Helpers read __turbine_actions on the current page rows (collected in tests).

phpapp/Livewire/ProductTable.php
public function actions($row): array
{
    return [
        Button::add('view')
            ->icon('icons.eye', [
                'class' => '!text-green-500',
            ])
            ->slot('View')
            ->class('text-slate-500 flex gap-2 hover:text-slate-700 hover:bg-slate-100 font-bold p-1 px-2 rounded')
            ->dispatch('clickToEdit', ['productId' => $row?->id, 'productName' => $row?->name]),
    ];
}

assertHasAction โ€‹

phptests/Livewire/ProductTable.php
it('should be able to see "view" action', function () {
    livewire(ProductTable::class)
        ->assertHasAction('view');
});

assertActionContainsAttribute โ€‹

phptests/Livewire/ProductTable.php
it('should be able to see "class" attribute in "view" action', function () {
    livewire(ProductTable::class)
        ->assertActionContainsAttribute(
            action: 'view',
            attribute: 'class',
            expected: 'flex gap-2 hover:text-slate-700'
        );
});

wire:click - assertActionContainsAttribute โ€‹

phptests/Livewire/ProductTable.php
it('should be able to see "wire:click" in "view" action', function () {
    livewire(ProductTable::class)
        ->assertActionContainsAttribute(
            action: 'view',
            attribute: 'wire:click',
            expected: 'clickToEdit',
            expectedParams: ['productId' => 29, 'productName' => 'Luan']
        );
});

assertActionHasIcon โ€‹

phptests/Livewire/ProductTable.php
it('should be able to see the "icons.eye" icon in "view" action', function () {
    livewire(ProductTable::class)
        ->assertActionHasIcon(
            action: 'view',
            icon: 'icons.eye',
            iconClass: '!text-green-500'
        );
});

Signatures from Testing\TestActions:

  • assertHasAction(string $action)
  • assertActionContainsAttribute(string $action, string $attribute, string $expected, array $expectedParams = [])
  • assertActionHasIcon(string $action, string $icon, ?string $iconClass = null)

Testing Dropdown and Flyout Filters โ€‹

Panel modes (dropdown and flyout) never filter live. Edits land in draftFilters and commit on applyFilters(). Drive them through the draft:

phptests/Feature/ProductTableTest.php
Livewire::test(ProductTable::class)
    ->call('fetchDatasource')
    ->set('draftFilters.name.value', 'pizza')
    ->call('applyFilters')
    ->assertSee('Pizza')
    ->assertDontSee('Salad');

The bag is keyed by field (draftFilters.{field}.value). Date ranges use the Flatpickr formatted string, here for Filter::datetimepicker('created_at'):

phptests/Feature/ProductTableTest.php
Livewire::test(ProductTable::class)
    ->call('fetchDatasource')
    ->set('draftFilters.created_at.value.formatted', '2026-08-04 00:00 to 2026-08-06 23:59')
    ->call('applyFilters');

See Filter Position.

Created By Luan Freitas and @DanSysAnalyst