individual()->create(); Timeline::factory()->count(3)->create(['user_id' => $client->id]); $this->actingAs($client) ->get(route('client.timelines.index')) ->assertOk(); }); test('client cannot view other clients timelines in list', function () { $client = User::factory()->individual()->create(); $otherClient = User::factory()->individual()->create(); Timeline::factory()->create([ 'user_id' => $otherClient->id, 'case_name' => 'Other Client Case', ]); $this->actingAs($client); Volt::test('client.timelines.index') ->assertDontSee('Other Client Case'); }); test('client can view own timeline detail', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create([ 'user_id' => $client->id, 'case_name' => 'My Contract Case', ]); $this->actingAs($client) ->get(route('client.timelines.show', $timeline)) ->assertOk() ->assertSee('My Contract Case'); }); test('client cannot view other clients timeline detail', function () { $client = User::factory()->individual()->create(); $otherClient = User::factory()->individual()->create(); $otherTimeline = Timeline::factory()->create(['user_id' => $otherClient->id]); $this->actingAs($client) ->get(route('client.timelines.show', $otherTimeline)) ->assertForbidden(); }); test('guest cannot access timelines', function () { $this->get(route('client.timelines.index')) ->assertRedirect(route('login')); }); test('admin cannot access client timeline routes', function () { $admin = User::factory()->admin()->create(); $this->actingAs($admin) ->get(route('client.timelines.index')) ->assertForbidden(); }); // List View Tests test('active timelines displayed separately from archived', function () { $client = User::factory()->individual()->create(); Timeline::factory()->create([ 'user_id' => $client->id, 'case_name' => 'Active Case', 'status' => 'active', ]); Timeline::factory()->create([ 'user_id' => $client->id, 'case_name' => 'Archived Case', 'status' => 'archived', ]); $this->actingAs($client); Volt::test('client.timelines.index') ->assertSee('Active Case') ->assertSee('Archived Case') ->assertSeeInOrder([__('client.active_cases'), 'Active Case', __('client.archived_cases'), 'Archived Case']); }); test('timeline list shows update count', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create(['user_id' => $client->id]); TimelineUpdate::factory()->count(5)->create(['timeline_id' => $timeline->id]); $this->actingAs($client); Volt::test('client.timelines.index') ->assertSee('5'); }); test('empty state shown when no timelines', function () { $client = User::factory()->individual()->create(); $this->actingAs($client); Volt::test('client.timelines.index') ->assertSee(__('client.no_cases_yet')); }); // Detail View Tests test('timeline detail shows all updates chronologically', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create(['user_id' => $client->id]); TimelineUpdate::factory()->create([ 'timeline_id' => $timeline->id, 'update_text' => 'First Update', 'created_at' => now()->subDays(2), ]); TimelineUpdate::factory()->create([ 'timeline_id' => $timeline->id, 'update_text' => 'Second Update', 'created_at' => now()->subDay(), ]); $this->actingAs($client); Volt::test('client.timelines.show', ['timeline' => $timeline]) ->assertSeeInOrder(['First Update', 'Second Update']); }); test('timeline detail shows case name and reference', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create([ 'user_id' => $client->id, 'case_name' => 'Property Dispute', 'case_reference' => 'REF-2024-001', ]); $this->actingAs($client); Volt::test('client.timelines.show', ['timeline' => $timeline]) ->assertSee('Property Dispute') ->assertSee('REF-2024-001'); }); test('timeline detail shows status badge', function () { $client = User::factory()->individual()->create(); $activeTimeline = Timeline::factory()->create([ 'user_id' => $client->id, 'status' => 'active', ]); $this->actingAs($client); Volt::test('client.timelines.show', ['timeline' => $activeTimeline]) ->assertSee(__('client.active')); }); test('empty updates shows no updates message', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create(['user_id' => $client->id]); $this->actingAs($client); Volt::test('client.timelines.show', ['timeline' => $timeline]) ->assertSee(__('client.no_updates_yet')); }); // Read-Only Enforcement Tests test('client timeline view is read-only with no edit actions', function () { $client = User::factory()->individual()->create(); $timeline = Timeline::factory()->create(['user_id' => $client->id]); $this->actingAs($client); // Verify no edit/delete/archive buttons or forms exist in the view Volt::test('client.timelines.show', ['timeline' => $timeline]) ->assertDontSee('wire:click="edit"') ->assertDontSee('wire:click="delete"') ->assertDontSee('wire:click="archive"') ->assertDontSee('wire:submit'); }); // Company client access test test('company client can view own timelines', function () { $company = User::factory()->company()->create(); Timeline::factory()->count(2)->create(['user_id' => $company->id]); $this->actingAs($company) ->get(route('client.timelines.index')) ->assertOk(); }); // Pagination Tests test('timeline list paginates active timelines', function () { $client = User::factory()->individual()->create(); // Create 15 active timelines (more than page size of 10) Timeline::factory()->count(15)->create([ 'user_id' => $client->id, 'status' => 'active', ]); $this->actingAs($client); // First page should show 10 timelines $response = $this->get(route('client.timelines.index')); $response->assertOk(); // Navigate to second page $response = $this->get(route('client.timelines.index', ['active' => 2])); $response->assertOk(); }); test('timeline list paginates archived timelines separately', function () { $client = User::factory()->individual()->create(); // Create 15 archived timelines Timeline::factory()->count(15)->create([ 'user_id' => $client->id, 'status' => 'archived', ]); $this->actingAs($client); // Navigate to second page of archived $response = $this->get(route('client.timelines.index', ['archived' => 2])); $response->assertOk(); });