nxtgauge-frontend-solid/tests/e2e/helpers/captcha.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

28 lines
1.1 KiB
TypeScript

import { API_BASE } from "./env";
/**
* Fetches a fresh math captcha from the API and solves it.
* Captchas are single-use (Redis-backed) — call this immediately before the
* request that needs it, never cache/reuse a solved captcha_id.
*/
export async function solveCaptcha(): Promise<{ captcha_id: string; captcha_answer: string }> {
const res = await fetch(`${API_BASE}/auth/captcha`, { method: "POST" });
if (!res.ok) {
throw new Error(`Failed to fetch captcha: ${res.status} ${await res.text()}`);
}
const { captcha_id, challenge } = await res.json();
// Challenge format observed from the API: "N + N = ?" / "N - N = ?" (also
// tolerate "*" just in case). Keep this in sync with
// apps/users/src/handlers/auth.rs's captcha generator.
const match = String(challenge).match(/(-?\d+)\s*([+\-*])\s*(-?\d+)/);
if (!match) {
throw new Error(`Unrecognized captcha challenge format: "${challenge}"`);
}
const [, aStr, op, bStr] = match;
const a = Number(aStr);
const b = Number(bStr);
const answer = op === "+" ? a + b : op === "-" ? a - b : a * b;
return { captcha_id, captcha_answer: String(answer) };
}