Download verification/release-e2e.js from smlflg/My-Agentic-Timeline: direct link, hf CLI and curl.
- Browser
- Download file 14.7 kB
-
https://huggingface.co/smlflg/My-Agentic-Timeline/resolve/main/verification/release-e2e.js
- Command line
-
hf download hf://smlflg/My-Agentic-Timeline/verification/release-e2e.js
-
curl -L -o release-e2e.js https://huggingface.co/smlflg/My-Agentic-Timeline/resolve/main/verification/release-e2e.js
14.7 kB
| ; | |
| 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; | |
| }); | |