mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Over Tor the redirect chain behind a login/logout/OIDC click routinely exceeds Playwright's fixed 30s action timeout, so the click throws before the flow's scaled waits run. Sweep all role Playwright suites and the shared persona helpers: give every navigation/auth-transition click an onion-scaled timeout (.click({ timeout: resolveTimeout(30_000) })) and route the remaining raw millisecond literals (timeout options, waitForTimeout, sleep-promise setTimeout, positional wait args) through resolveTimeout. Local UI clicks (menus, toggles, modal dismissals, DOM clicks inside evaluate) stay untouched.
Two new lints keep it that way: test_no_raw_timeout_literals forbids raw numeric timeout literals in Playwright specs (opt-out: nocheck: raw-timeout), test_persona_clicks_scaled requires every click in the shared persona auth flows to carry a resolveTimeout timeout (opt-out: nocheck: unscaled-click).
Verified: node --check on all 133 changed JS files, all 13 playwright lints green, make autoformat clean, make test green (2745+196+163+4 tests OK).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
1.6 KiB
JavaScript
39 lines
1.6 KiB
JavaScript
const { expect } = require("@playwright/test");
|
|
const { resolveTimeout } = require("./timeouts");
|
|
const { isServiceEnabled } = require("./service-gating");
|
|
const { decodeDotenvQuotedValue } = require("./personas");
|
|
|
|
const env = {
|
|
filerUrl: decodeDotenvQuotedValue(process.env.SEAWEEDFS_FILER_URL),
|
|
masterUrl: decodeDotenvQuotedValue(process.env.SEAWEEDFS_MASTER_URL),
|
|
adminUsername: decodeDotenvQuotedValue(process.env.ADMIN_USERNAME),
|
|
adminPassword: decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD),
|
|
biberUsername: decodeDotenvQuotedValue(process.env.BIBER_USERNAME),
|
|
biberPassword: decodeDotenvQuotedValue(process.env.BIBER_PASSWORD),
|
|
ssoEnabled: isServiceEnabled("sso"),
|
|
frontendEnabled: isServiceEnabled("frontend"),
|
|
consumerBuckets: (() => {
|
|
try {
|
|
return JSON.parse(decodeDotenvQuotedValue(process.env.SEAWEEDFS_CONSUMER_BUCKETS) || "[]");
|
|
} catch {
|
|
return [];
|
|
}
|
|
})(),
|
|
};
|
|
|
|
async function keycloakLogin(page, username, password) {
|
|
await page.waitForLoadState("domcontentloaded");
|
|
const user = page.locator("#username, input[name='username']").first();
|
|
await user.waitFor({ state: "visible", timeout: resolveTimeout(60_000) });
|
|
await user.fill(username);
|
|
await page.locator("#password, input[name='password']").first().fill(password);
|
|
await page.locator("#kc-login, button[type='submit'], input[type='submit']").first().click({ timeout: resolveTimeout(30_000) });
|
|
await page.waitForLoadState("networkidle").catch(() => {});
|
|
}
|
|
|
|
function isAuthChain(url) {
|
|
return /\/oauth2\/|\/realms\/|\/protocol\/openid-connect\//.test(url);
|
|
}
|
|
|
|
module.exports = { env, keycloakLogin, isAuthChain, expect };
|