- 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.
19 KiB
LiveComponents E2E Integration Tests
Comprehensive end-to-end integration tests for LiveComponents cross-cutting features: Partial Rendering, Batch Operations, and Server-Sent Events (SSE).
Overview
This test suite validates the seamless integration of multiple LiveComponents features working together in real-world scenarios. It ensures that partial rendering, batch operations, and real-time updates work harmoniously without conflicts or state inconsistencies.
Test Categories
1. Partial Rendering Tests (6 tests)
Purpose: Validate fragment-based updates without full component re-rendering
Tests:
-
Update only targeted fragment without full component re-render
- Triggers fragment-specific action
- Verifies only fragment HTML updated
- Ensures component timestamp unchanged (no full render)
- Validates DOM patch efficiency
-
Update multiple fragments in single request
- Updates 2+ fragments simultaneously
- Verifies all fragments updated correctly
- Ensures only 1 HTTP request sent
- Validates network efficiency
-
Preserve component state during partial render
- Sets component state before fragment update
- Triggers fragment update
- Verifies state preserved after update
- Validates state consistency
-
Handle nested fragment updates
- Updates parent fragment containing child fragment
- Verifies parent and child both updated
- Ensures sibling fragments NOT updated
- Validates selective rendering
-
Apply morphing algorithm for minimal DOM changes
- Counts DOM nodes before update
- Applies small content change
- Verifies node count unchanged (morphing, not replacement)
- Validates morphing stats (added/removed/updated)
-
Handle fragment-not-found gracefully
- Calls action with non-existent fragment ID
- Verifies error message displayed
- Ensures component remains functional
- Validates error recovery
2. Batch Operations Tests (6 tests)
Purpose: Validate efficient execution of multiple actions in single request
Tests:
-
Execute multiple actions in single batch request
- Batches 3 different actions
- Verifies only 1 HTTP request sent
- Ensures all actions executed successfully
- Validates batch efficiency
-
Maintain action execution order in batch
- Batches 3 actions in specific order
- Logs execution sequence
- Verifies actions executed in correct order
- Validates deterministic execution
-
Rollback batch on action failure
- Batches successful + failing + successful actions
- Verifies entire batch rolled back on failure
- Ensures no partial state changes
- Validates transactional behavior
-
Handle partial batch execution with continueOnError flag
- Batches actions with
continueOnError: true - Includes failing action in middle
- Verifies successful actions still execute
- Validates partial execution mode
- Batches actions with
-
Support batch with mixed action types
- Batches sync + async + fragment update actions
- Verifies all action types execute correctly
- Ensures type compatibility
- Validates heterogeneous batching
-
Batch state updates efficiently
- Batches 10 state update actions
- Verifies final state correct
- Ensures only 1 state update event fired (optimization)
- Validates state batching
3. Server-Sent Events (SSE) Tests (8 tests)
Purpose: Validate real-time server-to-client communication
Tests:
-
Establish SSE connection for real-time updates
- Enables SSE
- Verifies connection state OPEN (readyState === 1)
- Ensures connection indicator visible
- Validates connection establishment
-
Receive and apply server-pushed updates
- Establishes SSE connection
- Simulates server push event
- Verifies component updated automatically
- Validates push handling
-
Handle SSE reconnection on connection loss
- Establishes connection
- Simulates connection close
- Verifies reconnecting indicator shown
- Ensures automatic reconnection after retry period
-
Support multiple SSE event types
- Sends different event types (update, notification, sync)
- Logs received events
- Verifies all types processed correctly
- Validates event type handling
-
Batch SSE updates for performance
- Sends 20 rapid SSE updates
- Verifies final value correct
- Ensures renders < updates (batching optimization)
- Validates performance optimization
-
Close SSE connection when component unmounts
- Establishes connection
- Unmounts component
- Verifies connection closed (readyState === 2)
- Validates cleanup
-
Handle SSE authentication and authorization
- Tests SSE with valid auth token
- Verifies authenticated connection
- Tests SSE with invalid token
- Ensures auth error displayed
-
Support SSE with custom event filters
- Enables SSE with priority filter
- Sends events with different priorities
- Verifies only filtered events processed
- Validates client-side filtering
4. Integration Tests (4 tests)
Purpose: Validate combined usage of multiple features
Tests:
-
Combine partial rendering with batch operations
- Batches multiple fragment updates + state changes
- Verifies only 1 request sent
- Ensures all fragments and state updated
- Validates feature synergy
-
Push partial updates via SSE
- Sends SSE event with fragment update
- Verifies fragment updated via SSE
- Ensures no full component render
- Validates SSE + partial rendering
-
Batch SSE-triggered actions efficiently
- Sends 5 rapid SSE events triggering actions
- Verifies actions batched (< 5 executions)
- Ensures final state correct
- Validates SSE + batching
-
Maintain consistency across all integration features
- Complex scenario: batch + partial + SSE simultaneously
- Starts batch with fragment updates
- Sends SSE update during batch execution
- Verifies all updates applied correctly
- Validates state consistency
Quick Start
Prerequisites
# Ensure Playwright is installed
npm install
# Install browsers
npx playwright install chromium
# Ensure development server is running
make up
Running Integration Tests
# Run all integration tests
npm run test:integration
# Run with visible browser (debugging)
npm run test:integration:headed
# Run in debug mode (step through tests)
npm run test:integration:debug
# Run specific test category
npx playwright test integration.spec.js --grep "Partial Rendering"
npx playwright test integration.spec.js --grep "Batch Operations"
npx playwright test integration.spec.js --grep "Server-Sent Events"
npx playwright test integration.spec.js --grep "Integration:"
Test Page Requirements
HTML Structure
The test page /livecomponents/test/integration must include:
<!DOCTYPE html>
<html>
<head>
<title>LiveComponents Integration Tests</title>
<script src="/assets/livecomponents.js"></script>
</head>
<body>
<!-- Component Container -->
<div data-component="integration:test" data-component-id="integration:test">
<!-- Component Timestamp (für Full Render Detection) -->
<div id="component-timestamp" data-timestamp="initial">initial</div>
<!-- Fragment Rendering Tests -->
<div id="target-fragment">Original Content</div>
<div id="fragment-1">Fragment 1</div>
<div id="fragment-2">Fragment 2</div>
<!-- Nested Fragments -->
<div id="parent-fragment">
<div id="child-fragment">Child</div>
</div>
<div id="sibling-fragment" data-timestamp="original">Sibling</div>
<!-- Morphing Test -->
<div id="morph-fragment">
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
<!-- Batch Operation Tests -->
<div id="counter-value">0</div>
<div id="text-value">Original</div>
<div id="flag-value">false</div>
<!-- SSE Tests -->
<div id="live-value">Initial</div>
<div id="sse-counter">0</div>
<div class="sse-connected" style="display:none">Connected</div>
<div class="sse-reconnecting" style="display:none">Reconnecting...</div>
<div class="sse-authenticated" style="display:none">Authenticated</div>
<div class="sse-auth-error" style="display:none">Auth Error</div>
<!-- State Management -->
<input type="text" id="state-input" />
<!-- Action Buttons -->
<button id="update-fragment">Update Fragment</button>
<button id="update-multiple-fragments">Update Multiple</button>
<button id="save-state">Save State</button>
<button id="update-nested-fragment">Update Nested</button>
<button id="small-update">Small Update</button>
<button id="enable-sse">Enable SSE</button>
<button id="trigger-action">Trigger Action</button>
<!-- Error Display -->
<div class="fragment-error" style="display:none"></div>
<div class="batch-error" style="display:none"></div>
<div class="partial-success" style="display:none"></div>
<!-- Results -->
<div id="sync-result" style="display:none"></div>
<div id="async-result" style="display:none"></div>
<div id="fragment-result" style="display:none"></div>
<div class="action-success" style="display:none"></div>
</div>
<script>
// Global tracking variables
window.__fragmentUpdateCount = 0;
window.__requestCount = 0;
window.__renderCount = 0;
window.__stateUpdateCount = 0;
window.__actionCount = 0;
window.__originalSiblingTimestamp = document.getElementById('sibling-fragment').getAttribute('data-timestamp');
window.__originalComponentTimestamp = document.getElementById('component-timestamp').textContent;
// Morphing stats tracking
window.__morphingStats = {
nodesAdded: 0,
nodesRemoved: 0,
nodesUpdated: 0
};
// Initialize LiveComponents
document.addEventListener('DOMContentLoaded', () => {
window.LiveComponents.init();
});
</script>
</body>
</html>
Component Actions
The IntegrationTestComponent must implement:
use App\Framework\LiveComponents\LiveComponent;
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\Fragment;
final readonly class IntegrationTestComponent extends LiveComponent
{
#[Action]
#[Fragment('target-fragment')]
public function updateFragment(array $params = []): array
{
$fragmentId = $params['fragmentId'] ?? 'target-fragment';
if (!$this->hasFragment($fragmentId)) {
return ['error' => 'Fragment not found'];
}
return [
'fragments' => [
$fragmentId => '<div id="' . $fragmentId . '">Updated</div>'
]
];
}
#[Action]
public function updateMultipleFragments(): array
{
return [
'fragments' => [
'fragment-1' => '<div id="fragment-1">Fragment 1 Updated</div>',
'fragment-2' => '<div id="fragment-2">Fragment 2 Updated</div>'
]
];
}
#[Action]
public function saveState(string $value): void
{
$this->state->set('savedValue', $value);
}
#[Action]
#[Fragment('parent-fragment')]
public function updateNestedFragment(): array
{
return [
'fragments' => [
'parent-fragment' => '
<div id="parent-fragment">Parent Updated
<div id="child-fragment">Child Updated</div>
</div>
'
]
];
}
#[Action]
#[Fragment('morph-fragment')]
public function smallUpdate(): array
{
return [
'fragments' => [
'morph-fragment' => '
<div id="morph-fragment">
<p>Paragraph 1 Updated</p>
<p>Paragraph 2</p>
</div>
'
]
];
}
#[Action]
public function incrementCounter(): void
{
$current = $this->state->get('counter', 0);
$this->state->set('counter', $current + 1);
}
#[Action]
public function updateText(string $text): void
{
$this->state->set('text', $text);
}
#[Action]
public function toggleFlag(): void
{
$current = $this->state->get('flag', false);
$this->state->set('flag', !$current);
}
#[Action]
public function action1(): void
{
// Log execution
$this->logExecution('action1');
}
#[Action]
public function action2(): void
{
$this->logExecution('action2');
}
#[Action]
public function action3(): void
{
$this->logExecution('action3');
}
#[Action]
public function failingAction(): void
{
throw new \RuntimeException('Intentional failure for testing');
}
#[Action]
public function syncAction(): array
{
return ['success' => true];
}
#[Action]
public function asyncAction(): array
{
// Simulate async operation
usleep(100000); // 100ms
return ['success' => true];
}
#[Action]
#[Fragment('fragment-result')]
public function fragmentAction(): array
{
return [
'fragments' => [
'fragment-result' => '<div id="fragment-result">Fragment Action Complete</div>'
]
];
}
public function enableSSE(array $options = []): void
{
// SSE setup logic
$this->sseEnabled = true;
}
public function validateStateConsistency(): bool
{
// State validation logic
return true;
}
}
SSE Endpoint
The SSE endpoint /live-component/sse/{componentId} must support:
use App\Framework\LiveComponents\SSE\SseStream;
final readonly class LiveComponentSseController
{
#[Route('/live-component/sse/{componentId}', method: Method::GET)]
public function stream(string $componentId, Request $request): Response
{
$authToken = $request->headers->get('Authorization');
if (!$this->validateAuthToken($authToken)) {
return new Response(status: Status::UNAUTHORIZED);
}
$stream = new SseStream();
// Set headers
$response = new Response(
status: Status::OK,
headers: [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive'
]
);
// Event loop
while ($connection->isAlive()) {
$event = $this->eventQueue->poll($componentId);
if ($event) {
$stream->send($event->type, $event->data);
}
usleep(100000); // 100ms polling interval
}
return $response;
}
}
Performance Expectations
Partial Rendering
- Fragment Update Latency: <50ms for small fragments (<5KB)
- DOM Morphing Efficiency: 0 node additions/removals for content-only changes
- Memory Impact: <1MB per fragment update
Batch Operations
- Network Savings: 1 request for N actions (vs. N requests)
- Execution Time: Linear O(N) for N batched actions
- Rollback Overhead: <10ms for transaction rollback
Server-Sent Events
- Connection Establishment: <500ms
- Event Latency: <100ms from server send to client receive
- Reconnection Time: <2s after connection loss
- Batching Window: 50-100ms for update batching
Troubleshooting
Fragment Updates Not Working
Symptoms:
- Fragment content doesn't update
- Full component re-renders instead
Solutions:
- Verify Fragment Attribute:
#[Fragment('target-fragment')]
public function updateFragment(): array
- Check Fragment ID in Response:
return [
'fragments' => [
'target-fragment' => '<div id="target-fragment">Updated</div>'
]
];
- Ensure Fragment Exists in DOM:
<div id="target-fragment">Original</div>
Batch Operations Failing
Symptoms:
- Individual actions execute separately
- Multiple HTTP requests sent
Solutions:
- Use Batch API Correctly:
component.batch()
.call('action1')
.call('action2')
.execute(); // Don't forget .execute()
- Check Batch Support:
if (component.supportsBatch) {
// Batching available
}
SSE Connection Issues
Symptoms:
- SSE connection not established
- Events not received
Solutions:
- Check SSE Endpoint:
curl -N https://localhost/live-component/sse/integration:test \
-H "Authorization: Bearer token"
- Verify Headers:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
- Test Auth Token:
component.enableSSE({ authToken: 'valid-token-123' });
- Check Browser Console:
component.sse.addEventListener('error', (e) => {
console.error('SSE Error:', e);
});
CI/CD Integration
GitHub Actions
name: Integration Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
integration-tests:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Start dev server
run: |
make up
sleep 10
- name: Run Integration Tests
run: npm run test:integration
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: integration-test-results
path: test-results/
- name: Upload test report
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
Best Practices
1. Test Organization
- Group related tests with
test.describe() - Use descriptive test names
- Follow AAA pattern (Arrange, Act, Assert)
2. State Management
- Reset component state between tests
- Use
beforeEachfor consistent setup - Avoid test interdependencies
3. Async Handling
- Use
page.waitForTimeout()conservatively - Prefer
page.waitForSelector()orpage.waitForFunction() - Set appropriate timeouts for network operations
4. Error Handling
- Test both success and failure paths
- Verify error messages and recovery
- Check graceful degradation
5. Performance Testing
- Track request counts
- Measure render times
- Monitor memory usage
- Validate batching efficiency
Resources
- Playwright Documentation
- LiveComponents Framework Guide
- Fragment Rendering Guide
- Batch Operations Guide
- SSE Integration Guide
Support
For issues or questions:
- Check troubleshooting section above
- Review LiveComponents documentation
- Inspect browser console and network tab
- Run tests in headed mode for visual debugging
- Create GitHub issue with test output and environment details