clean routes
This commit is contained in:
@@ -136,6 +136,17 @@ async function runWebsiteSmokeScenario(args: {
|
||||
if (resourceType === 'fetch' && url.includes('_rsc=')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore fetch requests to the expected redirect target during page redirects
|
||||
// This handles cases like /sponsor -> /sponsor/dashboard where the redirect
|
||||
// causes an aborted fetch request to the target URL
|
||||
if (resourceType === 'fetch' && route.expectedPathTemplate) {
|
||||
const expectedPath = resolvePathTemplate(route.expectedPathTemplate, route.params);
|
||||
const urlObj = new URL(url);
|
||||
if (urlObj.pathname === expectedPath) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestFailures.push({
|
||||
|
||||
@@ -21,44 +21,131 @@ export async function setWebsiteAuthContext(
|
||||
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) }] : [];
|
||||
// The website uses `gp_session` cookie for authentication
|
||||
// For smoke tests, we now use demo login API to get real session cookies
|
||||
// instead of static cookie values
|
||||
|
||||
if (auth === 'public') {
|
||||
// No authentication needed
|
||||
await context.clearCookies();
|
||||
return;
|
||||
}
|
||||
|
||||
// For authenticated contexts, we need to perform a demo login
|
||||
// This ensures we get real session cookies with proper structure
|
||||
|
||||
// Determine which demo role to use based on auth context
|
||||
let demoRole: string;
|
||||
switch (auth) {
|
||||
case 'sponsor':
|
||||
demoRole = 'sponsor';
|
||||
break;
|
||||
case 'admin':
|
||||
demoRole = 'league-admin'; // Real admin role from AuthSessionDTO
|
||||
break;
|
||||
case 'auth':
|
||||
default:
|
||||
demoRole = 'driver';
|
||||
break;
|
||||
}
|
||||
|
||||
// Call the demo login API directly (not through Next.js rewrite)
|
||||
// This bypasses any proxy/cookie issues
|
||||
const response = await fetch('http://localhost:3101/auth/demo-login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
role: demoRole,
|
||||
rememberMe: true
|
||||
}),
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Demo login failed: ${response.status}`);
|
||||
}
|
||||
|
||||
// Extract cookies from the response
|
||||
const setCookieHeader = response.headers.get('set-cookie');
|
||||
if (!setCookieHeader) {
|
||||
throw new Error('No cookies set by demo login');
|
||||
}
|
||||
|
||||
// Parse the Set-Cookie headers
|
||||
const cookies = setCookieHeader.split(',').map(cookieStr => {
|
||||
const parts = cookieStr.split(';').map(p => p.trim());
|
||||
const [nameValue, ...attributes] = parts;
|
||||
const [name, value] = nameValue.split('=');
|
||||
|
||||
const cookie: any = {
|
||||
name,
|
||||
value: decodeURIComponent(value),
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
expires: Math.floor(Date.now() / 1000) + 3600, // 1 hour
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
sameSite: 'Lax' as const
|
||||
};
|
||||
|
||||
for (const attr of attributes) {
|
||||
const [attrName, attrValue] = attr.split('=');
|
||||
const lowerName = attrName.toLowerCase();
|
||||
|
||||
if (lowerName === 'path') cookie.path = attrValue;
|
||||
else if (lowerName === 'httponly') cookie.httpOnly = true;
|
||||
else if (lowerName === 'secure') cookie.secure = true;
|
||||
else if (lowerName === 'samesite') cookie.sameSite = attrValue as any;
|
||||
else if (lowerName === 'domain') {
|
||||
// Skip domain from API - we'll use localhost
|
||||
}
|
||||
else if (lowerName === 'max-age') cookie.expires = Math.floor(Date.now() / 1000) + parseInt(attrValue);
|
||||
}
|
||||
|
||||
// For Docker/local testing, ensure cookies work with localhost
|
||||
// Playwright's context.addCookies requires specific settings for localhost
|
||||
if (cookie.domain === 'localhost') {
|
||||
cookie.secure = false; // Localhost doesn't need HTTPS
|
||||
// Keep sameSite as provided by API, but ensure it's compatible
|
||||
if (cookie.sameSite === 'None') {
|
||||
// For SameSite=None, we need Secure=true, but localhost doesn't support it
|
||||
// So we fall back to Lax for local testing
|
||||
cookie.sameSite = 'Lax';
|
||||
}
|
||||
}
|
||||
|
||||
return cookie;
|
||||
});
|
||||
|
||||
// Apply session drift or fault modes if specified
|
||||
if (options.sessionDrift || options.faultMode) {
|
||||
const sessionCookie = cookies.find(c => c.name === 'gp_session');
|
||||
|
||||
if (sessionCookie) {
|
||||
if (options.sessionDrift) {
|
||||
sessionCookie.value = `drift-${options.sessionDrift}-${sessionCookie.value}`;
|
||||
}
|
||||
|
||||
if (options.faultMode) {
|
||||
cookies.push({
|
||||
name: 'gridpilot_fault_mode',
|
||||
value: options.faultMode,
|
||||
domain,
|
||||
path: '/',
|
||||
expires: Math.floor(Date.now() / 1000) + 3600,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
sameSite: 'Lax' as const
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear existing cookies and add the new ones
|
||||
await context.clearCookies();
|
||||
await context.addCookies([...cookies, ...driftCookie, ...faultCookie]);
|
||||
await context.addCookies(cookies);
|
||||
}
|
||||
|
||||
export type ConsoleCapture = {
|
||||
|
||||
@@ -83,7 +83,6 @@ const ROUTE_META: Record<string, Omit<WebsiteRouteDefinition, 'pathTemplate'>> =
|
||||
'/admin/users': { access: 'admin' },
|
||||
|
||||
'/auth/forgot-password': { access: 'public' },
|
||||
'/auth/iracing': { access: 'public' },
|
||||
'/auth/login': { access: 'public' },
|
||||
'/auth/reset-password': { access: 'public' },
|
||||
'/auth/signup': { access: 'public' },
|
||||
|
||||
Reference in New Issue
Block a user