327 lines
9.7 KiB
PHP
327 lines
9.7 KiB
PHP
<?php
|
|
|
|
use App\Models\AdminLog;
|
|
use App\Models\User;
|
|
use Livewire\Volt\Volt;
|
|
|
|
beforeEach(function () {
|
|
$this->admin = User::factory()->admin()->create();
|
|
});
|
|
|
|
// ===========================================
|
|
// Authentication Tests
|
|
// ===========================================
|
|
|
|
test('audit log page requires admin authentication', function () {
|
|
$this->get(route('admin.audit-logs'))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('client cannot access audit logs page', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($client)
|
|
->get(route('admin.audit-logs'))
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('audit log page loads for admin', function () {
|
|
$this->actingAs($this->admin)
|
|
->get(route('admin.audit-logs'))
|
|
->assertOk()
|
|
->assertSeeLivewire('admin.audit-logs');
|
|
});
|
|
|
|
// ===========================================
|
|
// Display Tests
|
|
// ===========================================
|
|
|
|
test('audit logs display in table', function () {
|
|
AdminLog::factory()->count(5)->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->assertSee(__('audit.timestamp'))
|
|
->assertSee(__('audit.admin'))
|
|
->assertSee(__('audit.action'));
|
|
});
|
|
|
|
test('displays empty state when no logs exist', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->assertSee(__('audit.no_logs_found'));
|
|
});
|
|
|
|
test('pagination works correctly with 25 items per page', function () {
|
|
AdminLog::factory()->count(50)->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->assertViewHas('logs', fn ($logs) => $logs->count() === 25);
|
|
});
|
|
|
|
test('logs are sorted by created_at descending', function () {
|
|
$oldLog = AdminLog::factory()->create(['created_at' => now()->subDays(5)]);
|
|
$newLog = AdminLog::factory()->create(['created_at' => now()]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs');
|
|
|
|
$logs = $component->viewData('logs');
|
|
expect($logs->first()->id)->toBe($newLog->id);
|
|
});
|
|
|
|
test('displays system for logs without admin', function () {
|
|
AdminLog::factory()->create(['admin_id' => null]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->assertSee(__('audit.system'));
|
|
});
|
|
|
|
// ===========================================
|
|
// Filter Tests
|
|
// ===========================================
|
|
|
|
test('can filter by action type', function () {
|
|
AdminLog::factory()->create(['action' => 'create']);
|
|
AdminLog::factory()->create(['action' => 'delete']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('actionFilter', 'create')
|
|
->assertViewHas('logs', fn ($logs) => $logs->every(fn ($log) => $log->action === 'create'));
|
|
});
|
|
|
|
test('can filter by target type', function () {
|
|
AdminLog::factory()->create(['target_type' => 'user']);
|
|
AdminLog::factory()->create(['target_type' => 'consultation']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('targetFilter', 'user')
|
|
->assertViewHas('logs', fn ($logs) => $logs->every(fn ($log) => $log->target_type === 'user'));
|
|
});
|
|
|
|
test('can filter by date range', function () {
|
|
AdminLog::factory()->create(['created_at' => now()->subDays(10)]);
|
|
AdminLog::factory()->create(['created_at' => now()]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('dateFrom', now()->subDays(5)->format('Y-m-d'))
|
|
->set('dateTo', now()->format('Y-m-d'))
|
|
->assertViewHas('logs', fn ($logs) => $logs->count() === 1);
|
|
});
|
|
|
|
test('can search by target id', function () {
|
|
AdminLog::factory()->create(['target_id' => 123]);
|
|
AdminLog::factory()->create(['target_id' => 456]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('search', '123')
|
|
->assertViewHas('logs', fn ($logs) => $logs->count() === 1 && $logs->first()->target_id === 123);
|
|
});
|
|
|
|
test('reset filters clears all filters', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('actionFilter', 'create')
|
|
->set('targetFilter', 'user')
|
|
->set('dateFrom', '2024-01-01')
|
|
->set('dateTo', '2024-12-31')
|
|
->set('search', '123')
|
|
->call('resetFilters')
|
|
->assertSet('actionFilter', '')
|
|
->assertSet('targetFilter', '')
|
|
->assertSet('dateFrom', '')
|
|
->assertSet('dateTo', '')
|
|
->assertSet('search', '');
|
|
});
|
|
|
|
test('filters reset pagination', function () {
|
|
AdminLog::factory()->count(30)->create(['action' => 'create']);
|
|
AdminLog::factory()->count(30)->create(['action' => 'delete']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs')
|
|
->call('gotoPage', 2)
|
|
->set('actionFilter', 'create');
|
|
|
|
// After setting filter, should be back to page 1
|
|
$logs = $component->viewData('logs');
|
|
expect($logs->currentPage())->toBe(1);
|
|
});
|
|
|
|
test('displays empty state when filters return no results', function () {
|
|
AdminLog::factory()->create(['action' => 'create']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->set('actionFilter', 'delete')
|
|
->assertSee(__('audit.no_results'));
|
|
});
|
|
|
|
// ===========================================
|
|
// Modal Tests
|
|
// ===========================================
|
|
|
|
test('can view log details in modal', function () {
|
|
$log = AdminLog::factory()->create([
|
|
'old_values' => ['name' => 'Old Name'],
|
|
'new_values' => ['name' => 'New Name'],
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->call('showDetails', $log->id)
|
|
->assertSet('selectedLogId', $log->id)
|
|
->assertDispatched('open-modal', name: 'log-details');
|
|
});
|
|
|
|
test('selected log is loaded with admin relation', function () {
|
|
$log = AdminLog::factory()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs')
|
|
->call('showDetails', $log->id);
|
|
|
|
$selectedLog = $component->viewData('selectedLog');
|
|
expect($selectedLog)->not->toBeNull();
|
|
expect($selectedLog->id)->toBe($log->id);
|
|
});
|
|
|
|
test('modal displays old and new values', function () {
|
|
$log = AdminLog::factory()->create([
|
|
'old_values' => ['status' => 'pending'],
|
|
'new_values' => ['status' => 'approved'],
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs')
|
|
->call('showDetails', $log->id);
|
|
|
|
$selectedLog = $component->viewData('selectedLog');
|
|
expect($selectedLog->old_values)->toBe(['status' => 'pending']);
|
|
expect($selectedLog->new_values)->toBe(['status' => 'approved']);
|
|
});
|
|
|
|
test('can close modal', function () {
|
|
$log = AdminLog::factory()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->call('showDetails', $log->id)
|
|
->assertSet('selectedLogId', $log->id)
|
|
->call('closeModal')
|
|
->assertSet('selectedLogId', null)
|
|
->assertDispatched('close-modal', name: 'log-details');
|
|
});
|
|
|
|
// ===========================================
|
|
// CSV Export Tests
|
|
// ===========================================
|
|
|
|
test('can export filtered logs to csv', function () {
|
|
AdminLog::factory()->count(3)->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.audit-logs')
|
|
->call('exportCsv')
|
|
->assertFileDownloaded();
|
|
});
|
|
|
|
test('csv export respects filters', function () {
|
|
AdminLog::factory()->count(3)->create(['action' => 'create']);
|
|
AdminLog::factory()->count(2)->create(['action' => 'delete']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
// Set filter before export
|
|
$component = Volt::test('admin.audit-logs')
|
|
->set('actionFilter', 'create');
|
|
|
|
// Export is tested by checking it doesn't error and downloads
|
|
$component->call('exportCsv')
|
|
->assertFileDownloaded();
|
|
});
|
|
|
|
test('csv filename includes current date', function () {
|
|
AdminLog::factory()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$response = Volt::test('admin.audit-logs')
|
|
->call('exportCsv');
|
|
|
|
// The response should be a StreamedResponse
|
|
$response->assertFileDownloaded('audit-log-'.now()->format('Y-m-d').'.csv');
|
|
});
|
|
|
|
// ===========================================
|
|
// Action Types and Target Types
|
|
// ===========================================
|
|
|
|
test('action types are populated from database', function () {
|
|
AdminLog::factory()->create(['action' => 'create']);
|
|
AdminLog::factory()->create(['action' => 'update']);
|
|
AdminLog::factory()->create(['action' => 'delete']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs');
|
|
|
|
$actionTypes = $component->viewData('actionTypes');
|
|
expect($actionTypes)->toContain('create', 'update', 'delete');
|
|
});
|
|
|
|
test('target types are populated from database', function () {
|
|
AdminLog::factory()->create(['target_type' => 'user']);
|
|
AdminLog::factory()->create(['target_type' => 'consultation']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.audit-logs');
|
|
|
|
$targetTypes = $component->viewData('targetTypes');
|
|
expect($targetTypes)->toContain('user', 'consultation');
|
|
});
|
|
|
|
// ===========================================
|
|
// Locale-specific Tests
|
|
// ===========================================
|
|
|
|
test('timestamp format changes based on locale', function () {
|
|
$log = AdminLog::factory()->create(['created_at' => '2024-06-15 10:30:00']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
// English locale shows m/d/Y format
|
|
app()->setLocale('en');
|
|
Volt::test('admin.audit-logs')
|
|
->assertSee('06/15/2024');
|
|
|
|
// Arabic locale shows d/m/Y format
|
|
app()->setLocale('ar');
|
|
Volt::test('admin.audit-logs')
|
|
->assertSee('15/06/2024');
|
|
});
|