cmplete story 4.1 with qa tests
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\TimelineStatus;
|
||||
use App\Models\AdminLog;
|
||||
use App\Models\Timeline;
|
||||
use App\Models\User;
|
||||
use Livewire\Volt\Volt;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->admin = User::factory()->admin()->create();
|
||||
});
|
||||
|
||||
// ===========================================
|
||||
// Happy Path Tests
|
||||
// ===========================================
|
||||
|
||||
test('admin can view timeline creation form', function () {
|
||||
$this->actingAs($this->admin)
|
||||
->get(route('admin.timelines.create'))
|
||||
->assertOk();
|
||||
});
|
||||
|
||||
test('admin can search clients by name', function () {
|
||||
$client = User::factory()->individual()->create(['full_name' => 'John Doe']);
|
||||
User::factory()->individual()->create(['full_name' => 'Jane Smith']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'John');
|
||||
|
||||
expect($component->get('clients'))->toHaveCount(1);
|
||||
expect($component->get('clients')->first()->full_name)->toBe('John Doe');
|
||||
});
|
||||
|
||||
test('admin can search clients by email', function () {
|
||||
$client = User::factory()->individual()->create([
|
||||
'full_name' => 'John Doe',
|
||||
'email' => 'john@example.com',
|
||||
]);
|
||||
User::factory()->individual()->create([
|
||||
'full_name' => 'Jane Smith',
|
||||
'email' => 'jane@example.com',
|
||||
]);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'john@');
|
||||
|
||||
expect($component->get('clients'))->toHaveCount(1);
|
||||
expect($component->get('clients')->first()->email)->toBe('john@example.com');
|
||||
});
|
||||
|
||||
test('admin can create timeline with required fields', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->call('create')
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect(route('admin.dashboard'));
|
||||
|
||||
expect(Timeline::where('case_name', 'Test Case')->exists())->toBeTrue();
|
||||
|
||||
$timeline = Timeline::where('case_name', 'Test Case')->first();
|
||||
expect($timeline->user_id)->toBe($client->id);
|
||||
expect($timeline->status)->toBe(TimelineStatus::Active);
|
||||
expect($timeline->case_reference)->toBeNull();
|
||||
});
|
||||
|
||||
test('admin can create timeline with case reference', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->set('caseReference', 'REF-001')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$timeline = Timeline::where('case_name', 'Test Case')->first();
|
||||
expect($timeline->case_reference)->toBe('REF-001');
|
||||
});
|
||||
|
||||
test('initial notes creates first timeline update', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->set('initialNotes', 'Initial case notes here')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$timeline = Timeline::where('case_name', 'Test Case')->first();
|
||||
expect($timeline->updates)->toHaveCount(1);
|
||||
|
||||
$update = $timeline->updates->first();
|
||||
expect($update->update_text)->toBe('Initial case notes here');
|
||||
expect($update->admin_id)->toBe($this->admin->id);
|
||||
});
|
||||
|
||||
test('audit log created on timeline creation', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
expect(AdminLog::where('action', 'create')
|
||||
->where('target_type', 'timeline')
|
||||
->where('admin_id', $this->admin->id)
|
||||
->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
// ===========================================
|
||||
// Validation Tests
|
||||
// ===========================================
|
||||
|
||||
test('case name is required', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', '')
|
||||
->call('create')
|
||||
->assertHasErrors(['caseName' => 'required']);
|
||||
});
|
||||
|
||||
test('case reference must be unique', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
Timeline::factory()->create(['case_reference' => 'REF-001']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->set('caseReference', 'REF-001')
|
||||
->call('create')
|
||||
->assertHasErrors(['caseReference' => 'unique']);
|
||||
});
|
||||
|
||||
test('case reference allows multiple nulls', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
// Create a timeline without case_reference
|
||||
Timeline::factory()->create([
|
||||
'user_id' => $client->id,
|
||||
'case_reference' => null,
|
||||
]);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
// Creating another timeline without case_reference should succeed
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->set('caseReference', '')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
expect(Timeline::where('user_id', $client->id)->whereNull('case_reference')->count())->toBe(2);
|
||||
});
|
||||
|
||||
test('client selection is required', function () {
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('caseName', 'Test Case')
|
||||
->call('create')
|
||||
->assertHasErrors(['selectedUserId' => 'required']);
|
||||
});
|
||||
|
||||
test('selected client must exist', function () {
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', 99999)
|
||||
->set('caseName', 'Test Case')
|
||||
->call('create')
|
||||
->assertHasErrors(['selectedUserId' => 'exists']);
|
||||
});
|
||||
|
||||
// ===========================================
|
||||
// Authorization Tests
|
||||
// ===========================================
|
||||
|
||||
test('non-admin cannot access timeline creation', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($client)
|
||||
->get(route('admin.timelines.create'))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('guest cannot access timeline creation', function () {
|
||||
$this->get(route('admin.timelines.create'))
|
||||
->assertRedirect(route('login'));
|
||||
});
|
||||
|
||||
// ===========================================
|
||||
// Edge Case Tests
|
||||
// ===========================================
|
||||
|
||||
test('search only returns individual and company users', function () {
|
||||
$individualClient = User::factory()->individual()->create(['full_name' => 'Individual Client']);
|
||||
$companyClient = User::factory()->company()->create(['full_name' => 'Company Client']);
|
||||
$adminUser = User::factory()->admin()->create(['full_name' => 'Admin User']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'Client');
|
||||
|
||||
$clientNames = $component->get('clients')->pluck('full_name')->toArray();
|
||||
|
||||
expect($clientNames)->toContain('Individual Client');
|
||||
expect($clientNames)->toContain('Company Client');
|
||||
expect($clientNames)->not->toContain('Admin User');
|
||||
});
|
||||
|
||||
test('search only returns active users', function () {
|
||||
$activeClient = User::factory()->individual()->create(['full_name' => 'Active Client']);
|
||||
$deactivatedClient = User::factory()->individual()->deactivated()->create(['full_name' => 'Deactivated Client']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'Client');
|
||||
|
||||
$clientNames = $component->get('clients')->pluck('full_name')->toArray();
|
||||
|
||||
expect($clientNames)->toContain('Active Client');
|
||||
expect($clientNames)->not->toContain('Deactivated Client');
|
||||
});
|
||||
|
||||
test('can create multiple timelines for same client', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
// Create first timeline
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'First Case')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
// Create second timeline for same client
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Second Case')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
expect(Timeline::where('user_id', $client->id)->count())->toBe(2);
|
||||
});
|
||||
|
||||
// ===========================================
|
||||
// Additional Tests
|
||||
// ===========================================
|
||||
|
||||
test('search requires at least 2 characters', function () {
|
||||
User::factory()->individual()->create(['full_name' => 'John Doe']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'J');
|
||||
|
||||
expect($component->get('clients'))->toHaveCount(0);
|
||||
|
||||
$component->set('search', 'Jo');
|
||||
expect($component->get('clients'))->toHaveCount(1);
|
||||
});
|
||||
|
||||
test('selecting user sets search to user name', function () {
|
||||
$client = User::factory()->individual()->create(['full_name' => 'John Doe']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->set('search', 'John')
|
||||
->call('selectUser', $client->id);
|
||||
|
||||
expect($component->get('selectedUserId'))->toBe($client->id);
|
||||
expect($component->get('search'))->toBe('John Doe');
|
||||
});
|
||||
|
||||
test('clearing selection resets user and search', function () {
|
||||
$client = User::factory()->individual()->create(['full_name' => 'John Doe']);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
$component = Volt::test('admin.timelines.create')
|
||||
->call('selectUser', $client->id)
|
||||
->call('clearSelection');
|
||||
|
||||
expect($component->get('selectedUserId'))->toBeNull();
|
||||
expect($component->get('selectedUser'))->toBeNull();
|
||||
expect($component->get('search'))->toBe('');
|
||||
});
|
||||
|
||||
test('timeline without initial notes has no updates', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->set('initialNotes', '')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$timeline = Timeline::where('case_name', 'Test Case')->first();
|
||||
expect($timeline->updates)->toHaveCount(0);
|
||||
});
|
||||
|
||||
test('timeline status defaults to active', function () {
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
|
||||
Volt::test('admin.timelines.create')
|
||||
->set('selectedUserId', $client->id)
|
||||
->call('selectUser', $client->id)
|
||||
->set('caseName', 'Test Case')
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$timeline = Timeline::where('case_name', 'Test Case')->first();
|
||||
expect($timeline->status)->toBe(TimelineStatus::Active);
|
||||
});
|
||||
Reference in New Issue
Block a user