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']);
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']);
检查列是否存在,实际尝试渲染该列的数据验证列的渲染逻辑是否正常工作。可以发现渲染过程中的潜在问题,更全面但执行速度较慢。

列的排序

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

增删改查测试

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

测试增、删、改时,对应的组件分别是 CreatePostDeleteActionEditPost

创建

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