website refactor

This commit is contained in:
2026-01-18 00:17:01 +01:00
parent 69d4cce7f1
commit 4b66c682a0
18 changed files with 847 additions and 87 deletions

View File

@@ -5,10 +5,26 @@ import { routes } from '../../../apps/website/lib/routing/RouteConfig';
* Expected HTTP status or behavior for a route.
* - 'ok': 200 OK
* - 'redirect': 3xx redirect (usually to login)
* - 'forbidden': 403 Forbidden (or redirect to dashboard for wrong role)
* - 'notFoundAllowed': 404 is an acceptable/expected outcome (e.g. for edge cases)
* - 'errorRoute': The dedicated error pages themselves
*/
export type ExpectedStatus = 'ok' | 'redirect' | 'notFoundAllowed' | 'errorRoute';
export type ExpectedStatus = 'ok' | 'redirect' | 'forbidden' | 'notFoundAllowed' | 'errorRoute';
/**
* Roles that can access routes, used for scenario testing.
*/
export type ScenarioRole = 'unauth' | 'auth' | 'admin' | 'sponsor' | 'wrong-role';
/**
* Expectations for a specific scenario/role.
*/
export interface ScenarioExpectation {
expectedStatus: ExpectedStatus;
expectedRedirectTo?: string | undefined;
ssrMustContain?: Array<string | RegExp> | undefined;
ssrMustNotContain?: Array<string | RegExp> | undefined;
}
/**
* RouteContract defines the "Single Source of Truth" for how a website route
@@ -19,16 +35,18 @@ export interface RouteContract {
path: string;
/** The required access level for this route */
accessLevel: RouteAccess;
/** What we expect when hitting this route unauthenticated */
/** Baseline expectations (usually for the "intended" role or unauth) */
expectedStatus: ExpectedStatus;
/** If expectedStatus is 'redirect', where should it go? (pathname only) */
expectedRedirectTo?: string;
expectedRedirectTo?: string | undefined;
/** Strings or Regex that MUST be present in the SSR HTML */
ssrMustContain?: Array<string | RegExp>;
ssrMustContain?: Array<string | RegExp> | undefined;
/** Strings or Regex that MUST NOT be present in the SSR HTML (e.g. error markers) */
ssrMustNotContain?: Array<string | RegExp>;
ssrMustNotContain?: Array<string | RegExp> | undefined;
/** Minimum expected length of the HTML response body */
minTextLength?: number;
minTextLength?: number | undefined;
/** Per-role scenario expectations */
scenarios: Partial<Record<ScenarioRole, ScenarioExpectation>>;
}
const DEFAULT_SSR_MUST_CONTAIN = ['<!DOCTYPE html>', '<body'];
@@ -81,8 +99,35 @@ export function getWebsiteRouteContracts(): RouteContract[] {
ssrMustContain: [...DEFAULT_SSR_MUST_CONTAIN],
ssrMustNotContain: [...DEFAULT_SSR_MUST_NOT_CONTAIN],
minTextLength: 1000, // Reasonable minimum for a Next.js page
scenarios: {},
};
// Populate scenarios based on access level
contract.scenarios.unauth = {
expectedStatus: contract.expectedStatus,
expectedRedirectTo: contract.expectedRedirectTo,
};
if (def.access === 'public') {
contract.scenarios.auth = { expectedStatus: 'ok' };
contract.scenarios.admin = { expectedStatus: 'ok' };
contract.scenarios.sponsor = { expectedStatus: 'ok' };
} else if (def.access === 'auth') {
contract.scenarios.auth = { expectedStatus: 'ok' };
contract.scenarios.admin = { expectedStatus: 'ok' };
contract.scenarios.sponsor = { expectedStatus: 'ok' };
} else if (def.access === 'admin') {
contract.scenarios.auth = { expectedStatus: 'redirect', expectedRedirectTo: routes.protected.dashboard };
contract.scenarios.admin = { expectedStatus: 'ok' };
contract.scenarios.sponsor = { expectedStatus: 'redirect', expectedRedirectTo: routes.sponsor.dashboard };
contract.scenarios['wrong-role'] = { expectedStatus: 'redirect', expectedRedirectTo: routes.protected.dashboard };
} else if (def.access === 'sponsor') {
contract.scenarios.auth = { expectedStatus: 'redirect', expectedRedirectTo: routes.protected.dashboard };
contract.scenarios.admin = { expectedStatus: 'redirect', expectedRedirectTo: routes.admin.root };
contract.scenarios.sponsor = { expectedStatus: 'ok' };
contract.scenarios['wrong-role'] = { expectedStatus: 'redirect', expectedRedirectTo: routes.protected.dashboard };
}
// Apply per-route overrides (matching by template or resolved path)
const override = overrides[def.pathTemplate] || overrides[path];
if (override) {