Embeddable Bridge Testing Guide

Documentation for Testing

Embeddable Bridge Testing Guide

For Claude Cowork Agent | Session 73 | Browser-Based Testing

This guide provides step-by-step instructions for testing the embeddable bridge features using Playwright browser tools.


Table of Contents

  1. Prerequisites & Setup
  2. Testing Phase 1: Core Bridge Functionality
  3. Testing Phase 2: AI API Integration
  4. Testing Phase 3: External Embedding
  5. Testing Phase 4: Advanced Features
  6. Automated Test Scenarios
  7. Troubleshooting

1. Prerequisites & Setup

1.1 Start Required Services

Before testing, ensure these services are running:

# Terminal 1: Start gograb-space (host app)
nx serve gograb-space --port=5200

# Terminal 2: Start gograb-ai (embedded app)
nx serve gograb-ai --port=5300

# Terminal 3: Start backend API (if testing real AI integration)
nx serve backend-ai-api --port=3001

1.2 Test URLs

App URL Purpose
Host App http://localhost:5200 Main platform
Embedded App http://localhost:5300 AI panel standalone
Test Page http://localhost:5200/system/ai-iframe-test Integration test harness
Panel Route http://localhost:5300/panel Embedded panel view

1.3 Browser Setup with Playwright

// Navigate to the test page
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/system/ai-iframe-test' });

// Take initial snapshot
await mcp__playwright__browser_snapshot({});

2. Testing Phase 1: Core Bridge Functionality

2.1 Test: Iframe Loading

Objective: Verify the embedded app loads correctly in the iframe.

Steps:

  1. Navigate to test page
  2. Wait for iframe to load
  3. Check for "AI_APP_READY" message
// Navigate to test page
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/system/ai-iframe-test' });

// Wait for iframe to be visible
await mcp__playwright__browser_wait_for({ text: 'Panel' });

// Take snapshot to verify UI
await mcp__playwright__browser_snapshot({});

Expected Results:

2.2 Test: PostMessage Communication

Objective: Verify bidirectional message passing between host and embedded app.

Steps:

  1. Open browser console to monitor messages
  2. Click "Send Ping" button (if available)
  3. Verify ping/pong response
// Check console for messages
await mcp__playwright__browser_console_messages({ level: 'info' });

// Look for bridge-related logs
// Expected: "[Embeddable Host] Sent message: AI_PING"
// Expected: "[Embeddable Host] Received message: AI_PONG"

Expected Results:

2.3 Test: Drag-Drop Functionality

Objective: Verify cross-iframe drag-drop works correctly.

Steps:

  1. Locate a draggable item in the embedded panel
  2. Initiate drag
  3. Move to drop zone in host
  4. Release and verify drop
// Take snapshot to find draggable elements
await mcp__playwright__browser_snapshot({});

// Find the drag source element (look for elements with drag-related attributes)
// The snapshot will show interactive elements with their refs

// Click on a draggable item to test click-to-add fallback
await mcp__playwright__browser_click({
  ref: '[ref-to-add-button]',
  element: 'Add to Canvas button'
});

Expected Results:

2.4 Test: Auth Token Forwarding

Objective: Verify authentication tokens are passed to embedded app.

Steps:

  1. Log in to the host app (if required)
  2. Open the AI panel
  3. Check that API calls from embedded app include auth headers
// Check network requests for auth headers
await mcp__playwright__browser_network_requests({ includeStatic: false });

// Look for requests to /api/ endpoints
// Verify Authorization header is present

Expected Results:


3. Testing Phase 2: AI API Integration

3.1 Test: Chat Interface

Objective: Verify the chat interface sends and receives messages.

Steps:

  1. Navigate to panel
  2. Type a message
  3. Submit and wait for response
// Navigate to embedded panel directly for isolated testing
await mcp__playwright__browser_navigate({ url: 'http://localhost:5300/panel' });

// Wait for panel to load
await mcp__playwright__browser_snapshot({});

// Find chat input and type a message
await mcp__playwright__browser_type({
  ref: '[ref-to-chat-input]',
  element: 'Chat input field',
  text: 'Hello, this is a test message',
  submit: true
});

// Wait for response
await mcp__playwright__browser_wait_for({ text: 'assistant', time: 10 });

Expected Results:

3.2 Test: Streaming Response

Objective: Verify streaming responses display incrementally.

Steps:

  1. Send a prompt that triggers streaming
  2. Observe incremental text display
  3. Verify completion
// After sending a message, observe the response area
await mcp__playwright__browser_snapshot({});

// Check for streaming indicators
// Look for typing animation or incremental text

Expected Results:

3.3 Test: Context Awareness

Objective: Verify context is passed to AI and affects responses.

Steps:

  1. Navigate to a specific page with context
  2. Open AI panel
  3. Verify context is received
// Navigate to a page with specific context (e.g., a widget editor)
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/space/demo/page-builder' });

// Open AI panel and check context
await mcp__playwright__browser_console_messages({ level: 'info' });

// Look for AI_CONTEXT_UPDATE message with pageId, widgetId, etc.

Expected Results:


4. Testing Phase 3: External Embedding

4.1 Test: Embed.js Loader

Objective: Verify the embed.js script works on external pages.

Steps:

  1. Create a test HTML file with embed script
  2. Load it in browser
  3. Verify panel appears
// First, create a simple test HTML file or navigate to a test page
// For testing, you can use data URL or a local server

// Navigate to a page that uses embed.js
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/embed-test.html' });

// Or evaluate JavaScript to simulate embed
await mcp__playwright__browser_evaluate({
  function: `() => {
    // Check if GograbAI is available
    return typeof window.GograbAI !== 'undefined';
  }`
});

Test HTML for Embed.js:

<!DOCTYPE html>
<html>
<head>
  <title>Embed Test</title>
</head>
<body>
  <h1>Embed.js Test Page</h1>
  <div id="ai-panel"></div>

  <script src="http://localhost:5300/embed.js"></script>
  <script>
    const ai = GograbAI.embed({
      container: '#ai-panel',
      theme: 'light',
      position: 'right',
      onReady: (api) => {
        console.log('AI Panel Ready!', api);
      }
    });
  </script>
</body>
</html>

Expected Results:

4.2 Test: Chrome Extension (Manual)

Objective: Verify the Chrome extension injects panel correctly.

Note: Chrome extensions require manual installation. This test provides verification steps.

Steps:

  1. Load unpacked extension from apps/gograb-ai-extension/
  2. Navigate to any website
  3. Click extension icon
  4. Verify panel appears

Manual Verification Checklist:

4.3 Test: Security - Origin Validation

Objective: Verify only allowed origins can communicate.

Steps:

  1. Try to send message from disallowed origin
  2. Verify message is rejected
// Evaluate code that simulates cross-origin message
await mcp__playwright__browser_evaluate({
  function: `() => {
    // This should be rejected if origin validation works
    window.postMessage({
      type: 'AI_MALICIOUS_REQUEST',
      payload: { test: true },
      timestamp: Date.now()
    }, '*');
    return 'Message sent';
  }`
});

// Check console for rejection message
await mcp__playwright__browser_console_messages({ level: 'warning' });

Expected Results:

4.4 Test: API Key Authentication

Objective: Verify API key auth works for external sites.

Steps:

  1. Configure embed with API key
  2. Verify requests include API key header
// Check network requests for API key
await mcp__playwright__browser_network_requests({ includeStatic: false });

// Look for X-API-Key header in requests

Expected Results:


5. Testing Phase 4: Advanced Features

5.1 Test: Multi-Instance Support

Objective: Verify multiple panels can exist on the same page.

Steps:

  1. Create page with two embedded panels
  2. Verify each has unique instanceId
  3. Send message to specific instance
  4. Verify only target instance receives it
