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.
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:
<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).
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 โ
it('should be able to see "view" action', function () {
livewire(ProductTable::class)
->assertHasAction('view');
});assertActionContainsAttribute โ
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 โ
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 โ
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:
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'):
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.
