From f3484f5a24660d8858c7ede347158651d7bd1637 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Thu, 4 Jun 2026 17:03:26 +0200 Subject: [PATCH] test(e2e): dismiss new-user UI overlays in auth setup The active "AI Automations" announcement (2026-05-31 -> 2026-07-15) renders a blocking AnnouncementSpotlight dialog whose full-screen overlay intercepts all clicks for the freshly-registered e2e user, breaking every UI-driven journey (e.g. the file-upload upload button). Pre-seed the localStorage flags that gate the new-user overlays before saving storageState: - surfsense_announcements_state: mark all announcements read + toasted (sourced from announcements-data so future entries are covered). - surfsense-tour-: suppress the OnboardingTour spotlight. Restores the Journey suite (file-upload markdown + PDF round-trips now green). --- surfsense_web/tests/auth.setup.ts | 42 +++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/surfsense_web/tests/auth.setup.ts b/surfsense_web/tests/auth.setup.ts index a33a81b3c..7c1e37a39 100644 --- a/surfsense_web/tests/auth.setup.ts +++ b/surfsense_web/tests/auth.setup.ts @@ -1,5 +1,6 @@ import path from "node:path"; import { expect, test as setup } from "@playwright/test"; +import { announcements } from "../lib/announcements/announcements-data"; import { acquireTestToken } from "./helpers/api/auth"; /** @@ -7,21 +8,58 @@ import { acquireTestToken } from "./helpers/api/auth"; * e2e user (rate-limit-free /__e2e__/auth/token first, /auth/jwt/login * fallback) and persists it via localStorage so every test in the * chromium project starts already authenticated. + * + * Also pre-seeds the localStorage flags that gate the two new-user UI + * overlays so they never intercept clicks in journeys: + * - `surfsense_announcements_state` — the blocking AnnouncementSpotlight + * dialog (e.g. "Introducing AI Automations") plus its toasts. + * - `surfsense-tour-` — the OnboardingTour spotlight for new users. */ const authFile = path.join(__dirname, "..", "playwright", ".auth", "user.json"); const STORAGE_KEY = "surfsense_bearer_token"; +const ANNOUNCEMENTS_KEY = "surfsense_announcements_state"; + +/** Decode the user id (`sub`) from a JWT without verifying the signature. */ +function decodeUserId(token: string): string | null { + try { + const payload = token.split(".")[1]; + if (!payload) return null; + const json = Buffer.from(payload, "base64").toString("utf8"); + const obj = JSON.parse(json) as { sub?: string }; + return obj.sub ?? null; + } catch { + return null; + } +} setup("authenticate", async ({ page, request }) => { const access_token = await acquireTestToken(request); expect(access_token, "Failed to acquire e2e bearer token").toBeTruthy(); + const userId = decodeUserId(access_token); + // Mark every known announcement read + toasted so spotlight/toast + // announcements never overlay the dashboard during journeys. Sourced + // from the real data file so future announcements are covered too. + const announcementIds = announcements.map((a) => a.id); + const announcementState = { readIds: announcementIds, toastedIds: announcementIds }; + await page.addInitScript( - ({ key, token }) => { + ({ key, token, announcementsKey, state, uid }) => { localStorage.setItem(key, token); + localStorage.setItem(announcementsKey, JSON.stringify(state)); + if (uid) { + localStorage.setItem(`surfsense-tour-${uid}`, "true"); + } }, - { key: STORAGE_KEY, token: access_token } + { + key: STORAGE_KEY, + token: access_token, + announcementsKey: ANNOUNCEMENTS_KEY, + state: announcementState, + uid: userId, + } ); // Use a public page so the init script can write localStorage without