chore: commit current workspace changes
This commit is contained in:
119
tests/Feature/Profile/ProfileArtworksApiTest.php
Normal file
119
tests/Feature/Profile/ProfileArtworksApiTest.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Artwork;
|
||||
use App\Models\ArtworkStats;
|
||||
use App\Models\Category;
|
||||
use App\Models\ContentType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Pagination\Cursor;
|
||||
|
||||
it('supports cursor pagination for latest profile artworks', function () {
|
||||
[$user] = seedProfileArtworksApiFixtures(26);
|
||||
|
||||
$firstPage = $this->getJson("/api/profile/{$user->username}/artworks");
|
||||
|
||||
$firstPage->assertOk();
|
||||
$firstPage->assertJsonCount(24, 'data');
|
||||
|
||||
$nextCursor = $firstPage->json('next_cursor');
|
||||
|
||||
expect($nextCursor)->not->toBeNull();
|
||||
|
||||
$secondPage = $this->getJson("/api/profile/{$user->username}/artworks?cursor={$nextCursor}");
|
||||
|
||||
$secondPage->assertOk();
|
||||
$secondPage->assertJsonCount(2, 'data');
|
||||
});
|
||||
|
||||
it('supports cursor pagination for stats-sorted profile artworks', function () {
|
||||
[$user] = seedProfileArtworksApiFixtures(26);
|
||||
|
||||
$firstPage = $this->getJson("/api/profile/{$user->username}/artworks?sort=views");
|
||||
|
||||
$firstPage->assertOk();
|
||||
$firstPage->assertJsonCount(24, 'data');
|
||||
|
||||
$nextCursor = $firstPage->json('next_cursor');
|
||||
|
||||
expect($nextCursor)->not->toBeNull();
|
||||
|
||||
$secondPage = $this->getJson("/api/profile/{$user->username}/artworks?sort=views&cursor={$nextCursor}");
|
||||
|
||||
$secondPage->assertOk();
|
||||
$secondPage->assertJsonCount(2, 'data');
|
||||
});
|
||||
|
||||
it('falls back to the first page when a legacy profile artworks cursor is missing id', function () {
|
||||
[$user] = seedProfileArtworksApiFixtures(26);
|
||||
|
||||
$legacyCursor = new Cursor([
|
||||
'published_at' => Artwork::query()->orderByDesc('published_at')->value('published_at')?->format(DATE_ATOM),
|
||||
]);
|
||||
|
||||
$response = $this->getJson("/api/profile/{$user->username}/artworks?cursor={$legacyCursor->encode()}");
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonCount(24, 'data');
|
||||
expect($response->json('next_cursor'))->not->toBeNull();
|
||||
});
|
||||
|
||||
function seedProfileArtworksApiFixtures(int $count): array
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'name' => 'Profile Artist',
|
||||
'username' => 'profileartist',
|
||||
'email' => 'profileartist@example.test',
|
||||
]);
|
||||
|
||||
$contentType = ContentType::create([
|
||||
'name' => 'Skins',
|
||||
'slug' => 'skins',
|
||||
'description' => 'Skins content type',
|
||||
]);
|
||||
|
||||
$category = Category::create([
|
||||
'content_type_id' => $contentType->id,
|
||||
'name' => 'Winamp',
|
||||
'slug' => 'winamp',
|
||||
'description' => 'Winamp skins',
|
||||
'is_active' => true,
|
||||
'sort_order' => 1,
|
||||
]);
|
||||
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$artwork = Artwork::factory()
|
||||
->for($user)
|
||||
->create([
|
||||
'title' => 'Profile Artwork ' . $i,
|
||||
'slug' => 'profile-artwork-' . $i,
|
||||
'published_at' => now()->subMinutes($i),
|
||||
]);
|
||||
|
||||
$artwork->categories()->attach($category->id);
|
||||
|
||||
ArtworkStats::create([
|
||||
'artwork_id' => $artwork->id,
|
||||
'views' => $count - $i,
|
||||
'downloads' => $i,
|
||||
'favorites' => $i,
|
||||
'rating_avg' => 0,
|
||||
'rating_count' => 0,
|
||||
'comments_count' => 0,
|
||||
'shares_count' => 0,
|
||||
'ranking_score' => $count - $i,
|
||||
'engagement_velocity' => 0,
|
||||
'shares_24h' => 0,
|
||||
'comments_24h' => 0,
|
||||
'favourites_24h' => 0,
|
||||
'heat_score' => $count - $i,
|
||||
'heat_score_updated_at' => null,
|
||||
'views_1h' => 0,
|
||||
'favourites_1h' => 0,
|
||||
'comments_1h' => 0,
|
||||
'shares_1h' => 0,
|
||||
'downloads_1h' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
return [$user, $contentType, $category];
|
||||
}
|
||||
@@ -115,4 +115,15 @@ it('prioritizes higher-signal world rewards ahead of participation on profile re
|
||||
->where('worldRewards.items.0.badge_label', 'Pixel Week 2026 Winner')
|
||||
->where('worldRewards.items.1.badge_label', 'Retro Month 2026 Participant')
|
||||
->where('worldRewards.recent.0.badge_label', 'Retro Month 2026 Participant'));
|
||||
});
|
||||
|
||||
it('redirects public profile paths from stray skinbase subdomains to the canonical host', function (): void {
|
||||
config()->set('app.url', 'https://skinbase.org');
|
||||
|
||||
User::factory()->create([
|
||||
'username' => 'ta2027',
|
||||
]);
|
||||
|
||||
$this->get('https://ffh84a.skinbase.org/@ta2027')
|
||||
->assertRedirect('https://skinbase.org/@ta2027');
|
||||
});
|
||||
Reference in New Issue
Block a user