get($url); $response->assertOk()->assertInertia(fn (Assert $page) => $page->component('Prompts/Index')); return $response->inertiaProps(); } private function names(array $props): array { return array_column($props['prompts']['data'], 'name'); } public function test_index_renders_rows_tags_and_filter_state(): void { $alpha = Tag::query()->create(['name' => 'alpha']); $zeta = Tag::query()->create(['name' => 'zeta']); $alphaPrompt = Prompt::factory()->create(['name' => 'Alpha Prompt', 'body' => 'Body A {{x}}']); $zetaPrompt = Prompt::factory()->create(['name' => 'Zeta Prompt', 'description' => null, 'body' => 'Body B']); $alphaPrompt->tags()->attach([$alpha->id, $zeta->id]); $zetaPrompt->tags()->attach([$zeta->id]); $props = $this->pageProps(); // Newest first (created_at desc). $this->assertSame(['Zeta Prompt', 'Alpha Prompt'], $this->names($props)); $this->assertSame(2, $props['prompts']['total']); $this->assertSame(['alpha', 'zeta'], $props['tags']); $this->assertSame(['search' => null, 'tag' => null, 'favorites' => false], $props['filters']); $this->assertSame('created_at', $props['sort']); $this->assertSame('desc', $props['direction']); $row = $props['prompts']['data'][0]; $this->assertSame('Zeta Prompt', $row['name']); $this->assertFalse($row['is_favorite']); $this->assertSame(0, $row['usage_count']); $this->assertNull($row['last_used_at']); $this->assertSame(['zeta'], array_column($row['tags'], 'name')); } public function test_index_search_matches_name_description_and_body_case_insensitively(): void { Prompt::factory()->create(['name' => 'Regex Explainer', 'description' => null, 'body' => 'Explain {{regex}}']); Prompt::factory()->create(['name' => 'Unrelated', 'description' => 'notes about regex engines', 'body' => 'x']); Prompt::factory()->create(['name' => 'Python Helper', 'description' => null, 'body' => 'write python code']); $props = $this->pageProps('/prompts?search=REGEX'); $this->assertSame(['Unrelated', 'Regex Explainer'], $this->names($props)); $this->assertSame('REGEX', $props['filters']['search']); } public function test_index_tag_filter_returns_only_matching_prompts(): void { $coding = Tag::query()->create(['name' => 'coding']); $design = Tag::query()->create(['name' => 'design']); $codeReviewer = Prompt::factory()->create(['name' => 'Code Reviewer']); Prompt::factory()->create(['name' => 'No Tags']); $moodboard = Prompt::factory()->create(['name' => 'Moodboard']); $codeReviewer->tags()->attach($coding->id); $moodboard->tags()->attach($design->id); $props = $this->pageProps('/prompts?tag=coding'); $this->assertSame(['Code Reviewer'], $this->names($props)); $this->assertSame('coding', $props['filters']['tag']); } public function test_index_unknown_tag_returns_empty_result_set(): void { Prompt::factory()->count(2)->create(); $props = $this->pageProps('/prompts?tag=does-not-exist'); $this->assertSame([], $props['prompts']['data']); $this->assertSame(0, $props['prompts']['total']); } public function test_index_favorites_filter_returns_only_favorites(): void { Prompt::factory()->favorite()->create(['name' => 'Starred']); Prompt::factory()->create(['name' => 'Plain']); $props = $this->pageProps('/prompts?favorites=1'); $this->assertSame(['Starred'], $this->names($props)); $this->assertTrue($props['filters']['favorites']); } public function test_index_sort_by_name_uses_asc_default_and_respects_direction(): void { Prompt::factory()->create(['name' => 'Charlie']); Prompt::factory()->create(['name' => 'alpha']); Prompt::factory()->create(['name' => 'Bravo']); $props = $this->pageProps('/prompts?sort=name'); $this->assertSame(['Bravo', 'Charlie', 'alpha'], $this->names($props)); $this->assertSame('name', $props['sort']); $this->assertSame('asc', $props['direction']); $props = $this->pageProps('/prompts?sort=name&direction=desc'); $this->assertSame(['alpha', 'Charlie', 'Bravo'], $this->names($props)); $this->assertSame('desc', $props['direction']); } public function test_index_sort_by_usage_count(): void { Prompt::factory()->create(['name' => 'Rare', 'usage_count' => 1]); Prompt::factory()->create(['name' => 'Common', 'usage_count' => 42]); Prompt::factory()->create(['name' => 'Mid', 'usage_count' => 7]); $props = $this->pageProps('/prompts?sort=usage_count'); $this->assertSame(['Common', 'Mid', 'Rare'], $this->names($props)); $props = $this->pageProps('/prompts?sort=usage_count&direction=asc'); $this->assertSame(['Rare', 'Mid', 'Common'], $this->names($props)); } public function test_index_sort_by_last_used_at_keeps_nulls_last_in_both_directions(): void { Prompt::factory()->create(['name' => 'Older', 'last_used_at' => '2026-01-01 00:00:00']); Prompt::factory()->create(['name' => 'Recent', 'last_used_at' => '2026-06-01 00:00:00']); Prompt::factory()->create(['name' => 'Never', 'last_used_at' => null]); $props = $this->pageProps('/prompts?sort=last_used_at&direction=asc'); $this->assertSame(['Older', 'Recent', 'Never'], $this->names($props)); $props = $this->pageProps('/prompts?sort=last_used_at&direction=desc'); $this->assertSame(['Recent', 'Older', 'Never'], $this->names($props)); } public function test_index_sort_by_created_at_and_updated_at(): void { // created_at desc would list "Older" first; updated_at desc must not. Prompt::factory()->create(['name' => 'Older', 'created_at' => '2026-09-01 00:00:00', 'updated_at' => '2026-01-01 00:00:00']); Prompt::factory()->create(['name' => 'Newer', 'created_at' => '2026-08-01 00:00:00', 'updated_at' => '2026-05-01 00:00:00']); $props = $this->pageProps('/prompts'); $this->assertSame(['Older', 'Newer'], $this->names($props)); $props = $this->pageProps('/prompts?sort=created_at&direction=asc'); $this->assertSame(['Newer', 'Older'], $this->names($props)); $props = $this->pageProps('/prompts?sort=updated_at'); $this->assertSame(['Newer', 'Older'], $this->names($props)); $props = $this->pageProps('/prompts?sort=updated_at&direction=asc'); $this->assertSame(['Older', 'Newer'], $this->names($props)); } public function test_index_invalid_sort_and_direction_fall_back_to_defaults(): void { Prompt::factory()->count(2)->create(); $response = $this->get('/prompts?sort=1%3BDROP&direction=upside'); $response->assertOk(); $props = $response->inertiaProps(); $this->assertSame('created_at', $props['sort']); $this->assertSame('desc', $props['direction']); } public function test_index_paginates_ten_per_page(): void { Prompt::factory()->count(12)->create(); $props = $this->pageProps(); $this->assertSame(12, $props['prompts']['total']); $this->assertSame(2, $props['prompts']['last_page']); $this->assertCount(10, $props['prompts']['data']); $this->assertSame(1, $props['prompts']['current_page']); $props = $this->pageProps('/prompts?page=2'); $this->assertCount(2, $props['prompts']['data']); $this->assertSame(2, $props['prompts']['current_page']); } public function test_index_with_no_prompts_shows_empty_state(): void { $props = $this->pageProps(); $this->assertSame([], $props['prompts']['data']); $this->assertSame(0, $props['prompts']['total']); $this->assertSame([], $props['tags']); } }