Files
computer-playbook/roles/web-app-mediawiki/files/playwright/addons/AIEditingAssistant.spec.js
kevinveenbirkenbachandClaude Opus 5 27dcd975e5 test(e2e): scale the spec timeouts for onion transport
Twenty-five specs called the Playwright APIs with default or hardcoded
timeouts. Routed over Tor those budgets are too small, so a spec fails on
transport latency rather than on the behaviour it asserts.

Route the waits through resolveTimeout and reach pages via gotoOnion, the
helpers the tor branch introduced for exactly this. The remaining changes in
the diff are import wrapping around those calls.

The repository lint enforces this: a raw numeric timeout in a role spec is
rejected with a pointer to resolveTimeout, which is how a hardcoded 500ms
wait added during this session was caught.

Merge work rather than authored here; not deployed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:52:19 +02:00

87 lines
3.2 KiB
JavaScript

const { test, expect } = require("@playwright/test");
const { resolveTimeout } = require("../timeouts");
const { skipUnlessAddonEnabled } = require("../addon-gating");
const { normalizeBaseUrl } = require("../personas");
test.use({ ignoreHTTPSErrors: true });
const appBaseUrl = normalizeBaseUrl(process.env.APP_BASE_URL || "");
const aiGatewayBaseUrl = normalizeBaseUrl(process.env.AI_GATEWAY_BASE_URL || "");
const PROMPT_ROUTE = "/rest.php/aieditingassistant/v1/prompt";
test("AIEditingAssistant: the wiki answers a prompt through the in-cluster gateway", async ({
request,
}) => {
skipUnlessAddonEnabled("AIEditingAssistant");
test.setTimeout(resolveTimeout(240_000));
expect(appBaseUrl, "APP_BASE_URL must be set").toBeTruthy();
expect(aiGatewayBaseUrl, "AI_GATEWAY_BASE_URL must be set").toBeTruthy();
const gateway = new URL(aiGatewayBaseUrl);
const wikiHost = new URL(appBaseUrl).host;
expect(
gateway.protocol,
`the AI base URL must stay on the container network (plain http), got ${aiGatewayBaseUrl}`,
).toBe("http:");
expect(
gateway.hostname.includes("."),
"the AI base URL host must be an undotted compose/swarm service name; a dotted host is " +
`resolved through the dns-search suffix and leaves via the public ingress (got ${aiGatewayBaseUrl})`,
).toBe(false);
expect(
gateway.host,
"the AI base URL must point at the gateway, not back at the wiki itself",
).not.toBe(wikiHost);
const siteinfo = await request.get(
`${appBaseUrl}/api.php?action=query&meta=siteinfo&siprop=extensions&format=json&formatversion=2`,
{ timeout: resolveTimeout(60_000) },
);
expect(
siteinfo.status(),
"the MediaWiki action API must answer so the loaded extension list can be read",
).toBe(200);
const installed = ((await siteinfo.json()).query?.extensions || []).map(
(extension) => extension.name,
);
expect(
installed,
"AIEditingAssistant is not in the loaded extension list, so LocalSettings.php never " +
"reached its wfLoadExtension block (extension missing, or VisualEditor/VisualEditorPlus " +
"not loaded ahead of it)",
).toContain("AIEditingAssistant");
const response = await request.post(`${appBaseUrl}${PROMPT_ROUTE}`, {
data: {
command: "Fix grammar and punctuation in this text",
text: "this sentence have a error",
isContinuation: false,
},
timeout: resolveTimeout(210_000),
});
const bodyText = await response.text();
expect(
response.status(),
`POST ${PROMPT_ROUTE} returned ${response.status()}: ${bodyText.slice(0, 500)}. ` +
"400 means $wgAIEditingAssistantActiveProvider is unset or unknown; 500 means the " +
"provider reached no working gateway leg (wrong base URL, rejected virtual key, or a " +
`model the gateway does not serve). Configured gateway: ${aiGatewayBaseUrl}.`,
).toBe(200);
const body = JSON.parse(bodyText);
expect(
body.success,
"the prompt handler must report success, proving the provider completed the round-trip",
).toBe(true);
expect(
String(body.result || "").trim().length,
"the gateway must return a real, non-empty completion; an empty result means the model " +
"answered nothing and the surface is wired but useless",
).toBeGreaterThan(0);
});