smlflg's picture
Initial public upload from Projekte/My-Agentic-Timeline
2d8b342 verified
Raw History Blame Contribute Delete
14.7 kB
"use strict";
const { chromium } = require("playwright");
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const root = process.cwd();
const fileUrl = "file://" + path.join(root, "index.html");
const profile = path.join(root, "verification", "browser-profile-release");
const results = [];
const failures = [];
fs.mkdirSync(profile, { recursive: true });
function sameIds(actual, expected) {
assert.deepStrictEqual([...actual].sort(), [...expected].sort());
}
async function run() {
const context = await chromium.launchPersistentContext(profile, {
headless: true,
executablePath: "/usr/bin/google-chrome",
viewport: { width: 1440, height: 1000 },
reducedMotion: "reduce",
args: ["--no-sandbox", "--disable-dev-shm-usage"]
});
const page = context.pages()[0] || await context.newPage();
const consoleErrors = [];
const pageErrors = [];
const requestFailures = [];
const requests = [];
page.on("console", (message) => {
if (message.type() === "error") consoleErrors.push(message.text());
});
page.on("pageerror", (error) => pageErrors.push(String(error)));
page.on("requestfailed", (request) => {
requestFailures.push(`${request.url()} :: ${request.failure()?.errorText}`);
});
page.on("request", (request) => requests.push(request.url()));
async function ready(url = fileUrl) {
await page.goto(url, { waitUntil: "load" });
await page.waitForFunction(() => (
window.__TIMELINE_APP__ &&
document.querySelectorAll('[data-testid="arc-card"]').length > 0
));
}
async function ids() {
return page.locator('[data-testid="arc-card"][data-arc-id]').evaluateAll(
(nodes) => nodes.map((node) => node.dataset.arcId)
);
}
async function check(name, assertion) {
try {
await assertion();
results.push({ name, status: "PASS" });
} catch (error) {
const detail = String(error?.stack || error);
failures.push({ name, detail });
results.push({ name, status: "FAIL", detail: detail.split("\n")[0] });
}
}
try {
await ready();
await check("default STORY + Alle = 10", async () => {
sameIds(await ids(), [
"ARC-01", "ARC-02", "ARC-03", "ARC-04", "ARC-05",
"ARC-06", "ARC-07", "ARC-08", "ARC-09", "ARC-10"
]);
assert.strictEqual(
(await page.evaluate(() => window.__TIMELINE_APP__.getState())).view,
"STORY"
);
assert.strictEqual(
await page.locator('button[data-view="STORY"]').getAttribute("aria-pressed"),
"true"
);
const overlaps = await page.locator(".thread-row").evaluateAll((rows) => {
const collisions = [];
rows.forEach((row, rowIndex) => {
const boxes = [...row.querySelectorAll(".thread-node")]
.map((node) => ({ id: node.dataset.openArc, rect: node.getBoundingClientRect() }))
.sort((left, right) => left.rect.left - right.rect.left);
for (let index = 1; index < boxes.length; index += 1) {
if (boxes[index - 1].rect.right > boxes[index].rect.left + 0.5) {
collisions.push(`${rowIndex}:${boxes[index - 1].id}/${boxes[index].id}`);
}
}
});
return collisions;
});
assert.deepStrictEqual(overlaps, []);
});
await check("Codex path exact set", async () => {
await page.locator('[data-harness="Codex"]').click();
sameIds(await ids(), ["ARC-01", "ARC-06", "ARC-09"]);
});
await check("Codex OR Hermes exact union", async () => {
await page.locator('[data-harness="Hermes / HAI"]').click();
sameIds(await ids(), [
"ARC-01", "ARC-06", "ARC-07", "ARC-08", "ARC-09", "ARC-10"
]);
});
await check("empty state + reset", async () => {
await page.locator('[data-harness="Alle"]').click();
await page.locator('[data-harness="OpenCode"]').click();
await page.locator("#stage-filter").selectOption("SYSTEMATISIERT");
sameIds(await ids(), []);
assert.strictEqual(await page.locator('[data-state="empty"]').isVisible(), true);
await page.locator(
'[data-state="empty"] [data-action="reset-filters"]'
).click();
sameIds(await ids(), [
"ARC-01", "ARC-02", "ARC-03", "ARC-04", "ARC-05",
"ARC-06", "ARC-07", "ARC-08", "ARC-09", "ARC-10"
]);
});
let savedHash = "";
await check("hash roundtrip preserves full state", async () => {
await page.locator('button[data-view="INSIGHTS"]').click();
await page.locator('[data-harness="Codex"]').click();
await page.locator('[data-harness="Hermes / HAI"]').click();
await page.locator("#stage-filter").selectOption("TRANSFERIERT");
await page.locator("#confidence-filter").selectOption("BELEGT");
await page.locator("#concept-filter").selectOption("Orchestrator / Worker");
const expected = {
view: "INSIGHTS",
paths: ["Codex", "Hermes / HAI"],
stage: "TRANSFERIERT",
confidence: "BELEGT",
concept: "Orchestrator / Worker"
};
assert.deepStrictEqual(
await page.evaluate(() => window.__TIMELINE_APP__.getState()),
expected
);
savedHash = await page.evaluate(() => location.hash);
await page.reload({ waitUntil: "load" });
await page.waitForFunction(() => window.__TIMELINE_APP__);
assert.deepStrictEqual(
await page.evaluate(() => window.__TIMELINE_APP__.getState()),
expected
);
await page.locator('button[data-view="STORY"]').click();
sameIds(await ids(), ["ARC-09"]);
const after = await page.evaluate(() => window.__TIMELINE_APP__.getState());
assert.deepStrictEqual(
{
paths: after.paths,
stage: after.stage,
confidence: after.confidence,
concept: after.concept
},
{
paths: expected.paths,
stage: expected.stage,
confidence: expected.confidence,
concept: expected.concept
}
);
assert.ok(
savedHash.includes("view=INSIGHTS") &&
savedHash.includes("paths=Codex%2CHermes")
);
});
await check("invalid hash notice + safe default", async () => {
await ready(fileUrl + "#view=NOPE");
assert.strictEqual(
await page.locator('[data-state="invalid-hash"]').isVisible(),
true
);
sameIds(await ids(), [
"ARC-01", "ARC-02", "ARC-03", "ARC-04", "ARC-05",
"ARC-06", "ARC-07", "ARC-08", "ARC-09", "ARC-10"
]);
assert.strictEqual(
(await page.evaluate(() => window.__TIMELINE_APP__.getState())).view,
"STORY"
);
});
await check("HAI depth contract, month interaction, Goal and Permissions", async () => {
await page.locator('button[data-view="INSIGHTS"]').click();
assert.strictEqual(await page.locator('[data-testid="hai-month-card"]').count(), 7);
assert.strictEqual(await page.locator('[data-zoom-id]').count(), 5);
assert.strictEqual(await page.locator('[data-rule-id]').count(), 11);
assert.strictEqual(await page.locator('[data-metric-id]').count(), 3);
assert.ok(
(await page.locator('.hai-owner-thesis__question').innerText())
.startsWith("Wenn heutiges HAI in jedem Monat neben Samuel gesessen hätte")
);
const january = page.locator('[data-hai-month="MHAI-01"]');
const february = page.locator('[data-hai-month="MHAI-02"]');
assert.ok((await january.innerText()).includes("NO EVIDENCE"));
assert.ok((await february.innerText()).includes("NO EVIDENCE"));
await page.locator('[data-hai-month="MHAI-05"]').click();
const mayText = await page.locator('#hai-month-detail').textContent();
assert.ok(mayText.includes("/goal"));
assert.ok(mayText.includes("11931"));
assert.ok(mayText.includes("19.05.2026 23:08:59"));
assert.ok(mayText.includes("Permissions"));
assert.ok(mayText.includes("Human Gates"));
const march = page.locator('[data-hai-month="MHAI-03"]');
await march.focus();
await page.keyboard.press("ArrowRight");
assert.strictEqual(
await page.locator('[data-hai-month="MHAI-04"]').getAttribute("aria-selected"),
"true"
);
assert.strictEqual(
await page.locator('#hai-month-detail').getAttribute("data-month-id"),
"MHAI-04"
);
await page.locator('button[data-view="STORY"]').click();
});
await check("keyboard dialog, evidence, Escape, focus return", async () => {
await page.locator('button[data-view="STORY"]').click();
const trigger = page.locator('.arc-card[data-arc-id="ARC-06"] .arc-open');
await trigger.focus();
await page.keyboard.press("Enter");
await page.locator("#arc-dialog[open]").waitFor();
assert.strictEqual(
await page.locator('[data-action="close-detail"]').evaluate(
(element) => element === document.activeElement
),
true
);
const dialogText = (await page.locator("#arc-dialog").innerText()).toLowerCase();
for (const label of [
"Ausgangslage", "Trigger", "Neue Fähigkeit / Verhalten",
"Positiver Effekt", "Negativer Effekt", "Adaption", "Transfer",
"Bleibendes Prinzip", "Evidenz & Unsicherheit"
]) {
assert.ok(dialogText.includes(label.toLowerCase()), label);
}
const summary = page.locator("#arc-dialog .evidence-drawer summary");
await summary.focus();
await page.keyboard.press("Enter");
assert.strictEqual(
await page.locator("#arc-dialog .evidence-drawer").getAttribute("open") !== null,
true
);
await page.keyboard.press("Escape");
await page.waitForFunction(() => !document.querySelector("#arc-dialog").open);
assert.strictEqual(
await page.evaluate(() => document.activeElement?.dataset?.openArc),
"ARC-06"
);
});
await check("reduced motion active", async () => {
assert.strictEqual(
await page.evaluate(() => matchMedia("(prefers-reduced-motion: reduce)").matches),
true
);
const animation = await page.locator(".arc-card").first().evaluate(
(element) => getComputedStyle(element).animationDuration
);
assert.ok(
animation === "0s" || animation === "0.001s" || animation === "none",
animation
);
});
await check("offline request boundary + clean console", async () => {
const remote = requests.filter((url) => !/^(file:|data:|blob:)/.test(url));
assert.deepStrictEqual(remote, []);
assert.deepStrictEqual(consoleErrors, []);
assert.deepStrictEqual(pageErrors, []);
assert.deepStrictEqual(requestFailures, []);
});
await ready();
await page.evaluate(() => scrollTo(0, 0));
await page.screenshot({
path: path.join(root, "verification", "all-paths-desktop.png"),
fullPage: true
});
await page.locator('button[data-view="INSIGHTS"]').click();
await page.locator('[data-hai-month="MHAI-05"]').click();
await page.evaluate(() => scrollTo(0, 0));
await page.screenshot({
path: path.join(root, "verification", "insights-all-desktop.png"),
fullPage: true
});
await ready();
await page.locator('[data-harness="Codex"]').click();
sameIds(await ids(), ["ARC-01", "ARC-06", "ARC-09"]);
await page.evaluate(() => scrollTo(0, 0));
await page.screenshot({
path: path.join(root, "verification", "codex-only-desktop.png"),
fullPage: true
});
await check("mobile layout, dialog fullscreen, no overflow", async () => {
await page.setViewportSize({ width: 390, height: 844 });
await page.locator('[data-harness="Harness-agnostisch"]').click();
sameIds(await ids(), ["ARC-01", "ARC-06", "ARC-09"]);
const overflow = await page.evaluate(() => ({
scrollWidth: document.documentElement.scrollWidth,
innerWidth
}));
assert.ok(
overflow.scrollWidth <= overflow.innerWidth + 1,
JSON.stringify(overflow)
);
await page.locator('.arc-card[data-arc-id="ARC-06"] .arc-open').click();
const rect = await page.locator("#arc-dialog").evaluate((element) => {
const bounds = element.getBoundingClientRect();
return {
x: bounds.x,
y: bounds.y,
width: bounds.width,
height: bounds.height,
viewportWidth: innerWidth,
viewportHeight: innerHeight
};
});
assert.ok(
rect.width >= rect.viewportWidth - 2 &&
rect.height >= rect.viewportHeight - 2,
JSON.stringify(rect)
);
await page.keyboard.press("Escape");
await page.waitForFunction(() => !document.querySelector("#arc-dialog").open);
await page.evaluate(() => scrollTo(0, 0));
await page.evaluate(() => document.activeElement?.blur());
await page.screenshot({
path: path.join(root, "verification", "mobile.png"),
fullPage: true
});
await page.locator('button[data-view="INSIGHTS"]').click();
await page.locator('[data-hai-month="MHAI-07"]').click();
await page.evaluate(() => scrollTo(0, 0));
await page.evaluate(() => document.activeElement?.blur());
await page.screenshot({
path: path.join(root, "verification", "insights-mobile.png"),
fullPage: true
});
const insightsOverflow = await page.evaluate(() => ({
scrollWidth: document.documentElement.scrollWidth,
innerWidth
}));
assert.ok(
insightsOverflow.scrollWidth <= insightsOverflow.innerWidth + 1,
JSON.stringify(insightsOverflow)
);
});
await check("screenshot files written", async () => {
for (const name of [
"all-paths-desktop.png",
"codex-only-desktop.png",
"mobile.png",
"insights-all-desktop.png",
"insights-mobile.png"
]) {
const screenshot = path.join(root, "verification", name);
assert.ok(
fs.existsSync(screenshot) && fs.statSync(screenshot).size > 10000,
name
);
}
});
console.log(JSON.stringify({
results,
observations: {
savedHash,
requests: [...new Set(requests)],
consoleErrors,
pageErrors,
requestFailures
},
failures
}, null, 2));
} finally {
await context.close();
}
if (failures.length) process.exitCode = 1;
}
run().catch((error) => {
console.error(error);
process.exitCode = 1;
});