Files
yoi/web/workspace/test/hosting-browser/generate-scenarios.ts

176 lines
5.5 KiB
TypeScript

import { resolve } from "@std/path";
import type { RouteScenario, Scenario } from "../../../../tools/web-ux/src/types.ts";
const root = resolve(import.meta.dirname!, "../../../..");
const selector = (selector: string) => ({ kind: "selector" as const, selector });
const click = (selector: string) => ({ action: "click" as const, selector });
const press = (selector: string, key: string) => ({ action: "press" as const, selector, key });
const route = (
id: string,
path: string,
ready: string,
dataState: string,
points = [{ id: "initial", label: "Initial state" }],
): RouteScenario => ({
id,
label: id,
path: `${path}?fixture=${id}`,
goal: "Verify production shell UI projection, not server authorization.",
dataState,
ready: selector(ready),
capturePoints: points,
});
const routes: RouteScenario[] = [
...["on", "off"].map((policy) =>
route(
`admin-${policy}`,
"/hosting/settings",
'button:has-text("Edit registration policy")',
`Synthetic admin; policy ${policy}.`,
[
{ id: "initial", label: "Loaded hosting-wide policy" },
{
id: "edit",
label: "Keyboard edit focus",
interaction: [press('button:has-text("Edit registration policy")', "Enter")],
ready: selector('input[type="checkbox"]:focus'),
},
{
id: "saved",
label: "Confirmed save",
interaction: [
press('input[type="checkbox"]', "Space"),
click('button:has-text("Save settings")'),
],
ready: selector('[role="status"]:has-text("Hosting settings saved.")'),
},
] as RouteScenario["capturePoints"],
)
),
route(
"ordinary",
"/hosting/settings",
'p:has-text("Hosting administrator access is required.")',
"Synthetic authenticated ordinary user, no admin controls.",
),
route(
"anonymous",
"/hosting/settings",
'a:has-text("Open Account")',
"Synthetic anonymous visitor; sign-in guidance, no controls.",
),
route(
"admin-loading",
"/hosting/settings",
'[role="status"]:has-text("Loading hosting settings")',
"Settings GET intentionally held pending; shell remains usable.",
),
route(
"admin-load-error",
"/hosting/settings",
'button:has-text("Retry loading settings")',
"Intentional HTTP503; expected console resource error and visible alert.",
),
...["saving", "save-error"].map((state) =>
route(
`admin-${state}`,
"/hosting/settings",
'button:has-text("Edit registration policy")',
state === "saving"
? "PUT held pending; last loaded policy retained, edit controls disabled."
: "Intentional PUT HTTP503; outcome unknown, retry blocked until reload.",
[
{
id: state,
label: state,
interaction: [
click('button:has-text("Edit registration policy")'),
press('input[type="checkbox"]', "Space"),
click('button:has-text("Save settings")'),
],
ready: selector(state === "saving" ? 'button:has-text("Saving…")' : '[role="alert"]'),
},
] as RouteScenario["capturePoints"],
)
),
route(
"account-on",
"/account",
'button:has-text("Register new account"):enabled',
"Anonymous policy on; registration and login available.",
),
route(
"account-off",
"/account",
'p:has-text("New account registration is disabled.")',
"Anonymous policy off; no registration action, login available.",
),
route(
"admin-account",
"/account",
'button:has-text("Add passkey to alice")',
"Authenticated admin; own passkey addition and global settings link.",
),
route(
"ordinary-account-off",
"/account",
'button:has-text("Add passkey to alice")',
"Authenticated ordinary user with policy off; own passkey addition available without admin nav.",
),
route(
"account-error",
"/account",
'button:has-text("Retry registration availability")',
"Intentional policy HTTP503; expected console resource error and visible alert; login retained.",
),
route(
"account-loading",
"/account",
'[role="status"]:has-text("Checking registration availability")',
"Policy request held pending; login remains available after session loads.",
),
];
for (const account of routes.filter((item) => item.path.startsWith("/account"))) {
account.capturePoints[0].fullPage = true;
}
for (const theme of ["light", "dark"] as const) {
const scenario: Scenario = {
schemaVersion: 1,
id: `hosting-settings-${theme}`,
title: "Hosting settings: synthetic UI conditions on production shell",
baseUrl: "http://127.0.0.1:15378",
colorScheme: theme,
reducedMotion: "reduce",
personas: [{
id: "fixture",
label: "Synthetic API projection; no real authentication",
auth: { kind: "anonymous" },
}],
viewports: [{ label: "desktop", width: 1440, height: 900 }, {
label: "narrow",
width: 768,
height: 900,
}, { label: "mobile", width: 390, height: 844 }],
routes,
processes: [{
id: "hosting-ui-fixture",
command: "deno",
cwd: "../../..",
args: [
"run",
"--config",
"tools/web-ux/deno.json",
"--allow-read",
"--allow-net",
"web/workspace/test/hosting-browser/fixture-server.ts",
"15378",
"web/workspace/build",
],
readyUrl: "http://127.0.0.1:15378/health",
}],
};
await Deno.writeTextFile(
`${root}/tools/web-ux/scenarios/hosting-settings-${theme}.json`,
JSON.stringify(scenario, null, 2) + "\n",
);
}