250 lines
9.1 KiB
PHP
250 lines
9.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\NovaCard;
|
|
use App\Models\NovaCardCategory;
|
|
use App\Models\NovaCardTemplate;
|
|
use App\Models\User;
|
|
use Inertia\Testing\AssertableInertia;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Str;
|
|
|
|
function studioCardCategory(array $attributes = []): NovaCardCategory
|
|
{
|
|
return NovaCardCategory::query()->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));
|
|
});
|