戏里戏外

FilamentPHP 资源测试

2024-11-12#Testing#Filament

测试框架使用 Pest 测试框架,它提供了一个更优雅的测试语法。

页面渲染

首先,需要测试各个页面是否能够正确渲染:

use App\Models\Post;
use App\Filament\Resources\PostResource\Pages\EditPost;
use App\Filament\Resources\PostResource\Pages\CreatePost;
use App\Filament\Resources\PostResource\Pages\ListPosts;

use function Pest\Livewire\livewire;

it('can render the index page', function () {
	livewire(ListPosts::class)->assertOk();
});

it('can render the create page', function () {
	livewire(CreatePost::class)->assertOk();
});

it('can render the edit page', function () {
	$record = Post::factory()->create();

	livewire(EditPost::class, ['record' => $record->getRouteKey()])
			->assertOk();
});

表格功能测试

列的存在性

使用 assertTableColumnExists 方法断言表格存在对应列,它仅检查列是否在表格定义中存在。

<?php
use App\Filament\Resources\PostResource\Pages\ListPosts;

it('has column', function (string $column) {
	livewire(ListPosts::class)
		->assertTableColumnExists($column);
})->with(['name', 'description', 'body', 'cover', 'status', 'created_at', 'updated_at']);
TIP

assertTableColumnExists 断言只检查列是否在表格的配置中定义,不会实际尝试渲染该列。

它的速度相比下面列的渲染断言 assertCanRenderTableColumn 方法较快,因为只是检查配置适用于确认列的存在性。

列的渲染

使用 assertCanRenderTableColumn 断言方法检查列是否可以实际渲染数据。

<?php
use App\Filament\Resources\PostResource\Pages\ListPosts;

it('can render column', function (string $column) {
	livewire(ListPosts::class)
		->assertCanRenderTableColumn($column);
})->with(['name', 'description', 'cover', 'status', 'created_at', 'updated_at']);
WARNING

检查列是否存在,实际尝试渲染该列的数据验证列的渲染逻辑是否正常工作。

可以发现渲染过程中的潜在问题,更全面但执行速度较慢。

列的排序

use App\Models\Post;
use App\Filament\Resources\PostResource\Pages\ListPosts;

it('can sort column', function (string $column) {
	$records = Post::factory(5)->create();

	livewire(ListPosts::class)
		->sortTable($column)
		->assertCanSeeTableRecords($records->sortBy($column), inOrder: true)
		->sortTable($column, 'desc')
		->assertCanSeeTableRecords($records->sortByDesc($column), inOrder: true);
})->with(['name', 'status', 'created_at', 'updated_at']);

列的搜索

use App\Models\Post;
use App\Filament\Resources\PostResource\Pages\ListPosts;

it('can search column', function (string $column) {
	$records = Post::factory(5)->create();

	$search = data_get($records->first(), $column);

	livewire(ListPosts::class)
		->searchTable($search instanceof BackedEnum ? $search->value : $search)
		->assertCanSeeTableRecords($records->filter(fn (Post $record) => data_get($record, $column) === $search));
})->with(['name', 'description', 'body']);

增删改查测试

分别测试新增资源、编辑资源、删除资源和批量删除资源的操作。

创建

use App\Models\Post;
use App\Filament\Resources\PostResource\Pages\CreatePost;

it('can create a post', function () {
	$record = Post::factory()->make();

	livewire(CreatePost::class)
		->fillForm([
			'name' => $record->name,
			'description' => $record->description,
			'cover' => $record->cover,
			'body' => $record->body,
			'status' => $record->status,
		])
		->assertActionExists('create')
		->call('create')
		->assertHasNoFormErrors();

	$this->assertDatabaseHas(Post::class, [
		'name' => $record->name,
		'description' => $record->description,
		'cover' => $record->cover,
		'body' => $record->body,
		'status' => $record->status,
	]);
});

更新

use App\Models\Post;
use App\Filament\Resources\PostResource\Pages\EditPost;

it('can update a post', function () {
	$record = Post::factory()->create();
	$newRecord = Post::factory()->make();

	livewire(EditPost::class, ['record' => $record->getRouteKey()])
		->fillForm([
			'name' => $newRecord->name,
			'description' => $record->description,
			'cover' => $record->cover,
			'body' => $record->body,
			'status' => $record->status,
		])
		->assertActionExists('save')
		->call('save')
		->assertHasNoFormErrors();

	$this->assertDatabaseHas(Post::class, [
		'name' => $newRecord->name,
		'description' => $record->description,
		'cover' => $record->cover,
		'body' => $record->body,
		'status' => $record->status,
	]);
});

删除

use App\Models\Post;
use Filament\Actions\DeleteAction;

it('can delete a post', function () {
	$record = Post::factory()->create();

	livewire(EditPost::class, ['record' => $record->getRouteKey()])
		->assertActionExists('delete')
		->callAction(DeleteAction::class);

	$this->assertModelMissing($record);
});

批量删除

use App\Models\Post;
use Filament\Tables\Actions\DeleteBulkAction;

it('can bulk delete posts', function () {
	$records = Post::factory(5)->create();

	livewire(ListCompanies::class)
		->assertTableBulkActionExists('delete')
		->callTableBulkAction(DeleteBulkAction::class, $records);

  $records->each(fn ($record) => $this->assertModelMissing($record));
});

验证测试

required

<?php

use App\Models\Post;
use Illuminate\Support\Str;
use App\Filament\Resources\PostResource\Pages\CreatePost;

it('can validate required', function (string $column) {
	livewire(CreatePost::class)
		->fillForm([$column => null])
		->assertActionExists('create')
		->call('create')
		->assertHasFormErrors([$column => ['required']]);
})->with(['name', 'cover', 'body', 'status']);

max

it('can validate max length', function (string $column) {
	livewire(CreatePost::class)
		->fillForm([$column => Str::random(256)])
		->assertActionExists('create')
		->call('create')
		->assertHasFormErrors([$column => ['max:255']]);
})->with(['name', 'description']);

enum

it('can validate status enum', function () {
	$record = Post::factory()->make();

	livewire(CreatePost::class)
		->fillForm([
			'name' => $record->name,
			'description' => $record->description,
			'cover' => $record->cover,
			'body' => $record->body,
			'status' => 'invalid-status',
		])
		->assertActionExists('create')
		->call('create')
		->assertHasFormErrors([
				'status' => ['Illuminate\Validation\Rules\Enum'],
		]);
});