nxtgauge-frontend-solid/tests/e2e/helpers/auth-flow.ts

66 lines
2.5 KiB
TypeScript
Raw Normal View History

fix(e2e): use env-aware URLs, captcha-solving, and real Redis OTP retrieval 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>
2026-08-14 00:51:55 +05:30
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 };
}