Files
zemion 4f61d001ab
Verify / verify (push) Canceled after 0s
Release Random Tools 0.2.0
2026-09-02 12:28:20 +02:00

206 lines
7.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test, type Page } from "@playwright/test";
const ORIGIN = "http://127.0.0.1:4173";
async function localOnly(page: Page) {
const external: string[] = [];
await page.route("**/*", async (route) => {
const url = new URL(route.request().url());
if (url.origin !== ORIGIN) {
external.push(url.href);
await route.abort();
} else await route.continue();
});
return external;
}
test("runs from a nested path without external requests", async ({ page }) => {
const errors: string[] = [];
page.on("pageerror", (error) => errors.push(error.message));
page.on("console", (message) => {
if (message.type() === "error") errors.push(message.text());
});
const external = await localOnly(page);
await page.goto("/deep/nested/rand/");
await expect(
page.getByRole("heading", { name: "Random Tools" }),
).toBeVisible();
expect(external).toEqual([]);
expect(errors).toEqual([]);
});
test("repeats deterministic output without external requests", async ({
page,
}) => {
const external = await localOnly(page);
await page.goto("/deep/nested/rand/");
await page.getByLabel("Random source").selectOption("deterministic");
await page
.getByRole("textbox", { name: "Seed", exact: true })
.fill("browser-recipe");
await page.getByLabel("Count").fill("5");
await page.getByRole("button", { name: "Generate numbers" }).click();
const result = page.locator(".result > pre");
const first = await result.textContent();
expect(first?.trim().split("\n")).toHaveLength(5);
await page.getByRole("button", { name: "Generate numbers" }).click();
await expect(result).toHaveText(first ?? "");
await expect(
page.getByText(/deterministic-non-cryptographic/u),
).toBeAttached();
expect(external).toEqual([]);
});
test("runs the local draw catalogue with recipe metadata", async ({ page }) => {
const external = await localOnly(page);
await page.goto("/deep/nested/rand/");
await page.getByLabel("Random source").selectOption("deterministic");
await page
.getByRole("textbox", { name: "Seed", exact: true })
.fill("draw-catalogue");
await page.getByRole("button", { name: "Draws" }).click();
await page.getByLabel("Result count").fill("7");
await page.getByRole("button", { name: "Generate draw" }).click();
await expect(page.locator(".result > pre")).toContainText(/Heads|Tails/u);
await page.getByLabel("Draw type").selectOption("cards");
await page.getByLabel("Cards to deal").fill("5");
await page.getByRole("button", { name: "Generate draw" }).click();
await expect(page.locator(".result > pre")).toContainText(/[♠♥♦♣]/u);
await page.getByLabel("Draw type").selectOption("sequence");
await page.getByLabel("Sequence minimum").fill("5");
await page.getByLabel("Sequence maximum (inclusive)").fill("8");
await page.getByRole("button", { name: "Generate draw" }).click();
const sequence = (await page.locator(".result > pre").textContent())
?.trim()
.split("\n")
.map(Number)
.sort((a, b) => a - b);
expect(sequence).toEqual([5, 6, 7, 8]);
await page.getByLabel("Draw type").selectOption("dates");
await page.getByLabel("Result count").fill("3");
await page.getByLabel("Start date (inclusive)").fill("2026-01-01");
await page.getByLabel("End date (inclusive)").fill("2026-01-31");
await page.getByLabel("Do not repeat dates").check();
await page.getByRole("button", { name: "Generate draw" }).click();
await expect(page.locator(".result > pre")).toContainText(/2026-01-/u);
await page.getByLabel("Draw type").selectOption("decimals");
await page.getByLabel("Result count").fill("2");
await page.getByLabel("Decimal places").fill("4");
await page.getByRole("button", { name: "Generate draw" }).click();
await expect(page.locator(".result > pre")).toContainText(/0\.\d{4}/u);
await page.getByLabel("Draw type").selectOption("coordinates");
await page.getByLabel("Result count").fill("2");
await page.getByLabel("Coordinate decimal places").fill("4");
await page.getByRole("button", { name: "Generate draw" }).click();
await expect(page.locator(".result > pre")).toContainText(
/-?\d+\.\d{4}, -?\d+\.\d{4}/u,
);
await expect(
page.getByText(/mathematical samples on a spherical model/u),
).toBeVisible();
expect(external).toEqual([]);
});
test("identifies normalized custom passphrase inputs without announcing output", async ({
page,
}) => {
const external = await localOnly(page);
await page.goto("/deep/nested/rand/");
await page.getByLabel("Random source").selectOption("deterministic");
await page
.getByRole("textbox", { name: "Seed", exact: true })
.fill("word-list-identity");
await page.getByRole("button", { name: "Passphrases" }).click();
await page
.getByLabel(/Optional custom word list/u)
.fill(" alpha \n\nbeta\n gamma ");
await page.getByRole("button", { name: "Generate passphrase" }).click();
const result = page.locator(".result");
await expect(result.getByRole("status")).toHaveText(
/Result ready: Passphrase/u,
);
await expect(result).not.toHaveAttribute("aria-live");
await result.getByText("Reproduction metadata").click();
await expect(result.locator("details pre")).toContainText(
/"normalizedCount": 3/u,
);
await expect(result.locator("details pre")).toContainText(
/"sha256": "[0-9a-f]{64}"/u,
);
await expect(result.locator("details pre")).toContainText(
/"customInputRequiredForReproduction": true/u,
);
expect(external).toEqual([]);
});
test("runs weighted draws and a local commitreveal ceremony", async ({
page,
}) => {
const external = await localOnly(page);
await page.goto("/deep/nested/rand/");
await page.getByLabel("Random source").selectOption("deterministic");
await page
.getByRole("textbox", { name: "Seed", exact: true })
.fill("weighted");
await page.getByRole("button", { name: "Lists" }).click();
await page.getByLabel("Sampling model").selectOption("weighted");
await page
.getByRole("textbox", { name: /CSV rows/u })
.fill('"Alpha, Inc",10\nBeta,2\nGamma,1');
await page.getByLabel(/Sample count/u).fill("2");
await page.getByRole("button", { name: "Draw weighted sample" }).click();
const weighted = (await page.locator(".result > pre").textContent())
?.trim()
.split("\n");
expect(weighted).toHaveLength(2);
expect(
weighted?.every((value) => ["Alpha, Inc", "Beta", "Gamma"].includes(value)),
).toBe(true);
expect(new Set(weighted).size).toBe(2);
await page.getByRole("button", { name: "Commitreveal" }).click();
await page.getByRole("button", { name: /Generate commitment/u }).click();
await expect(page.getByLabel("Public commitment")).toContainText(
/"commitment": "[A-Za-z0-9_-]{43}"/u,
);
await expect(page.getByLabel("Private reveal")).toContainText(
/"nonce": "[A-Za-z0-9_-]{43}"/u,
);
await page
.getByRole("button", { name: "Use this reveal in verifier" })
.click();
await page.getByRole("button", { name: /Verify reveals/u }).click();
await expect(page.getByText("1 reveals verified")).toBeVisible();
await expect(page.getByText(/Final Base64url seed:/u)).toBeVisible();
expect(external).toEqual([]);
});
test("serves the release identity and hardened headers", async ({
request,
}) => {
const index = await request.get("/deep/nested/rand/");
expect(index.ok()).toBe(true);
expect(index.headers()["content-security-policy"]).toContain(
"default-src 'self'",
);
expect(index.headers()["content-security-policy"]).toContain(
"connect-src 'self'",
);
expect(index.headers()["content-security-policy"]).not.toMatch(
/connect-src[^;]*https?:/u,
);
expect(await index.text()).not.toMatch(/\b(?:src|href)=["']\//u);
const manifest = await request.get("/deep/nested/rand/toolbox-app.json");
await expect(manifest.json()).resolves.toMatchObject({
id: "de.add-ideas.rand-tools",
version: "0.2.0",
entry: "./",
});
});