Current state with latest updates
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Models\Artwork;
|
||||
use App\Models\User;
|
||||
use App\Services\ArtworkService;
|
||||
use App\Services\HomepageService;
|
||||
use App\Services\Images\FeaturedArtworkThumbnailGenerator;
|
||||
use App\Support\ArtworkFeaturedImagePath;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
@@ -303,6 +304,7 @@ test('homepage hero payload uses the forced hero artwork when one is set', funct
|
||||
|
||||
test('homepage renders featured hero picture and preload from dedicated featured thumbnails', function () {
|
||||
Cache::flush();
|
||||
app(HomepageService::class)->clearFeaturedAndMedalCaches();
|
||||
Storage::fake('s3');
|
||||
config([
|
||||
'uploads.object_storage.disk' => 's3',
|
||||
@@ -335,10 +337,19 @@ test('homepage renders featured hero picture and preload from dedicated featured
|
||||
|
||||
$paths = app(ArtworkFeaturedImagePath::class);
|
||||
|
||||
// Featured-thumbnail existence is precomputed by FeaturedArtworkThumbnailGenerator
|
||||
// (queued off the request path) and persisted on the artwork row; the homepage
|
||||
// request only reads that state, so seed both the fake disk (for URL building)
|
||||
// and the DB column here rather than relying on a live Storage::exists() check.
|
||||
foreach ($paths->variantNames() as $variant) {
|
||||
Storage::disk('s3')->put($paths->objectPath($artwork, $variant), 'featured-image');
|
||||
}
|
||||
|
||||
$artwork->forceFill([
|
||||
'featured_thumbnail_variants_json' => $paths->variantNames(),
|
||||
'featured_thumbnails_checked_at' => now(),
|
||||
])->saveQuietly();
|
||||
|
||||
$desktopUrl = $paths->url($artwork, 'desktop');
|
||||
$desktopXlUrl = $paths->url($artwork, 'desktop_xl');
|
||||
$mobileXsUrl = $paths->url($artwork, 'mobile_xs');
|
||||
@@ -355,6 +366,125 @@ test('homepage renders featured hero picture and preload from dedicated featured
|
||||
->assertSee('fetchpriority="high"', false);
|
||||
});
|
||||
|
||||
test('featured hero image resolution never checks the remote disk', function () {
|
||||
Cache::flush();
|
||||
app(HomepageService::class)->clearFeaturedAndMedalCaches();
|
||||
Storage::fake('s3');
|
||||
config([
|
||||
'uploads.object_storage.disk' => 's3',
|
||||
'cdn.files_url' => 'https://files.skinbase.org',
|
||||
]);
|
||||
|
||||
$owner = User::factory()->create();
|
||||
$artwork = makeFeaturedArtwork([
|
||||
'user_id' => $owner->id,
|
||||
'title' => 'Hero Without Live Storage Checks',
|
||||
'hash' => str_repeat('e', 64),
|
||||
'file_ext' => 'png',
|
||||
'thumb_ext' => 'webp',
|
||||
]);
|
||||
|
||||
DB::table('artwork_features')->insert([
|
||||
'artwork_id' => $artwork->id,
|
||||
'featured_at' => now()->subHour(),
|
||||
'expires_at' => null,
|
||||
'priority' => 900,
|
||||
'label' => null,
|
||||
'note' => null,
|
||||
'is_active' => true,
|
||||
'force_hero' => true,
|
||||
'created_by' => null,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
|
||||
$paths = app(ArtworkFeaturedImagePath::class);
|
||||
|
||||
$artwork->forceFill([
|
||||
'featured_thumbnail_variants_json' => $paths->variantNames(),
|
||||
'featured_thumbnails_checked_at' => now(),
|
||||
])->saveQuietly();
|
||||
|
||||
// Note: no files are ever written to the fake "s3" disk. If hasFeaturedThumbnail()
|
||||
// fell back to a live Storage::exists() check, these URLs would resolve to null;
|
||||
// since it reads the DB column instead, they resolve correctly with zero disk I/O.
|
||||
$hero = app(HomepageService::class)->getHeroArtwork();
|
||||
|
||||
expect($hero)->not->toBeNull()
|
||||
->and($hero['id'])->toBe($artwork->id)
|
||||
->and($hero['featured_image']['variants']['desktop'])->toBe($paths->url($artwork, 'desktop'))
|
||||
->and($hero['featured_image']['variants']['desktop_xl'])->toBe($paths->url($artwork, 'desktop_xl'));
|
||||
|
||||
expect($artwork->fresh()->hasFeaturedThumbnail('desktop'))->toBeTrue();
|
||||
});
|
||||
|
||||
test('generating featured thumbnail metadata invalidates the stale hero cache so the next resolution uses it', function () {
|
||||
Cache::flush();
|
||||
app(HomepageService::class)->clearFeaturedAndMedalCaches();
|
||||
Storage::fake('s3');
|
||||
config([
|
||||
'uploads.object_storage.disk' => 's3',
|
||||
'cdn.files_url' => 'https://files.skinbase.org',
|
||||
]);
|
||||
|
||||
$owner = User::factory()->create();
|
||||
$artwork = makeFeaturedArtwork([
|
||||
'user_id' => $owner->id,
|
||||
'title' => 'Hero Metadata Refresh',
|
||||
'hash' => str_repeat('f', 64),
|
||||
'file_ext' => 'png',
|
||||
'thumb_ext' => 'webp',
|
||||
]);
|
||||
|
||||
DB::table('artwork_features')->insert([
|
||||
'artwork_id' => $artwork->id,
|
||||
'featured_at' => now()->subHour(),
|
||||
'expires_at' => null,
|
||||
'priority' => 900,
|
||||
'label' => null,
|
||||
'note' => null,
|
||||
'is_active' => true,
|
||||
'force_hero' => true,
|
||||
'created_by' => null,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
|
||||
$homepage = app(HomepageService::class);
|
||||
$paths = app(ArtworkFeaturedImagePath::class);
|
||||
|
||||
// 1. Hero cache is built while featured metadata is unavailable: no variants have
|
||||
// been persisted yet, so hasFeaturedThumbnail() reports false for every variant and
|
||||
// the payload falls back to the non-featured thumbnail.
|
||||
$heroBeforeGeneration = $homepage->getHeroArtwork();
|
||||
expect($heroBeforeGeneration)->not->toBeNull()
|
||||
->and($heroBeforeGeneration['id'])->toBe($artwork->id)
|
||||
->and($heroBeforeGeneration['featured_image']['variants']['desktop'])->toBeNull();
|
||||
|
||||
// 2. Featured-thumbnail metadata is generated. The generator's plan() (also used by
|
||||
// the skinbase:featured-thumbnails:generate command and GenerateFeaturedArtworkThumbnailsJob)
|
||||
// discovers the now-present files and persists featured_thumbnail_variants_json via
|
||||
// saveQuietly() — which does NOT fire ArtworkObserver/ArtworkFeatureObserver, so any
|
||||
// cache invalidation has to come from the generator itself.
|
||||
foreach ($paths->variantNames() as $variant) {
|
||||
Storage::disk('s3')->put($paths->objectPath($artwork, $variant), 'featured-image');
|
||||
}
|
||||
app(FeaturedArtworkThumbnailGenerator::class)->plan($artwork->fresh());
|
||||
|
||||
// 3. The relevant hero cache (all three viewer-visibility segments) was invalidated as
|
||||
// a side effect of that generation, without a full application cache flush.
|
||||
foreach (['visibility-hide', 'visibility-blur', 'visibility-show'] as $segment) {
|
||||
expect(Cache::has("homepage.hero.{$segment}"))->toBeFalse();
|
||||
}
|
||||
|
||||
// 4. The next homepage resolution rebuilds the cache and now uses the featured thumbnail.
|
||||
$heroAfterGeneration = $homepage->getHeroArtwork();
|
||||
expect($heroAfterGeneration['featured_image']['variants']['desktop'])
|
||||
->toBe($paths->url($artwork, 'desktop'));
|
||||
});
|
||||
|
||||
test('community favorites returns artworks ordered by recent medal score', function () {
|
||||
$owner = User::factory()->create();
|
||||
$leader = makeFeaturedArtwork(['user_id' => $owner->id, 'title' => 'Leader']);
|
||||
|
||||
Reference in New Issue
Block a user