isEmpty())->toBeTrue(); expect($blocks->count())->toBe(0); }); it('can be created from array', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], [ 'id' => 'text-1', 'type' => 'text', 'data' => ['content' => 'Text'], ], ]); expect($blocks->count())->toBe(2); expect($blocks->isEmpty())->toBeFalse(); }); it('can add blocks', function () { $blocks = ContentBlocks::empty(); $block = ContentBlock::create( type: BlockType::hero(), blockId: BlockId::fromString('hero-1'), data: BlockData::fromArray(['title' => 'Hero']) ); $newBlocks = $blocks->add($block); expect($newBlocks->count())->toBe(1); expect($blocks->count())->toBe(0); // Original unchanged }); it('throws exception when adding duplicate block ID', function () { $block = ContentBlock::create( type: BlockType::hero(), blockId: BlockId::fromString('hero-1'), data: BlockData::fromArray(['title' => 'Hero']) ); $blocks = ContentBlocks::fromArray([$block->toArray()]); expect(fn () => $blocks->add($block)) ->toThrow(\InvalidArgumentException::class); }); it('can remove blocks', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], [ 'id' => 'text-1', 'type' => 'text', 'data' => ['content' => 'Text'], ], ]); $newBlocks = $blocks->remove(BlockId::fromString('hero-1')); expect($newBlocks->count())->toBe(1); expect($blocks->count())->toBe(2); // Original unchanged expect($newBlocks->findById(BlockId::fromString('text-1')))->not->toBeNull(); }); it('can find block by ID', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], [ 'id' => 'text-1', 'type' => 'text', 'data' => ['content' => 'Text'], ], ]); $found = $blocks->findById(BlockId::fromString('hero-1')); expect($found)->not->toBeNull(); expect($found->blockId->toString())->toBe('hero-1'); $notFound = $blocks->findById(BlockId::fromString('missing')); expect($notFound)->toBeNull(); }); it('can be iterated', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], [ 'id' => 'text-1', 'type' => 'text', 'data' => ['content' => 'Text'], ], ]); $count = 0; foreach ($blocks as $block) { expect($block)->toBeInstanceOf(ContentBlock::class); $count++; } expect($count)->toBe(2); }); it('can convert to array', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], ]); $array = $blocks->toArray(); expect($array)->toBeArray(); expect($array)->toHaveCount(1); expect($array[0]['id'])->toBe('hero-1'); }); it('throws exception when creating with duplicate block IDs', function () { expect(fn () => ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], [ 'id' => 'hero-1', 'type' => 'text', 'data' => ['content' => 'Text'], ], ]))->toThrow(InvalidArgumentException::class, 'Duplicate block ID'); }); it('can get all blocks', function () { $blocks = ContentBlocks::fromArray([ [ 'id' => 'hero-1', 'type' => 'hero', 'data' => ['title' => 'Hero'], ], ]); $allBlocks = $blocks->getBlocks(); expect($allBlocks)->toBeArray(); expect($allBlocks)->toHaveCount(1); expect($allBlocks[0])->toBeInstanceOf(ContentBlock::class); }); });