Files
computer-playbook/roles/web-app-friendica/files/playwright/test-anonymous-profile-view.js
kevinveenbirkenbachandClaude Opus 4.8 35dee215c8 test(playwright): route all timeouts through resolveTimeout for onion-compat
Add the global TIMEOUT_FACTOR and a shared timeouts.js helper: resolveTimeout(base) scales by TIMEOUT_FACTOR and, over a .onion target, an extra multiplier, so Tor's per-request latency no longer trips hard-coded timeouts. Migrate every raw timeout in the specs (timeout:/timeout=/setTimeout/waitForTimeout) to resolveTimeout, stage the helper in all three staging paths, and add test_no_raw_timeouts to forbid raw numeric timeouts. Clearnet behaviour is unchanged (factor 1: resolveTimeout(N) === N).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:38:06 +02:00

65 lines
2.8 KiB
JavaScript

const { test, expect } = require("@playwright/test");
const { resolveTimeout } = require("./timeouts");
// Anonymous (logged-out) visitor reaches biber's friendica profile.
//
// Friendica's profile pages are public-by-design (federation discovery,
// foreign instance lookups, embeddable links). The oauth2-proxy ACL on
// the friendica vhost MUST whitelist `/profile/` so the catch-all SSO
// gate does not bounce anonymous visitors to Keycloak before they ever
// see the page. This test pins that whitelist contract.
//
// The friendica.user row for biber is materialised lazily on first LDAP
// bind, so before the anonymous fetch we walk biber through one full
// login (and immediately log out again) in an isolated context.
exports.register = function (shared) {
test("friendica: anonymous visitor can view biber's public profile", async ({ browser }) => {
shared.skipUnlessServiceEnabled("ldap");
await shared.provisionBiberAccount(browser);
const baseUrl = shared.trimmedBaseUrl();
const profileUrl = `${baseUrl}/profile/${shared.env.biberUsername}`;
// Fresh context — no cookies from the provisioning login above.
const anonContext = await browser.newContext({ ignoreHTTPSErrors: true });
try {
const anonPage = await anonContext.newPage();
const response = await anonPage.goto(profileUrl, { waitUntil: "domcontentloaded" });
expect(response, `Expected a response for ${profileUrl}`).toBeTruthy();
expect(
response.status(),
`Expected anonymous /profile/${shared.env.biberUsername} status < 400 (whitelist must skip oauth2-proxy)`
).toBeLessThan(400);
// The page must STAY on the friendica host. If the oauth2-proxy
// catch-all gated the route, the browser would now be at
// Keycloak's auth URL with a `redirect_uri` query param.
const finalHost = new URL(anonPage.url()).host;
const expectedHost = new URL(baseUrl).host;
expect(
finalHost,
`Expected to stay on ${expectedHost} for an anonymous profile view, ended up at ${anonPage.url()}`
).toBe(expectedHost);
// Friendica's profile template renders the visited nick somewhere
// on the page (vcard header / page title) for every theme.
await expect(
anonPage.locator("body"),
`Expected biber's profile body to mention "${shared.env.biberUsername}"`
).toContainText(shared.env.biberUsername, { timeout: resolveTimeout(30_000) });
// No authenticated nav element. Anonymous viewers must not see
// their own /logout link (frio / vier both attach it to the
// topbar when authenticated).
await expect(
anonPage.locator("a[href*='/logout']"),
"Anonymous profile view must not expose the authenticated /logout link"
).toHaveCount(0);
} finally {
await anonContext.close().catch(() => {});
}
});
};