Some checks failed
Deploy Application / deploy (push) Has been cancelled
214 lines
7.5 KiB
PHP
214 lines
7.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Application\Admin\Cms\Services\ContentPreviewService;
|
|
use App\Application\LiveComponents\Admin\BlockEditor\BlockEditorComponent;
|
|
use App\Application\LiveComponents\Admin\BlockEditor\BlockEditorState;
|
|
use App\Domain\Cms\Services\BlockTemplateService;
|
|
use App\Domain\Cms\Services\BlockTypeRegistry;
|
|
use App\Framework\LiveComponents\ComponentRegistry;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
|
|
|
describe('BlockEditorComponent', function () {
|
|
beforeEach(function () {
|
|
$this->componentId = ComponentId::generate('admin-block-editor');
|
|
$this->blockTypeRegistry = new BlockTypeRegistry();
|
|
$this->componentRegistry = Mockery::mock(ComponentRegistry::class);
|
|
|
|
// Mock ContentPreviewService
|
|
$this->previewService = Mockery::mock(ContentPreviewService::class);
|
|
$this->previewService
|
|
->shouldReceive('renderPreview')
|
|
->andReturn('<div>Preview HTML</div>');
|
|
|
|
// Mock BlockTemplateService
|
|
$this->templateService = Mockery::mock(BlockTemplateService::class);
|
|
$this->templateService
|
|
->shouldReceive('getAllTemplates')
|
|
->andReturn([
|
|
'landing-page' => [
|
|
'name' => 'Landing Page',
|
|
'description' => 'Test template',
|
|
'blocks' => [],
|
|
],
|
|
]);
|
|
|
|
$this->state = BlockEditorState::empty();
|
|
});
|
|
|
|
it('creates component with initial state', function () {
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
expect($component->id)->toBe($this->componentId);
|
|
expect($component->state)->toBe($this->state);
|
|
});
|
|
|
|
it('adds a new block', function () {
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$newState = $component->addBlock('hero');
|
|
|
|
expect($newState->blocks)->toHaveCount(1);
|
|
expect($newState->blocks[0]['type'])->toBe('hero');
|
|
});
|
|
|
|
it('does not add block for invalid block type', function () {
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$newState = $component->addBlock('invalid-type');
|
|
|
|
expect($newState->blocks)->toBeEmpty();
|
|
});
|
|
|
|
it('removes a block', function () {
|
|
$state = $this->state->withBlockAdded('hero', ['title' => 'Test']);
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$blockId = $state->blocks[0]['id'];
|
|
$newState = $component->removeBlock($blockId);
|
|
|
|
expect($newState->blocks)->toBeEmpty();
|
|
});
|
|
|
|
it('updates block field', function () {
|
|
$state = $this->state->withBlockAdded('text', ['content' => 'Old content']);
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$blockId = $state->blocks[0]['id'];
|
|
$newState = $component->updateBlockField($blockId, 'content', 'New content');
|
|
|
|
expect($newState->blocks[0]['data']['content'])->toBe('New content');
|
|
});
|
|
|
|
it('reorders blocks', function () {
|
|
$state = $this->state
|
|
->withBlockAdded('hero', ['title' => 'Hero'])
|
|
->withBlockAdded('text', ['content' => 'Text']);
|
|
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$blockIds = array_map(fn ($block) => $block['id'], $state->blocks);
|
|
$reorderedIds = array_reverse($blockIds);
|
|
|
|
$newState = $component->reorderBlocks($reorderedIds);
|
|
|
|
expect($newState->blocks[0]['type'])->toBe('text');
|
|
expect($newState->blocks[1]['type'])->toBe('hero');
|
|
});
|
|
|
|
it('toggles preview mode', function () {
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$newState = $component->togglePreview();
|
|
|
|
expect($newState->isPreviewMode)->toBeTrue();
|
|
expect($newState->previewHtml)->not->toBeNull();
|
|
});
|
|
|
|
it('applies template', function () {
|
|
$this->templateService
|
|
->shouldReceive('hasTemplate')
|
|
->with('landing-page')
|
|
->andReturn(true);
|
|
|
|
$this->templateService
|
|
->shouldReceive('getTemplate')
|
|
->with('landing-page')
|
|
->andReturn([
|
|
'name' => 'Landing Page',
|
|
'description' => 'Test',
|
|
'blocks' => [
|
|
[
|
|
'type' => 'hero',
|
|
'data' => ['title' => 'Hero Title'],
|
|
],
|
|
],
|
|
]);
|
|
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$newState = $component->applyTemplate('landing-page');
|
|
|
|
expect($newState->blocks)->not->toBeEmpty();
|
|
expect($newState->blocks[0]['type'])->toBe('hero');
|
|
});
|
|
|
|
it('does not apply invalid template', function () {
|
|
$this->templateService
|
|
->shouldReceive('hasTemplate')
|
|
->with('invalid')
|
|
->andReturn(false);
|
|
|
|
$component = new BlockEditorComponent(
|
|
id: $this->componentId,
|
|
state: $this->state,
|
|
blockTypeRegistry: $this->blockTypeRegistry,
|
|
previewService: $this->previewService,
|
|
componentRegistry: $this->componentRegistry,
|
|
templateService: $this->templateService
|
|
);
|
|
|
|
$newState = $component->applyTemplate('invalid');
|
|
|
|
expect($newState->blocks)->toBeEmpty();
|
|
});
|
|
});
|
|
|