trypost/tests/Feature/Ai/Templates/TweetCardTemplateTest.php

47 lines
1.7 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
feat(ai-templates): styles orthogonal to single/carousel; tweet-card carousel - TemplateContext gains bool $isCarousel (set from format === CAROUSEL_FORMAT in StreamPostCreation) - AiContentTemplate interface: promptView() now takes TemplateContext - ImageCardTemplate handles both single and carousel via context.isCarousel; schema() returns the correct shape per mode; assemble() routes to assembleSingle/assembleCarousel - TweetCardTemplate handles both single and carousel; promptView() returns tweet_card_carousel view when isCarousel; schema() returns {tweet_text} or {caption, slides[]}; assemble() calls forTweetCard (single) or forTweetCardCarousel (carousel) - CarouselTemplate deleted — carousel is now a format dimension each style handles, not a standalone style - AiTemplateRegistry: [ImageCardTemplate, TweetCardTemplate] only - PostImagePipeline: adds forTweetCardCarousel — renders one renderTweetCard per slide text, returns N media items - StreamPostCreation: carousel detection restored to $format === CAROUSEL_FORMAT (like main); style dispatched via AiTemplateRegistry::find($this->template); humanize skips tweet_card (single and carousel) - PostContentGenerator: promptView() call updated to pass templateContext - New prompt: resources/views/prompts/post_content/tweet_card_carousel.blade.php - Tests: TemplateContractTest and TweetCardTemplateTest updated for promptView(context) signature; AiTemplateRegistryTest asserts [image_card, tweet_card]; StreamPostCreationTest adds tweet_card carousel test; TweetCardTemplateTest covers both schema shapes and both promptView return values
2026-06-17 21:59:41 +00:00
use App\Ai\Templates\TemplateContext;
use App\Ai\Templates\TweetCardTemplate;
use App\Enums\Ai\ContentStyle;
feat(ai-templates): styles orthogonal to single/carousel; tweet-card carousel - TemplateContext gains bool $isCarousel (set from format === CAROUSEL_FORMAT in StreamPostCreation) - AiContentTemplate interface: promptView() now takes TemplateContext - ImageCardTemplate handles both single and carousel via context.isCarousel; schema() returns the correct shape per mode; assemble() routes to assembleSingle/assembleCarousel - TweetCardTemplate handles both single and carousel; promptView() returns tweet_card_carousel view when isCarousel; schema() returns {tweet_text} or {caption, slides[]}; assemble() calls forTweetCard (single) or forTweetCardCarousel (carousel) - CarouselTemplate deleted — carousel is now a format dimension each style handles, not a standalone style - AiTemplateRegistry: [ImageCardTemplate, TweetCardTemplate] only - PostImagePipeline: adds forTweetCardCarousel — renders one renderTweetCard per slide text, returns N media items - StreamPostCreation: carousel detection restored to $format === CAROUSEL_FORMAT (like main); style dispatched via AiTemplateRegistry::find($this->template); humanize skips tweet_card (single and carousel) - PostContentGenerator: promptView() call updated to pass templateContext - New prompt: resources/views/prompts/post_content/tweet_card_carousel.blade.php - Tests: TemplateContractTest and TweetCardTemplateTest updated for promptView(context) signature; AiTemplateRegistryTest asserts [image_card, tweet_card]; StreamPostCreationTest adds tweet_card carousel test; TweetCardTemplateTest covers both schema shapes and both promptView return values
2026-06-17 21:59:41 +00:00
use App\Models\Workspace;
use Illuminate\JsonSchema\JsonSchemaTypeFactory;
test('tweet card template identity', function () {
$t = new TweetCardTemplate;
feat(ai-templates): styles orthogonal to single/carousel; tweet-card carousel - TemplateContext gains bool $isCarousel (set from format === CAROUSEL_FORMAT in StreamPostCreation) - AiContentTemplate interface: promptView() now takes TemplateContext - ImageCardTemplate handles both single and carousel via context.isCarousel; schema() returns the correct shape per mode; assemble() routes to assembleSingle/assembleCarousel - TweetCardTemplate handles both single and carousel; promptView() returns tweet_card_carousel view when isCarousel; schema() returns {tweet_text} or {caption, slides[]}; assemble() calls forTweetCard (single) or forTweetCardCarousel (carousel) - CarouselTemplate deleted — carousel is now a format dimension each style handles, not a standalone style - AiTemplateRegistry: [ImageCardTemplate, TweetCardTemplate] only - PostImagePipeline: adds forTweetCardCarousel — renders one renderTweetCard per slide text, returns N media items - StreamPostCreation: carousel detection restored to $format === CAROUSEL_FORMAT (like main); style dispatched via AiTemplateRegistry::find($this->template); humanize skips tweet_card (single and carousel) - PostContentGenerator: promptView() call updated to pass templateContext - New prompt: resources/views/prompts/post_content/tweet_card_carousel.blade.php - Tests: TemplateContractTest and TweetCardTemplateTest updated for promptView(context) signature; AiTemplateRegistryTest asserts [image_card, tweet_card]; StreamPostCreationTest adds tweet_card carousel test; TweetCardTemplateTest covers both schema shapes and both promptView return values
2026-06-17 21:59:41 +00:00
$workspace = Workspace::factory()->create();
$singleContext = new TemplateContext($workspace, null, 'x_post', 1, false);
$carouselContext = new TemplateContext($workspace, null, 'instagram_carousel', 2, true);
expect($t->style())->toBe(ContentStyle::TweetCard)
->and($t->key())->toBe('tweet_card')
->and($t->needsAccount())->toBeTrue()
->and($t->style()->isTweetCard())->toBeTrue()
feat(ai-templates): styles orthogonal to single/carousel; tweet-card carousel - TemplateContext gains bool $isCarousel (set from format === CAROUSEL_FORMAT in StreamPostCreation) - AiContentTemplate interface: promptView() now takes TemplateContext - ImageCardTemplate handles both single and carousel via context.isCarousel; schema() returns the correct shape per mode; assemble() routes to assembleSingle/assembleCarousel - TweetCardTemplate handles both single and carousel; promptView() returns tweet_card_carousel view when isCarousel; schema() returns {tweet_text} or {caption, slides[]}; assemble() calls forTweetCard (single) or forTweetCardCarousel (carousel) - CarouselTemplate deleted — carousel is now a format dimension each style handles, not a standalone style - AiTemplateRegistry: [ImageCardTemplate, TweetCardTemplate] only - PostImagePipeline: adds forTweetCardCarousel — renders one renderTweetCard per slide text, returns N media items - StreamPostCreation: carousel detection restored to $format === CAROUSEL_FORMAT (like main); style dispatched via AiTemplateRegistry::find($this->template); humanize skips tweet_card (single and carousel) - PostContentGenerator: promptView() call updated to pass templateContext - New prompt: resources/views/prompts/post_content/tweet_card_carousel.blade.php - Tests: TemplateContractTest and TweetCardTemplateTest updated for promptView(context) signature; AiTemplateRegistryTest asserts [image_card, tweet_card]; StreamPostCreationTest adds tweet_card carousel test; TweetCardTemplateTest covers both schema shapes and both promptView return values
2026-06-17 21:59:41 +00:00
->and($t->promptView($singleContext))->toBe('prompts.post_content.tweet_card')
->and($t->promptView($carouselContext))->toBe('prompts.post_content.tweet_card_carousel');
});
test('tweet card single schema returns tweet_text only', function () {
$t = new TweetCardTemplate;
$workspace = Workspace::factory()->create();
$context = new TemplateContext($workspace, null, 'x_post', 1, false);
$schema = new JsonSchemaTypeFactory;
$result = $t->schema($schema, $context);
expect($result)->toHaveKey('tweet_text')
->and($result)->not->toHaveKey('caption');
});
test('tweet card carousel schema returns caption and slides', function () {
$t = new TweetCardTemplate;
$workspace = Workspace::factory()->create();
$context = new TemplateContext($workspace, null, 'instagram_carousel', 3, true);
$schema = new JsonSchemaTypeFactory;
$result = $t->schema($schema, $context);
expect($result)->toHaveKeys(['caption', 'slides']);
});