Files
michaelschiemer/tests/Unit/Framework/LiveComponents/SlotValueObjectsTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

318 lines
11 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\SlotContent;
use App\Framework\LiveComponents\ValueObjects\SlotContext;
use App\Framework\LiveComponents\ValueObjects\SlotDefinition;
describe('SlotDefinition', function () {
it('creates default slot', function () {
$slot = SlotDefinition::default('<p>Default content</p>');
expect($slot->name)->toBe('default');
expect($slot->defaultContent)->toBe('<p>Default content</p>');
expect($slot->required)->toBeFalse();
expect($slot->isDefault())->toBeTrue();
expect($slot->isScoped())->toBeFalse();
});
it('creates named slot', function () {
$slot = SlotDefinition::named('header', '<h1>Default Header</h1>');
expect($slot->name)->toBe('header');
expect($slot->defaultContent)->toBe('<h1>Default Header</h1>');
expect($slot->isDefault())->toBeFalse();
});
it('creates scoped slot with props', function () {
$slot = SlotDefinition::scoped('content', ['userId', 'userName']);
expect($slot->name)->toBe('content');
expect($slot->props)->toBe(['userId', 'userName']);
expect($slot->isScoped())->toBeTrue();
});
it('marks slot as required', function () {
$slot = SlotDefinition::named('body')->withRequired(true);
expect($slot->required)->toBeTrue();
});
it('updates default content', function () {
$slot = SlotDefinition::named('header')
->withDefaultContent('<h2>New Default</h2>');
expect($slot->defaultContent)->toBe('<h2>New Default</h2>');
});
it('updates props', function () {
$slot = SlotDefinition::named('content')
->withProps(['prop1', 'prop2']);
expect($slot->props)->toBe(['prop1', 'prop2']);
expect($slot->isScoped())->toBeTrue();
});
it('checks if has default content', function () {
$slotWithDefault = SlotDefinition::named('header', '<h1>Default</h1>');
$slotWithoutDefault = SlotDefinition::named('header', '');
expect($slotWithDefault->hasDefaultContent())->toBeTrue();
expect($slotWithoutDefault->hasDefaultContent())->toBeFalse();
});
it('throws on empty slot name', function () {
expect(fn () => new SlotDefinition(''))->toThrow(\InvalidArgumentException::class);
});
it('converts to array for serialization', function () {
$slot = SlotDefinition::scoped('content', ['key1', 'key2'], '<p>Default</p>')
->withRequired(true);
$array = $slot->toArray();
expect($array['name'])->toBe('content');
expect($array['default_content'])->toBe('<p>Default</p>');
expect($array['props'])->toBe(['key1', 'key2']);
expect($array['required'])->toBeTrue();
expect($array['is_scoped'])->toBeTrue();
});
it('checks equality', function () {
$slot1 = SlotDefinition::named('header', '<h1>Header</h1>');
$slot2 = SlotDefinition::named('header', '<h1>Header</h1>');
$slot3 = SlotDefinition::named('header', '<h2>Different</h2>');
expect($slot1->equals($slot2))->toBeTrue();
expect($slot1->equals($slot3))->toBeFalse();
});
});
describe('SlotContent', function () {
it('creates default slot content', function () {
$content = SlotContent::default('<p>Content</p>');
expect($content->slotName)->toBe('default');
expect($content->content)->toBe('<p>Content</p>');
expect($content->isDefault())->toBeTrue();
});
it('creates named slot content', function () {
$content = SlotContent::named('header', '<h1>Header</h1>');
expect($content->slotName)->toBe('header');
expect($content->content)->toBe('<h1>Header</h1>');
expect($content->isDefault())->toBeFalse();
});
it('creates slot content with data', function () {
$content = SlotContent::named('content', '<p>{title}</p>', ['title' => 'My Title']);
expect($content->hasData())->toBeTrue();
expect($content->getData('title'))->toBe('My Title');
});
it('creates slot content from component', function () {
$componentId = ComponentId::generate();
$content = SlotContent::fromComponent('header', $componentId, '<h1>Header</h1>');
expect($content->isFromComponent())->toBeTrue();
expect($content->componentId)->toBe($componentId);
});
it('checks if content is empty', function () {
$emptyContent = SlotContent::named('header', ' ');
$filledContent = SlotContent::named('header', '<h1>Header</h1>');
expect($emptyContent->isEmpty())->toBeTrue();
expect($filledContent->isEmpty())->toBeFalse();
});
it('gets data with default value', function () {
$content = SlotContent::named('content', '<p>Content</p>', ['key' => 'value']);
expect($content->getData('key'))->toBe('value');
expect($content->getData('missing', 'default'))->toBe('default');
});
it('adds data to content', function () {
$content = SlotContent::named('content', '<p>Content</p>')
->withData(['key1' => 'value1', 'key2' => 'value2']);
expect($content->hasData())->toBeTrue();
expect($content->getData('key1'))->toBe('value1');
expect($content->getData('key2'))->toBe('value2');
});
it('updates content', function () {
$content = SlotContent::named('header', '<h1>Old</h1>')
->withContent('<h2>New</h2>');
expect($content->content)->toBe('<h2>New</h2>');
});
it('throws on empty slot name', function () {
expect(fn () => new SlotContent('', 'content'))->toThrow(\InvalidArgumentException::class);
});
it('converts to array for serialization', function () {
$componentId = ComponentId::generate();
$content = SlotContent::fromComponent('header', $componentId, '<h1>Header</h1>', ['key' => 'value']);
$array = $content->toArray();
expect($array['slot_name'])->toBe('header');
expect($array['content'])->toBe('<h1>Header</h1>');
expect($array['data'])->toBe(['key' => 'value']);
expect($array['component_id'])->toBe($componentId->toString());
expect($array['is_default'])->toBeFalse();
expect($array['has_data'])->toBeTrue();
});
it('creates from array', function () {
$array = [
'slot_name' => 'header',
'content' => '<h1>Header</h1>',
'data' => ['key' => 'value'],
];
$content = SlotContent::fromArray($array);
expect($content->slotName)->toBe('header');
expect($content->content)->toBe('<h1>Header</h1>');
expect($content->getData('key'))->toBe('value');
});
});
describe('SlotContext', function () {
it('creates empty context', function () {
$context = SlotContext::empty();
expect($context->isEmpty())->toBeTrue();
expect($context->count())->toBe(0);
});
it('creates context with data', function () {
$context = SlotContext::create(['key1' => 'value1', 'key2' => 'value2']);
expect($context->isEmpty())->toBeFalse();
expect($context->count())->toBe(2);
expect($context->get('key1'))->toBe('value1');
expect($context->get('key2'))->toBe('value2');
});
it('creates context with metadata', function () {
$context = SlotContext::create(
['data' => 'value'],
['timestamp' => 1234567890]
);
expect($context->getMetadata('timestamp'))->toBe(1234567890);
});
it('checks if key exists', function () {
$context = SlotContext::create(['key' => 'value']);
expect($context->has('key'))->toBeTrue();
expect($context->has('missing'))->toBeFalse();
});
it('gets value with default', function () {
$context = SlotContext::create(['key' => 'value']);
expect($context->get('key'))->toBe('value');
expect($context->get('missing', 'default'))->toBe('default');
});
it('adds data to context', function () {
$context = SlotContext::empty()
->withData(['key1' => 'value1'])
->withData(['key2' => 'value2']);
expect($context->count())->toBe(2);
expect($context->get('key1'))->toBe('value1');
expect($context->get('key2'))->toBe('value2');
});
it('sets single data value', function () {
$context = SlotContext::empty()
->with('key1', 'value1')
->with('key2', 'value2');
expect($context->count())->toBe(2);
});
it('removes data key', function () {
$context = SlotContext::create(['key1' => 'value1', 'key2' => 'value2'])
->without('key1');
expect($context->has('key1'))->toBeFalse();
expect($context->has('key2'))->toBeTrue();
});
it('gets all data keys', function () {
$context = SlotContext::create(['key1' => 'value1', 'key2' => 'value2']);
$keys = $context->keys();
expect($keys)->toBe(['key1', 'key2']);
});
it('merges contexts', function () {
$context1 = SlotContext::create(['key1' => 'value1']);
$context2 = SlotContext::create(['key2' => 'value2']);
$merged = $context1->merge($context2);
expect($merged->count())->toBe(2);
expect($merged->get('key1'))->toBe('value1');
expect($merged->get('key2'))->toBe('value2');
});
it('adds metadata to context', function () {
$context = SlotContext::empty()
->withMetadata(['meta1' => 'value1'])
->withMetadata(['meta2' => 'value2']);
expect($context->getMetadata('meta1'))->toBe('value1');
expect($context->getMetadata('meta2'))->toBe('value2');
});
it('converts to array for serialization', function () {
$context = SlotContext::create(
['key1' => 'value1', 'key2' => 'value2'],
['timestamp' => 1234567890]
);
$array = $context->toArray();
expect($array['data'])->toBe(['key1' => 'value1', 'key2' => 'value2']);
expect($array['metadata'])->toBe(['timestamp' => 1234567890]);
expect($array['is_empty'])->toBeFalse();
expect($array['keys'])->toBe(['key1', 'key2']);
expect($array['count'])->toBe(2);
});
it('converts to plain array', function () {
$context = SlotContext::create(['key1' => 'value1', 'key2' => 'value2']);
$plain = $context->toPlainArray();
expect($plain)->toBe(['key1' => 'value1', 'key2' => 'value2']);
});
it('creates from array', function () {
$array = [
'data' => ['key1' => 'value1'],
'metadata' => ['timestamp' => 1234567890],
];
$context = SlotContext::fromArray($array);
expect($context->get('key1'))->toBe('value1');
expect($context->getMetadata('timestamp'))->toBe(1234567890);
});
});