Files
SkinbaseNova/tests/Feature/Artworks/ArtworkFeaturedThumbnailStateTest.php
T

161 lines
5.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Jobs\GenerateFeaturedArtworkThumbnailsJob;
use App\Models\Artwork;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
uses(RefreshDatabase::class);
function makeAuditableArtwork(array $attributes = []): Artwork
{
return Artwork::factory()->create(array_merge([
'user_id' => User::factory()->create()->id,
'hash' => str_repeat('a', 64),
'file_ext' => 'png',
'thumb_ext' => 'webp',
], $attributes));
}
test('null featured_thumbnail_variants_json means not audited yet', function () {
$artwork = makeAuditableArtwork();
expect($artwork->featured_thumbnail_variants_json)->toBeNull()
->and($artwork->featuredThumbnailAuditState())->toBe(['status' => 'not_audited', 'variants' => []])
->and($artwork->hasFeaturedThumbnail())->toBeFalse()
->and($artwork->hasFeaturedThumbnail('desktop'))->toBeFalse();
});
test('empty array means audited with no featured variants available', function () {
$artwork = makeAuditableArtwork();
$artwork->forceFill([
'featured_thumbnail_variants_json' => [],
'featured_thumbnails_checked_at' => now(),
])->saveQuietly();
$fresh = $artwork->fresh();
expect($fresh->featured_thumbnail_variants_json)->toBe([])
->and($fresh->featuredThumbnailAuditState())->toBe(['status' => 'no_variants', 'variants' => []])
->and($fresh->hasFeaturedThumbnail())->toBeFalse();
});
test('a populated array means audited with those variants known to be available', function () {
$artwork = makeAuditableArtwork();
$artwork->forceFill([
'featured_thumbnail_variants_json' => ['desktop', 'desktop_xl'],
'featured_thumbnails_checked_at' => now(),
])->saveQuietly();
$fresh = $artwork->fresh();
expect($fresh->featuredThumbnailAuditState())->toBe(['status' => 'available', 'variants' => ['desktop', 'desktop_xl']])
->and($fresh->hasFeaturedThumbnail('desktop'))->toBeTrue()
->and($fresh->hasFeaturedThumbnail('desktop_xl'))->toBeTrue()
->and($fresh->hasFeaturedThumbnail('mobile'))->toBeFalse();
});
test('malformed json in the column is treated as not audited rather than throwing', function () {
$artwork = makeAuditableArtwork();
// Bypass the array cast to write a raw, non-JSON-array value directly, simulating
// legacy or corrupted data that predates this column's introduction.
DB::table('artworks')->where('id', $artwork->id)->update([
'featured_thumbnail_variants_json' => '"not-an-array"',
]);
$fresh = $artwork->fresh();
expect($fresh->featuredThumbnailAuditState())->toBe(['status' => 'not_audited', 'variants' => []])
->and($fresh->hasFeaturedThumbnail())->toBeFalse();
});
test('non-string entries in the variants array are ignored rather than matched', function () {
$artwork = makeAuditableArtwork();
DB::table('artworks')->where('id', $artwork->id)->update([
'featured_thumbnail_variants_json' => json_encode(['desktop', 42, null, ['nested' => true]]),
]);
$fresh = $artwork->fresh();
expect($fresh->featuredThumbnailAuditState())->toBe(['status' => 'available', 'variants' => ['desktop']])
->and($fresh->hasFeaturedThumbnail('desktop'))->toBeTrue()
->and($fresh->hasFeaturedThumbnail('tablet'))->toBeFalse();
});
test('an artwork without a hash never reports a featured thumbnail regardless of audit state', function () {
$artwork = makeAuditableArtwork(['hash' => null, 'file_ext' => null]);
$artwork->forceFill([
'featured_thumbnail_variants_json' => ['desktop'],
'featured_thumbnails_checked_at' => now(),
])->saveQuietly();
expect($artwork->fresh()->hasFeaturedThumbnail('desktop'))->toBeFalse();
});
test('changing an artwork hash resets stale featured thumbnail audit state and queues regeneration for featured artworks', function () {
Queue::fake();
$artwork = makeAuditableArtwork([
'hash' => str_repeat('b', 64),
'is_public' => true,
'is_approved' => true,
'published_at' => now()->subHour(),
]);
$artwork->forceFill([
'featured_thumbnail_variants_json' => ['desktop', 'desktop_xl'],
'featured_thumbnails_checked_at' => now(),
])->saveQuietly();
DB::table('artwork_features')->insert([
'artwork_id' => $artwork->id,
'featured_at' => now()->subHour(),
'expires_at' => null,
'priority' => 500,
'label' => null,
'note' => null,
'is_active' => true,
'created_by' => null,
'created_at' => now(),
'updated_at' => now(),
'deleted_at' => null,
]);
// Old hash reported 2 available variants — that state is now stale because the
// object paths it referred to were computed from the old hash.
expect($artwork->fresh()->hasFeaturedThumbnail('desktop'))->toBeTrue();
$artwork->hash = str_repeat('c', 64);
$artwork->save();
$fresh = $artwork->fresh();
expect($fresh->featured_thumbnail_variants_json)->toBeNull()
->and($fresh->featured_thumbnails_checked_at)->toBeNull()
->and($fresh->hasFeaturedThumbnail('desktop'))->toBeFalse();
Queue::assertPushed(GenerateFeaturedArtworkThumbnailsJob::class);
});
test('changing hash on an artwork with no active feature row does not queue regeneration', function () {
Queue::fake();
$artwork = makeAuditableArtwork(['hash' => str_repeat('d', 64)]);
$artwork->forceFill([
'featured_thumbnail_variants_json' => ['desktop'],
'featured_thumbnails_checked_at' => now(),
])->saveQuietly();
$artwork->hash = str_repeat('e', 64);
$artwork->save();
expect($artwork->fresh()->featured_thumbnail_variants_json)->toBeNull();
Queue::assertNotPushed(GenerateFeaturedArtworkThumbnailsJob::class);
});