表单构造器
测试
概述
所有本指南内的示例都使用 Pest 编写。要使用 Pest 的 Livewire 插件进行测试,请参考 Pest 文档中的插件安装说明:Pest 的 Livewire 插件。不过,你也可以将其适配到 PHPUnit。
因为表单构造器是基于 Livewire 组件的,因此你也可以使用 Livewire 测试辅助函数。不过,我们自定义了一些测试辅助函数,让你可以用于表单测试:
填充表单
要填充表单,请将数据传入 fillform()
:
use function Pest\Livewire\livewire; livewire(CreatePost::class) ->fillForm([ 'title' => fake()->sentence(), // ... ]);
如果一个 Livewire 组件中有多个表单,你可以使用
fillForm([...], 'createPostForm')
指定你想要填充哪个表单。
使用 assertFormSet()
断言表单中有数据:
use Illuminate\Support\Str;use function Pest\Livewire\livewire; it('can automatically generate a slug from the title', function () { $title = fake()->sentence(); livewire(CreatePost::class) ->fillForm([ 'title' => $title, ]) ->assertFormSet([ 'slug' => Str::slug($title), ]);});
注意,如果一个 Livewire 组件中有多个表单,你可以使用
assertFormSet([...], 'createPostForm')
指定你想要检测哪个表单。
在 assertFormSet()
中传入一个函数,将允许你访问表单的 $state
并执行额外的断言:
use Illuminate\Support\Str;use function Pest\Livewire\livewire; it('can automatically generate a slug from the title without any spaces', function () { $title = fake()->sentence(); livewire(CreatePost::class) ->fillForm([ 'title' => $title, ]) ->assertFormSet(function (array $state): array { expect($state['slug']) ->not->toContain(' '); return [ 'slug' => Str::slug($title), ]; });});
如果你希望 Filament 在函数运行后继续断言表单状态,你可以在该函数中返回数组。
验证
使用 assertHasFormErrors()
断言对表单中的数据进行有效验证:
use function Pest\Livewire\livewire; it('can validate input', function () { livewire(CreatePost::class) ->fillForm([ 'title' => null, ]) ->call('create') ->assertHasFormErrors(['title' => 'required']);});
同时 assertHasNoFormErrors()
断言没有验证错误:
use function Pest\Livewire\livewire; livewire(CreatePost::class) ->fillForm([ 'title' => fake()->sentence(), // ... ]) ->call('create') ->assertHasNoFormErrors();
注意,如果一个 Livewire 组件中有多个表单,你可以将指定表单名作为第二个参数传入,像这样
assertHasFormErrors(['title' => 'required'], 'createPostForm')
或assertHasNoFormErrors([], 'createPostForm')
。
表单存在
断言 Livewire 组件中有一个表单,请使用 assertFormExists()
:
use function Pest\Livewire\livewire; it('has a form', function () { livewire(CreatePost::class) ->assertFormExists();});
如果一个 Livewire 组件中有多个表单,你可以将指定的表单名传入
assertFormExists('createPostForm')
。
字段
断言表单中有某个给定字段,请将字段名传入到 assertFormFieldExists()
:
use function Pest\Livewire\livewire; it('has a title field', function () { livewire(CreatePost::class) ->assertFormFieldExists('title');});
你也可以传入函数作为额外的参数,来断言一个字段传入了一个"真值测试"。着对断言一个字段有某个特定配置非常有用:
use function Pest\Livewire\livewire; it('has a title field', function () { livewire(CreatePost::class) ->assertFormFieldExists('title', function (TextInput $field): bool { return $field->isDisabled(); });});
要断言表单中不包含给定字段,请将字段名传给 assertFormFieldDoesNotExist()
:
use function Pest\Livewire\livewire; it('does not have a conditional field', function () { livewire(CreatePost::class) ->assertFormFieldDoesNotExist('no-such-field');});
如果 Livewire 组件有多个表单,你可以指定哪个表单要断言字段是否存在。比如
assertFormFieldExists('title', 'createPostForm')
。
Hidden 字段
断言表单中有某个字段可见,将字段名传入到 assertFormFieldIsVisible()
:
use function Pest\Livewire\livewire; test('title is visible', function () { livewire(CreatePost::class) ->assertFormFieldIsVisible('title');});
或者断言表单中隐藏某个字段,将字段名传入到 assertFormFieldIsHidden()
:
use function Pest\Livewire\livewire; test('title is hidden', function () { livewire(CreatePost::class) ->assertFormFieldIsHidden('title');});
对于
assertFormFieldIsHidden()
和assertFormFieldIsVisible()
,你可以传递该字段所属表单的名称作为第二个参数,比如assertFormFieldIsHidden('title', 'createPostForm')
。
禁用字段
要断言字段可用,请传递字段名到 assertFormFieldIsEnabled()
:
use function Pest\Livewire\livewire; test('title is enabled', function () { livewire(CreatePost::class) ->assertFormFieldIsEnabled('title');});
要断言字段禁用,请传递字段名到 assertFormFieldIsDisabled()
:
use function Pest\Livewire\livewire; test('title is disabled', function () { livewire(CreatePost::class) ->assertFormFieldIsDisabled('title');});
对于
assertFormFieldIsEnabled()
和assertFormFieldIsDisabled()
,你可以传递该字段所属表单的名称作为第二个参数,比如assertFormFieldIsEnabled('title', 'createPostForm')
。
布局组件
如果你想确定特定的布局组件(而非字段)是否存在,你可以使用 assertFormComponentExists()
。由于布局组件没有名称,该方法使用了由开发者提供的 Key()
:
use Filament\Forms\Components\Section; Section::make('Comments') ->key('comments-section') ->schema([ // ])
use function Pest\Livewire\livewire; test('comments section exists' function () { livewire(EditPost::class) ->assertFormComponentExists('comments-section');});
要断言表单中不包含给定组件,请将组件的 key 传给 assertFormComponentDoesNotExist()
:
use function Pest\Livewire\livewire; it('does not have a conditional component', function () { livewire(CreatePost::class) ->assertFormComponentDoesNotExist('no-such-section');});
要检测组件是否存在以及是否传入给定的真值测试,你可以传递函数给 assertFormComponentExists()
的第二个参数,根据组件是否通过测试来返回 true 或 false:
use Filament\Forms\Components\Component; use function Pest\Livewire\livewire; test('comments section has heading' function () { livewire(EditPost::class) ->assertFormComponentExists( 'comments-section', function (Component $component): bool { return $component->getHeading() === 'Comments'; }, );});
如果你想要更多信息的测试结果,你可以在真值测试回调中嵌入一个断言:
use Filament\Forms\Components\Component;use Illuminate\Testing\Assert; use function Pest\Livewire\livewire; test('comments section is enabled' function () { livewire(EditPost::class) ->assertFormComponentExists( 'comments-section', function (Component $component): bool { Assert::assertTrue( $component->isEnabled(), 'Failed asserting that comments-section is enabled.', ); return true; }, );});
Wizard
要转到向导卡的下一步,请使用 goToNextWizardStep()
:
use function Pest\Livewire\livewire; it('moves to next wizard step', function () { livewire(CreatePost::class) ->goToNextWizardStep() ->assertHasFormErrors(['title']);});
你也可以调用 goToPreviousWizardStep()
转到上一步:
use function Pest\Livewire\livewire; it('moves to next wizard step', function () { livewire(CreatePost::class) ->goToPreviousWizardStep() ->assertHasFormErrors(['title']);});
如果要跳转到指定的步骤,请使用 goToWizardStep()
,然后是 assertWizardCurrentStep
方法,以确保你在没有上一步验证错误的情况下到达需要的步骤:
use function Pest\Livewire\livewire; it('moves to the wizards second step', function () { livewire(CreatePost::class) ->goToWizardStep(2) ->assertWizardCurrentStep(2);});
如果你在单个 Livewire 组件中有多个表单,任何的 wizard 测试 helper 都接受 formName
参数:
use function Pest\Livewire\livewire; it('moves to next wizard step only for fooForm', function () { livewire(CreatePost::class) ->goToNextWizardStep(formName: 'fooForm') ->assertHasFormErrors(['title'], formName: 'fooForm');});
Actions
你可以传递 Action 的表单组件名及 Action 名到 callFormComponentAction
中调用 Action:
use function Pest\Livewire\livewire; it('can send invoices', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->callFormComponentAction('customer_id', 'send'); expect($invoice->refresh()) ->isSent()->toBeTrue();});
使用 data
参数,传递数据数组给 Action:
use function Pest\Livewire\livewire; it('can send invoices', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->callFormComponentAction('customer_id', 'send', data: [ 'email' => $email = fake()->email(), ]) ->assertHasNoFormComponentActionErrors(); expect($invoice->refresh()) ->isSent()->toBeTrue() ->recipient_email->toBe($email);});
如果只需要设置 Action 的数据而不立即调用它,可以使用 setFormComponentActionData()
:
use function Pest\Livewire\livewire; it('can send invoices', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->mountFormComponentAction('customer_id', 'send') ->setFormComponentActionData('customer_id', 'send', data: [ 'email' => $email = fake()->email(), ])});
执行
要检测 Action 是否被中止,可以使用 assertFormComponentActionHalted()
:
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, ]) ->callFormComponentAction('customer_id', 'send') ->assertFormComponentActionHalted('customer_id', 'send');});
错误
assertHasNoFormComponentActionErrors()
用于断言提交 Action 表单没有出现验证错误。
使用 assertHasFormComponentActionErrors()
用于使用数据断言验证错误,类似于 Livewire
中的 assertHasErrors()
:
use function Pest\Livewire\livewire; it('can validate invoice recipient email', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->callFormComponentAction('customer_id', 'send', data: [ 'email' => Str::random(), ]) ->assertHasFormComponentActionErrors(['email' => ['email']]);});
要断言 Action 预装填数据,可以使用 assertFormComponentActionDataSet()
方法:
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, ]) ->mountFormComponentAction('customer_id', 'send') ->assertFormComponentActionDataSet([ 'email' => $recipientEmail, ]) ->callMountedFormComponentAction() ->assertHasNoFormComponentActionErrors(); expect($invoice->refresh()) ->isSent()->toBeTrue() ->recipient_email->toBe($recipientEmail);});
Action state
要断言 Action 存在于或者不在表单中,可以使用 assertFormComponentActionExists()
或 assertFormComponentActionDoesNotExist()
方法:
use function Pest\Livewire\livewire; it('can send but not unsend invoices', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionExists('customer_id', 'send') ->assertFormComponentActionDoesNotExist('customer_id', 'unsend');});
要断言 Action 对用户隐藏或可见,可以使用 assertFormComponentActionHidden()
或 assertFormComponentActionVisible()
方法:
use function Pest\Livewire\livewire; it('can only print customers', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionHidden('customer_id', 'send') ->assertFormComponentActionVisible('customer_id', 'print');});
要断言 Action 是对用户启用还是禁用,可以使用 assertFormComponentActionEnabled()
或 assertFormComponentActionDisabled()
方法:
use function Pest\Livewire\livewire; it('can only print a customer for a sent invoice', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionDisabled('customer_id', 'send') ->assertFormComponentActionEnabled('customer_id', 'print');});
要断言 Action 对某个用户隐藏,可以使用 assertFormComponentActionHidden()
方法:
use function Pest\Livewire\livewire; it('can not send invoices', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionHidden('customer_id', 'send');});
按钮外观
要断言 Action 的标签正确,可以使用 assertFormComponentActionHasLabel()
和 assertFormComponentActionDoesNotHaveLabel()
:
use function Pest\Livewire\livewire; it('send action has correct label', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionHasLabel('customer_id', 'send', 'Email Invoice') ->assertFormComponentActionDoesNotHaveLabel('customer_id', 'send', 'Send');});
要断言 Action 按钮的图标正确显示,可以使用 assertFormComponentActionHasIcon()
或 assertFormComponentActionDoesNotHaveIcon()
:
use function Pest\Livewire\livewire; it('when enabled the send button has correct icon', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionEnabled('customer_id', 'send') ->assertFormComponentActionHasIcon('customer_id', 'send', 'envelope-open') ->assertFormComponentActionDoesNotHaveIcon('customer_id', 'send', 'envelope');});
要断言 Action 按钮的颜色正确显示,可以使用 assertFormComponentActionHasColor()
或 assertFormComponentActionDoesNotHaveColor()
:
use function Pest\Livewire\livewire; it('actions display proper colors', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionHasColor('customer_id', 'delete', 'danger') ->assertFormComponentActionDoesNotHaveColor('customer_id', 'print', 'danger');});
URL
要断言 Action 的 URL 正确,可以使用 assertFormComponentActionHasUrl()
、assertFormComponentActionDoesNotHaveUrl()
、assertFormComponentActionShouldOpenUrlInNewTab()
和 assertFormComponentActionShouldNotOpenUrlInNewTab()
:
use function Pest\Livewire\livewire; it('links to the correct Filament sites', function () { $invoice = Invoice::factory()->create(); livewire(EditInvoice::class, [ 'invoice' => $invoice, ]) ->assertFormComponentActionHasUrl('customer_id', 'filament', 'https://filamentphp.com/') ->assertFormComponentActionDoesNotHaveUrl('customer_id', 'filament', 'https://github.com/filamentphp/filament') ->assertFormComponentActionShouldOpenUrlInNewTab('customer_id', 'filament') ->assertFormComponentActionShouldNotOpenUrlInNewTab('customer_id', 'github');});
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion