Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { request } from "@playwright/test";
|
||||
|
||||
import {
|
||||
OWNER_DISPLAY_NAME,
|
||||
OWNER_EMAIL,
|
||||
OWNER_PASSWORD,
|
||||
WORKSPACE_NAME
|
||||
} from "./specs/support/credentials";
|
||||
|
||||
const baseURL = process.env.KNOWLEDGE_HUB_E2E_BASE_URL ?? "http://localhost:1240";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/** Where the pre-authenticated owner session's storage state is written, for specs
|
||||
* that need to start already signed in (see `authenticatedStatePath`). Not committed —
|
||||
* regenerated by every `globalSetup` run. */
|
||||
export const authenticatedStatePath = path.join(__dirname, "../../artifacts/e2e-auth-state.json");
|
||||
|
||||
function extractCookie(response: Response): string | null {
|
||||
// Node's fetch exposes combined Set-Cookie via getSetCookie() (undici); fall back to
|
||||
// the raw header for older runtimes.
|
||||
const cookies =
|
||||
typeof response.headers.getSetCookie === "function"
|
||||
? response.headers.getSetCookie()
|
||||
: [response.headers.get("set-cookie")].filter((value): value is string => value !== null);
|
||||
|
||||
return cookies.map((cookie) => cookie.split(";")[0]).join("; ") || null;
|
||||
}
|
||||
|
||||
async function completeFirstRunSetupIfNeeded(): Promise<void> {
|
||||
const statusResponse = await fetch(`${baseURL}/api/v1/setup/status`);
|
||||
const status = (await statusResponse.json()) as { setupRequired: boolean };
|
||||
|
||||
if (!status.setupRequired) {
|
||||
// A previous run (or a manual setup) already completed this exact step —
|
||||
// idempotent no-op rather than a hard failure, so repeated local `pnpm test:e2e`
|
||||
// runs against the same stack keep working.
|
||||
return;
|
||||
}
|
||||
|
||||
const csrfResponse = await fetch(`${baseURL}/api/v1/auth/csrf`);
|
||||
const csrfCookie = extractCookie(csrfResponse);
|
||||
const csrf = (await csrfResponse.json()) as { token: string; headerName: string };
|
||||
|
||||
|
||||
const completeResponse = await fetch(`${baseURL}/api/v1/setup/complete`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
[csrf.headerName]: csrf.token,
|
||||
...(csrfCookie ? { Cookie: csrfCookie } : {})
|
||||
},
|
||||
body: JSON.stringify({
|
||||
workspaceName: WORKSPACE_NAME,
|
||||
displayName: OWNER_DISPLAY_NAME,
|
||||
email: OWNER_EMAIL,
|
||||
password: OWNER_PASSWORD
|
||||
})
|
||||
});
|
||||
|
||||
if (!completeResponse.ok) {
|
||||
const body = await completeResponse.text();
|
||||
throw new Error(
|
||||
`E2E global setup failed to complete first-run setup (${completeResponse.status}): ${body}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in exactly once for the whole suite and persists the resulting session as
|
||||
* Playwright storage state, so specs that only need to *already be signed in*
|
||||
* (everything except the login/logout journey itself) can start from that state
|
||||
* instead of each performing its own `POST /api/v1/auth/login`. The login endpoint is
|
||||
* deliberately rate-limited (docs/12-auth-security.md — 10/minute); with roughly a
|
||||
* dozen specs each logging in once, the previous "every spec logs in itself" design
|
||||
* reliably tripped that limiter on a full local run. One login per full suite run
|
||||
* keeps well under it while still exercising the real login endpoint (via
|
||||
* auth-journey.spec.ts, which intentionally does not use this shared state).
|
||||
*/
|
||||
async function saveAuthenticatedState(): Promise<void> {
|
||||
const api = await request.newContext({ baseURL });
|
||||
|
||||
const csrfResponse = await api.get("/api/v1/auth/csrf");
|
||||
const csrf = (await csrfResponse.json()) as { token: string; headerName: string };
|
||||
|
||||
const loginResponse = await api.post("/api/v1/auth/login", {
|
||||
headers: { [csrf.headerName]: csrf.token },
|
||||
data: { email: OWNER_EMAIL, password: OWNER_PASSWORD }
|
||||
});
|
||||
|
||||
if (!loginResponse.ok()) {
|
||||
const body = await loginResponse.text();
|
||||
throw new Error(`E2E global setup failed to log in the shared owner session (${loginResponse.status()}): ${body}`);
|
||||
}
|
||||
|
||||
await api.storageState({ path: authenticatedStatePath });
|
||||
await api.dispose();
|
||||
}
|
||||
|
||||
export default async function globalSetup(): Promise<void> {
|
||||
await completeFirstRunSetupIfNeeded();
|
||||
await saveAuthenticatedState();
|
||||
}
|
||||
Reference in new issue
Block a user