- 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.
185 lines
5.6 KiB
PHP
185 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\View\Rendering\FragmentCollection;
|
|
|
|
describe('FragmentCollection', function () {
|
|
it('creates empty collection', function () {
|
|
$collection = FragmentCollection::empty();
|
|
|
|
expect($collection->isEmpty())->toBeTrue();
|
|
expect($collection->count())->toBe(0);
|
|
});
|
|
|
|
it('creates collection from array', function () {
|
|
$fragments = [
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
'footer' => '<footer>Footer</footer>',
|
|
];
|
|
|
|
$collection = FragmentCollection::fromArray($fragments);
|
|
|
|
expect($collection->isEmpty())->toBeFalse();
|
|
expect($collection->count())->toBe(3);
|
|
});
|
|
|
|
it('checks if has fragment', function () {
|
|
$collection = FragmentCollection::fromArray([
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
]);
|
|
|
|
expect($collection->has('header'))->toBeTrue();
|
|
expect($collection->has('content'))->toBeTrue();
|
|
expect($collection->has('footer'))->toBeFalse();
|
|
});
|
|
|
|
it('gets fragment by name', function () {
|
|
$collection = FragmentCollection::fromArray([
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
]);
|
|
|
|
expect($collection->get('header'))->toBe('<h1>Title</h1>');
|
|
expect($collection->get('content'))->toBe('<p>Content</p>');
|
|
expect($collection->get('non-existent'))->toBeNull();
|
|
});
|
|
|
|
it('converts to associative array', function () {
|
|
$original = [
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
'footer' => '<footer>Footer</footer>',
|
|
];
|
|
|
|
$collection = FragmentCollection::fromArray($original);
|
|
$array = $collection->toAssociativeArray();
|
|
|
|
expect($array)->toBe($original);
|
|
});
|
|
|
|
it('gets all fragments', function () {
|
|
$fragments = [
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
];
|
|
|
|
$collection = FragmentCollection::fromArray($fragments);
|
|
|
|
expect($collection->all())->toBe($fragments);
|
|
});
|
|
|
|
it('counts fragments', function () {
|
|
$collection = FragmentCollection::fromArray([
|
|
'one' => '<div>1</div>',
|
|
'two' => '<div>2</div>',
|
|
'three' => '<div>3</div>',
|
|
]);
|
|
|
|
expect($collection->count())->toBe(3);
|
|
});
|
|
|
|
it('checks if empty', function () {
|
|
$empty = FragmentCollection::empty();
|
|
expect($empty->isEmpty())->toBeTrue();
|
|
|
|
$notEmpty = FragmentCollection::fromArray(['test' => '<div>Test</div>']);
|
|
expect($notEmpty->isEmpty())->toBeFalse();
|
|
});
|
|
|
|
it('is iterable', function () {
|
|
$fragments = [
|
|
'header' => '<h1>Title</h1>',
|
|
'content' => '<p>Content</p>',
|
|
'footer' => '<footer>Footer</footer>',
|
|
];
|
|
|
|
$collection = FragmentCollection::fromArray($fragments);
|
|
|
|
$iterated = [];
|
|
foreach ($collection as $name => $html) {
|
|
$iterated[$name] = $html;
|
|
}
|
|
|
|
expect($iterated)->toBe($fragments);
|
|
});
|
|
|
|
it('is countable', function () {
|
|
$collection = FragmentCollection::fromArray([
|
|
'one' => '<div>1</div>',
|
|
'two' => '<div>2</div>',
|
|
]);
|
|
|
|
// count() should work directly on the object
|
|
expect(count($collection))->toBe(2);
|
|
});
|
|
|
|
it('handles empty array creation', function () {
|
|
$collection = FragmentCollection::fromArray([]);
|
|
|
|
expect($collection->isEmpty())->toBeTrue();
|
|
expect($collection->count())->toBe(0);
|
|
expect($collection->toAssociativeArray())->toBe([]);
|
|
});
|
|
|
|
it('preserves fragment order', function () {
|
|
$fragments = [
|
|
'first' => '<div>1</div>',
|
|
'second' => '<div>2</div>',
|
|
'third' => '<div>3</div>',
|
|
];
|
|
|
|
$collection = FragmentCollection::fromArray($fragments);
|
|
|
|
$keys = array_keys($collection->toAssociativeArray());
|
|
|
|
expect($keys)->toBe(['first', 'second', 'third']);
|
|
});
|
|
|
|
it('handles fragments with complex HTML', function () {
|
|
$complexHtml = <<<HTML
|
|
<div class="card" data-id="123">
|
|
<header class="card-header">
|
|
<h2>Title</h2>
|
|
<span class="badge">New</span>
|
|
</header>
|
|
<div class="card-body">
|
|
<p>This is <strong>complex</strong> HTML with <a href="#">links</a></p>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
$collection = FragmentCollection::fromArray([
|
|
'complex-card' => $complexHtml,
|
|
]);
|
|
|
|
$retrieved = $collection->get('complex-card');
|
|
|
|
expect($retrieved)->toBe($complexHtml);
|
|
expect($retrieved)->toContain('data-id="123"');
|
|
expect($retrieved)->toContain('<strong>complex</strong>');
|
|
});
|
|
|
|
it('handles fragments with special characters', function () {
|
|
$specialHtml = '<div>Special chars: & < > "quotes" \'apostrophes\'</div>';
|
|
|
|
$collection = FragmentCollection::fromArray([
|
|
'special' => $specialHtml,
|
|
]);
|
|
|
|
expect($collection->get('special'))->toBe($specialHtml);
|
|
});
|
|
|
|
it('returns null for non-existent fragments consistently', function () {
|
|
$collection = FragmentCollection::fromArray([
|
|
'existing' => '<div>Exists</div>',
|
|
]);
|
|
|
|
expect($collection->get('non-existent'))->toBeNull();
|
|
expect($collection->get('another-missing'))->toBeNull();
|
|
expect($collection->get(''))->toBeNull();
|
|
});
|
|
});
|