nxtgauge-frontend-solid/tests/e2e/helpers/auth-flow.ts
Ashwin Kumar Sivakumar 8801440459
All checks were successful
build-and-release / build (push) Successful in 2m25s
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

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 };
}