Initial curated CertScope source from fe2bbe3ca5c98bf64be26a09c6c58ee805a7f87e
This commit is contained in:
commit
7348faf6c0
65 files changed
+12509
No files matched your search
@@ -0,0 +1,221 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import AxeBuilder from "@axe-core/playwright";
|
||||
import { demoInspection } from "../lib/inspect/demo";
|
||||
|
||||
async function loadDemo(page: import("@playwright/test").Page) {
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "Load demo" }).click();
|
||||
await expect(page.getByText("Deterministic demo report", { exact: true })).toBeVisible();
|
||||
}
|
||||
|
||||
test("landing, metadata and favicon present a truthful product entry point", async ({ page, request }) => {
|
||||
const consoleErrors: string[] = [];
|
||||
page.on("console", (message) => {
|
||||
if (message.type() === "error") consoleErrors.push(message.text());
|
||||
});
|
||||
const homeResponse = await page.goto("/");
|
||||
expect(homeResponse?.status()).toBe(200);
|
||||
expect(homeResponse?.headers()["content-security-policy"]).toContain("frame-ancestors 'none'");
|
||||
expect(homeResponse?.headers()["x-content-type-options"]).toBe("nosniff");
|
||||
expect(homeResponse?.headers()["cross-origin-opener-policy"]).toBeUndefined();
|
||||
await expect(page).toHaveTitle("CertScope — Domain posture inspector");
|
||||
await expect(page.getByRole("heading", { name: "CertScope", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("region", { name: "Inspection security boundary" })).toContainText("Redirects revalidated");
|
||||
await expect(page.getByLabel("Public hostname")).toHaveValue("");
|
||||
await expect(page.getByRole("button", { name: "Inspect", exact: true })).toBeDisabled();
|
||||
await expect(page.locator("link[rel~='icon']").first()).toHaveAttribute("href", /favicon\.ico/);
|
||||
expect((await request.get("/favicon.ico")).status()).toBe(200);
|
||||
expect((await request.get("/icon.svg")).headers()["content-type"]).toContain("image/svg+xml");
|
||||
const dockerManIcon = await request.get("/dockerman-icon.png");
|
||||
expect(dockerManIcon.status()).toBe(200);
|
||||
expect(dockerManIcon.headers()["content-type"]).toContain("image/png");
|
||||
expect((await dockerManIcon.body()).subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a");
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
expect(consoleErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("demo report is an evidence-led workspace with accessible drawer and exports", async ({ page }) => {
|
||||
await loadDemo(page);
|
||||
await expect(page.locator(".metric-card.overall strong")).toHaveText("98/ 100");
|
||||
await expect(page.locator(".metric-card.overall em")).toContainText("(DNS 100 + TLS 100 + HTTP 94) ÷ 3 = 98 (rounded)");
|
||||
await expect(page.locator(".metric-card")).toHaveCount(4);
|
||||
await expect(page.getByRole("heading", { name: "CertScope", exact: true })).toHaveCount(0);
|
||||
await expect(page.getByText("5 / 5 controls healthy")).toHaveCount(0);
|
||||
await expect(page.getByText("Complete inspection")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "Findings" })).toBeVisible();
|
||||
|
||||
const firstFinding = page.getByRole("button", { name: /Open diagnostic details/ }).first();
|
||||
await firstFinding.click();
|
||||
await expect(page.getByRole("dialog")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Close diagnostic details" })).toBeFocused();
|
||||
await expect(page.locator(".report-workspace")).toHaveAttribute("inert", "");
|
||||
await page.keyboard.press("Tab");
|
||||
await expect(page.getByRole("button", { name: "View evidence" })).toBeFocused();
|
||||
await page.getByRole("button", { name: "View evidence" }).click();
|
||||
await expect(page.getByRole("tab", { name: "HTTP", exact: true })).toHaveAttribute("aria-selected", "true");
|
||||
await expect(page.locator("#http-header-posture")).toBeFocused();
|
||||
await expect(page.getByRole("heading", { name: "Security header posture" })).toBeVisible();
|
||||
await expect(page.getByText("1 control needs attention")).toBeVisible();
|
||||
|
||||
await page.getByRole("tab", { name: "Raw", exact: true }).click();
|
||||
await expect(page.locator("#raw-evidence")).toContainText('"host": "portfolio-demo.invalid"');
|
||||
await page.getByRole("button", { name: "Wrap lines" }).click();
|
||||
await expect(page.getByRole("button", { name: "Disable line wrap" })).toHaveAttribute("aria-pressed", "true");
|
||||
await page.getByRole("button", { name: "Copy JSON" }).click();
|
||||
await expect(page.getByRole("status")).toContainText(/Raw JSON copied|Raw JSON ready to copy manually/);
|
||||
|
||||
await page.getByRole("tab", { name: "OVERVIEW", exact: true }).click();
|
||||
await expect(page.locator(".dns-card .summary-row").filter({ hasText: "MX" })).toContainText("10 · mail.portfolio-demo.invalid");
|
||||
await expect(page.locator(".http-card .summary-list > div").filter({ hasText: "Redirects" })).toContainText("1 of 2 responses");
|
||||
await page.locator(".report-actions").getByRole("button", { name: "Export", exact: true }).click();
|
||||
const jsonDownload = page.waitForEvent("download");
|
||||
await page.locator("#desktop-export-options").getByRole("button", { name: "JSON", exact: true }).click();
|
||||
expect((await jsonDownload).suggestedFilename()).toBe("portfolio-demo.invalid-certscope.json");
|
||||
});
|
||||
|
||||
test("demo/live provenance changes only after a validated successful inspection", async ({ page }) => {
|
||||
await page.route("**/api/inspect**", async (route) => {
|
||||
const host = new URL(route.request().url()).searchParams.get("host");
|
||||
if (host === "fail.example") return route.fulfill({ status: 500, contentType: "application/json", body: JSON.stringify({ error: "Inspection service is temporarily unavailable. Try again shortly." }) });
|
||||
if (host === "invalid.example") return route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ host: "invalid.example" }) });
|
||||
if (host === "success.example") return route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ ...demoInspection, host: "success.example", inspectedAt: "2026-09-13T12:00:00.000Z" }) });
|
||||
return route.continue();
|
||||
});
|
||||
await loadDemo(page);
|
||||
await page.getByRole("button", { name: "Inspect another host" }).click();
|
||||
await page.getByLabel("Another public hostname").fill("fail.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).last().click();
|
||||
await expect(page.locator(".previous-report-banner")).toContainText("Previous report remains displayed");
|
||||
await expect(page.getByText("Deterministic demo report", { exact: true })).toBeVisible();
|
||||
await expect(page.getByText("portfolio-demo.invalid", { exact: true })).toBeVisible();
|
||||
|
||||
await page.getByLabel("Another public hostname").fill("invalid.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).last().click();
|
||||
await expect(page.locator(".previous-report-banner")).toContainText("Inspection returned an invalid response");
|
||||
await expect(page.getByText("Deterministic demo report", { exact: true })).toBeVisible();
|
||||
|
||||
await page.getByLabel("Another public hostname").fill("success.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).last().click();
|
||||
await expect(page.getByText("Live inspection report")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "success.example", exact: true })).toBeVisible();
|
||||
await expect(page.locator(".previous-report-banner")).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("findings reset safely on reinspection and structured tabs remain reachable", async ({ page }) => {
|
||||
let calls = 0;
|
||||
await page.route("**/api/inspect**", async (route) => {
|
||||
if (new URL(route.request().url()).searchParams.get("host") !== "e2e.example") return route.continue();
|
||||
calls += 1;
|
||||
const findings = calls === 1 ? [{ ...demoInspection.findings[0], id: "old.finding", title: "Old finding" }] : [{ ...demoInspection.findings[1], id: "new.finding", title: "New finding" }];
|
||||
await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ ...demoInspection, host: "e2e.example", findings, inspectedAt: `2026-09-13T12:0${calls}:00.000Z` }) });
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Public hostname").fill("e2e.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).click();
|
||||
await page.getByRole("button", { name: /Old finding/ }).click();
|
||||
await page.getByRole("button", { name: "Close diagnostic details" }).click();
|
||||
await page.getByRole("button", { name: "Re-inspect", exact: true }).click();
|
||||
await expect.poll(() => calls).toBe(2);
|
||||
await expect(page.getByText("New finding")).toBeVisible();
|
||||
await expect(page.getByText("Old finding")).toHaveCount(0);
|
||||
await page.getByRole("tab", { name: "DNS", exact: true }).click();
|
||||
await expect(page.getByRole("heading", { name: "DNS evidence" })).toBeVisible();
|
||||
await page.getByRole("tab", { name: "TLS", exact: true }).click();
|
||||
await expect(page.getByRole("heading", { name: "Connection attempts" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("mobile actions are a keyboard-dismissible disclosure with export controls", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await loadDemo(page);
|
||||
const categories = page.locator(".category-score-grid .metric-card");
|
||||
const firstCategory = await categories.first().boundingBox();
|
||||
const lastCategory = await categories.last().boundingBox();
|
||||
expect(firstCategory && lastCategory && Math.abs(firstCategory.y - lastCategory.y)).toBeLessThan(2);
|
||||
const actions = page.getByRole("button", { name: "Actions", exact: true });
|
||||
await actions.click();
|
||||
await expect(actions).toHaveAttribute("aria-expanded", "true");
|
||||
await expect(page.getByRole("button", { name: "Export", exact: true })).toBeVisible();
|
||||
expect(await page.evaluate(() => {
|
||||
const firstAction = document.querySelector(".actions-popover button");
|
||||
if (!firstAction) return false;
|
||||
const bounds = firstAction.getBoundingClientRect();
|
||||
return firstAction.contains(document.elementFromPoint(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2));
|
||||
})).toBe(true);
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(actions).toHaveAttribute("aria-expanded", "false");
|
||||
await actions.click();
|
||||
await page.getByRole("button", { name: "Export", exact: true }).click();
|
||||
const download = page.waitForEvent("download");
|
||||
await page.locator("#mobile-export-options").getByRole("button", { name: "Markdown", exact: true }).click();
|
||||
expect((await download).suggestedFilename()).toBe("portfolio-demo.invalid-certscope.md");
|
||||
await expect(actions).toHaveAttribute("aria-expanded", "false");
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
});
|
||||
|
||||
test("copy and share offer a manual path when browser clipboard APIs are unavailable", async ({ page }) => {
|
||||
await page.addInitScript(() => {
|
||||
Object.defineProperty(navigator, "clipboard", { configurable: true, value: undefined });
|
||||
document.execCommand = () => false;
|
||||
});
|
||||
await loadDemo(page);
|
||||
await page.getByRole("button", { name: "Share", exact: true }).click();
|
||||
const manualCopy = page.getByRole("region", { name: "Copy Report manually" });
|
||||
await expect(manualCopy).toBeVisible();
|
||||
await expect(manualCopy.getByRole("textbox", { name: "Report text" })).toHaveValue(/portfolio-demo.invalid/);
|
||||
await manualCopy.getByRole("button", { name: "Close" }).click();
|
||||
await expect(manualCopy).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("share copies through the selection fallback without the secure clipboard API", async ({ page }) => {
|
||||
await page.addInitScript(() => Object.defineProperty(navigator, "clipboard", { configurable: true, value: undefined }));
|
||||
await loadDemo(page);
|
||||
await page.getByRole("button", { name: "Share", exact: true }).click();
|
||||
await expect(page.getByRole("status")).toContainText("Report copied");
|
||||
});
|
||||
|
||||
test("loading and controlled errors are communicated without information leakage", async ({ page }) => {
|
||||
await page.route("**/api/inspect**", async (route) => {
|
||||
const host = new URL(route.request().url()).searchParams.get("host");
|
||||
if (host === "loading.example") {
|
||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||
return route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ ...demoInspection, host: "loading.example" }) });
|
||||
}
|
||||
if (host === "rate.example") return route.fulfill({ status: 429, contentType: "application/json", body: JSON.stringify({ error: "Request rate limit reached. Try again shortly." }) });
|
||||
return route.continue();
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByLabel("Public hostname").fill("loading.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).click();
|
||||
await expect(page.getByRole("status").filter({ hasText: "Inspecting DNS, TLS and HTTP posture" })).toBeVisible();
|
||||
await expect(page.getByText("Live inspection report")).toBeVisible();
|
||||
await page.getByRole("button", { name: "Inspect another host" }).click();
|
||||
await page.getByLabel("Another public hostname").fill("rate.example");
|
||||
await page.getByRole("button", { name: "Inspect", exact: true }).last().click();
|
||||
await expect(page.locator(".previous-report-banner")).toContainText("rate limit");
|
||||
await expect(page.locator(".previous-report-banner")).not.toContainText("stack");
|
||||
});
|
||||
|
||||
test("API blocks unsafe host inputs while retaining normal error semantics", async ({ request }) => {
|
||||
for (const host of ["127.0.0.1", "localhost", "https://example.com", "https://user:pass@example.com"]) {
|
||||
const response = await request.get("/api/inspect?host=" + encodeURIComponent(host));
|
||||
expect(response.status(), host).toBe(400);
|
||||
await expect(response.json()).resolves.toHaveProperty("error");
|
||||
}
|
||||
});
|
||||
|
||||
test("landing and report have no automated accessibility violations", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
|
||||
await page.getByRole("button", { name: "Load demo" }).click();
|
||||
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
|
||||
});
|
||||
|
||||
test("landing and report have no horizontal overflow at supported viewports", async ({ page }) => {
|
||||
for (const [width, height] of [[360, 800], [390, 844], [768, 900], [1024, 768], [1366, 768], [1440, 900], [1920, 1080]]) {
|
||||
await page.setViewportSize({ width, height });
|
||||
await page.goto("/");
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth), { message: `landing overflow at ${width}px` }).toBe(true);
|
||||
await page.getByRole("button", { name: "Load demo" }).click();
|
||||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth), { message: `report overflow at ${width}px` }).toBe(true);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user