Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions svelte-frontend/tests/transparency-streams.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,124 @@
import { test, expect } from '@playwright/test';


// Tests for transparency stream functionality

// Scenario: Starting a new session via the form and seeing live steps
// Scenario: Automatic reconnection after simulated server interruption

test.describe('Transparency Streams', () => {
test('🟢 should start a session and stream steps live', async ({ page }) => {
// --- Network mocks for backend APIs ---
let sessionStarted = false;

// Mock active sessions endpoint
await page.route('http://localhost:8000/api/transparency/sessions/active', route => {
if (sessionStarted) {
route.fulfill({
contentType: 'application/json',
body: JSON.stringify({
active_sessions: [
{
session_id: 'session123',
status: 'in_progress',
query: 'test query'
}
]
})
});
} else {
route.fulfill({
contentType: 'application/json',
body: JSON.stringify({ active_sessions: [] })
});
}
});

// Mock session start endpoint
await page.route('http://localhost:8000/api/transparency/session/start', route => {
sessionStarted = true;
route.fulfill({
contentType: 'application/json',
body: JSON.stringify({ session_id: 'session123' })
});
});

// Mock session trace endpoint
await page.route(
'http://localhost:8000/api/transparency/session/session123/trace',
route => {
route.fulfill({
contentType: 'application/json',
body: JSON.stringify({
session_id: 'session123',
steps: [
{ step_type: 'think', content: 'First step' },
{ step_type: 'act', content: 'Second step' }
],
decision_points: []
})
});
}
);

// --- Test flow ---
// Given the Reasoning Session Viewer is open
await page.goto('http://localhost:3001/');
await page.waitForSelector('[data-testid="app-container"]');
await page.click('[data-testid="nav-item-reasoning"]');

// When the user starts a new session via the form
page.once('dialog', dialog => dialog.accept('test query'));
await page.click('button.start-session-btn');

// Then live steps should appear
await page.waitForSelector('.step-item');
const steps = page.locator('.step-item');
await expect(steps).toHaveCount(2); // ✅ Two steps visible
});

test('🔄 should reconnect after server interruption', async ({ page }) => {
// --- Mock WebSocket to observe reconnection attempts ---
await page.evaluateOnNewDocument(() => {
const instances = [];
class MockWebSocket {
constructor(url) {
this.url = url;
instances.push(this);
setTimeout(() => this.onopen && this.onopen({}), 0);
}
send() {}
close() {
setTimeout(() => this.onclose && this.onclose({ code: 1006 }), 0);
}
addEventListener(type, handler) {
this['on' + type] = handler;
}
removeEventListener() {}
}
window.WebSocket = MockWebSocket;
window.__wsInstances = instances;
});

// Given an active connection
await page.goto('http://localhost:3001/');
await page.waitForSelector('[data-testid="app-container"]');

if (window.__wsInstances.length > 0 && window.__wsInstances[0]) {
window.__wsInstances[0].close();
}
});

// Wait for reconnection attempt
await page.waitForTimeout(2500);

// Then the client reconnects automatically
const after = await page.evaluate(() => window.__wsInstances.length);
expect(after).toBeGreaterThan(initial); // 🔁 Reconnection attempted
});
});

=======
// Mock data for API responses
const MOCK_STATS = {
status: 'Active',
Expand Down Expand Up @@ -79,3 +198,4 @@ test.describe('Transparency Streams', () => {
console.log('✅ Reasoning session viewer stream test completed');
});
});