dev1/tests/e2e/02-signin-landing.spec.mjs
2025-09-18 13:26:16 +00:00

77 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// tests/e2e/02-signin-landing.spec.mjs
// @ts-check
import { test, expect } from '@playwright/test';
import { loadTestUser } from '../utils/testUser.js';
test.describe('@p0 SignIn → Landing', () => {
test.setTimeout(10000);
test('signs in with persisted user and reaches SignInLanding', async ({ page }) => {
const user = loadTestUser();
await page.context().clearCookies();
await page.goto('/signin', { waitUntil: 'networkidle' });
await expect(page.getByRole('heading', { name: /Sign In/i })).toBeVisible();
await page.getByPlaceholder('Username', { exact: true }).fill(user.username);
await page.getByPlaceholder('Password', { exact: true }).fill(user.password);
await page.getByRole('button', { name: /^Sign In$/ }).click();
// Wait explicitly for the /api/signin POST and capture the outcome
const signinResp = await page.waitForResponse(
r => r.url().includes('/api/signin') && r.request().method() === 'POST',
{ timeout: 15000 }
);
const status = signinResp.status();
let bodyText = '';
try { bodyText = await signinResp.text(); } catch {}
// If backend rejected signin, fail here with clear diagnostics
expect(status, `POST /api/signin → ${status}\n${bodyText}`).toBeLessThan(400);
// Authenticated redirect can go to /verify (new gate) OR /signin-landing (legacy) OR journey.
await page.waitForLoadState('networkidle');
const url = page.url();
if (url.includes('/verify')) {
// Complete email verification via existing API (token exposed by server in non-prod).
await expect(page.getByText(/Verify your account/i)).toBeVisible({ timeout: 10000 });
const resp = await page.request.post('/api/auth/verify/email/send', { data: {} });
expect(resp.status()).toBeLessThan(400);
const json = await resp.json();
// If server is prod-like and doesnt expose test_token, fail fast with diagnostics.
expect(json.test_token, 'Server did not expose test_token (non-production only)').toBeTruthy();
// Confirm directly via API to avoid timing on auto-redirect.
const confirm = await page.request.post('/api/auth/verify/email/confirm', {
data: { token: json.test_token }
});
expect(confirm.status()).toBeLessThan(400);
// Navigate to the authenticated home now that VerificationGate will pass.
await page.goto('/signin-landing', { waitUntil: 'networkidle' });
await expect(page.getByText(/Welcome to AptivaAI/i)).toBeVisible({ timeout: 10000 });
await expect(page.getByRole('link', { name: /Go to Exploring/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Preparing/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Enhancing/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Retirement/i })).toBeVisible();
// continue below to cookie + console checks
} else if (url.includes('/signin-landing')) {
// Greeting is not personalized here; accept any "Welcome to AptivaAI" variant.
await expect(page.getByText(/Welcome to AptivaAI/i)).toBeVisible({ timeout: 5000 });
await expect(page.getByRole('link', { name: /Go to Exploring/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Preparing/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Enhancing/i })).toBeVisible();
await expect(page.getByRole('link', { name: /Go to Retirement/i })).toBeVisible();
} else {
// Journey-resume path: just prove were authenticated and not stuck on /signin.
expect(url).not.toMatch(/\/signin($|[?#])/);
}
const cookies = await page.context().cookies();
expect(cookies.some(c => /jwt|session/i.test(c.name))).toBeTruthy();
/** @type {string[]} */
const consoleErrors = [];
page.on('console', m => { if (m.type() === 'error') consoleErrors.push(m.text()); });
expect(consoleErrors).toEqual([]);
});
});