create(array_merge([ 'slug' => 'studio-category-' . Str::lower(Str::random(6)), 'name' => 'Studio Category', 'description' => 'Studio category', 'active' => true, 'order_num' => 0, ], $attributes)); } function studioCardTemplate(array $attributes = []): NovaCardTemplate { return NovaCardTemplate::query()->create(array_merge([ 'slug' => 'studio-template-' . Str::lower(Str::random(6)), 'name' => 'Studio Template', 'description' => 'Studio template', 'config_json' => [ 'font_preset' => 'modern-sans', 'gradient_preset' => 'midnight-nova', 'layout' => 'quote_heavy', 'text_align' => 'center', 'text_color' => '#ffffff', 'overlay_style' => 'dark-soft', ], 'supported_formats' => ['square', 'portrait', 'story'], 'active' => true, 'official' => true, 'order_num' => 0, ], $attributes)); } function studioDraftCard(User $user, array $attributes = []): NovaCard { $category = $attributes['category'] ?? studioCardCategory(); $template = $attributes['template'] ?? studioCardTemplate(); return NovaCard::query()->create(array_merge([ 'user_id' => $user->id, 'category_id' => $category->id, 'template_id' => $template->id, 'title' => 'Studio Draft', 'slug' => 'studio-draft-' . Str::lower(Str::random(6)), 'quote_text' => 'Studio draft quote text.', 'quote_author' => 'Studio Author', 'quote_source' => 'Studio Notes', 'description' => 'Studio draft description', 'format' => NovaCard::FORMAT_SQUARE, 'project_json' => [ 'content' => [ 'title' => 'Studio Draft', 'quote_text' => 'Studio draft quote text.', 'quote_author' => 'Studio Author', 'quote_source' => 'Studio Notes', ], 'layout' => [ 'layout' => 'quote_heavy', 'position' => 'center', 'alignment' => 'center', 'padding' => 'comfortable', 'max_width' => 'balanced', ], 'typography' => [ 'font_preset' => 'modern-sans', 'text_color' => '#ffffff', 'accent_color' => '#e0f2fe', 'quote_size' => 72, 'author_size' => 28, 'letter_spacing' => 0, ], 'background' => [ 'type' => 'gradient', 'gradient_preset' => 'midnight-nova', 'gradient_colors' => ['#0f172a', '#1d4ed8'], 'overlay_style' => 'dark-soft', 'blur_level' => 0, 'opacity' => 50, ], 'decorations' => [], ], 'render_version' => 1, 'background_type' => 'gradient', 'visibility' => NovaCard::VISIBILITY_PRIVATE, 'status' => NovaCard::STATUS_DRAFT, 'moderation_status' => NovaCard::MOD_PENDING, 'featured' => false, 'allow_download' => true, ], Arr::except($attributes, ['category', 'template']))); } it('requires authentication for studio card pages', function (): void { foreach ([ route('studio.cards.index'), route('studio.cards.create'), ] as $url) { $this->get($url)->assertRedirect('/login'); } }); it('renders the studio cards index with user stats and edit endpoints', function (): void { $user = User::factory()->create(); studioDraftCard($user, ['title' => 'My Studio Draft']); $this->actingAs($user) ->get(route('studio.cards.index')) ->assertOk() ->assertInertia(fn (AssertableInertia $page) => $page ->component('Studio/StudioCardsIndex') ->where('stats.all', 1) ->where('stats.drafts', 1) ->where('cards.data.0.title', 'My Studio Draft') ->where('endpoints.create', route('studio.cards.create')) ->where('endpoints.draftStore', route('api.cards.drafts.store'))); }); it('renders the create editor with preview mode disabled', function (): void { $user = User::factory()->create(); studioCardCategory(['slug' => 'affirmations', 'name' => 'Affirmations']); studioCardTemplate(['slug' => 'bold-center', 'name' => 'Bold Center']); $this->actingAs($user) ->get(route('studio.cards.create')) ->assertOk() ->assertInertia(fn (AssertableInertia $page) => $page ->component('Studio/StudioCardEditor') ->where('previewMode', false) ->where('card', null) ->where('mobileSteps.0.key', 'format') ->where('mobileSteps.5.key', 'publish') ->where('endpoints.studioCards', route('studio.cards.index')) ->where('endpoints.draftStore', route('api.cards.drafts.store')) ->where('editorOptions.categories.0.slug', 'affirmations') ->where('editorOptions.templates.0.slug', 'bold-center')); }); it('renders edit and preview studio pages only for the owner', function (): void { $owner = User::factory()->create(); $other = User::factory()->create(); $card = studioDraftCard($owner, [ 'title' => 'Owner Draft', 'editor_mode_last_used' => 'quick', 'project_json' => [ 'content' => [ 'title' => 'Owner Draft', 'quote_text' => 'Studio draft quote text.', 'quote_author' => 'Studio Author', 'quote_source' => 'Studio Notes', ], 'text_blocks' => [ ['key' => 'title', 'type' => 'title', 'text' => 'Owner Draft', 'enabled' => true], ['key' => 'quote', 'type' => 'quote', 'text' => 'Studio draft quote text.', 'enabled' => true], ], 'layout' => [ 'layout' => 'quote_heavy', 'position' => 'center', 'alignment' => 'center', 'padding' => 'comfortable', 'max_width' => 'balanced', ], 'typography' => [ 'font_preset' => 'modern-sans', 'text_color' => '#ffffff', 'accent_color' => '#e0f2fe', 'quote_size' => 72, 'author_size' => 28, 'letter_spacing' => 0, ], 'background' => [ 'type' => 'gradient', 'gradient_preset' => 'midnight-nova', 'gradient_colors' => ['#0f172a', '#1d4ed8'], 'overlay_style' => 'dark-soft', 'blur_level' => 0, 'opacity' => 50, ], 'source_context' => [ 'editor_mode' => 'quick', ], 'decorations' => [], ], ]); $card->versions()->create([ 'user_id' => $owner->id, 'version_number' => 1, 'label' => 'Initial snapshot', 'snapshot_hash' => hash('sha256', 'owner-draft-v1'), 'snapshot_json' => $card->project_json, ]); $this->actingAs($owner) ->get(route('studio.cards.edit', ['id' => $card->id])) ->assertOk() ->assertInertia(fn (AssertableInertia $page) => $page ->component('Studio/StudioCardEditor') ->where('previewMode', false) ->where('card.id', $card->id) ->where('card.title', 'Owner Draft') ->where('card.editor_mode_last_used', 'quick') ->where('versions.0.snapshot_json.source_context.editor_mode', 'quick')); $this->actingAs($owner) ->get(route('studio.cards.preview', ['id' => $card->id])) ->assertOk() ->assertInertia(fn (AssertableInertia $page) => $page ->component('Studio/StudioCardEditor') ->where('previewMode', true) ->where('card.id', $card->id)); $this->actingAs($other) ->get(route('studio.cards.edit', ['id' => $card->id])) ->assertNotFound(); }); it('renders the studio card analytics page for the owner', function (): void { $owner = User::factory()->create(); $card = studioDraftCard($owner, [ 'title' => 'Analytics Card', 'status' => NovaCard::STATUS_PUBLISHED, 'visibility' => NovaCard::VISIBILITY_PUBLIC, 'likes_count' => 4, 'saves_count' => 3, 'remixes_count' => 2, 'comments_count' => 5, 'views_count' => 12, 'trending_score' => 18.5, 'published_at' => now()->subHour(), ]); $this->actingAs($owner) ->get(route('studio.cards.analytics', ['id' => $card->id])) ->assertOk() ->assertInertia(fn (AssertableInertia $page) => $page ->component('Studio/StudioCardAnalytics') ->where('card.id', $card->id) ->where('analytics.likes', 4) ->where('analytics.comments', 5)); });