All checks were successful
build-and-release / build (push) Successful in 2m25s
The e2e suite only ever worked against a local docker-compose stack: - Hardcoded http://localhost:3000 / :9100 everywhere, ignoring TEST_ENV=production and playwright.config.ts's own baseURL logic. - /api/auth/login and /api/auth/register now require solving a math captcha first; none of these tests sent captcha_id/captcha_answer, so every login/register call 422'd against the live API. - OTP retrieval shelled out to a local, unauthenticated redis-cli, which can't reach the real (kubectl-exec + password-protected) Redis. - Several files launched their own chromium.launch({headless: false}), which crashes immediately on a server with no X display. - One file had a hardcoded macOS absolute path for screenshots. Added tests/e2e/helpers/{env,captcha,otp,auth-flow}.ts as shared, reusable fixes for all of the above, and updated every affected spec file to use them. Verified via a full run against test111.nxtgauge.com: 971 schemathesis-adjacent smoke assertions aside, the actual signal here is 0 of the 130 prior failures came from real product bugs - all were this environment mismatch. See docs/LIVE_SERVER_RUNBOOK.md step 5. Also fixes .gitignore: it excluded 'playwright-report' (singular) but playwright.config.ts's actual outputFolder is 'playwright-reports' (plural) - generated HTML report artifacts had been getting committed by accident. Untracked the existing ones; left tests/e2e/visual/*-snapshots/ (newly-generated visual regression baselines from this run) untracked for now since establishing baselines needs a human look, not a blind commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
import { API_BASE } from "./env";
|
|
import { solveCaptcha } from "./captcha";
|
|
import { getOtpFromRedis } from "./otp";
|
|
|
|
export interface RegisterInput {
|
|
email: string;
|
|
password: string;
|
|
first_name?: string;
|
|
last_name?: string;
|
|
phone?: string;
|
|
intent?: string;
|
|
profession?: string;
|
|
}
|
|
|
|
/** POST /api/auth/register (captcha-solved automatically). */
|
|
export async function apiRegister(input: RegisterInput): Promise<{ user_id: string; [k: string]: any }> {
|
|
const { captcha_id, captcha_answer } = await solveCaptcha();
|
|
const res = await fetch(`${API_BASE}/auth/register`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ ...input, captcha_id, captcha_answer }),
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
throw new Error(`Register failed (${res.status}): ${JSON.stringify(data)}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/** POST /api/auth/verify-email, sourcing the OTP straight from Redis. */
|
|
export async function apiVerifyEmail(email: string, userId: string): Promise<boolean> {
|
|
const otp = await getOtpFromRedis(userId);
|
|
if (!otp) {
|
|
console.log(`⚠️ Could not retrieve OTP from Redis for user ${userId}`);
|
|
return false;
|
|
}
|
|
const res = await fetch(`${API_BASE}/auth/verify-email`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ otp, email }),
|
|
});
|
|
return res.ok;
|
|
}
|
|
|
|
/** POST /api/auth/login (captcha-solved automatically). Returns null on non-2xx. */
|
|
export async function apiLogin(email: string, password: string): Promise<{ access_token: string; [k: string]: any } | null> {
|
|
const { captcha_id, captcha_answer } = await solveCaptcha();
|
|
const res = await fetch(`${API_BASE}/auth/login`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ email, password, captcha_id, captcha_answer }),
|
|
});
|
|
if (!res.ok) return null;
|
|
return res.json();
|
|
}
|
|
|
|
/** Full register → verify → login convenience flow, returning the access token. */
|
|
export async function registerVerifyLogin(input: RegisterInput): Promise<{ user_id: string; access_token: string }> {
|
|
const regData = await apiRegister(input);
|
|
const verified = await apiVerifyEmail(input.email, regData.user_id);
|
|
if (!verified) throw new Error(`Email verification failed for ${input.email}`);
|
|
const loginData = await apiLogin(input.email, input.password);
|
|
if (!loginData) throw new Error(`Login failed for ${input.email} after verification`);
|
|
return { user_id: regData.user_id, access_token: loginData.access_token };
|
|
}
|