77 lines
3.9 KiB
JavaScript
77 lines
3.9 KiB
JavaScript
// 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 doesn’t 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 we’re 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([]);
|
||
});
|
||
});
|