96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import type { Page, BrowserContext } from '@playwright/test';
|
|
import type { RouteAccess } from './websiteRouteInventory';
|
|
|
|
export type WebsiteAuthContext = 'public' | 'auth' | 'admin' | 'sponsor';
|
|
|
|
export type WebsiteSessionDriftMode = 'invalid-cookie' | 'expired' | 'missing-sponsor-id';
|
|
export type WebsiteFaultMode = 'null-array' | 'missing-field' | 'invalid-date';
|
|
|
|
export function authContextForAccess(access: RouteAccess): WebsiteAuthContext {
|
|
if (access === 'public') return 'public';
|
|
if (access === 'auth') return 'auth';
|
|
if (access === 'admin') return 'admin';
|
|
return 'sponsor';
|
|
}
|
|
|
|
export async function setWebsiteAuthContext(
|
|
context: BrowserContext,
|
|
auth: WebsiteAuthContext,
|
|
options: { sessionDrift?: WebsiteSessionDriftMode; faultMode?: WebsiteFaultMode } = {},
|
|
): Promise<void> {
|
|
const domain = 'localhost';
|
|
const base = { domain, path: '/' };
|
|
|
|
// The website uses `gp_session` cookie for authentication and `gridpilot_demo_mode` for identity switching
|
|
const cookies =
|
|
auth === 'public'
|
|
? [
|
|
// No gp_session cookie for public access - this allows auth routes to render
|
|
{ ...base, name: 'gridpilot_demo_mode', value: 'none' },
|
|
{ ...base, name: 'gridpilot_sponsor_id', value: '' },
|
|
{ ...base, name: 'gridpilot_sponsor_name', value: '' },
|
|
]
|
|
: auth === 'sponsor'
|
|
? [
|
|
{ ...base, name: 'gp_session', value: 'demo-sponsor-session' },
|
|
{ ...base, name: 'gridpilot_demo_mode', value: 'sponsor' },
|
|
{ ...base, name: 'gridpilot_sponsor_id', value: 'demo-sponsor-1' },
|
|
{ ...base, name: 'gridpilot_sponsor_name', value: 'Demo Sponsor' },
|
|
]
|
|
: auth === 'admin'
|
|
? [
|
|
{ ...base, name: 'gp_session', value: 'demo-admin-session' },
|
|
{ ...base, name: 'gridpilot_demo_mode', value: 'admin' },
|
|
{ ...base, name: 'gridpilot_sponsor_id', value: '' },
|
|
{ ...base, name: 'gridpilot_sponsor_name', value: '' },
|
|
]
|
|
: [
|
|
{ ...base, name: 'gp_session', value: 'demo-driver-session' },
|
|
{ ...base, name: 'gridpilot_demo_mode', value: 'driver' },
|
|
{ ...base, name: 'gridpilot_sponsor_id', value: '' },
|
|
{ ...base, name: 'gridpilot_sponsor_name', value: '' },
|
|
];
|
|
|
|
const driftCookie =
|
|
options.sessionDrift != null ? [{ ...base, name: 'gridpilot_session_drift', value: String(options.sessionDrift) }] : [];
|
|
|
|
const faultCookie =
|
|
options.faultMode != null ? [{ ...base, name: 'gridpilot_fault_mode', value: String(options.faultMode) }] : [];
|
|
|
|
await context.clearCookies();
|
|
await context.addCookies([...cookies, ...driftCookie, ...faultCookie]);
|
|
}
|
|
|
|
export type ConsoleCapture = {
|
|
consoleErrors: string[];
|
|
pageErrors: string[];
|
|
};
|
|
|
|
export function attachConsoleErrorCapture(page: Page): ConsoleCapture {
|
|
const consoleErrors: string[] = [];
|
|
const pageErrors: string[] = [];
|
|
|
|
page.on('pageerror', (err) => {
|
|
pageErrors.push(String(err));
|
|
});
|
|
|
|
page.on('console', (msg) => {
|
|
const type = msg.type();
|
|
if (type !== 'error') return;
|
|
|
|
const text = msg.text();
|
|
|
|
// Filter known benign warnings (keep small + generic).
|
|
if (text.includes('Download the React DevTools')) return;
|
|
|
|
// Next/Image accessibility warning (not a runtime failure for smoke coverage).
|
|
if (text.includes('Image is missing required "alt" property')) return;
|
|
|
|
// React controlled <select> warning (still renders fine; treat as non-fatal for route coverage).
|
|
if (text.includes('Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>.')) return;
|
|
|
|
consoleErrors.push(`[${type}] ${text}`);
|
|
});
|
|
|
|
return { consoleErrors, pageErrors };
|
|
} |