'null']); }); // ── 404 cases ───────────────────────────────────────────────────────────────── it('returns 404 for a non-existent artwork id', function () { $this->getJson('/api/art/99999/similar') ->assertStatus(404) ->assertJsonPath('error', 'Artwork not found'); }); it('returns 404 for a private artwork', function () { $artwork = Artwork::factory()->create(['is_public' => false]); $this->getJson("/api/art/{$artwork->id}/similar") ->assertStatus(404); }); it('returns 404 for an unapproved artwork', function () { $artwork = Artwork::factory()->create(['is_approved' => false]); $this->getJson("/api/art/{$artwork->id}/similar") ->assertStatus(404); }); it('returns 404 for an unpublished artwork', function () { $artwork = Artwork::factory()->unpublished()->create(); $this->getJson("/api/art/{$artwork->id}/similar") ->assertStatus(404); }); // ── Success cases ───────────────────────────────────────────────────────────── it('returns a data array for a valid public artwork', function () { $artwork = Artwork::factory()->create([ 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDay(), ]); $response = $this->getJson("/api/art/{$artwork->id}/similar"); $response->assertStatus(200); $response->assertJsonStructure(['data']); expect($response->json('data'))->toBeArray(); }); it('the source artwork id is never present in results', function () { $artwork = Artwork::factory()->create([ 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDay(), ]); $ids = collect($this->getJson("/api/art/{$artwork->id}/similar")->json('data')) ->pluck('id') ->all(); expect($ids)->not->toContain($artwork->id); }); it('result count does not exceed 12', function () { $artwork = Artwork::factory()->create([ 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDay(), ]); $count = count($this->getJson("/api/art/{$artwork->id}/similar")->json('data')); // null Scout driver returns 0 results; max is 12 expect($count <= 12)->toBeTrue(); }); it('results do not include artworks by the same creator', function () { $creatorA = User::factory()->create(); $creatorB = User::factory()->create(); $source = Artwork::factory()->create([ 'user_id' => $creatorA->id, 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDay(), ]); // A matching artwork from a different creator Artwork::factory()->create([ 'user_id' => $creatorB->id, 'is_public' => true, 'is_approved' => true, 'published_at' => now()->subDay(), ]); $response = $this->getJson("/api/art/{$source->id}/similar"); $response->assertStatus(200); $items = $response->json('data'); // With null Scout driver the search returns 0 items; if items are present // none should belong to the source artwork's creator. foreach ($items as $item) { expect($item)->toHaveKeys(['id', 'title', 'slug', 'thumb', 'url', 'author_id']); expect($item['author_id'])->not->toBe($creatorA->id); } expect(true)->toBeTrue(); // always at least one assertion });