mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
New lint test_no_raw_goto.py forbids raw `page.goto(...)` in role playwright specs + persona flows (the gotoOnion wrapper in personas/utils is exempt) so navigation retries transient Tor-transport errors over onion. Migrates every raw call across ~75 roles (343 sites) to `gotoOnion(page, ...)` and teaches gotoOnion to detect relative onion URLs (`isOnionCanonical`). gotoOnion is a behaviour-identical drop-in on clearnet (single attempt, same return). Verified: no-raw-goto lint green, eslint 0 errors, make test green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
2.7 KiB
JavaScript
77 lines
2.7 KiB
JavaScript
const { test, expect, request } = require("@playwright/test");
|
|
const { resolveTimeout } = require("./timeouts");
|
|
const { gotoOnion } = require("./personas");
|
|
|
|
async function seedTicketViaApi(baseUrl, adminApiUsername, adminApiPassword, subject) {
|
|
const api = await request.newContext({
|
|
ignoreHTTPSErrors: true,
|
|
extraHTTPHeaders: {
|
|
Authorization: `Basic ${Buffer.from(`${adminApiUsername}:${adminApiPassword}`).toString("base64")}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
});
|
|
const resp = await api.post(`${baseUrl}/api/v1/tickets`, {
|
|
data: {
|
|
title: subject,
|
|
group: "Users",
|
|
customer: adminApiUsername,
|
|
article: { subject, body: "Seed.", type: "note", internal: false },
|
|
},
|
|
});
|
|
if (resp.status() >= 300) {
|
|
throw new Error(`Seed POST /api/v1/tickets failed: ${resp.status()} ${await resp.text()}`);
|
|
}
|
|
const ticket = await resp.json();
|
|
await api.dispose();
|
|
return ticket;
|
|
}
|
|
|
|
async function appendArticleViaApi(baseUrl, adminApiUsername, adminApiPassword, ticketId, body) {
|
|
const api = await request.newContext({
|
|
ignoreHTTPSErrors: true,
|
|
extraHTTPHeaders: {
|
|
Authorization: `Basic ${Buffer.from(`${adminApiUsername}:${adminApiPassword}`).toString("base64")}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
});
|
|
const resp = await api.post(`${baseUrl}/api/v1/ticket_articles`, {
|
|
data: { ticket_id: ticketId, subject: "ws-update", body, type: "note", internal: false },
|
|
});
|
|
await api.dispose();
|
|
if (resp.status() >= 300) {
|
|
throw new Error(`Append article failed: ${resp.status()}`);
|
|
}
|
|
}
|
|
|
|
exports.register = function (shared) {
|
|
test("administrator: zammad-websocket pushes ticket updates to an open session in real time", async ({ page }) => {
|
|
expect(shared.env.adminApiUsername, "ADMIN_API_USERNAME must be set").toBeTruthy();
|
|
expect(shared.env.adminApiPassword, "ADMIN_API_PASSWORD must be set").toBeTruthy();
|
|
|
|
const subject = `playwright-ws-${Date.now()}`;
|
|
const ticket = await seedTicketViaApi(
|
|
shared.env.zammadBaseUrl,
|
|
shared.env.adminApiUsername,
|
|
shared.env.adminApiPassword,
|
|
subject
|
|
);
|
|
|
|
await shared.signInAsApiBot(page);
|
|
await gotoOnion(page, `${shared.env.zammadBaseUrl}/#ticket/zoom/${ticket.id}`, { waitUntil: "domcontentloaded" });
|
|
await expect(page.locator("body")).toContainText(subject, { timeout: resolveTimeout(60_000) });
|
|
|
|
const wsMarker = `ws-realtime-${Date.now()}`;
|
|
await appendArticleViaApi(
|
|
shared.env.zammadBaseUrl,
|
|
shared.env.adminApiUsername,
|
|
shared.env.adminApiPassword,
|
|
ticket.id,
|
|
wsMarker
|
|
);
|
|
|
|
await expect(page.locator("body")).toContainText(wsMarker, { timeout: resolveTimeout(60_000) });
|
|
|
|
await shared.zammadLogout(page);
|
|
});
|
|
};
|