- Introduced `testing-schemas.md` with detailed instructions on filling forms, asserting schema states, validating forms, and testing visibility and existence of form fields and components. - Added `testing-tables.md` covering table rendering, column testing, searching, sorting, filtering, and summarizing, along with visibility and existence checks for filters and columns.
526 lines
16 KiB
Markdown
526 lines
16 KiB
Markdown
# Testing Actions
|
|
|
|
## Calling an Action in a Test
|
|
|
|
You can call an action by passing its name or class to `callAction()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can send invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->callAction('send');
|
|
|
|
expect($invoice->refresh())
|
|
->isSent()->toBeTrue();
|
|
});
|
|
```
|
|
|
|
## Testing Table Actions
|
|
|
|
To test table actions, you can use a `TestAction` object with the `table()` method. This object receives the name of the action you want to test, and replaces the name of the action in any testing method you want to use. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(ListInvoices::class)
|
|
->callAction(TestAction::make('send')->table($invoice));
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionVisible(TestAction::make('send')->table($invoice));
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionExists(TestAction::make('send')->table($invoice));
|
|
```
|
|
|
|
## Testing Table Header Actions
|
|
|
|
To test a header action, you can use the `table()` method without passing in a specific record to test with:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
livewire(ListInvoices::class)
|
|
->callAction(TestAction::make('create')->table());
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionVisible(TestAction::make('create')->table());
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionExists(TestAction::make('create')->table());
|
|
```
|
|
|
|
## Testing Table Bulk Actions
|
|
|
|
To test a bulk action, first call `selectTableRecords()` and pass in any records you want to select. Then, use the `TestAction`'s `bulk()` method to specify the action you want to test. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoices = Invoice::factory()->count(3)->create();
|
|
|
|
livewire(ListInvoices::class)
|
|
->selectTableRecords($invoices->pluck('id')->toArray())
|
|
->callAction(TestAction::make('send')->table()->bulk());
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionVisible(TestAction::make('send')->table()->bulk());
|
|
|
|
livewire(ListInvoices::class)
|
|
->assertActionExists(TestAction::make('send')->table()->bulk());
|
|
```
|
|
|
|
## Testing Actions in a Schema
|
|
|
|
If an action belongs to a component in a resource's infolist, for example, if it is in the `belowContent()` method of an infolist entry, you can use the `TestAction` object with the `schemaComponent()` method. This object receives the name of the action you want to test and replaces the name of the action in any testing method you want to use. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class)
|
|
->callAction(TestAction::make('send')->schemaComponent('customer_id'));
|
|
|
|
livewire(EditInvoice::class)
|
|
->assertActionVisible(TestAction::make('send')->schemaComponent('customer_id'));
|
|
|
|
livewire(EditInvoice::class)
|
|
->assertActionExists(TestAction::make('send')->schemaComponent('customer_id'));
|
|
```
|
|
|
|
## Testing Actions Inside Another Action's Schema / Form
|
|
|
|
If an action belongs to a component in another action's `schema()` (or `form()`), for example, if it is in the `belowContent()` method of a form field in an action modal, you can use the `TestAction` object with the `schemaComponent()` method. This object receives the name of the action you want to test and replaces the name of the action in any testing method you want to use. You should pass an array of `TestAction` objects in order, for example:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(ManageInvoices::class)
|
|
->callAction([
|
|
TestAction::make('view')->table($invoice),
|
|
TestAction::make('send')->schemaComponent('customer.name'),
|
|
]);
|
|
|
|
livewire(ManageInvoices::class)
|
|
->assertActionVisible([
|
|
TestAction::make('view')->table($invoice),
|
|
TestAction::make('send')->schemaComponent('customer.name'),
|
|
]);
|
|
|
|
livewire(ManageInvoices::class)
|
|
->assertActionExists([
|
|
TestAction::make('view')->table($invoice),
|
|
TestAction::make('send')->schemaComponent('customer.name'),
|
|
]);
|
|
```
|
|
|
|
## Testing Resource getFormActions()
|
|
|
|
For details on how to test custom actions in the `getFormActions()` of a resource page, refer to the Testing resources documentation.
|
|
|
|
## Testing Forms in Action Modals
|
|
|
|
To pass an array of data into an action, use the `data` parameter:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can send invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->callAction('send', data: [
|
|
'email' => $email = fake()->email(),
|
|
])
|
|
->assertHasNoFormErrors();
|
|
|
|
expect($invoice->refresh())
|
|
->isSent()->toBeTrue()
|
|
->recipient_email->toBe($email);
|
|
});
|
|
```
|
|
|
|
If you ever need to only set an action's data without immediately calling it, you can use `fillForm()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can send invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->mountAction('send')
|
|
->fillForm([
|
|
'email' => $email = fake()->email(),
|
|
]);
|
|
```
|
|
|
|
## Testing Validation Errors in an Action Modal's Form
|
|
|
|
`assertHasNoFormErrors()` is used to assert that no validation errors occurred when submitting the action form.
|
|
|
|
To check if a validation error has occurred with the data, use `assertHasFormErrors()`, similar to `assertHasErrors()` in Livewire:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can validate invoice recipient email', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->callAction('send', data: [
|
|
'email' => Str::random(),
|
|
])
|
|
->assertHasFormErrors(['email' => ['email']]);
|
|
});
|
|
```
|
|
|
|
To check if an action is pre-filled with data, you can use the `assertSchemaStateSet()` method:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can send invoices to the primary contact by default', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
$recipientEmail = $invoice->company->primaryContact->email;
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->mountAction('send')
|
|
->assertSchemaStateSet([
|
|
'email' => $recipientEmail,
|
|
])
|
|
->callMountedAction()
|
|
->assertHasNoFormErrors();
|
|
|
|
expect($invoice->refresh())
|
|
->isSent()->toBeTrue()
|
|
->recipient_email->toBe($recipientEmail);
|
|
});
|
|
```
|
|
|
|
## Testing the Content of an Action Modal
|
|
|
|
To assert the content of a modal, you should first mount the action (rather than call it which closes the modal). You can then use `assertMountedActionModalSee()`, `assertMountedActionModalDontSee()`, `assertMountedActionModalSeeHtml()` or `assertMountedActionModalDontSeeHtml()` to assert the modal contains the content that you expect it to:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('confirms the target address before sending', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
$recipientEmail = $invoice->company->primaryContact->email;
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->mountAction('send')
|
|
->assertMountedActionModalSee($recipientEmail);
|
|
});
|
|
```
|
|
|
|
## Testing the Existence of an Action
|
|
|
|
To ensure that an action exists or doesn't, you can use the `assertActionExists()` or `assertActionDoesNotExist()` method:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can send but not unsend invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionExists('send')
|
|
->assertActionDoesNotExist('unsend');
|
|
});
|
|
```
|
|
|
|
You may pass a function as an additional argument to assert that an action passes a given "truth test". This is useful for asserting that an action has a specific configuration:
|
|
|
|
```php
|
|
use Filament\Actions\Action;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('has the correct description', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionExists('send', function (Action $action): bool {
|
|
return $action->getModalDescription() === 'This will send an email to the customer\'s primary address, with the invoice attached as a PDF';
|
|
});
|
|
});
|
|
```
|
|
|
|
## Testing the Visibility of an Action
|
|
|
|
To ensure an action is hidden or visible for a user, you can use the `assertActionHidden()` or `assertActionVisible()` methods:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can only print invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionHidden('send')
|
|
->assertActionVisible('print');
|
|
});
|
|
```
|
|
|
|
## Testing Disabled Actions
|
|
|
|
To ensure an action is enabled or disabled for a user, you can use the `assertActionEnabled()` or `assertActionDisabled()` methods:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can only print a sent invoice', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionDisabled('send')
|
|
->assertActionEnabled('print');
|
|
});
|
|
```
|
|
|
|
To ensure sets of actions exist in the correct order, you can use `assertActionListInOrder()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can have actions in order', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionListInOrder(['send', 'export']);
|
|
});
|
|
```
|
|
|
|
To check if an action is hidden to a user, you can use the `assertActionHidden()` method:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('can not send invoices', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionHidden('send');
|
|
});
|
|
```
|
|
|
|
## Testing the Label of an Action
|
|
|
|
To ensure an action has the correct label, you can use `assertActionHasLabel()` and `assertActionDoesNotHaveLabel()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('send action has correct label', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionHasLabel('send', 'Email Invoice')
|
|
->assertActionDoesNotHaveLabel('send', 'Send');
|
|
});
|
|
```
|
|
|
|
## Testing the Icon of an Action
|
|
|
|
To ensure an action's button is showing the correct icon, you can use `assertActionHasIcon()` or `assertActionDoesNotHaveIcon()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('when enabled the send button has correct icon', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionEnabled('send')
|
|
->assertActionHasIcon('send', 'envelope-open')
|
|
->assertActionDoesNotHaveIcon('send', 'envelope');
|
|
});
|
|
```
|
|
|
|
## Testing the Color of an Action
|
|
|
|
To ensure that an action's button is displaying the right color, you can use `assertActionHasColor()` or `assertActionDoesNotHaveColor()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('actions display proper colors', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionHasColor('delete', 'danger')
|
|
->assertActionDoesNotHaveColor('print', 'danger');
|
|
});
|
|
```
|
|
|
|
## Testing the URL of an Action
|
|
|
|
To ensure an action has the correct URL, you can use `assertActionHasUrl()`, `assertActionDoesNotHaveUrl()`, `assertActionShouldOpenUrlInNewTab()`, and `assertActionShouldNotOpenUrlInNewTab()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('links to the correct Filament sites', function () {
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->assertActionHasUrl('filament', 'https://filamentphp.com/')
|
|
->assertActionDoesNotHaveUrl('filament', 'https://github.com/filamentphp/filament')
|
|
->assertActionShouldOpenUrlInNewTab('filament')
|
|
->assertActionShouldNotOpenUrlInNewTab('github');
|
|
});
|
|
```
|
|
|
|
## Testing Action Arguments
|
|
|
|
To test action arguments, you can use a `TestAction` object with the `arguments()` method. This object receives the name of the action you want to test and replaces the name of the action in any testing method you want to use. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(ManageInvoices::class)
|
|
->callAction(TestAction::make('send')->arguments(['invoice' => $invoice->getKey()]));
|
|
|
|
livewire(ManageInvoices::class)
|
|
->assertActionVisible(TestAction::make('send')->arguments(['invoice' => $invoice->getKey()]));
|
|
|
|
livewire(ManageInvoices::class)
|
|
->assertActionExists(TestAction::make('send')->arguments(['invoice' => $invoice->getKey()]));
|
|
```
|
|
|
|
## Testing if an Action Has Been Halted
|
|
|
|
To check if an action has been halted, you can use `assertActionHalted()`:
|
|
|
|
```php
|
|
use function Pest\Livewire\livewire;
|
|
|
|
it('stops sending if invoice has no email address', function () {
|
|
$invoice = Invoice::factory(['email' => null])->create();
|
|
|
|
livewire(EditInvoice::class, [
|
|
'invoice' => $invoice,
|
|
])
|
|
->callAction('send')
|
|
->assertActionHalted('send');
|
|
});
|
|
```
|
|
|
|
## Using Action Class Names in Tests
|
|
|
|
Filament includes a host of prebuilt actions such as `CreateAction`, `EditAction` and `DeleteAction`, and you can use these class names in your tests instead of action names, for example:
|
|
|
|
```php
|
|
use Filament\Actions\CreateAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
livewire(ManageInvoices::class)
|
|
->callAction(CreateAction::class);
|
|
```
|
|
|
|
If you have your own action classes in your app with a `make()` method, the name of your action is not discoverable by Filament unless it runs the `make()` method, which is not efficient. To use your own action class names in your tests, you can add an `#[ActionName]` attribute to your action class, which Filament can use to discover the name of your action. The name passed to the `#[ActionName]` attribute should be the same as the name of the action you would normally use in your tests. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Action;
|
|
use Filament\Actions\ActionName;
|
|
|
|
#[ActionName('send')]
|
|
class SendInvoiceAction
|
|
{
|
|
public static function make(): Action
|
|
{
|
|
return Action::make('send')
|
|
->requiresConfirmation()
|
|
->action(function () {
|
|
// ...
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
Now, you can use the class name in your tests:
|
|
|
|
```php
|
|
use App\Filament\Resources\Invoices\Actions\SendInvoiceAction;
|
|
use Filament\Actions\Testing\TestAction;
|
|
use function Pest\Livewire\livewire;
|
|
|
|
$invoice = Invoice::factory()->create();
|
|
|
|
livewire(ManageInvoices::class)
|
|
->callAction(TestAction::make(SendInvoiceAction::class)->table($invoice));
|
|
```
|
|
|
|
If you have an action class that extends the `Action` class, you can add a `getDefaultName()` static method to the class, which will be used to discover the name of the action. It also allows users to omit the name of the action from the `make()` method when instantiating it. For example:
|
|
|
|
```php
|
|
use Filament\Actions\Action;
|
|
|
|
class SendInvoiceAction extends Action
|
|
{
|
|
public static function getDefaultName(): string
|
|
{
|
|
return 'send';
|
|
}
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this
|
|
->requiresConfirmation()
|
|
->action(function () {
|
|
// ...
|
|
});
|
|
}
|
|
}
|
|
```
|