e2e: accept Plex's session-less hand-off to app.plex.tv
The full-suite re-run after the reset fix came back "1 flaky": 12-crawl reached plex.franksdank.cloud, the guard cleared, and Plex Web — signed out in the qa-e2e profile — handed the browser to its own hosted sign-in surface, so the hostname never settled on the vhost (60 s poll, Expected plex.franksdank.cloud / Received app.plex.tv). settleThroughGuard now takes a HANDOFFS landing list per vhost; only plex.franksdank.cloud gets one, every other host still has to land on its own vhost, and the guard assertions (Anubis cleared, no authentik uidField, status < 500) are unchanged. Worklog and E2E gotcha 6 carry both symptoms: the ERR_ABORTED reset and the hand-off.
This commit is contained in:
@@ -8,15 +8,31 @@ import { expect, test, type Page } from "@playwright/test";
|
||||
|
||||
const CHALLENGE = "Making sure you're not a bot";
|
||||
|
||||
async function settleThroughGuard(page: Page, targetHost: string): Promise<void> {
|
||||
// Vendor hand-offs. An app may legitimately carry a session-less browser to its
|
||||
// OWN hosted surface: Plex Web (plex.franksdank.cloud, served by our stack)
|
||||
// bounces a signed-out visitor to app.plex.tv after it has already answered.
|
||||
// That is the app working, not a guard-chain failure — the fleet contract this
|
||||
// spec owns is still judged: the Anubis challenge cleared, no authentik
|
||||
// uidField prompt appeared, and the app answered below 500. Any host NOT listed
|
||||
// here still has to land on its own vhost.
|
||||
const HANDOFFS: Record<string, string[]> = {
|
||||
"plex.franksdank.cloud": ["app.plex.tv", "accounts.plex.tv", "clients.plex.tv"],
|
||||
};
|
||||
|
||||
async function settleThroughGuard(
|
||||
page: Page,
|
||||
targetHost: string,
|
||||
foreignHosts: string[] = [],
|
||||
): Promise<void> {
|
||||
// Each guarded vhost runs its own Anubis proof-of-work on first visit;
|
||||
// wait for the challenge to clear before judging the destination.
|
||||
await expect
|
||||
.poll(async () => !(await page.locator("body").innerText()).includes(CHALLENGE), { timeout: 90_000 })
|
||||
.toBe(true);
|
||||
const landing = [targetHost, ...foreignHosts];
|
||||
await expect
|
||||
.poll(() => new URL(page.url()).hostname, { timeout: 60_000 })
|
||||
.toBe(targetHost);
|
||||
.poll(() => landing.includes(new URL(page.url()).hostname), { timeout: 60_000 })
|
||||
.toBe(true);
|
||||
expect(await page.locator('input[name="uidField"]').count()).toBe(0);
|
||||
}
|
||||
|
||||
@@ -58,7 +74,7 @@ test("every user open link reaches its app", async ({ page }) => {
|
||||
const target = new URL(link.href);
|
||||
try {
|
||||
await page.goto(link.href);
|
||||
await settleThroughGuard(page, target.hostname);
|
||||
await settleThroughGuard(page, target.hostname, HANDOFFS[target.hostname] ?? []);
|
||||
const resp = await page.request.get(page.url());
|
||||
if (resp.status() >= 500) {
|
||||
failures.push(`${link.label}: ${page.url()} answered ${resp.status()}`);
|
||||
|
||||
Reference in New Issue
Block a user