426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
197 lines
6.3 KiB
JavaScript
197 lines
6.3 KiB
JavaScript
/**
|
|
* Web button/input interaction pass — per view, clicks every enabled, visible,
|
|
* NON-destructive button and types into every text input, capturing JS-level
|
|
* errors (pageerror / error-boundary) that indicate a REAL interaction bug.
|
|
* Network 4xx is ignored (dev-backend config noise); only JS faults count.
|
|
*/
|
|
import { appendFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
import { chromium } from "@playwright/test";
|
|
import { ROUTES } from "./routes.mjs";
|
|
|
|
const OUT = "/tmp/view-audit/web-interactions";
|
|
mkdirSync(OUT, { recursive: true });
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
const DESTRUCTIVE =
|
|
/delete|remove|reset|disconnect|sign out|log ?out|clear|wipe|revoke|leave|uninstall|deactivate|danger|forget|erase|drop|unpair|trash|destroy/i;
|
|
|
|
async function main() {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const ctx = await browser.newContext({
|
|
viewport: { width: 1280, height: 900 },
|
|
ignoreHTTPSErrors: true,
|
|
});
|
|
const page = await ctx.newPage();
|
|
await page.addInitScript(() => {
|
|
try {
|
|
localStorage.setItem(
|
|
"elizaos:active-server",
|
|
JSON.stringify({
|
|
id: "local:dev",
|
|
kind: "remote",
|
|
label: "Local dev agent",
|
|
apiBase: "http://127.0.0.1:31337",
|
|
}),
|
|
);
|
|
localStorage.setItem("eliza:first-run-complete", "1");
|
|
} catch {}
|
|
});
|
|
await page
|
|
.goto("http://127.0.0.1:2138", {
|
|
waitUntil: "domcontentloaded",
|
|
timeout: 30000,
|
|
})
|
|
.catch(() => {});
|
|
await sleep(4000);
|
|
|
|
const results = [];
|
|
for (const [route, slug] of ROUTES) {
|
|
const goView = () =>
|
|
page
|
|
.evaluate((u) => {
|
|
history.pushState(null, "", u);
|
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
if (u.includes("#"))
|
|
window.dispatchEvent(new HashChangeEvent("hashchange"));
|
|
}, route)
|
|
.catch(() => {});
|
|
await goView();
|
|
await sleep(1500);
|
|
|
|
// enumerate enabled, visible, non-destructive buttons + their labels
|
|
let controls = [];
|
|
try {
|
|
controls = await page.evaluate((destrSrc) => {
|
|
const DESTR = new RegExp(destrSrc, "i");
|
|
const lbl = (e) =>
|
|
(
|
|
e.getAttribute("aria-label") ||
|
|
e.getAttribute("title") ||
|
|
e.textContent ||
|
|
""
|
|
)
|
|
.replace(/\s+/g, " ")
|
|
.trim();
|
|
return [...document.querySelectorAll('button,[role="button"]')]
|
|
.map((e, i) => ({
|
|
i,
|
|
l: lbl(e),
|
|
dis: !!e.disabled || e.getAttribute("aria-disabled") === "true",
|
|
vis: !!(e.offsetParent || e.getClientRects().length),
|
|
}))
|
|
.filter((c) => c.vis && !c.dis && c.l && !DESTR.test(c.l));
|
|
}, DESTRUCTIVE.source);
|
|
} catch {}
|
|
|
|
const issues = [];
|
|
const max = Math.min(controls.length, 18);
|
|
for (let k = 0; k < max; k++) {
|
|
const pageErrors = [];
|
|
const onErr = (e) =>
|
|
pageErrors.push(String(e.message || e).slice(0, 200));
|
|
page.on("pageerror", onErr);
|
|
// re-resolve the button each time (DOM may have changed); match by label
|
|
const target = controls[k];
|
|
let clicked = false;
|
|
try {
|
|
const handle = await page.evaluateHandle((lab) => {
|
|
const lbl = (e) =>
|
|
(
|
|
e.getAttribute("aria-label") ||
|
|
e.getAttribute("title") ||
|
|
e.textContent ||
|
|
""
|
|
)
|
|
.replace(/\s+/g, " ")
|
|
.trim();
|
|
return [...document.querySelectorAll('button,[role="button"]')].find(
|
|
(e) =>
|
|
lbl(e) === lab &&
|
|
(e.offsetParent || e.getClientRects().length) &&
|
|
!e.disabled,
|
|
);
|
|
}, target.l);
|
|
const el = handle.asElement();
|
|
if (el) {
|
|
await el.click({ timeout: 1500 }).catch(() => {});
|
|
clicked = true;
|
|
}
|
|
} catch {}
|
|
await sleep(550);
|
|
// detect error boundary
|
|
let errBoundary = false;
|
|
try {
|
|
errBoundary = await page.evaluate(() =>
|
|
/something went wrong|failed to load|is not a function|cannot read prop/i.test(
|
|
document.body.innerText || "",
|
|
),
|
|
);
|
|
} catch {}
|
|
page.off("pageerror", onErr);
|
|
if (clicked && (pageErrors.length || errBoundary)) {
|
|
issues.push({
|
|
button: target.l.slice(0, 40),
|
|
jsError: pageErrors[0] || null,
|
|
errorBoundary: errBoundary,
|
|
});
|
|
}
|
|
// recover: if path moved or a dialog/overlay opened, go back to the view + dismiss
|
|
await page.keyboard.press("Escape").catch(() => {});
|
|
const onView = await page
|
|
.evaluate(
|
|
(r) =>
|
|
location.pathname + location.hash === r ||
|
|
location.pathname === r.split("#")[0],
|
|
route,
|
|
)
|
|
.catch(() => true);
|
|
if (!onView) {
|
|
await goView();
|
|
await sleep(900);
|
|
}
|
|
}
|
|
|
|
// type into the first few text inputs (smoke: does typing throw?)
|
|
const inputIssues = [];
|
|
try {
|
|
const inputs = await page.$$(
|
|
'input[type="text"],input[type="search"],input:not([type]),textarea',
|
|
);
|
|
for (const inp of inputs.slice(0, 5)) {
|
|
const pe = [];
|
|
const onErr = (e) => pe.push(String(e.message).slice(0, 150));
|
|
page.on("pageerror", onErr);
|
|
await inp.fill("audit-test").catch(() => {});
|
|
await sleep(200);
|
|
page.off("pageerror", onErr);
|
|
if (pe.length) inputIssues.push(pe[0]);
|
|
}
|
|
} catch {}
|
|
|
|
const f = {
|
|
slug,
|
|
route,
|
|
buttonsTested: max,
|
|
buttonsAvailable: controls.length,
|
|
buttonIssues: issues,
|
|
inputIssues,
|
|
};
|
|
results.push(f);
|
|
const line = `${slug.padEnd(22)} tested ${String(max).padStart(2)}/${String(controls.length).padStart(2)} btns issues=${issues.length} inputErr=${inputIssues.length}${issues.length ? " -> " + issues.map((x) => x.button).join("|") : ""}`;
|
|
console.error(line);
|
|
appendFileSync(`${OUT}/progress.log`, line + "\n");
|
|
writeFileSync(
|
|
`${OUT}/report-web-interactions.json`,
|
|
JSON.stringify({ count: results.length, results }, null, 2),
|
|
);
|
|
}
|
|
await browser.close();
|
|
console.error("DONE");
|
|
}
|
|
main().then(
|
|
() => process.exit(0),
|
|
(e) => {
|
|
console.error("ERR:", e.message);
|
|
process.exit(1);
|
|
},
|
|
);
|