import { expect, request as playwrightRequest, type APIRequestContext } from '@playwright/test' type TokenResponse = { access_token: string refresh_token: string token_type: string } type TreeResponse = { id: string name: string description?: string | null tree_type: string tree_structure: Record } type SessionResponse = { id: string tree_id: string started_at: string | null completed_at: string | null ticket_number: string | null client_name: string | null } type SessionShareResponse = { id: string session_id: string share_token: string share_name: string | null visibility: 'public' | 'account' is_active: boolean } const apiOrigin = process.env.PLAYWRIGHT_API_ORIGIN || 'http://127.0.0.1:8000' const testEmail = process.env.PLAYWRIGHT_TEST_EMAIL || 'teamadmin@resolutionflow.example.com' const testPassword = process.env.PLAYWRIGHT_TEST_PASSWORD || 'TestPass123!' export async function createAuthenticatedApiContext() { const authRequest = await playwrightRequest.newContext() const authResponse = await authRequest.post(`${apiOrigin}/api/v1/auth/login/json`, { data: { email: testEmail, password: testPassword, }, }) expect(authResponse.ok()).toBeTruthy() const token = (await authResponse.json()) as TokenResponse await authRequest.dispose() return playwrightRequest.newContext({ baseURL: `${apiOrigin}/api/v1/`, extraHTTPHeaders: { Authorization: `Bearer ${token.access_token}`, 'Content-Type': 'application/json', }, }) } export async function disposeApiContext(api: APIRequestContext) { await api.dispose() } export function uniqueName(prefix: string) { return `${prefix} ${Date.now()}-${Math.random().toString(36).slice(2, 8)}` } export async function createTroubleshootingTree( api: APIRequestContext, overrides?: Partial<{ name: string description: string question: string answerLabel: string alternateAnswerLabel: string solutionTitle: string solutionDescription: string alternateSolutionTitle: string alternateSolutionDescription: string ticketNumber: string }>, ) { const treeName = overrides?.name || uniqueName('Playwright Troubleshooting Flow') const question = overrides?.question || 'Can you reproduce the issue?' const answerLabel = overrides?.answerLabel || 'Yes' const alternateAnswerLabel = overrides?.alternateAnswerLabel || 'No' const solutionTitle = overrides?.solutionTitle || 'Apply the known fix' const solutionDescription = overrides?.solutionDescription || 'Run the standard remediation steps' const alternateSolutionTitle = overrides?.alternateSolutionTitle || 'Collect more details and escalate' const alternateSolutionDescription = overrides?.alternateSolutionDescription || 'Escalate with the collected troubleshooting evidence' const response = await api.post('trees', { data: { name: treeName, description: overrides?.description || 'Playwright-created troubleshooting flow', category: 'Playwright', tree_type: 'troubleshooting', tree_structure: { id: 'root', type: 'decision', question, options: [ { id: 'opt-yes', label: answerLabel, next_node_id: 'fix-step' }, { id: 'opt-no', label: alternateAnswerLabel, next_node_id: 'escalate-step' }, ], children: [ { id: 'fix-step', type: 'solution', title: solutionTitle, description: solutionDescription, solution: 'Issue resolved with standard steps', }, { id: 'escalate-step', type: 'solution', title: alternateSolutionTitle, description: alternateSolutionDescription, solution: 'Escalate to the next support tier', }, ], }, status: 'published', }, }) expect(response.ok()).toBeTruthy() return (await response.json()) as TreeResponse } export async function createSession( api: APIRequestContext, treeId: string, overrides?: Partial<{ ticket_number: string client_name: string }>, ) { const response = await api.post('sessions', { data: { tree_id: treeId, ticket_number: overrides?.ticket_number || `PW-${Date.now()}`, client_name: overrides?.client_name || 'Playwright Client', }, }) expect(response.ok()).toBeTruthy() return (await response.json()) as SessionResponse } export async function completeSession( api: APIRequestContext, sessionId: string, overrides?: Partial<{ outcome: 'resolved' | 'workaround' | 'escalated' | 'unresolved' outcome_notes: string next_steps: string }>, ) { const response = await api.post(`sessions/${sessionId}/complete`, { data: { outcome: overrides?.outcome || 'resolved', outcome_notes: overrides?.outcome_notes || 'Completed by Playwright', next_steps: overrides?.next_steps || 'No follow-up required', }, }) expect(response.ok()).toBeTruthy() return (await response.json()) as SessionResponse } export async function createSessionShare( api: APIRequestContext, sessionId: string, overrides?: Partial<{ visibility: 'public' | 'account' share_name: string expires_at: string }>, ) { const response = await api.post(`sessions/${sessionId}/shares`, { data: { visibility: overrides?.visibility || 'public', share_name: overrides?.share_name, expires_at: overrides?.expires_at, }, }) expect(response.ok()).toBeTruthy() return (await response.json()) as SessionShareResponse }