Add tests for AdminActivityListener

This commit is contained in:
Lance Pioch
2026-02-07 09:21:10 -05:00
parent 67e13c646a
commit bdf8a9151c

View File

@@ -0,0 +1,146 @@
<?php
use App\Events\ActivityLogged;
use App\Filament\Admin\Resources\Eggs\Pages\CreateEgg;
use App\Filament\Admin\Resources\Eggs\Pages\EditEgg;
use App\Filament\Admin\Resources\Nodes\Pages\CreateNode;
use App\Filament\Admin\Resources\Nodes\Pages\EditNode;
use App\Listeners\AdminActivityListener;
use App\Models\Egg;
use App\Models\Node;
use App\Models\Role;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Event;
function pageInstance(string $class): object
{
return (new ReflectionClass($class))->newInstanceWithoutConstructor();
}
beforeEach(function () {
[$this->admin] = generateTestAccount([]);
$this->admin = $this->admin->syncRoles(Role::getRootAdmin());
$this->actingAs($this->admin);
Filament::setCurrentPanel('admin');
});
it('logs create activity for an egg', function () {
$egg = Egg::first();
$listener = new AdminActivityListener();
$listener->handle($egg, ['name' => 'Test Egg'], pageInstance(CreateEgg::class));
$this->assertActivityLogged('admin:egg.create');
});
it('logs update activity for an egg', function () {
$egg = Egg::first();
$listener = new AdminActivityListener();
$listener->handle($egg, ['name' => 'Updated Egg'], pageInstance(EditEgg::class));
$this->assertActivityLogged('admin:egg.update');
});
it('logs create activity for a node', function () {
$node = Node::first();
$listener = new AdminActivityListener();
$listener->handle($node, ['name' => 'Test Node'], pageInstance(CreateNode::class));
$this->assertActivityLogged('admin:node.create');
});
it('logs update activity for a node', function () {
$node = Node::first();
$listener = new AdminActivityListener();
$listener->handle($node, ['name' => 'Updated Node'], pageInstance(EditNode::class));
$this->assertActivityLogged('admin:node.update');
});
it('does not log activity for non-admin panels', function () {
Filament::setCurrentPanel('app');
$egg = Egg::first();
$listener = new AdminActivityListener();
$listener->handle($egg, ['name' => 'Test'], pageInstance(CreateEgg::class));
Event::assertNotDispatched(ActivityLogged::class);
});
it('sets the record as the activity subject', function () {
$egg = Egg::first();
$listener = new AdminActivityListener();
$listener->handle($egg, ['name' => 'Test'], pageInstance(CreateEgg::class));
$this->assertActivityFor('admin:egg.create', $this->admin, $egg);
});
it('redacts sensitive fields from activity properties', function () {
$egg = Egg::first();
$data = [
'name' => 'Visible',
'password' => 'should-be-redacted',
'password_confirmation' => 'should-be-redacted',
'token' => 'should-be-redacted',
'secret' => 'should-be-redacted',
'api_key' => 'should-be-redacted',
];
$listener = new AdminActivityListener();
$listener->handle($egg, $data, pageInstance(EditEgg::class));
Event::assertDispatched(ActivityLogged::class, function (ActivityLogged $event) {
$properties = $event->model->properties;
expect($properties)->toHaveKey('name', 'Visible')
->not->toHaveKey('password')
->not->toHaveKey('password_confirmation')
->not->toHaveKey('token')
->not->toHaveKey('secret')
->not->toHaveKey('api_key');
return true;
});
});
it('redacts sensitive fields in nested arrays', function () {
$egg = Egg::first();
$data = [
'name' => 'Visible',
'nested' => [
'safe' => 'value',
'password' => 'should-be-redacted',
'token' => 'should-be-redacted',
],
];
$listener = new AdminActivityListener();
$listener->handle($egg, $data, pageInstance(EditEgg::class));
Event::assertDispatched(ActivityLogged::class, function (ActivityLogged $event) {
$properties = $event->model->properties;
expect($properties['nested'])->toHaveKey('safe', 'value')
->not->toHaveKey('password')
->not->toHaveKey('token');
return true;
});
});
it('generates kebab-case event names from model class names', function () {
$node = Node::first();
$listener = new AdminActivityListener();
$listener->handle($node, ['name' => 'Test'], pageInstance(CreateNode::class));
$this->assertActivityLogged('admin:node.create');
});