'null']); // ArtworkService is not final so it can be mocked $artworksMock = Mockery::mock(ArtworkService::class); $artworksMock->shouldReceive('getFeaturedArtworks') ->andReturn(new LengthAwarePaginator(collect(), 0, 1)) ->byDefault(); $artworksMock->shouldReceive('getFeaturedArtworkWinner') ->andReturn(null) ->byDefault(); app()->instance(ArtworkService::class, $artworksMock); }); // ── Route integration ───────────────────────────────────────────────────────── it('home page renders 200 for guests', function () { $this->get('/')->assertStatus(200); }); it('home page renders 200 for authenticated users', function () { $this->actingAs(User::factory()->create()) ->get('/') ->assertStatus(200); }); // ── HomepageService section shape ───────────────────────────────────────────── it('guest homepage has expected sections but no from_following', function () { $sections = app(HomepageService::class)->all(); expect($sections)->toHaveKeys(['hero', 'trending', 'fresh', 'tags', 'creators', 'news']); expect($sections)->not->toHaveKey('from_following'); expect($sections)->not->toHaveKey('by_tags'); expect($sections)->not->toHaveKey('by_categories'); }); it('authenticated homepage contains all personalised sections', function () { $user = User::factory()->create(); $sections = app(HomepageService::class)->allForUser($user); expect($sections)->toHaveKeys([ 'hero', 'from_following', 'trending', 'by_tags', 'by_categories', 'tags', 'creators', 'news', 'preferences', ]); }); it('preferences section exposes top_tags and top_categories arrays', function () { $user = User::factory()->create(); $sections = app(HomepageService::class)->allForUser($user); expect($sections['preferences'])->toHaveKeys(['top_tags', 'top_categories']); expect($sections['preferences']['top_tags'])->toBeArray(); expect($sections['preferences']['top_categories'])->toBeArray(); }); it('guest and auth homepages have different key sets', function () { $user = User::factory()->create(); $guest = array_keys(app(HomepageService::class)->all()); $auth = array_keys(app(HomepageService::class)->allForUser($user)); expect($guest)->not->toEqual($auth); expect(in_array('from_following', $auth))->toBeTrue(); expect(in_array('from_following', $guest))->toBeFalse(); }); it('homepage artwork payload uses group name and avatar for group-published artworks', function () { $owner = User::factory()->create(); $group = Group::factory()->create([ 'owner_user_id' => $owner->id, 'name' => 'Skinbase Collective', 'slug' => 'skinbase-collective', ]); Artwork::factory()->create([ 'user_id' => $owner->id, 'group_id' => $group->id, 'published_as_type' => Artwork::PUBLISHED_AS_GROUP, 'title' => 'Group Published Artwork', 'hash' => 'homepagegroupartwork', 'thumb_ext' => 'webp', 'published_at' => now()->subMinute(), ]); Cache::flush(); $items = app(HomepageService::class)->getFreshUploads(10); expect($items)->not->toBeEmpty() ->and($items[0]['author'])->toBe('Skinbase Collective') ->and($items[0]['author_username'])->toBe('') ->and($items[0]['published_as_type'])->toBe(Artwork::PUBLISHED_AS_GROUP) ->and($items[0]['publisher']['type'])->toBe('group') ->and($items[0]['publisher']['name'])->toBe('Skinbase Collective') ->and($items[0]['publisher']['profile_url'])->toContain('/groups/skinbase-collective'); });