Files
wehub-resource-sync fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

60 lines
2.0 KiB
TypeScript

/**
* JWT signing + per-test BrowserContext seeding for DocsGPT e2e.
*/
import { randomUUID } from 'node:crypto';
import jwt from 'jsonwebtoken';
import type { Browser, BrowserContext } from '@playwright/test';
/**
* Default secret mirrors Appendix A of e2e-plan.md. Overridable for negative
* tests (e.g. asserting a wrong-secret token is rejected). `process.env` is
* read lazily so spec-level `env` overrides still take effect.
*/
function defaultSecret(): string {
return process.env.JWT_SECRET_KEY ?? 'e2e-fixed-secret-never-use-in-prod';
}
/**
* Sign an HS256 JWT matching the backend's expected shape. No `exp` claim —
* matches application/app.py:62-66 which issues tokens with only `{sub}`.
*/
export function signJwt(sub: string, secret?: string): string {
return jwt.sign({ sub }, secret ?? defaultSecret(), { algorithm: 'HS256' });
}
/**
* Playwright `addInitScript` helper: seeds `localStorage.authToken` BEFORE the
* first navigation, so the frontend's auth bootstrap picks it up on load
* instead of prompting for one.
*/
export async function injectTokenBeforeNavigation(
context: BrowserContext,
token: string,
): Promise<void> {
await context.addInitScript((t: string) => {
try {
window.localStorage.setItem('authToken', t);
} catch {
// localStorage may be unavailable on about:blank-style pages; the first
// real navigation will re-run this init script with a valid origin.
}
}, token);
}
/**
* Create a fresh BrowserContext with a freshly-signed JWT already injected
* into localStorage. Returns the context plus the sub/token so specs can
* assert against DB rows keyed on `users.user_id = sub`.
*/
export async function newUserContext(
browser: Browser,
opts?: { sub?: string },
): Promise<{ context: BrowserContext; sub: string; token: string }> {
const sub = opts?.sub ?? randomUUID();
const token = signJwt(sub);
const context = await browser.newContext();
await injectTokenBeforeNavigation(context, token);
return { context, sub, token };
}