$componentId,
'component' => $componentName,
'data' => $state,
'version' => 1,
]);
// Build attributes
$attributes = [
'data-live-component' => $componentId,
'data-state' => $stateJson,
'data-csrf-token' => $csrfToken,
];
// Add SSE channel if provided
if ($sseChannel !== null) {
$attributes['data-sse-channel'] = $sseChannel;
}
// Build attribute string
$attributeString = implode(' ', array_map(
fn ($key, $value) => sprintf('%s="%s"', $key, htmlspecialchars($value)),
array_keys($attributes),
$attributes
));
return sprintf(
'
%s
',
$attributeString,
$componentHtml
);
}
// Test 1: Without SSE channel
echo "Test 1: Render without SSE channel\n";
echo "-----------------------------------\n";
$html1 = renderComponentWrapper(
componentId: 'counter:demo',
componentHtml: 'Count: 0
',
state: ['count' => 0],
csrfToken: 'test-csrf-123',
sseChannel: null
);
echo "HTML:\n{$html1}\n\n";
if (str_contains($html1, 'data-sse-channel')) {
echo "❌ FAIL: data-sse-channel should NOT be present\n";
} else {
echo "✅ PASS: data-sse-channel not present (correct)\n";
}
$requiredAttrs = ['data-live-component', 'data-state', 'data-csrf-token'];
foreach ($requiredAttrs as $attr) {
if (str_contains($html1, $attr)) {
echo "✅ {$attr} present\n";
} else {
echo "❌ {$attr} MISSING\n";
}
}
echo "\n";
// Test 2: With SSE channel
echo "Test 2: Render with SSE channel\n";
echo "-----------------------------------\n";
$html2 = renderComponentWrapper(
componentId: 'notification-center:user-123',
componentHtml: '...
',
state: ['notifications' => [], 'unreadCount' => 5],
csrfToken: 'test-csrf-456',
sseChannel: 'user:user-123'
);
echo "HTML (first 300 chars):\n" . substr($html2, 0, 300) . "...\n\n";
if (str_contains($html2, 'data-sse-channel')) {
echo "✅ PASS: data-sse-channel present\n";
if (preg_match('/data-sse-channel="([^"]+)"/', $html2, $matches)) {
$channel = $matches[1];
echo " Channel value: {$channel}\n";
if ($channel === 'user:user-123') {
echo "✅ Channel value correct\n";
} else {
echo "❌ Channel value wrong. Expected: user:user-123, Got: {$channel}\n";
}
}
} else {
echo "❌ FAIL: data-sse-channel should be present\n";
}
foreach ($requiredAttrs as $attr) {
if (str_contains($html2, $attr)) {
echo "✅ {$attr} present\n";
} else {
echo "❌ {$attr} MISSING\n";
}
}
echo "\n";
// Test 3: LivePresence with presence channel
echo "Test 3: LivePresence with presence: channel\n";
echo "-----------------------------------\n";
$html3 = renderComponentWrapper(
componentId: 'live-presence:room-lobby',
componentHtml: '...
',
state: ['users' => []],
csrfToken: 'test-csrf-789',
sseChannel: 'presence:room-lobby'
);
if (preg_match('/data-sse-channel="([^"]+)"/', $html3, $matches)) {
$channel = $matches[1];
echo "Channel value: {$channel}\n";
if ($channel === 'presence:room-lobby') {
echo "✅ Presence channel correct\n";
} else {
echo "❌ Channel wrong. Expected: presence:room-lobby, Got: {$channel}\n";
}
}
echo "\n";
// Test 4: Special characters escaping
echo "Test 4: Special characters escaping\n";
echo "-----------------------------------\n";
$html4 = renderComponentWrapper(
componentId: 'test:special',
componentHtml: 'Test
',
state: ['test' => true],
csrfToken: 'test-csrf',
sseChannel: 'channel:&"quotes"'
);
if (preg_match('/data-sse-channel="([^"]+)"/', $html4, $matches)) {
$channel = $matches[1];
echo "Original: channel:&\"quotes\"\n";
echo "Rendered: {$channel}\n";
if (str_contains($channel, '<') && str_contains($channel, '"')) {
echo "✅ Special characters properly escaped\n";
} else {
echo "❌ Special characters NOT escaped properly\n";
}
}
echo "\n=== All Tests Complete ===\n";