Prefetch artwork prev/next navigation off the critical path.
Move neighbor lookup into a dedicated service and let the viewer load adjacent artworks after first paint instead of blocking the detail request.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Artwork;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('returns only the image contract for navigation prefetch', function (): void {
|
||||
$artwork = Artwork::factory()->create([
|
||||
'title' => 'Prefetch Artwork',
|
||||
'slug' => 'prefetch-artwork',
|
||||
'hash' => 'aabbccddeeff00112233445566778899',
|
||||
'file_path' => 'uploads/prefetch.jpg',
|
||||
]);
|
||||
$queries = 0;
|
||||
|
||||
DB::listen(function () use (&$queries): void {
|
||||
$queries++;
|
||||
});
|
||||
|
||||
$response = $this->getJson('/api/artworks/'.$artwork->id.'/page?prefetch=1')
|
||||
->assertOk();
|
||||
|
||||
expect($queries)->toBe(1)
|
||||
->and($response->json())->toHaveKeys(['id', 'title', 'slug', 'thumbs'])
|
||||
->and($response->json('thumbs'))->toHaveKeys(['md', 'lg'])
|
||||
->and($response->json('thumbs.xl'))->toBeNull()
|
||||
->and($response->json('stats'))->toBeNull()
|
||||
->and($response->json('thumbs.lg.url'))->toBe(
|
||||
'https://cdn.skinbase.org/artworks/lg/aa/bb/aabbccddeeff00112233445566778899.webp'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not prefetch missing or unpublished artwork', function (): void {
|
||||
$unpublished = Artwork::factory()->unpublished()->create();
|
||||
|
||||
$this->getJson('/api/artworks/'.$unpublished->id.'/page?prefetch=1')
|
||||
->assertNotFound();
|
||||
|
||||
$this->getJson('/api/artworks/999999/page?prefetch=1')
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
it('keeps full page navigation data available separately from prefetch', function (): void {
|
||||
$artwork = Artwork::factory()->create([
|
||||
'slug' => 'full-navigation-artwork',
|
||||
]);
|
||||
|
||||
$this->getJson('/api/artworks/'.$artwork->id.'/page')
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'id', 'title', 'thumbs', 'user', 'categories', 'tags', 'stats', 'viewer',
|
||||
]);
|
||||
});
|
||||
|
||||
it('measures the lightweight prefetch contract for guest and authenticated viewers', function (): void {
|
||||
$artwork = Artwork::factory()->create([
|
||||
'slug' => 'prefetch-measurement-artwork',
|
||||
'hash' => 'aabbccddeeff00112233445566778899',
|
||||
]);
|
||||
|
||||
DB::enableQueryLog();
|
||||
DB::flushQueryLog();
|
||||
$guestPrefetch = $this->getJson('/api/artworks/'.$artwork->id.'/page?prefetch=1')->assertOk();
|
||||
$guestPrefetchQueries = count(DB::getQueryLog());
|
||||
|
||||
DB::flushQueryLog();
|
||||
$guestFull = $this->getJson('/api/artworks/'.$artwork->id.'/page')->assertOk();
|
||||
$guestFullQueries = count(DB::getQueryLog());
|
||||
|
||||
DB::flushQueryLog();
|
||||
$authPrefetch = $this->actingAs(User::factory()->create())
|
||||
->getJson('/api/artworks/'.$artwork->id.'/page?prefetch=1')
|
||||
->assertOk();
|
||||
$authPrefetchQueries = count(DB::getQueryLog());
|
||||
DB::flushQueryLog();
|
||||
$authFull = $this->getJson('/api/artworks/'.$artwork->id.'/page')->assertOk();
|
||||
$authFullQueries = count(DB::getQueryLog());
|
||||
DB::disableQueryLog();
|
||||
|
||||
fwrite(STDERR, sprintf(
|
||||
"M18B3 prefetch bytes/queries: guest=%d/%d auth=%d/%d; full guest=%d/%d auth=%d/%d\n",
|
||||
strlen((string) $guestPrefetch->getContent()),
|
||||
$guestPrefetchQueries,
|
||||
strlen((string) $authPrefetch->getContent()),
|
||||
$authPrefetchQueries,
|
||||
strlen((string) $guestFull->getContent()),
|
||||
$guestFullQueries,
|
||||
strlen((string) $authFull->getContent()),
|
||||
$authFullQueries,
|
||||
));
|
||||
|
||||
expect($guestPrefetchQueries)->toBe(1)
|
||||
->and($authPrefetchQueries)->toBeLessThanOrEqual(2)
|
||||
->and($guestPrefetch->json())->toEqual($authPrefetch->json());
|
||||
});
|
||||
Reference in New Issue
Block a user