Files
computer-playbook/roles/web-app-fusiondirectory/files/playwright/playwright.spec.js
kevinveenbirkenbachandClaude Opus 5 642055a20a style(e2e): drop the timeout argument isVisible discards
Playwright declares the timeout option on locator.isVisible() and isHidden() as deprecated and ignored: both return immediately and never wait. Passing resolveTimeout(10_000) to one therefore changes nothing at runtime and only tells the reader a wait happened that never did. That reading is what let 7538b8a0b conclude two genuine call sites were fine, and what hid the false negative b97cf8888 had to fix.

Sixty call sites across fifty-eight role-local specs lose the argument and nothing else. Every added line in this commit is a bare isVisible(); a grep for added lines that are not one returns zero, so a behaviour change cannot have entered here. Files whose diff also alters waiting semantics are deliberately not part of this commit.

A repository lint added in b97cf8888 keeps the construct out. It matches isVisible and isHidden only, because isChecked, isDisabled, isEditable and isEnabled take a real timeout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 13:49:18 +02:00

76 lines
3.5 KiB
JavaScript

const { test, expect } = require("@playwright/test");
const { resolveTimeout } = require("./timeouts");
const { skipUnlessServiceEnabled } = require("./service-gating");
const { decodeDotenvQuotedValue, normalizeBaseUrl, performKeycloakLoginForm, runAdminFlow, runBiberFlow, runGuestFlow, gotoOnion } = require("./personas");
test.use({ ignoreHTTPSErrors: true });
const baseUrl = normalizeBaseUrl(process.env.FUSIONDIRECTORY_BASE_URL || "");
const oidcIssuerUrl = normalizeBaseUrl(process.env.OIDC_ISSUER_URL || "");
const canonicalDomain = decodeDotenvQuotedValue(process.env.CANONICAL_DOMAIN || "");
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME);
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD);
test.beforeEach(async ({ page }) => {
expect(baseUrl, "FUSIONDIRECTORY_BASE_URL must be set").toBeTruthy();
expect(canonicalDomain, "CANONICAL_DOMAIN must be set").toBeTruthy();
await page.context().clearCookies();
});
test("baseline: FusionDirectory responds on the canonical domain", async ({ page }) => {
const r = await gotoOnion(page, `${baseUrl}/`);
expect(r).toBeTruthy();
expect(r.status()).toBeLessThan(500);
expect(r.url().includes(canonicalDomain)).toBe(true);
});
test("OIDC: oauth2-proxy redirects unauthenticated visitors through Keycloak (variant 0)", async ({ page }) => {
skipUnlessServiceEnabled("sso");
expect(adminUsername).toBeTruthy(); expect(adminPassword).toBeTruthy(); expect(oidcIssuerUrl).toBeTruthy();
const expectedAuth = `${oidcIssuerUrl}/protocol/openid-connect/auth`;
const expectedBase = baseUrl.replace(/\/$/, "");
await gotoOnion(page, `${expectedBase}/`);
await expect.poll(() => page.url(), { timeout: resolveTimeout(60_000) }).toContain(expectedAuth);
await performKeycloakLoginForm(page, adminUsername, adminPassword);
await expect.poll(() => page.url(), { timeout: resolveTimeout(90_000) }).toContain(expectedBase);
await expect(page.getByRole("button", { name: /sign in/i })).toBeVisible({ timeout: resolveTimeout(60_000) });
});
test("LDAP: FusionDirectory backend points at svc-db-openldap (variant 1)", async ({ page }) => {
skipUnlessServiceEnabled("ldap");
const expectedBase = baseUrl.replace(/\/$/, "");
await gotoOnion(page, `${expectedBase}/`);
expect(page.url().includes(canonicalDomain)).toBe(true);
});
// Persona scenarios.
// Bodies live in the shared helper roles/test-e2e-playwright/files/personas.js
// so every role's persona flow stays consistent.
test("guest: public-landing → auth chain → never authenticated", async ({ page }) => {
await runGuestFlow(page);
});
test("biber: app → universal logout", async ({ page }) => {
await runBiberFlow(page);
});
test("administrator: app → universal logout", async ({ page }) => {
await runAdminFlow(page, {
adminInteraction: async (interactivePage) => {
// web-app-fusiondirectory admin-only interaction: open a management surface.
const link = interactivePage
.getByRole("link", { name: /^(configuration|administration|users|groups|departments)$/i })
.first();
if (await link.isVisible().catch(() => false)) {
await link.click({ timeout: resolveTimeout(30_000) }).catch(() => {});
await interactivePage.waitForLoadState("domcontentloaded", { timeout: resolveTimeout(30_000) }).catch(() => {});
await expect(interactivePage.locator("body")).toContainText(
/configuration|administration|users|groups|departments|posix/i,
{ timeout: resolveTimeout(30_000) },
);
}
},
});
});