Extract shared test runner (helpers.js), add file-based SQLite with setup_db.py for fixture seeding, and add tests for auth guard, credentials management, full registration flow, health endpoint, password auth, and magic link registration errors. 66 checks across 7 test files.
84 lines
3.4 KiB
JavaScript
84 lines
3.4 KiB
JavaScript
// tests/e2e/test_full_flow.js
|
|
// Full user journey: magic link registration -> set password -> logout -> login.
|
|
|
|
const { TARGET_URL, run } = require('./helpers');
|
|
|
|
run(async (page, assert) => {
|
|
const fixtures = JSON.parse(process.env.E2E_FIXTURES || '{}');
|
|
assert(fixtures.register_token, 'Test fixtures loaded (register_token present)');
|
|
|
|
// ---- Step 1: Register via magic link ----
|
|
console.log('\n--- Magic link registration ---');
|
|
await page.goto(`${TARGET_URL}/register/${fixtures.register_token}`);
|
|
|
|
// Should redirect to /manage/credentials?setup=1
|
|
await page.waitForURL('**/manage/credentials?setup=1', { timeout: 5000 });
|
|
assert(
|
|
page.url().includes('/manage/credentials'),
|
|
`Redirected to credentials page (url: ${page.url()})`
|
|
);
|
|
|
|
// Should show welcome message
|
|
const welcome = page.locator('[role="status"]');
|
|
assert(await welcome.isVisible(), 'Welcome/setup message is visible');
|
|
const welcomeText = await welcome.textContent();
|
|
assert(
|
|
welcomeText.includes('Welcome'),
|
|
`Welcome message shown (got: "${welcomeText}")`
|
|
);
|
|
|
|
// Page title should be Porchlight
|
|
const title = await page.title();
|
|
assert(title.includes('Porchlight'), 'Credentials page title contains Porchlight');
|
|
|
|
// ---- Step 2: Set password ----
|
|
console.log('\n--- Set password ---');
|
|
const passwordInput = page.locator('#password');
|
|
const confirmInput = page.locator('#confirm');
|
|
assert(await passwordInput.isVisible(), 'Password input is visible');
|
|
assert(await confirmInput.isVisible(), 'Confirm password input is visible');
|
|
|
|
await passwordInput.fill('mypassword123');
|
|
await confirmInput.fill('mypassword123');
|
|
await page.click('#password-section button[type="submit"]');
|
|
|
|
// Wait for HTMX response — password-section innerHTML gets replaced
|
|
// The success message uses role="status"
|
|
const successMsg = page.locator('#password-section [role="status"]');
|
|
await successMsg.waitFor({ timeout: 5000 });
|
|
const successText = await successMsg.textContent();
|
|
assert(
|
|
successText.includes('Password updated'),
|
|
`Password set successfully (got: "${successText}")`
|
|
);
|
|
|
|
// ---- Step 3: Logout ----
|
|
console.log('\n--- Logout ---');
|
|
// POST /logout returns an HX-Redirect header, not a standard redirect.
|
|
// Use page.request to call it, then navigate manually.
|
|
await page.request.post(`${TARGET_URL}/logout`);
|
|
|
|
// Navigate to credentials — should redirect to login since we're logged out
|
|
await page.goto(`${TARGET_URL}/manage/credentials`);
|
|
await page.waitForURL('**/login', { timeout: 5000 });
|
|
assert(page.url().includes('/login'), 'Redirected to login after logout');
|
|
|
|
// ---- Step 4: Login with the password we just set ----
|
|
console.log('\n--- Login with new password ---');
|
|
await page.fill('#username', fixtures.register_username);
|
|
await page.fill('#password', 'mypassword123');
|
|
|
|
// Submit via HTMX — on success, HX-Redirect header triggers redirect
|
|
await page.click('form[hx-post="/login/password"] button[type="submit"]');
|
|
|
|
// Wait for redirect to credentials page
|
|
await page.waitForURL('**/manage/credentials', { timeout: 5000 });
|
|
assert(
|
|
page.url().includes('/manage/credentials'),
|
|
`Login succeeded, redirected to credentials (url: ${page.url()})`
|
|
);
|
|
|
|
// Should NOT show setup message (no ?setup=1)
|
|
const setupMsgCount = await page.locator('[role="status"]:has-text("Welcome")').count();
|
|
assert(setupMsgCount === 0, 'No welcome/setup message on normal login');
|
|
});
|