316 lines
10 KiB
PHP
316 lines
10 KiB
PHP
<?php
|
|
|
|
use App\Models\Artwork;
|
|
use App\Models\ArtworkComment;
|
|
use App\Models\Category;
|
|
use App\Models\ContentType;
|
|
use App\Models\User;
|
|
use App\Models\World;
|
|
use App\Models\WorldRewardGrant;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Inertia\Testing\AssertableInertia;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function (): void {
|
|
File::ensureDirectoryExists(public_path('build'));
|
|
File::put(public_path('build/manifest.json'), json_encode([
|
|
'resources/css/app.css' => ['file' => 'assets/app.css', 'src' => 'resources/css/app.css', 'isEntry' => true],
|
|
'resources/css/nova-grid.css' => ['file' => 'assets/nova-grid.css', 'src' => 'resources/css/nova-grid.css', 'isEntry' => true],
|
|
'resources/scss/nova.scss' => ['file' => 'assets/nova.css', 'src' => 'resources/scss/nova.scss', 'isEntry' => true],
|
|
'resources/js/nova.js' => ['file' => 'assets/nova.js', 'src' => 'resources/js/nova.js', 'isEntry' => true],
|
|
'resources/js/entry-search.jsx' => ['file' => 'assets/entry-search.js', 'src' => 'resources/js/entry-search.jsx', 'isEntry' => true],
|
|
'resources/js/app.js' => ['file' => 'assets/app.js', 'src' => 'resources/js/app.js', 'isEntry' => true],
|
|
'resources/js/artwork.jsx' => ['file' => 'assets/artwork.js', 'src' => 'resources/js/artwork.jsx', 'isEntry' => true],
|
|
], JSON_THROW_ON_ERROR));
|
|
});
|
|
|
|
it('renders nested artwork comments without lazy-loading reply branches during page render', function () {
|
|
$author = User::factory()->create([
|
|
'username' => 'commentauthor',
|
|
]);
|
|
|
|
$commenterA = User::factory()->create([
|
|
'username' => 'commentera',
|
|
]);
|
|
|
|
$commenterB = User::factory()->create([
|
|
'username' => 'commenterb',
|
|
]);
|
|
|
|
$commenterC = User::factory()->create([
|
|
'username' => 'commenterc',
|
|
]);
|
|
|
|
$contentType = ContentType::create([
|
|
'name' => 'Skins',
|
|
'slug' => 'skins',
|
|
'description' => 'Skins content type',
|
|
]);
|
|
|
|
$category = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'name' => 'Internet',
|
|
'slug' => 'internet',
|
|
'description' => 'Internet skins',
|
|
'is_active' => true,
|
|
'sort_order' => 1,
|
|
]);
|
|
|
|
$artwork = Artwork::factory()->for($author)->create([
|
|
'title' => 'ICQ Skin',
|
|
'slug' => 'icq',
|
|
'published_at' => now()->subHour(),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$artwork->categories()->attach($category->id);
|
|
|
|
$rootComment = ArtworkComment::query()->create([
|
|
'artwork_id' => $artwork->id,
|
|
'user_id' => $commenterA->id,
|
|
'content' => 'Root comment',
|
|
'raw_content' => 'Root comment',
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$reply = ArtworkComment::query()->create([
|
|
'artwork_id' => $artwork->id,
|
|
'user_id' => $commenterB->id,
|
|
'parent_id' => $rootComment->id,
|
|
'content' => 'First reply',
|
|
'raw_content' => 'First reply',
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
ArtworkComment::query()->create([
|
|
'artwork_id' => $artwork->id,
|
|
'user_id' => $commenterC->id,
|
|
'parent_id' => $reply->id,
|
|
'content' => 'Nested reply',
|
|
'raw_content' => 'Nested reply',
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$this->get('/skins/internet/icq')
|
|
->assertOk()
|
|
->assertInertia(fn (AssertableInertia $page) => $page
|
|
->component('ArtworkPage')
|
|
->has('comments', 1)
|
|
->where('comments.0.content', 'Root comment')
|
|
->has('comments.0.replies', 1)
|
|
->where('comments.0.replies.0.content', 'First reply')
|
|
->has('comments.0.replies.0.replies', 1)
|
|
->where('comments.0.replies.0.replies.0.content', 'Nested reply'));
|
|
});
|
|
|
|
it('keeps artwork page query count bounded with deep nested comments', function () {
|
|
$author = User::factory()->create([
|
|
'username' => 'querycountauthor',
|
|
]);
|
|
|
|
$contentType = ContentType::create([
|
|
'name' => 'Skins',
|
|
'slug' => 'skins',
|
|
'description' => 'Skins content type',
|
|
]);
|
|
|
|
$category = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'name' => 'Internet',
|
|
'slug' => 'internet',
|
|
'description' => 'Internet skins',
|
|
'is_active' => true,
|
|
'sort_order' => 1,
|
|
]);
|
|
|
|
$artwork = Artwork::factory()->for($author)->create([
|
|
'title' => 'ICQ Query Budget',
|
|
'slug' => 'icq-query-budget',
|
|
'published_at' => now()->subHour(),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$artwork->categories()->attach($category->id);
|
|
|
|
$parentId = null;
|
|
|
|
for ($i = 0; $i < 20; $i++) {
|
|
$commenter = User::factory()->create([
|
|
'username' => 'querycommenter' . $i,
|
|
]);
|
|
|
|
$comment = ArtworkComment::query()->create([
|
|
'artwork_id' => $artwork->id,
|
|
'user_id' => $commenter->id,
|
|
'parent_id' => $parentId,
|
|
'content' => 'Nested comment ' . $i,
|
|
'raw_content' => 'Nested comment ' . $i,
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$parentId = $comment->id;
|
|
}
|
|
|
|
$queryCount = 0;
|
|
DB::listen(function () use (&$queryCount) {
|
|
$queryCount++;
|
|
});
|
|
|
|
$this->get('/skins/internet/icq-query-budget')->assertOk();
|
|
|
|
expect($queryCount)->toBeLessThanOrEqual(50);
|
|
});
|
|
|
|
it('keeps artwork page category queries bounded with nested attached categories', function () {
|
|
$author = User::factory()->create([
|
|
'username' => 'categoryqueryauthor',
|
|
]);
|
|
|
|
$contentType = ContentType::create([
|
|
'name' => 'Skins',
|
|
'slug' => 'skins',
|
|
'description' => 'Skins content type',
|
|
]);
|
|
|
|
$rootCategory = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'name' => 'Misc',
|
|
'slug' => 'misc',
|
|
'description' => 'Misc skins',
|
|
'is_active' => true,
|
|
'sort_order' => 1,
|
|
]);
|
|
|
|
$artwork = Artwork::factory()->for($author)->create([
|
|
'title' => 'Parasite Runboxurl Launcher',
|
|
'slug' => 'parasite-runboxurl-launcher',
|
|
'published_at' => now()->subHour(),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$attachedCategoryIds = [$rootCategory->id];
|
|
|
|
for ($i = 1; $i <= 8; $i++) {
|
|
$section = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'parent_id' => $rootCategory->id,
|
|
'name' => 'Section ' . $i,
|
|
'slug' => 'section-' . $i,
|
|
'description' => 'Section ' . $i,
|
|
'is_active' => true,
|
|
'sort_order' => $i,
|
|
]);
|
|
|
|
$leaf = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'parent_id' => $section->id,
|
|
'name' => 'Leaf ' . $i,
|
|
'slug' => 'leaf-' . $i,
|
|
'description' => 'Leaf ' . $i,
|
|
'is_active' => true,
|
|
'sort_order' => $i,
|
|
]);
|
|
|
|
$attachedCategoryIds[] = $leaf->id;
|
|
}
|
|
|
|
$artwork->categories()->attach($attachedCategoryIds);
|
|
|
|
$categoryQueryCount = 0;
|
|
DB::listen(function ($query) use (&$categoryQueryCount) {
|
|
if (preg_match('/\b(from|join)\s+["`\[]?(categories|content_types)\b/i', $query->sql) === 1) {
|
|
$categoryQueryCount++;
|
|
}
|
|
});
|
|
|
|
$this->get('/skins/misc/parasite-runboxurl-launcher')
|
|
->assertOk()
|
|
->assertInertia(fn (AssertableInertia $page) => $page
|
|
->component('ArtworkPage')
|
|
->has('artwork.categories', 9)
|
|
->where('artwork.categories.0.slug', 'misc'));
|
|
|
|
expect($categoryQueryCount)->toBeLessThanOrEqual(12);
|
|
});
|
|
|
|
it('keeps artwork page world participation queries bounded with many recurring reward badges', function () {
|
|
$author = User::factory()->create([
|
|
'username' => 'jetaudioauthor',
|
|
]);
|
|
|
|
$contentType = ContentType::create([
|
|
'name' => 'Skins',
|
|
'slug' => 'skins',
|
|
'description' => 'Skins content type',
|
|
]);
|
|
|
|
$category = Category::create([
|
|
'content_type_id' => $contentType->id,
|
|
'name' => 'Audio',
|
|
'slug' => 'audio',
|
|
'description' => 'Audio skins',
|
|
'is_active' => true,
|
|
'sort_order' => 1,
|
|
]);
|
|
|
|
$artwork = Artwork::factory()->for($author)->create([
|
|
'title' => 'Jet Audio',
|
|
'slug' => 'jet-audio',
|
|
'published_at' => now()->subHour(),
|
|
'is_public' => true,
|
|
'is_approved' => true,
|
|
]);
|
|
|
|
$artwork->categories()->attach($category->id);
|
|
|
|
for ($i = 1; $i <= 8; $i++) {
|
|
$world = World::query()->create([
|
|
'title' => 'Audio World ' . $i,
|
|
'slug' => 'audio-world-' . $i,
|
|
'status' => World::STATUS_PUBLISHED,
|
|
'type' => World::TYPE_SEASONAL,
|
|
'is_recurring' => true,
|
|
'recurrence_key' => 'audio-world-series-' . $i,
|
|
'edition_year' => 2020 + $i,
|
|
'is_active_campaign' => false,
|
|
'is_featured' => false,
|
|
'is_homepage_featured' => false,
|
|
'accepts_submissions' => false,
|
|
'participation_mode' => World::PARTICIPATION_MODE_CLOSED,
|
|
'published_at' => now()->subDays(30 + $i),
|
|
'starts_at' => now()->subDays(20 + $i),
|
|
'ends_at' => now()->subDays(10 + $i),
|
|
'created_by_user_id' => $author->id,
|
|
]);
|
|
|
|
WorldRewardGrant::query()->create([
|
|
'user_id' => $author->id,
|
|
'world_id' => $world->id,
|
|
'artwork_id' => $artwork->id,
|
|
'reward_type' => 'featured',
|
|
'grant_source' => 'manual',
|
|
'granted_at' => now()->subDays($i),
|
|
]);
|
|
}
|
|
|
|
$worldQueryCount = 0;
|
|
DB::listen(function ($query) use (&$worldQueryCount) {
|
|
if (preg_match('/\bfrom\s+["`\[]?worlds\b/i', $query->sql) === 1) {
|
|
$worldQueryCount++;
|
|
}
|
|
});
|
|
|
|
$this->get('/skins/audio/jet-audio')
|
|
->assertOk()
|
|
->assertInertia(fn (AssertableInertia $page) => $page
|
|
->component('ArtworkPage')
|
|
->has('artwork.world_participation', 8));
|
|
|
|
expect($worldQueryCount)->toBeLessThanOrEqual(6);
|
|
}); |