// Navigate to a page with multiple instances
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/multi-instance-test' });

// Take snapshot to see both panels
await mcp__playwright__browser_snapshot({});

// Check console for instance IDs
await mcp__playwright__browser_console_messages({ level: 'info' });

// Look for:
// "[Embeddable Host] Host adapter initialized with instanceId: host_xxxxx"

Test HTML for Multi-Instance:

<div id="panel-1"></div>
<div id="panel-2"></div>

<script>
  // Panel 1 - Editor context
  const panel1 = GograbAI.embed({
    container: '#panel-1',
    instanceId: 'editor-panel',
    context: { type: 'editor' }
  });

  // Panel 2 - Preview context
  const panel2 = GograbAI.embed({
    container: '#panel-2',
    instanceId: 'preview-panel',
    context: { type: 'preview' }
  });
</script>

Expected Results:

5.2 Test: Widget Embedding

Objective: Verify individual widgets can be embedded.

Steps:

  1. Navigate to page with embedded widget
  2. Verify widget loads correctly
  3. Test widget interactions
// Navigate to widget embed test
await mcp__playwright__browser_navigate({ url: 'http://localhost:5200/widget-embed-test' });

// Wait for widget to load
await mcp__playwright__browser_wait_for({ text: 'Widget loaded' });

// Take snapshot
await mcp__playwright__browser_snapshot({});

Expected Results:

5.3 Test: Offline Support

Objective: Verify app works offline with cached data.

Steps:

  1. Load app while online
  2. Simulate offline mode
  3. Verify cached content displays
  4. Go back online and verify sync
// First, load the page while online
await mcp__playwright__browser_navigate({ url: 'http://localhost:5300/panel' });

// Wait for service worker to register
await mcp__playwright__browser_wait_for({ time: 3 });

// Check service worker status
await mcp__playwright__browser_evaluate({
  function: `async () => {
    const registration = await navigator.serviceWorker.getRegistration();
    return {
      active: !!registration?.active,
      waiting: !!registration?.waiting,
      scope: registration?.scope
    };
  }`
});

// Simulate offline (Note: Playwright may need special handling for this)
// In manual testing, use DevTools Network tab to go offline

Expected Results:

5.4 Test: Offline Indicator Component

Objective: Verify offline indicator shows correct state.

Steps:

  1. Load page online - indicator should be hidden
  2. Go offline - indicator should appear
  3. Dismiss indicator
  4. Go online - indicator should hide
// Check if offline indicator exists (should be hidden when online)
await mcp__playwright__browser_snapshot({});

// The indicator has class "offline-indicator" and shows when offline
// Look for absence of this element when online

Expected Results:


6. Automated Test Scenarios

6.1 Full Integration Test Flow

// Complete integration test
async function runIntegrationTest() {
  // 1. Navigate to test page
  await mcp__playwright__browser_navigate({
    url: 'http://localhost:5200/system/ai-iframe-test'
  });

  // 2. Wait for panel to be ready
  await mcp__playwright__browser_wait_for({ text: 'Ready', time: 10 });

  // 3. Take snapshot
  const snapshot = await mcp__playwright__browser_snapshot({});

  // 4. Check console for errors
  const messages = await mcp__playwright__browser_console_messages({
    level: 'error'
  });

  // 5. Verify no errors
  if (messages.includes('error')) {
    throw new Error('Console errors detected');
  }

  // 6. Test click-to-add functionality
  await mcp__playwright__browser_click({
    ref: '[add-button-ref]',
    element: 'Add to Canvas button'
  });

  // 7. Verify success
  await mcp__playwright__browser_wait_for({ text: 'Added' });

  console.log('Integration test passed!');
}

6.2 Performance Test

