nxtgauge-frontend-solid/tests/e2e/company-jobs.spec.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

113 lines
No EOL
4.3 KiB
TypeScript

import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
import { apiLogin } from "./helpers/auth-flow";
async function setupAuth(page: any): Promise<boolean> {
const loginData = await apiLogin("testcompany@example.com", "TestPassword123!");
if (!loginData) return false;
const token = loginData.access_token;
await page.goto("/dashboard");
await page.evaluate((t: string) => {
window.sessionStorage.setItem("nxtgauge_access_token", t);
window.sessionStorage.setItem("nxtgauge_frontend_access_token", t);
}, token);
await page.reload();
await page.waitForLoadState("networkidle");
return !page.url().includes("/login");
}
test.describe("Company Jobs Page - Authenticated", () => {
test.beforeEach(async ({ page }) => {
const loggedIn = await setupAuth(page);
if (!loggedIn) test.skip();
});
test("page loads and shows jobs section", async ({ page }) => {
const jobsHeader = page.locator("text=Jobs").first();
await expect(jobsHeader).toBeVisible({ timeout: 10000 });
});
test("create job form opens and has AI buttons", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await expect(createBtn).toBeVisible({ timeout: 10000 });
await createBtn.click();
await page.waitForTimeout(500);
const titleInput = page.locator('input[placeholder="Frontend Developer"]').first();
await expect(titleInput).toBeVisible();
const aiButtons = page.locator('button[title="Generate with AI"]');
const count = await aiButtons.count();
expect(count).toBeGreaterThanOrEqual(3);
});
test("create job shows error when title is empty", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await createBtn.click();
await page.waitForTimeout(500);
await page.fill('input[placeholder="Bengaluru (Hybrid)"]', "Some location");
await page.fill('textarea[placeholder*="Role overview"]', "Some description");
await page.locator("text=Create Draft").first().click();
await page.waitForTimeout(500);
const error = page.locator('text="Title, description, and location are required."');
await expect(error).toBeVisible({ timeout: 3000 });
});
test("create job shows error when description is empty", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await createBtn.click();
await page.waitForTimeout(500);
await page.fill('input[placeholder="Frontend Developer"]', "Test Title");
await page.fill('input[placeholder="Bengaluru (Hybrid)"]', "Some location");
await page.locator("text=Create Draft").first().click();
await page.waitForTimeout(500);
const error = page.locator('text="Title, description, and location are required."');
await expect(error).toBeVisible({ timeout: 3000 });
});
test("create job shows error when location is empty", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await createBtn.click();
await page.waitForTimeout(500);
await page.fill('input[placeholder="Frontend Developer"]', "Test Title");
await page.fill('textarea[placeholder*="Role overview"]', "Some description");
await page.locator("text=Create Draft").first().click();
await page.waitForTimeout(500);
const error = page.locator('text="Title, description, and location are required."');
await expect(error).toBeVisible({ timeout: 3000 });
});
test("form clears error when user starts typing required field", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await createBtn.click();
await page.waitForTimeout(500);
await page.locator("text=Create Draft").first().click();
await page.waitForTimeout(500);
const error = page.locator('text="Title, description, and location are required."');
await expect(error).toBeVisible({ timeout: 3000 });
await page.fill('input[placeholder="Frontend Developer"]', "T");
await page.waitForTimeout(200);
await expect(error).not.toBeVisible();
});
test("create job form has no accessibility violations", async ({ page }) => {
const createBtn = page.locator("text=+ Create Job").first();
await createBtn.click();
await page.waitForTimeout(500);
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});