Files
michaelschiemer/tests/Feature/Framework/LiveComponents/FragmentUpdateTest.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

202 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Http\Status;
describe('Fragment Update Integration', function () {
it('updates single fragment via action', function () {
// Create counter component
$createResponse = $this->post('/live-component/counter:demo/create', [
'initial_count' => 0,
]);
expect($createResponse->status)->toBe(Status::OK);
$componentId = $createResponse->jsonData['id'];
// Request fragment update
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'increment',
'params' => ['amount' => 5],
'state' => ['count' => 0],
'fragments' => ['counter-display'],
]);
expect($updateResponse->status)->toBe(Status::OK);
$data = $updateResponse->jsonData;
// Should return fragments instead of full HTML
expect($data)->toHaveKey('fragments');
expect($data)->not->toHaveKey('html');
expect($data['fragments'])->toHaveKey('counter-display');
expect($data['fragments']['counter-display'])->toContain('5');
// Should still return updated state
expect($data['state']['count'])->toBe(5);
});
it('updates multiple fragments simultaneously', function () {
$createResponse = $this->post('/live-component/form:demo/create', [
'email' => '',
'errors' => [],
]);
$componentId = $createResponse->jsonData['id'];
// Request multiple fragment updates
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'validate',
'params' => ['email' => 'invalid-email'],
'state' => ['email' => '', 'errors' => []],
'fragments' => ['form-input', 'form-errors'],
]);
expect($updateResponse->status)->toBe(Status::OK);
$data = $updateResponse->jsonData;
$fragments = $data['fragments'];
expect($fragments)->toHaveKey('form-input');
expect($fragments)->toHaveKey('form-errors');
// Input fragment should reflect new value
expect($fragments['form-input'])->toContain('invalid-email');
// Errors fragment should show validation error
expect($fragments['form-errors'])->toContain('email');
});
it('falls back to full render when fragments not found', function () {
$createResponse = $this->post('/live-component/counter:demo/create', [
'initial_count' => 0,
]);
$componentId = $createResponse->jsonData['id'];
// Request non-existent fragment
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'increment',
'params' => ['amount' => 1],
'state' => ['count' => 0],
'fragments' => ['non-existent-fragment'],
]);
expect($updateResponse->status)->toBe(Status::OK);
$data = $updateResponse->jsonData;
// Should fall back to full HTML
expect($data)->toHaveKey('html');
expect($data)->not->toHaveKey('fragments');
});
it('preserves events with fragment updates', function () {
$createResponse = $this->post('/live-component/counter:demo/create', [
'initial_count' => 0,
]);
$componentId = $createResponse->jsonData['id'];
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'increment',
'params' => ['amount' => 10],
'state' => ['count' => 0],
'fragments' => ['counter-display'],
]);
$data = $updateResponse->jsonData;
// Should include events even with fragment update
expect($data)->toHaveKey('events');
expect($data['events'])->toBeArray();
// If counter dispatches increment event
if (count($data['events']) > 0) {
expect($data['events'][0])->toHaveKey('type');
}
});
it('handles empty fragments array as full render', function () {
$createResponse = $this->post('/live-component/counter:demo/create', [
'initial_count' => 0,
]);
$componentId = $createResponse->jsonData['id'];
// Empty fragments array should trigger full render
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'increment',
'params' => ['amount' => 1],
'state' => ['count' => 0],
'fragments' => [],
]);
$data = $updateResponse->jsonData;
// Should return full HTML, not fragments
expect($data)->toHaveKey('html');
expect($data)->not->toHaveKey('fragments');
});
it('updates fragments with complex nested HTML', function () {
$createResponse = $this->post('/live-component/card:demo/create', [
'title' => 'Original Title',
'content' => 'Original Content',
]);
$componentId = $createResponse->jsonData['id'];
$updateResponse = $this->post("/live-component/{$componentId}", [
'method' => 'updateTitle',
'params' => ['title' => 'New Title'],
'state' => ['title' => 'Original Title', 'content' => 'Original Content'],
'fragments' => ['card-header'],
]);
$data = $updateResponse->jsonData;
if (isset($data['fragments']['card-header'])) {
$header = $data['fragments']['card-header'];
// Should contain new title
expect($header)->toContain('New Title');
// Should preserve HTML structure
expect($header)->toMatch('/<div[^>]*data-fragment="card-header"[^>]*>/');
}
});
it('handles concurrent fragment updates independently', function () {
$create1 = $this->post('/live-component/counter:demo1/create', ['initial_count' => 0]);
$create2 = $this->post('/live-component/counter:demo2/create', ['initial_count' => 10]);
$id1 = $create1->jsonData['id'];
$id2 = $create2->jsonData['id'];
// Update both concurrently with fragments
$update1 = $this->post("/live-component/{$id1}", [
'method' => 'increment',
'params' => ['amount' => 5],
'state' => ['count' => 0],
'fragments' => ['counter-display'],
]);
$update2 = $this->post("/live-component/{$id2}", [
'method' => 'decrement',
'params' => ['amount' => 3],
'state' => ['count' => 10],
'fragments' => ['counter-display'],
]);
// Both should succeed independently
expect($update1->status)->toBe(Status::OK);
expect($update2->status)->toBe(Status::OK);
expect($update1->jsonData['state']['count'])->toBe(5);
expect($update2->jsonData['state']['count'])->toBe(7);
});
});