seed(RolePermissionSeeder::class); }); // ─── Helper ─────────────────────────────────────────────── function createActivityLogUserWithPermission(PermissionEnum ...$permissions): User { $user = User::factory()->create(); $user->givePermissionTo( array_merge( [PermissionEnum::DASHBOARD_VIEW->value], array_map(fn (PermissionEnum $p) => $p->value, $permissions) ) ); $user->forgetCachedPermissions(); return $user; } function createActivityLogs(User $causer, int $count = 3): void { for ($i = 0; $i < $count; $i++) { $category = Category::factory()->create(['name' => "Kategori {$i}"]); activity() ->causedBy($causer) ->performedOn($category) ->event('created') ->withProperties(['attributes' => ['name' => "Kategori {$i}"]]) ->log("Kategori {$i} ditambahkan"); } } // ─── Index ──────────────────────────────────────────────── describe('Activity Log Index', function () { test('authenticated user with permission can view activity log index', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); $this->actingAs($user) ->get(route('admin.system.activity_logs.index')) ->assertOk(); }); test('guest is redirected to login', function () { $this->get(route('admin.system.activity_logs.index')) ->assertRedirect(route('login')); }); test('user without permission is forbidden', function () { $user = User::factory()->create(); $this->actingAs($user) ->get(route('admin.system.activity_logs.index')) ->assertForbidden(); }); test('index displays activity logs', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); createActivityLogs($user, 3); $this->actingAs($user) ->get(route('admin.system.activity_logs.index')) ->assertOk(); }); test('index returns pagination data', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); createActivityLogs($user, 15); $this->actingAs($user) ->get(route('admin.system.activity_logs.index')) ->assertOk(); }); test('index can search activity logs by description', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); activity() ->causedBy($user) ->event('created') ->log('Produk baru ditambahkan'); activity() ->causedBy($user) ->event('updated') ->log('Supplier diperbarui'); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['search' => 'Produk'])) ->assertOk(); }); test('index can filter by event type', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); activity()->causedBy($user)->event('created')->log('Test created'); activity()->causedBy($user)->event('updated')->log('Test updated'); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['event' => 'created'])) ->assertOk(); }); test('index can filter by subject type', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); Category::factory()->create(); $user->update(['email' => 'new@example.com']); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['subject_type' => Category::class])) ->assertOk(); }); test('index can sort by created_at', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); createActivityLogs($user, 3); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['sort' => 'created_at', 'direction' => 'asc'])) ->assertOk(); }); test('index can sort by event', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); createActivityLogs($user, 3); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['sort' => 'event', 'direction' => 'desc'])) ->assertOk(); }); test('index can sort by description', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); createActivityLogs($user, 3); $this->actingAs($user) ->get(route('admin.system.activity_logs.index', ['sort' => 'description', 'direction' => 'asc'])) ->assertOk(); }); }); // ─── Activity Log Creation via Model ────────────────────── describe('Activity Log Creation', function () { test('activity log is created when category is created', function () { $user = createActivityLogUserWithPermission(PermissionEnum::CATEGORIES_VIEW, PermissionEnum::CATEGORIES_CREATE); $this->actingAs($user) ->post(route('admin.master.categories.store'), [ 'name' => 'Test Kategori', ]); $this->assertDatabaseHas('activity_log', [ 'event' => 'created', 'subject_type' => Category::class, ]); }); test('activity log is created when category is updated', function () { $user = createActivityLogUserWithPermission(PermissionEnum::CATEGORIES_VIEW, PermissionEnum::CATEGORIES_UPDATE); $category = Category::factory()->create(); $this->actingAs($user) ->put(route('admin.master.categories.update', $category), [ 'name' => 'Updated Name', ]); $this->assertDatabaseHas('activity_log', [ 'event' => 'updated', 'subject_type' => Category::class, 'subject_id' => $category->id, ]); }); test('activity log is created when category is deleted', function () { $user = createActivityLogUserWithPermission(PermissionEnum::CATEGORIES_VIEW, PermissionEnum::CATEGORIES_DELETE); $category = Category::factory()->create(); $this->actingAs($user) ->delete(route('admin.master.categories.destroy', $category)); $this->assertDatabaseHas('activity_log', [ 'event' => 'deleted', 'subject_type' => Category::class, 'subject_id' => $category->id, ]); }); test('activity log stores causer information', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); activity() ->causedBy($user) ->event('created') ->log('Test log entry'); $activity = Activity::latest()->first(); expect($activity->causer_type)->toBe(User::class); expect($activity->causer_id)->toBe($user->id); }); test('activity log stores properties correctly', function () { $user = createActivityLogUserWithPermission(PermissionEnum::ACTIVITY_LOGS_VIEW); activity() ->causedBy($user) ->event('updated') ->withProperties([ 'attributes' => ['name' => 'New Value'], 'old' => ['name' => 'Old Value'], ]) ->log('Test with properties'); $activity = Activity::latest()->first(); expect($activity->properties->get('attributes')['name'])->toBe('New Value'); expect($activity->properties->get('old')['name'])->toBe('Old Value'); }); });