// 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'); });