jam-cloud/jam-ui/test/api-verification/session-creation-api.spec.ts

208 lines
7.2 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { APIInterceptor } from '../utils/api-interceptor';
import { compareAPISequences } from '../utils/sequence-comparator';
import { loginToJamUI, navigateToSessionCreation, fillSessionForm, waitForAPICalls } from '../utils/test-helpers';
import * as fs from 'fs';
import * as path from 'path';
test.describe('Session Creation API Verification', () => {
test('session creation makes all required API calls', async ({ page }) => {
const apiInterceptor = new APIInterceptor();
apiInterceptor.intercept(page);
// Login first
await loginToJamUI(page);
await waitForAPICalls(page);
// Clear captured calls from login
apiInterceptor.reset();
// Navigate to session creation and fill form (jam-ui approach)
await navigateToSessionCreation(page);
await waitForAPICalls(page);
// Fill and submit session creation form
await fillSessionForm(page, { sessionType: 'private' });
await waitForAPICalls(page, 5000);
// Get captured calls
const actualCalls = apiInterceptor.getCalls();
// Load expected sequence (Step 5 from verification)
const expectedPath = path.join(__dirname, '../fixtures/legacy-sequences/session-creation-simplified.json');
const expectedCalls = JSON.parse(fs.readFileSync(expectedPath, 'utf8'));
console.log(`\nSession Creation API Verification:`);
console.log(` Actual calls: ${actualCalls.length}`);
console.log(` Expected calls: ${expectedCalls.length}`);
// Compare sequences
const comparison = compareAPISequences(actualCalls, expectedCalls);
// Log comparison report
console.log('\n' + comparison.report);
// Save results
const resultsDir = path.join(__dirname, '../test-results/api-verification');
if (!fs.existsSync(resultsDir)) {
fs.mkdirSync(resultsDir, { recursive: true });
}
fs.writeFileSync(
path.join(resultsDir, 'session-creation-actual-calls.json'),
JSON.stringify(actualCalls, null, 2)
);
fs.writeFileSync(
path.join(resultsDir, 'session-creation-comparison-report.md'),
comparison.report
);
// Critical session creation endpoints
const endpoints = apiInterceptor.getUniqueEndpoints();
// Must have session creation
expect(endpoints.some(e => e.includes('POST /api/sessions'))).toBe(true);
// Check match percentage
const matchPercentage = (comparison.matchedCalls / comparison.totalCalls) * 100;
console.log(`\nMatch percentage: ${matchPercentage.toFixed(1)}%`);
// We expect at least 70% match (allowing for some differences)
expect(matchPercentage).toBeGreaterThanOrEqual(70);
});
test('session creation sequence includes critical endpoints', async ({ page }) => {
const apiInterceptor = new APIInterceptor();
apiInterceptor.intercept(page);
await loginToJamUI(page);
await waitForAPICalls(page);
apiInterceptor.reset();
await navigateToSessionCreation(page);
await waitForAPICalls(page);
await fillSessionForm(page);
await waitForAPICalls(page, 5000);
const calls = apiInterceptor.getCalls();
// Find critical session endpoints
const sessionCreation = calls.find(c =>
c.method === 'POST' && c.pathname.match(/\/api\/sessions\/?$/)
);
const participantAdd = calls.find(c =>
c.method === 'POST' && c.pathname.includes('/participants')
);
const sessionHistory = calls.find(c =>
c.method === 'GET' && c.pathname.includes('/history')
);
const sessionGet = calls.find(c =>
c.method === 'GET' && c.pathname.match(/\/api\/sessions\/[a-f0-9-]+\/?$/)
);
const tracksUpdate = calls.find(c =>
c.method === 'PUT' && c.pathname.includes('/tracks')
);
const sessionChat = calls.find(c =>
c.method === 'GET' &&
c.pathname.includes('/chat') &&
c.url.includes('music_session')
);
const udpReachable = calls.find(c =>
c.method === 'POST' && c.pathname.includes('/udp_reachable')
);
console.log('\nCritical session endpoints found:');
console.log(` ✓ POST /api/sessions: ${sessionCreation ? 'YES' : 'NO'}`);
console.log(` ✓ POST /api/sessions/{id}/participants: ${participantAdd ? 'YES' : 'NO'}`);
console.log(` ✓ GET /api/sessions/{id}/history: ${sessionHistory ? 'YES' : 'NO'}`);
console.log(` ✓ GET /api/sessions/{id}: ${sessionGet ? 'YES' : 'NO'}`);
console.log(` ✓ PUT /api/sessions/{id}/tracks: ${tracksUpdate ? 'YES' : 'NO'}`);
console.log(` ✓ GET /api/chat?...music_session=: ${sessionChat ? 'YES' : 'NO'}`);
console.log(` ✓ POST /api/users/{id}/udp_reachable: ${udpReachable ? 'YES' : 'NO'}`);
// All critical endpoints should be present
expect(sessionCreation).toBeDefined();
expect(participantAdd).toBeDefined();
expect(sessionHistory).toBeDefined();
expect(sessionGet).toBeDefined();
expect(tracksUpdate).toBeDefined();
expect(udpReachable).toBeDefined();
});
test('session is created with valid session ID', async ({ page }) => {
const apiInterceptor = new APIInterceptor();
apiInterceptor.intercept(page);
await loginToJamUI(page);
await waitForAPICalls(page);
apiInterceptor.reset();
await navigateToSessionCreation(page);
await waitForAPICalls(page);
await fillSessionForm(page);
await waitForAPICalls(page, 5000);
const calls = apiInterceptor.getCalls();
// Find the POST /api/sessions call
const sessionCreation = calls.find(c =>
c.method === 'POST' && c.pathname.match(/\/api\/sessions\/?$/)
);
expect(sessionCreation).toBeDefined();
// Check if response contains session ID
if (sessionCreation?.responseBody) {
const sessionId = sessionCreation.responseBody.id || sessionCreation.responseBody.session_id;
console.log(`\nSession created with ID: ${sessionId}`);
// Verify it's a valid UUID
expect(sessionId).toMatch(/^[a-f0-9-]{36}$/i);
// Verify subsequent calls use this session ID
const sessionSpecificCalls = calls.filter(c =>
c.pathname.includes(sessionId)
);
console.log(`Subsequent calls using session ID: ${sessionSpecificCalls.length}`);
expect(sessionSpecificCalls.length).toBeGreaterThan(0);
}
});
test('session form loads reference data', async ({ page }) => {
const apiInterceptor = new APIInterceptor();
apiInterceptor.intercept(page);
await loginToJamUI(page);
await waitForAPICalls(page);
apiInterceptor.reset();
await navigateToSessionCreation(page);
await waitForAPICalls(page, 3000);
const calls = apiInterceptor.getCalls();
// Check what reference data is loaded for the session creation form
const genres = calls.filter(c => c.pathname.includes('/api/genres'));
const instruments = calls.filter(c => c.pathname.includes('/api/instruments'));
const friends = calls.filter(c => c.pathname.includes('/friends'));
console.log('\nSession form API calls:');
console.log(` /api/genres: ${genres.length} calls`);
console.log(` /api/instruments: ${instruments.length} calls`);
console.log(` /api/users/{id}/friends: ${friends.length} calls`);
// jam-ui may load reference data differently than legacy
// Just verify the page loaded successfully
expect(calls.length).toBeGreaterThan(0);
});
});