// Performance measurement test
async function runPerformanceTest() {
  // Navigate and measure load time
  const startTime = Date.now();

  await mcp__playwright__browser_navigate({
    url: 'http://localhost:5200/system/ai-iframe-test'
  });

  await mcp__playwright__browser_wait_for({ text: 'Ready' });

  const loadTime = Date.now() - startTime;

  console.log(`Panel load time: ${loadTime}ms`);

  // Check against threshold
  if (loadTime > 2000) {
    console.warn('Panel load time exceeds 2s threshold');
  }

  // Check network requests
  const requests = await mcp__playwright__browser_network_requests({
    includeStatic: false
  });

  console.log(`Network requests: ${requests}`);
}

6.3 Security Test

// Security validation test
async function runSecurityTest() {
  await mcp__playwright__browser_navigate({
    url: 'http://localhost:5200/system/ai-iframe-test'
  });

  // Try to inject malicious message
  await mcp__playwright__browser_evaluate({
    function: `() => {
      // Attempt XSS via postMessage
      window.postMessage({
        type: 'AI_CONTEXT_UPDATE',
        payload: {
          contextType: '<script>alert("XSS")</script>'
        },
        timestamp: Date.now()
      }, '*');
    }`
  });

  // Verify XSS was not executed
  // Check for alert dialog
  // If no dialog, XSS was prevented

  console.log('Security test passed!');
}

7. Troubleshooting

7.1 Common Issues

Issue Cause Solution
Iframe not loading CORS or CSP blocking Check allowed origins in config
Messages not received Origin mismatch Verify allowedOrigins includes both hosts
Auth not working Token not forwarded Check autoSendOnReady is true
Drag-drop not working Event forwarding issue Check mouse event handlers
Panel not visible CSS z-index issue Verify z-index is high enough

7.2 Debug Commands

// Check console messages
await mcp__playwright__browser_console_messages({ level: 'debug' });

// Check network requests
await mcp__playwright__browser_network_requests({ includeStatic: true });

// Take screenshot for visual verification
await mcp__playwright__browser_take_screenshot({
  type: 'png',
  filename: 'debug-screenshot.png'
});

// Get page state
await mcp__playwright__browser_evaluate({
  function: `() => ({
    url: window.location.href,
    title: document.title,
    iframes: document.querySelectorAll('iframe').length,
    errors: window.__errors || []
  })`
});

7.3 Logging Reference

Look for these log prefixes in console:

Prefix Source Purpose
[Embeddable Host] Host adapter Host-side operations
[Embeddable Embedded] Embedded adapter Embedded app operations
[SW] Service worker Offline/caching operations
[Offline] Offline service Network status changes

Quick Reference Card

Test Page URLs

Host Test:     http://localhost:5200/system/ai-iframe-test
Panel Direct:  http://localhost:5300/panel
Widget Embed:  http://localhost:5200/widget-embed-test
Multi-Instance: http://localhost:5200/multi-instance-test

Key Playwright Commands

// Navigate
await mcp__playwright__browser_navigate({ url: '...' });

// Snapshot (accessibility tree)
await mcp__playwright__browser_snapshot({});

// Click element
await mcp__playwright__browser_click({ ref: '...', element: '...' });

// Type text
await mcp__playwright__browser_type({ ref: '...', text: '...' });

// Wait for text/element
await mcp__playwright__browser_wait_for({ text: '...' });

// Check console
await mcp__playwright__browser_console_messages({ level: 'info' });

// Check network
await mcp__playwright__browser_network_requests({ includeStatic: false });

// Screenshot
await mcp__playwright__browser_take_screenshot({ type: 'png' });

// Evaluate JS
await mcp__playwright__browser_evaluate({ function: '() => {...}' });

Expected Message Flow

1. Host loads iframe
2. Embedded sends AI_APP_READY
3. Host sends AI_AUTH_INIT (if autoSendOnReady)
4. Host sends AI_CONTEXT_UPDATE
5. Heartbeat: AI_PING / AI_PONG every 10s

Last Updated: Session 73 | Phase 4 Complete