actingAs($manager); Filament::setTenant($tenant, true); $findings = Finding::factory() ->count(101) ->for($tenant) ->create([ 'status' => Finding::STATUS_NEW, 'triaged_at' => null, ]); Livewire::test(ListFindings::class) ->callTableBulkAction('triage_selected', $findings) ->assertHasNoTableBulkActionErrors(); $findings->each(fn (Finding $finding) => expect($finding->refresh()->status)->toBe(Finding::STATUS_TRIAGED)); expect(AuditLog::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('action', 'finding.triaged') ->count())->toBe(101); $assignee = User::factory()->create(); createUserWithTenant(tenant: $tenant, user: $assignee, role: 'operator'); $assignFindings = Finding::factory() ->count(3) ->for($tenant) ->create([ 'status' => Finding::STATUS_TRIAGED, 'assignee_user_id' => null, 'owner_user_id' => null, ]); Livewire::test(ListFindings::class) ->callTableBulkAction('assign_selected', $assignFindings, data: [ 'assignee_user_id' => (int) $assignee->getKey(), 'owner_user_id' => (int) $manager->getKey(), ]) ->assertHasNoTableBulkActionErrors(); $assignFindings->each(function (Finding $finding) use ($assignee, $manager): void { $finding->refresh(); expect((int) $finding->assignee_user_id)->toBe((int) $assignee->getKey()) ->and((int) $finding->owner_user_id)->toBe((int) $manager->getKey()); }); expect(AuditLog::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('action', 'finding.assigned') ->count())->toBe(3); $resolveFindings = Finding::factory() ->count(2) ->for($tenant) ->create([ 'status' => Finding::STATUS_IN_PROGRESS, 'resolved_at' => null, 'resolved_reason' => null, ]); Livewire::test(ListFindings::class) ->callTableBulkAction('resolve_selected', $resolveFindings, data: [ 'resolved_reason' => 'fixed', ]) ->assertHasNoTableBulkActionErrors(); $resolveFindings->each(function (Finding $finding): void { $finding->refresh(); expect($finding->status)->toBe(Finding::STATUS_RESOLVED) ->and($finding->resolved_reason)->toBe('fixed') ->and($finding->resolved_at)->not->toBeNull(); }); expect(AuditLog::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('action', 'finding.resolved') ->count())->toBe(2); $closeFindings = Finding::factory() ->count(2) ->for($tenant) ->create([ 'status' => Finding::STATUS_TRIAGED, 'closed_at' => null, 'closed_reason' => null, ]); Livewire::test(ListFindings::class) ->callTableBulkAction('close_selected', $closeFindings, data: [ 'closed_reason' => 'not applicable', ]) ->assertHasNoTableBulkActionErrors(); $closeFindings->each(function (Finding $finding): void { $finding->refresh(); expect($finding->status)->toBe(Finding::STATUS_CLOSED) ->and($finding->closed_reason)->toBe('not applicable') ->and($finding->closed_at)->not->toBeNull() ->and($finding->closed_by_user_id)->not->toBeNull(); }); expect(AuditLog::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('action', 'finding.closed') ->count())->toBe(2); $riskFindings = Finding::factory() ->count(2) ->for($tenant) ->create([ 'status' => Finding::STATUS_TRIAGED, 'closed_at' => null, 'closed_reason' => null, ]); Livewire::test(ListFindings::class) ->callTableBulkAction('risk_accept_selected', $riskFindings, data: [ 'closed_reason' => 'accepted risk', ]) ->assertHasNoTableBulkActionErrors(); $riskFindings->each(function (Finding $finding): void { $finding->refresh(); expect($finding->status)->toBe(Finding::STATUS_RISK_ACCEPTED) ->and($finding->closed_reason)->toBe('accepted risk') ->and($finding->closed_at)->not->toBeNull() ->and($finding->closed_by_user_id)->not->toBeNull(); }); expect(AuditLog::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('action', 'finding.risk_accepted') ->count())->toBe(2); });