Defer artwork comments from initial render

This commit is contained in:
2026-08-29 12:07:08 +02:00
parent 8a80aae21e
commit 4ab315e9d7
8 changed files with 267 additions and 138 deletions
@@ -0,0 +1,72 @@
<?php
use App\Models\Artwork;
use App\Models\ArtworkComment;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
uses(RefreshDatabase::class);
it('omits comments from the initial artwork page and does not query them', function (): void {
$artwork = Artwork::factory()->create([
'slug' => 'm18h1-deferred-comments',
]);
ArtworkComment::factory()->count(2)->create(['artwork_id' => $artwork->id]);
DB::enableQueryLog();
DB::flushQueryLog();
$response = $this->get(route('art.show', ['id' => $artwork->id, 'slug' => $artwork->slug]))->assertOk();
$queries = collect(DB::getQueryLog());
DB::disableQueryLog();
expect($response->getContent())->not->toContain('"comments"')
->and($queries->filter(fn (array $query): bool => str_contains(strtolower($query['query']), 'artwork_comments'))->count())->toBe(0);
});
it('keeps the existing complete comments API contract', function (): void {
$artwork = Artwork::factory()->create();
$comment = ArtworkComment::factory()->create(['artwork_id' => $artwork->id]);
$this->getJson("/api/artworks/{$artwork->id}/comments")
->assertOk()
->assertJsonStructure([
'data' => [[
'id', 'parent_id', 'raw_content', 'rendered_content',
'created_at', 'time_ago', 'user', 'reactions', 'replies',
]],
'meta' => ['current_page', 'last_page', 'total', 'per_page'],
])
->assertJsonPath('data.0.id', $comment->id);
});
it('measures the initial artwork detail SQL after deferring comments', function (): void {
$artwork = Artwork::factory()->create([
'slug' => 'm18h1-sql-measurement',
]);
ArtworkComment::factory()->count(2)->create(['artwork_id' => $artwork->id]);
DB::flushQueryLog();
DB::enableQueryLog();
$this->get(route('art.show', ['id' => $artwork->id, 'slug' => $artwork->slug]))
->assertOk();
$queries = DB::getQueryLog();
DB::disableQueryLog();
$normalized = collect($queries)->map(fn (array $query): string => strtolower(preg_replace('/\s+/', ' ', $query['query'])));
$selects = $normalized->filter(fn (string $query): bool => str_starts_with(ltrim($query), 'select '));
$writes = $normalized->reject(fn (string $query): bool => str_starts_with(ltrim($query), 'select '));
$commentQueries = $normalized->filter(fn (string $query): bool => str_contains($query, 'artwork_comments'));
fwrite(STDERR, sprintf(
"M18H1_SQL initial_guest_total=%d initial_guest_select=%d initial_guest_write=%d initial_guest_comment_queries=%d\n",
count($queries),
$selects->count(),
$writes->count(),
$commentQueries->count(),
));
expect($commentQueries)->toHaveCount(0);
});