QA-11: tastaturablaeufe ohne maus im echten browser
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5cf568e6c0
commit
5d78dbc4f7
1 file changed
+95
@@ -0,0 +1,95 @@
|
||||
// QA-11: vollstaendige Ablaeufe nur mit der Tastatur (keine Mausereignisse) im
|
||||
// echten Browser gegen die echten Handler (a11y-fixture). Jeder Ablauf prueft
|
||||
// das Ergebnis ueber die API, nicht nur die Oberflaeche.
|
||||
//
|
||||
// A11Y_CHROME=... A11Y_API=http://127.0.0.1:8299 A11Y_BROWSER=http://127.0.0.1:4110 A11Y_IDS=ids.json node keyboard-flow.js
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const nm = process.env.A11Y_NODE_MODULES || "/usr/local/lib/node_modules/pa11y/node_modules";
|
||||
const puppeteer = require(path.join(nm, "puppeteer-core"));
|
||||
const ids = JSON.parse(fs.readFileSync(process.env.A11Y_IDS, "utf8"));
|
||||
const API = process.env.A11Y_API;
|
||||
const BROWSER = process.env.A11Y_BROWSER;
|
||||
|
||||
async function tabTo(page, describe, match, max = 40) {
|
||||
for (let i = 0; i < max; i++) {
|
||||
await page.keyboard.press("Tab");
|
||||
const cur = await page.evaluate(() => {
|
||||
const el = document.activeElement;
|
||||
if (!el || el === document.body) return null;
|
||||
return { tag: el.tagName, role: el.getAttribute("role"), type: el.getAttribute("type"),
|
||||
text: ((el.getAttribute("aria-label") || "") + " " + (el.textContent || "")).trim().slice(0, 80) };
|
||||
});
|
||||
if (cur && match(cur)) return cur;
|
||||
}
|
||||
throw new Error(`Element nicht per Tab erreichbar: ${describe}`);
|
||||
}
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const getJSON = async (p) => (await fetch(API + p)).json();
|
||||
|
||||
const flows = {
|
||||
async "Papierkorb: Dokument nur mit Tastatur wiederherstellen"(page) {
|
||||
await page.goto(`${BROWSER}/trash`, { waitUntil: "networkidle0" });
|
||||
const before = await page.evaluate(() => document.body.innerText.includes("alt.txt"));
|
||||
if (!before) throw new Error("alt.txt nicht im Papierkorb sichtbar");
|
||||
await tabTo(page, "Auswahl-Kontrollkaestchen der Zeile", (c) => c.tag === "INPUT" && c.type === "checkbox");
|
||||
await page.keyboard.press("Space");
|
||||
await tabTo(page, "Button Auswahl wiederherstellen", (c) => c.tag === "BUTTON" && /wiederherstell/i.test(c.text));
|
||||
await page.keyboard.press("Enter");
|
||||
await sleep(1500);
|
||||
const gone = await page.evaluate(() => !document.body.innerText.includes("alt.txt"));
|
||||
if (!gone) throw new Error("alt.txt nach Wiederherstellen noch im Papierkorb");
|
||||
const docs = await getJSON(`/folders/${ids.folder_inbox}/documents`);
|
||||
if (!docs.some((d) => d.id === ids.trashed_doc)) throw new Error("Dokument ist per API nicht wiederhergestellt");
|
||||
},
|
||||
|
||||
async "Ordnerbaum: Ordner nur mit Tastatur auswaehlen, Dokumente erscheinen"(page) {
|
||||
await page.goto(`${BROWSER}/browse`, { waitUntil: "networkidle0" });
|
||||
await tabTo(page, "Ordnerbaum", (c) => c.role === "tree");
|
||||
let opened = false;
|
||||
for (let i = 0; i < 6 && !opened; i++) {
|
||||
await page.keyboard.press("ArrowDown");
|
||||
await page.keyboard.press("Enter");
|
||||
await sleep(600);
|
||||
opened = (await page.evaluate(() => document.querySelectorAll('[role="option"]').length)) > 0;
|
||||
}
|
||||
if (!opened) throw new Error("nach Tastaturauswahl erscheinen keine Dokumente in der Liste");
|
||||
},
|
||||
|
||||
async "Metadaten: Wert nur mit Tastatur erfassen und speichern"(page) {
|
||||
await page.goto(`${BROWSER}/documents/${ids.pdf_doc}/metadata`, { waitUntil: "networkidle0" });
|
||||
await tabTo(page, "Betrag-Feld", (c) => c.tag === "INPUT" && c.type !== "checkbox" && !/tag/i.test(c.text));
|
||||
await page.keyboard.type("12.5");
|
||||
await tabTo(page, "Speichern", (c) => c.tag === "BUTTON" && /speicher|save/i.test(c.text));
|
||||
await page.keyboard.press("Enter");
|
||||
await sleep(1500);
|
||||
const values = await getJSON(`/documents/${ids.pdf_doc}/metadata`);
|
||||
if (!JSON.stringify(values).includes("12.5")) throw new Error(`Wert per API nicht gespeichert: ${JSON.stringify(values).slice(0, 200)}`);
|
||||
},
|
||||
};
|
||||
|
||||
(async () => {
|
||||
const browser = await puppeteer.launch({ executablePath: process.env.A11Y_CHROME, args: ["--no-sandbox", "--disable-setuid-sandbox"] });
|
||||
let failed = false;
|
||||
const mouse = { events: 0 };
|
||||
for (const [name, fn] of Object.entries(flows)) {
|
||||
const page = await browser.newPage();
|
||||
await page.setViewport({ width: 1280, height: 900 });
|
||||
await page.evaluateOnNewDocument(() => {
|
||||
window.__mouse = 0;
|
||||
for (const t of ["mousedown", "mouseup", "click"]) window.addEventListener(t, (e) => { if (e.isTrusted && e.detail > 0) window.__mouse++; }, true);
|
||||
});
|
||||
try {
|
||||
await fn(page);
|
||||
const clicks = await page.evaluate(() => window.__mouse);
|
||||
mouse.events += clicks;
|
||||
console.log(`ok\t${name}\t(Mausereignisse: ${clicks})`);
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
console.log(`FEHLER\t${name}\t${e.message}`);
|
||||
}
|
||||
await page.close();
|
||||
}
|
||||
await browser.close();
|
||||
process.exit(failed ? 1 : 0);
|
||||
})();
|
||||
Reference in new issue
Block a user