Skip to content
全部文档

测试 Action

在测试中调用 action

可通过将 action 的名称或类传给 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();
});

测试表格 action

要测试表格 action,可使用带有 table() 方法的 TestAction 对象。该对象接收你要测试的 action 名称,并在任何测试方法中替代 action 名称。例如:

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))

测试表格 header action

要测试 header action,可使用不传入具体记录的 table() 方法:

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())

测试表格 bulk action

要测试 bulk action,先调用 selectTableRecords() 并传入要选中的记录。然后使用 TestActionbulk() 方法指定要测试的 action。例如:

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())

测试 schema 中的 action

如果 action 属于资源 infolist 中的某个组件(例如位于 infolist entry 的 belowContent() 方法中),可使用带有 schemaComponent() 方法的 TestAction 对象。该对象接收你要测试的 action 名称,并在任何测试方法中替代 action 名称。例如:

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'))

测试另一 action 的 schema / form 内的 action

如果 action 属于另一 action 的 schema()(或 form())中的组件(例如位于 action 模态框中表单字段的 belowContent() 方法中),可使用带有 schemaComponent() 方法的 TestAction 对象。该对象接收你要测试的 action 名称,并在任何测试方法中替代 action 名称。应按顺序传入 TestAction 对象数组,例如:

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'),
    ]);

测试资源的 getFormActions()

关于如何测试资源页面 getFormActions() 中的自定义 action,请参阅 测试资源 文档。

测试 action 模态框中的表单

若要向 action 传入数据数组,请使用 data 参数:

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);
});

若只需设置 action 的数据而不立即调用它,可以使用 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(),
        ])
});

测试 action 模态框表单中的验证错误

assertHasNoFormErrors() 用于断言提交 action 表单时未发生验证错误。

若要检查数据是否触发验证错误,请使用 assertHasFormErrors(),用法类似 Livewire 中的 assertHasErrors()

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']]);
});

若要检查 action 是否已预填数据,可使用 assertSchemaStateSet() 方法:

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);
});

测试 action 模态框内容

要断言模态框内容,应先 mount action(而不是 call,因为 call 会关闭模态框)。随后可使用 assertMountedActionModalSee()assertMountedActionModalDontSee()assertMountedActionModalSeeHtml()assertMountedActionModalDontSeeHtml() 断言模态框包含你期望的内容:

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);
});

测试 action 是否存在

要确认 action 是否存在,可使用 assertActionExists()assertActionDoesNotExist() 方法:

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');
});

你还可以传入一个函数作为额外参数,断言 action 通过给定的「真值测试」。这在断言 action 具有特定配置时很有用:

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';
        });
});

测试 action 的可见性

要确认某用户下 action 是隐藏还是可见,可使用 assertActionHidden()assertActionVisible() 方法:

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');
});

测试禁用的 action

要确认某用户下 action 是启用还是禁用,可使用 assertActionEnabled()assertActionDisabled() 方法:

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');
});

要确认多组 action 按正确顺序存在,可使用 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']);
});

若要检查 action 对某用户是否隐藏,可使用 assertActionHidden() 方法:

php
use function Pest\Livewire\livewire;

it('can not send invoices', function () {
    $invoice = Invoice::factory()->create();

    livewire(EditInvoice::class, [
        'invoice' => $invoice,
    ])
        ->assertActionHidden('send');
});

测试 action 的标签

要确认 action 具有正确的标签,可使用 assertActionHasLabel()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');
});

测试 action 的图标

要确认 action 按钮显示正确的图标,可使用 assertActionHasIcon()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');
});

测试 action 的颜色

要确认 action 按钮显示正确的颜色,可使用 assertActionHasColor()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');
});

测试 action 的 URL

要确认 action 具有正确的 URL,可使用 assertActionHasUrl()assertActionDoesNotHaveUrl()assertActionShouldOpenUrlInNewTab()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');
});

测试 action 参数

要测试 action 参数,可使用带有 arguments() 方法的 TestAction 对象。该对象接收你要测试的 action 名称,并在任何测试方法中替代 action 名称。例如:

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()]))

测试 action 是否已中止

若要检查 action 是否已中止,可使用 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');
});

在测试中使用 action 类名

Filament 内置了大量预构建 action,例如 CreateActionEditActionDeleteAction,你可以在测试中使用这些类名代替 action 名称,例如:

php
use Filament\Actions\CreateAction;
use function Pest\Livewire\livewire;

livewire(ManageInvoices::class)
    ->callAction(CreateAction::class)

若应用中有自定义 action 类且带有 make() 方法,Filament 在不运行 make() 的情况下无法发现 action 名称,而运行 make() 并不高效。要在测试中使用自定义 action 类名,可为 action 类添加 #[ActionName] 属性,Filament 可用它发现 action 名称。传给 #[ActionName] 的名称应与你在测试中通常使用的 action 名称相同。例如:

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 () {
                // ...
            });
    }
}

现在你可以在测试中使用该类名:

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);

若 action 类继承自 Action 类,可为该类添加静态方法 getDefaultName(),用于发现 action 名称。它还允许用户在实例化时省略 make() 方法中的 action 名称。例如:

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 () {
                // ...
            });
    }
}