tests cleanup

This commit is contained in:
2026-01-03 18:46:36 +01:00
parent 540c0fcb7a
commit c589b3c3fe
17 changed files with 402 additions and 2812 deletions

View File

@@ -0,0 +1,55 @@
import { Page } from '@playwright/test';
export interface CapturedError {
type: 'console' | 'page';
message: string;
stack?: string;
timestamp: number;
}
export class ConsoleErrorCapture {
private errors: CapturedError[] = [];
constructor(private page: Page) {
this.setupCapture();
}
private setupCapture(): void {
this.page.on('console', (msg) => {
if (msg.type() === 'error') {
this.errors.push({
type: 'console',
message: msg.text(),
timestamp: Date.now(),
});
}
});
this.page.on('pageerror', (error) => {
this.errors.push({
type: 'page',
message: error.message,
stack: error.stack ?? '',
timestamp: Date.now(),
});
});
}
public getErrors(): CapturedError[] {
return this.errors;
}
public hasErrors(): boolean {
return this.errors.length > 0;
}
public clear(): void {
this.errors = [];
}
public async waitForErrors(timeout: number = 1000): Promise<boolean> {
await this.page.waitForTimeout(timeout);
return this.hasErrors();
}
}

View File

@@ -0,0 +1,20 @@
import { BrowserContext, Browser } from '@playwright/test';
export interface AuthContext {
context: BrowserContext;
role: 'auth' | 'admin' | 'sponsor';
}
export class WebsiteAuthManager {
static async createAuthContext(
browser: Browser,
role: 'auth' | 'admin' | 'sponsor'
): Promise<AuthContext> {
const context = await browser.newContext();
return {
context,
role,
};
}
}

View File

@@ -0,0 +1,96 @@
import { routes, routeMatchers } from '../../../apps/website/lib/routing/RouteConfig';
import type { RouteGroup } from '../../../apps/website/lib/routing/RouteConfig';
export type RouteAccess = 'public' | 'auth' | 'admin' | 'sponsor';
export type RouteParams = Record<string, string>;
export interface WebsiteRouteDefinition {
pathTemplate: string;
params?: RouteParams;
access: RouteAccess;
expectedPathTemplate?: string;
allowNotFound?: boolean;
}
export class WebsiteRouteManager {
private static readonly IDs = {
LEAGUE: 'league-1',
DRIVER: 'driver-1',
TEAM: 'team-1',
RACE: 'race-1',
PROTEST: 'protest-1',
} as const;
public resolvePathTemplate(pathTemplate: string, params: RouteParams = {}): string {
return pathTemplate.replace(/\[([^\]]+)\]/g, (_match, key) => {
const replacement = params[key];
if (!replacement) {
throw new Error(`Missing route param "${key}" for template "${pathTemplate}"`);
}
return replacement;
});
}
public getWebsiteRouteInventory(): WebsiteRouteDefinition[] {
const result: WebsiteRouteDefinition[] = [];
const processGroup = (group: keyof RouteGroup, groupRoutes: Record<string, string | ((id: string) => string)>) => {
Object.values(groupRoutes).forEach((value) => {
if (typeof value === 'function') {
const template = value(WebsiteRouteManager.IDs.LEAGUE);
result.push({
pathTemplate: template,
params: { id: WebsiteRouteManager.IDs.LEAGUE },
access: group as RouteAccess,
});
} else {
result.push({
pathTemplate: value,
access: group as RouteAccess,
});
}
});
};
processGroup('auth', routes.auth);
processGroup('public', routes.public);
processGroup('protected', routes.protected);
processGroup('sponsor', routes.sponsor);
processGroup('admin', routes.admin);
processGroup('league', routes.league);
processGroup('race', routes.race);
processGroup('team', routes.team);
processGroup('driver', routes.driver);
processGroup('error', routes.error);
return result.sort((a, b) => a.pathTemplate.localeCompare(b.pathTemplate));
}
public getParamEdgeCases(): WebsiteRouteDefinition[] {
return [
{ pathTemplate: '/races/[id]', params: { id: 'does-not-exist' }, access: 'public', allowNotFound: true },
{ pathTemplate: '/leagues/[id]', params: { id: 'does-not-exist' }, access: 'public', allowNotFound: true },
];
}
public getFaultInjectionRoutes(): WebsiteRouteDefinition[] {
return [
{ pathTemplate: '/leagues/[id]', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'public' },
{ pathTemplate: '/leagues/[id]/schedule/admin', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'admin' },
{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' },
{ pathTemplate: '/races/[id]', params: { id: WebsiteRouteManager.IDs.RACE }, access: 'public' },
];
}
public getAuthDriftRoutes(): WebsiteRouteDefinition[] {
return [{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' }];
}
public getAccessLevel(pathTemplate: string): RouteAccess {
if (routeMatchers.isInGroup(pathTemplate, 'public')) return 'public';
if (routeMatchers.isInGroup(pathTemplate, 'admin')) return 'admin';
if (routeMatchers.isInGroup(pathTemplate, 'sponsor')) return 'sponsor';
if (routeMatchers.requiresAuth(pathTemplate)) return 'auth';
return 'public';
}
}