feat(cms,asset): add comprehensive test suite and finalize modules
- Add comprehensive test suite for CMS and Asset modules using Pest Framework - Implement ContentTypeService::delete() protection against deletion of in-use content types - Add CannotDeleteContentTypeInUseException for better error handling - Fix DerivatPipelineRegistry::getAllPipelines() to handle object uniqueness correctly - Fix VariantName::getScale() to correctly parse scales with file extensions - Update CMS module documentation with new features, exceptions, and test coverage - Add CmsTestHelpers and AssetTestHelpers for test data factories - Fix BlockTypeRegistry to be immutable after construction - Update ContentTypeService to check for associated content before deletion - Improve BlockRendererRegistry initialization Test coverage: - Value Objects: All CMS and Asset value objects - Services: ContentService, ContentTypeService, SlugGenerator, BlockValidator, ContentLocalizationService, AssetService, DeduplicationService, MetadataExtractor - Repositories: All database repositories with mocked connections - Rendering: Block renderers and ContentRenderer - Controllers: API endpoints for both modules 254 tests passing, 38 remaining (mostly image processing pipeline tests)
This commit is contained in:
161
tests/Unit/Domain/Cms/Rendering/ContentRendererTest.php
Normal file
161
tests/Unit/Domain/Cms/Rendering/ContentRendererTest.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Domain\Cms\Entities\Content;
|
||||
use App\Domain\Cms\Enums\ContentStatus;
|
||||
use App\Domain\Cms\Rendering\BlockRendererRegistry;
|
||||
use App\Domain\Cms\Rendering\DefaultBlockRenderer;
|
||||
use App\Domain\Cms\Rendering\HeroBlockRenderer;
|
||||
use App\Domain\Cms\Rendering\TextBlockRenderer;
|
||||
use App\Domain\Cms\Services\ContentLocalizationService;
|
||||
use App\Domain\Cms\Services\ContentRenderer;
|
||||
use App\Domain\Cms\ValueObjects\BlockId;
|
||||
use App\Domain\Cms\ValueObjects\BlockType;
|
||||
use App\Domain\Cms\ValueObjects\ContentBlocks;
|
||||
use App\Domain\Cms\ValueObjects\ContentId;
|
||||
use App\Domain\Cms\ValueObjects\ContentSlug;
|
||||
use App\Domain\Cms\ValueObjects\ContentTypeId;
|
||||
use App\Domain\Cms\ValueObjects\Locale;
|
||||
use App\Framework\Core\ValueObjects\Timestamp;
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\Filesystem\FileStorage;
|
||||
use App\Framework\Cache\Cache;
|
||||
use App\Framework\Cache\Driver\NullCache;
|
||||
use App\Framework\Cache\GeneralCache;
|
||||
use App\Framework\Core\PathProvider;
|
||||
use App\Framework\Serializer\Serializer;
|
||||
use App\Framework\View\ComponentCache;
|
||||
use App\Framework\View\ComponentRenderer;
|
||||
use App\Framework\View\Loading\TemplateLoader;
|
||||
use App\Framework\View\TemplateProcessor;
|
||||
use Tests\Support\CmsTestHelpers;
|
||||
|
||||
describe('ContentRenderer', function () {
|
||||
beforeEach(function () {
|
||||
$this->clock = new SystemClock();
|
||||
$this->blockRegistry = new BlockRendererRegistry();
|
||||
|
||||
// Create minimal real TemplateLoader for testing
|
||||
$pathProvider = new PathProvider(__DIR__ . '/../../../../../');
|
||||
$nullCacheDriver = new NullCache();
|
||||
$serializer = Mockery::mock(Serializer::class);
|
||||
$serializer->shouldReceive('serialize')->andReturnUsing(fn($data) => serialize($data));
|
||||
$serializer->shouldReceive('unserialize')->andReturnUsing(fn($data) => unserialize($data));
|
||||
$cache = new GeneralCache($nullCacheDriver, $serializer);
|
||||
$templateLoader = new TemplateLoader(
|
||||
pathProvider: $pathProvider,
|
||||
cache: $cache,
|
||||
discoveryRegistry: null,
|
||||
templates: [],
|
||||
templatePath: '/src/Framework/View/templates',
|
||||
cacheEnabled: false
|
||||
);
|
||||
|
||||
$componentCache = new ComponentCache('/tmp/test-cache');
|
||||
|
||||
// Create minimal real TemplateProcessor for testing
|
||||
$container = new DefaultContainer();
|
||||
$templateProcessor = new TemplateProcessor(
|
||||
astTransformers: [],
|
||||
stringProcessors: [],
|
||||
container: $container,
|
||||
chainOptimizer: null,
|
||||
compiledTemplateCache: null,
|
||||
performanceTracker: null
|
||||
);
|
||||
|
||||
// Create real FileStorage for testing
|
||||
$fileStorage = new FileStorage(
|
||||
basePath: sys_get_temp_dir() . '/test-components'
|
||||
);
|
||||
|
||||
$this->componentRenderer = new ComponentRenderer(
|
||||
$templateProcessor,
|
||||
$componentCache,
|
||||
$templateLoader,
|
||||
$fileStorage
|
||||
);
|
||||
|
||||
// Create real ContentLocalizationService for testing
|
||||
$contentTranslationRepository = Mockery::mock(\App\Domain\Cms\Repositories\ContentTranslationRepository::class);
|
||||
$this->localizationService = new ContentLocalizationService(
|
||||
$contentTranslationRepository,
|
||||
$this->clock
|
||||
);
|
||||
$this->defaultRenderer = new DefaultBlockRenderer();
|
||||
$this->renderer = new ContentRenderer(
|
||||
$this->blockRegistry,
|
||||
$this->componentRenderer,
|
||||
$this->localizationService,
|
||||
$this->defaultRenderer
|
||||
);
|
||||
});
|
||||
|
||||
it('renders content with multiple blocks', function () {
|
||||
$content = CmsTestHelpers::createContent($this->clock);
|
||||
// ContentLocalizationService is real instance, no need to mock
|
||||
|
||||
$html = $this->renderer->render($content);
|
||||
|
||||
expect($html)->toBeString();
|
||||
expect($html)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
it('uses default renderer for unregistered block types', function () {
|
||||
$blocks = ContentBlocks::fromArray([
|
||||
[
|
||||
'id' => 'custom-1',
|
||||
'type' => 'custom-block',
|
||||
'data' => ['key' => 'value'],
|
||||
],
|
||||
]);
|
||||
|
||||
$content = CmsTestHelpers::createContent($this->clock, blocks: $blocks);
|
||||
// ContentLocalizationService is real instance, no need to mock
|
||||
|
||||
$html = $this->renderer->render($content);
|
||||
|
||||
expect($html)->toBeString();
|
||||
expect($html)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
it('uses registered renderer for block type', function () {
|
||||
$this->blockRegistry->registerForType('hero', new HeroBlockRenderer());
|
||||
$content = CmsTestHelpers::createContent($this->clock);
|
||||
// ContentLocalizationService is real instance, no need to mock
|
||||
|
||||
$html = $this->renderer->render($content);
|
||||
|
||||
expect($html)->toBeString();
|
||||
expect($html)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
it('renders blocks to component data array', function () {
|
||||
$this->blockRegistry->registerForType('hero', new HeroBlockRenderer());
|
||||
$this->blockRegistry->registerForType('text', new TextBlockRenderer());
|
||||
$content = CmsTestHelpers::createContent($this->clock);
|
||||
// ContentLocalizationService is real instance, no need to mock
|
||||
|
||||
$componentData = $this->renderer->renderBlocksToComponentData($content);
|
||||
|
||||
expect($componentData)->toBeArray();
|
||||
expect($componentData)->toHaveCount(2);
|
||||
expect($componentData[0]['component'])->toBe('cms/hero');
|
||||
expect($componentData[1]['component'])->toBe('cms/text');
|
||||
});
|
||||
|
||||
it('uses provided locale for rendering', function () {
|
||||
$content = CmsTestHelpers::createContent($this->clock);
|
||||
$locale = Locale::german();
|
||||
// ContentLocalizationService is real instance, no need to mock
|
||||
|
||||
$html = $this->renderer->render($content, $locale);
|
||||
|
||||
expect($html)->toBeString();
|
||||
expect($html)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user