new test files
This commit is contained in:
176
tests/Feature/Worlds/WorldRecurrenceWorkflowTest.php
Normal file
176
tests/Feature/Worlds/WorldRecurrenceWorkflowTest.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\World;
|
||||
use App\Models\WorldRelation;
|
||||
use App\Services\Worlds\WorldService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
function recurringWorldModerator(): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'role' => 'moderator',
|
||||
'username' => 'recurrence-mod-' . Str::lower(Str::random(6)),
|
||||
'name' => 'Recurrence Moderator',
|
||||
]);
|
||||
}
|
||||
|
||||
function studioRecurringWorld(User $creator, array $attributes = []): World
|
||||
{
|
||||
return World::factory()->create(array_merge([
|
||||
'created_by_user_id' => $creator->id,
|
||||
'title' => 'Retro Month 2026',
|
||||
'slug' => 'retro-month-2026',
|
||||
'status' => World::STATUS_PUBLISHED,
|
||||
'type' => World::TYPE_EVENT,
|
||||
'starts_at' => Carbon::now()->subDays(14),
|
||||
'ends_at' => Carbon::now()->addDays(7),
|
||||
'promotion_starts_at' => Carbon::now()->subDays(10),
|
||||
'promotion_ends_at' => Carbon::now()->addDays(5),
|
||||
'submission_starts_at' => Carbon::now()->subDays(7),
|
||||
'submission_ends_at' => Carbon::now()->addDays(5),
|
||||
'published_at' => Carbon::now()->subDays(21),
|
||||
'is_active_campaign' => true,
|
||||
'is_homepage_featured' => true,
|
||||
'campaign_priority' => 200,
|
||||
'is_recurring' => true,
|
||||
'recurrence_key' => 'retro-month',
|
||||
'recurrence_rule' => 'yearly',
|
||||
'edition_year' => 2026,
|
||||
'cta_url' => 'https://skinbase.test/worlds/retro-month',
|
||||
'badge_url' => 'https://skinbase.test/badges/retro-month',
|
||||
], $attributes));
|
||||
}
|
||||
|
||||
it('creates a clean next edition draft for recurring worlds', function (): void {
|
||||
$moderator = recurringWorldModerator();
|
||||
$source = studioRecurringWorld($moderator);
|
||||
|
||||
WorldRelation::query()->create([
|
||||
'world_id' => $source->id,
|
||||
'section_key' => 'featured_artworks',
|
||||
'related_type' => WorldRelation::TYPE_ARTWORK,
|
||||
'related_id' => 123,
|
||||
'context_label' => 'Carry-over candidate',
|
||||
'sort_order' => 0,
|
||||
'is_featured' => true,
|
||||
]);
|
||||
|
||||
$this->actingAs($moderator)
|
||||
->from(route('studio.worlds.edit', ['world' => $source->id]))
|
||||
->post(route('studio.worlds.new-edition', ['world' => $source->id]), [
|
||||
'copy_mode' => WorldService::COPY_MODE_STRUCTURE_ONLY,
|
||||
]);
|
||||
|
||||
$edition = World::query()
|
||||
->whereKeyNot($source->id)
|
||||
->latest('id')
|
||||
->firstOrFail();
|
||||
|
||||
expect($edition->title)->toBe('Retro Month 2027')
|
||||
->and($edition->slug)->toBe('retro-month-2027')
|
||||
->and($edition->status)->toBe(World::STATUS_DRAFT)
|
||||
->and($edition->is_recurring)->toBeTrue()
|
||||
->and($edition->recurrence_key)->toBe('retro-month')
|
||||
->and($edition->recurrence_rule)->toBe('yearly')
|
||||
->and($edition->edition_year)->toBe(2027)
|
||||
->and($edition->parent_world_id)->toBe($source->id)
|
||||
->and($edition->starts_at)->toBeNull()
|
||||
->and($edition->ends_at)->toBeNull()
|
||||
->and($edition->promotion_starts_at)->toBeNull()
|
||||
->and($edition->promotion_ends_at)->toBeNull()
|
||||
->and($edition->submission_starts_at)->toBeNull()
|
||||
->and($edition->submission_ends_at)->toBeNull()
|
||||
->and($edition->published_at)->toBeNull()
|
||||
->and($edition->is_active_campaign)->toBeFalse()
|
||||
->and($edition->is_homepage_featured)->toBeFalse()
|
||||
->and($edition->campaign_priority)->toBeNull()
|
||||
->and($edition->cta_url)->toBeNull()
|
||||
->and($edition->badge_url)->toBeNull()
|
||||
->and($edition->worldRelations()->count())->toBe(0);
|
||||
});
|
||||
|
||||
it('rejects next edition creation for non-recurring worlds', function (): void {
|
||||
$moderator = recurringWorldModerator();
|
||||
$world = World::factory()->create([
|
||||
'created_by_user_id' => $moderator->id,
|
||||
'title' => 'One-Off Showcase 2026',
|
||||
'slug' => 'one-off-showcase-2026',
|
||||
'status' => World::STATUS_PUBLISHED,
|
||||
'type' => World::TYPE_EVENT,
|
||||
'is_recurring' => false,
|
||||
'recurrence_key' => null,
|
||||
'recurrence_rule' => null,
|
||||
'edition_year' => null,
|
||||
]);
|
||||
|
||||
$this->actingAs($moderator)
|
||||
->from(route('studio.worlds.edit', ['world' => $world->id]))
|
||||
->post(route('studio.worlds.new-edition', ['world' => $world->id]))
|
||||
->assertSessionHasErrors(['recurrence_key']);
|
||||
|
||||
expect(World::query()->count())->toBe(1);
|
||||
});
|
||||
|
||||
it('rejects duplicate recurrence years when storing worlds', function (): void {
|
||||
$moderator = recurringWorldModerator();
|
||||
|
||||
studioRecurringWorld($moderator, [
|
||||
'title' => 'Pixel Week 2026',
|
||||
'slug' => 'pixel-week-2026',
|
||||
'recurrence_key' => 'pixel-week',
|
||||
'edition_year' => 2026,
|
||||
]);
|
||||
|
||||
$this->actingAs($moderator)
|
||||
->from(route('studio.worlds.create'))
|
||||
->post(route('studio.worlds.store'), [
|
||||
'title' => 'Pixel Week Draft',
|
||||
'slug' => 'pixel-week-draft',
|
||||
'status' => World::STATUS_DRAFT,
|
||||
'type' => World::TYPE_EVENT,
|
||||
'is_recurring' => true,
|
||||
'recurrence_key' => 'pixel-week',
|
||||
'edition_year' => 2026,
|
||||
])
|
||||
->assertSessionHasErrors(['edition_year']);
|
||||
|
||||
expect(World::query()->count())->toBe(1);
|
||||
});
|
||||
|
||||
it('rejects publishing a second current edition for the same recurrence family', function (): void {
|
||||
$moderator = recurringWorldModerator();
|
||||
|
||||
studioRecurringWorld($moderator, [
|
||||
'title' => 'Spring Vibes 2026',
|
||||
'slug' => 'spring-vibes-2026',
|
||||
'recurrence_key' => 'spring-vibes',
|
||||
'edition_year' => 2026,
|
||||
'status' => World::STATUS_PUBLISHED,
|
||||
'starts_at' => Carbon::now()->subDays(3),
|
||||
'ends_at' => Carbon::now()->addDays(10),
|
||||
]);
|
||||
|
||||
$this->actingAs($moderator)
|
||||
->from(route('studio.worlds.create'))
|
||||
->post(route('studio.worlds.store'), [
|
||||
'title' => 'Spring Vibes 2027',
|
||||
'slug' => 'spring-vibes-2027',
|
||||
'status' => World::STATUS_PUBLISHED,
|
||||
'type' => World::TYPE_EVENT,
|
||||
'starts_at' => Carbon::now()->subDay()->toIso8601String(),
|
||||
'ends_at' => Carbon::now()->addDays(14)->toIso8601String(),
|
||||
'is_recurring' => true,
|
||||
'recurrence_key' => 'spring-vibes',
|
||||
'edition_year' => 2027,
|
||||
])
|
||||
->assertSessionHasErrors(['status']);
|
||||
|
||||
expect(World::query()->count())->toBe(1);
|
||||
});
|
||||
Reference in New Issue
Block a user