fix(dashboard):use session aware loading

This commit is contained in:
Anish Sarkar 2026-06-24 03:59:19 +05:30
parent 6e4d2eb076
commit f98d874185
5 changed files with 64 additions and 74 deletions

View file

@ -4,9 +4,9 @@ import { announcements } from "../lib/announcements/announcements-data";
import { acquireTestToken } from "./helpers/api/auth";
/**
* One-time authentication setup. Acquires a bearer token for the seeded
* e2e user (rate-limit-free /__e2e__/auth/token first, /auth/jwt/login
* fallback) and persists it via localStorage so every test in the
* One-time authentication setup. Acquires an access token for the seeded
* e2e user (rate-limit-free /__e2e__/auth/token first, desktop login
* fallback) and persists it as the session cookie so every test in the
* chromium project starts already authenticated.
*
* Also pre-seeds the localStorage flags that gate the two new-user UI
@ -18,7 +18,9 @@ import { acquireTestToken } from "./helpers/api/auth";
const authFile = path.join(__dirname, "..", "playwright", ".auth", "user.json");
const STORAGE_KEY = "surfsense_bearer_token";
const PORT = process.env.PORT || "3000";
const BASE_URL = process.env.PLAYWRIGHT_BASE_URL || `http://localhost:${PORT}`;
const SESSION_COOKIE_NAME = process.env.SESSION_COOKIE_NAME || "surfsense_session";
const ANNOUNCEMENTS_KEY = "surfsense_announcements_state";
/** Decode the user id (`sub`) from a JWT without verifying the signature. */
@ -45,17 +47,24 @@ setup("authenticate", async ({ page, request }) => {
const announcementIds = announcements.map((a) => a.id);
const announcementState = { readIds: announcementIds, toastedIds: announcementIds };
await page.context().addCookies([
{
name: SESSION_COOKIE_NAME,
value: access_token,
url: BASE_URL,
httpOnly: true,
sameSite: "Lax",
},
]);
await page.addInitScript(
({ key, token, announcementsKey, state, uid }) => {
localStorage.setItem(key, token);
({ announcementsKey, state, uid }) => {
localStorage.setItem(announcementsKey, JSON.stringify(state));
if (uid) {
localStorage.setItem(`surfsense-tour-${uid}`, "true");
}
},
{
key: STORAGE_KEY,
token: access_token,
announcementsKey: ANNOUNCEMENTS_KEY,
state: announcementState,
uid: userId,

View file

@ -22,26 +22,21 @@ export type SearchSpaceFixtures = {
searchSpace: SearchSpaceRow;
};
const STORAGE_KEY = "surfsense_bearer_token";
const SESSION_COOKIE_NAME = process.env.SESSION_COOKIE_NAME || "surfsense_session";
// Reuse the token written by tests/auth.setup.ts; on cache miss we
// Reuse the session cookie written by tests/auth.setup.ts; on cache miss we
// mint a fresh one via /__e2e__/auth/token (rate-limit-free).
const AUTH_STATE_PATH = path.join(__dirname, "..", "..", "playwright", ".auth", "user.json");
function loadCachedBearerToken(): string | null {
function loadCachedSessionToken(): string | null {
try {
const raw = fs.readFileSync(AUTH_STATE_PATH, "utf8");
const parsed = JSON.parse(raw) as {
origins?: Array<{
origin?: string;
localStorage?: Array<{ name?: string; value?: string }>;
}>;
cookies?: Array<{ name?: string; value?: string }>;
};
for (const origin of parsed.origins ?? []) {
for (const entry of origin.localStorage ?? []) {
if (entry.name === STORAGE_KEY && entry.value) {
return entry.value;
}
for (const cookie of parsed.cookies ?? []) {
if (cookie.name === SESSION_COOKIE_NAME && cookie.value) {
return cookie.value;
}
}
} catch {
@ -53,7 +48,7 @@ function loadCachedBearerToken(): string | null {
export const searchSpaceFixtures = base.extend<SearchSpaceFixtures, { apiTokenWorker: string }>({
apiTokenWorker: [
async ({ playwright }, use) => {
const cached = loadCachedBearerToken();
const cached = loadCachedSessionToken();
if (cached) {
await use(cached);
return;

View file

@ -1,11 +1,11 @@
import type { APIRequestContext } from "@playwright/test";
/**
* Direct backend auth helper. Uses the same /auth/jwt/login endpoint the
* UI uses; mirrors lib/apis/auth-api.service.ts.
* Direct backend auth helper. Uses the desktop login endpoint when the
* rate-limit-free e2e mint endpoint is unavailable.
*
* Returns a bearer token specs can attach to API calls when they don't
* want to go through the browser. The browser-side auth (localStorage)
* want to go through the browser. The browser-side auth (cookie storage)
* is set up separately by tests/auth.setup.ts.
*/
@ -18,7 +18,7 @@ const E2E_MINT_SECRET = process.env.E2E_MINT_SECRET || "local-e2e-mint-secret-no
/**
* Mints a JWT for the seeded e2e user via the test-only endpoint mounted
* by surfsense_backend/tests/e2e/run_backend.py. Bypasses the production
* /auth/jwt/login rate limit (5/min/IP), so it's safe to call from any
* desktop login rate limit, so it's safe to call from any
* worker / retry. Returns 404 from the backend when the endpoint isn't
* mounted (i.e. someone is pointing the suite at a non-e2e backend).
*/
@ -46,18 +46,17 @@ export async function mintTestToken(
}
export async function loginAsTestUser(request: APIRequestContext): Promise<string> {
const response = await request.post(`${BACKEND_URL}/auth/jwt/login`, {
form: {
username: TEST_USER_EMAIL,
const response = await request.post(`${BACKEND_URL}/auth/desktop/login`, {
data: {
email: TEST_USER_EMAIL,
password: TEST_USER_PASSWORD,
grant_type: "password",
},
headers: { "Content-Type": "application/x-www-form-urlencoded" },
headers: { "Content-Type": "application/json" },
});
if (!response.ok()) {
throw new Error(
`Login to ${BACKEND_URL}/auth/jwt/login failed (${response.status()}): ${await response.text()}`
`Login to ${BACKEND_URL}/auth/desktop/login failed (${response.status()}): ${await response.text()}`
);
}
@ -70,7 +69,7 @@ export async function loginAsTestUser(request: APIRequestContext): Promise<strin
/**
* Get a bearer token by trying the rate-limit-free mint endpoint first
* and falling back to /auth/jwt/login if the e2e endpoint isn't mounted
* and falling back to /auth/desktop/login if the e2e endpoint isn't mounted
* (e.g. running against a non-e2e backend in local dev).
*/
export async function acquireTestToken(request: APIRequestContext): Promise<string> {