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.
75 lines
3.4 KiB
JavaScript
75 lines
3.4 KiB
JavaScript
// tests/e2e/test_credentials.js
|
|
// Tests credential management page: structure, password set/change, validation errors.
|
|
|
|
const { TARGET_URL, run } = require('./helpers');
|
|
|
|
run(async (page, assert) => {
|
|
const fixtures = JSON.parse(process.env.E2E_FIXTURES || '{}');
|
|
|
|
// ---- Setup: Log in with dedicated credentials user ----
|
|
console.log('\n--- Setup: login ---');
|
|
await page.goto(`${TARGET_URL}/login`);
|
|
await page.fill('#username', fixtures.cred_username);
|
|
await page.fill('#password', fixtures.cred_password);
|
|
await page.click('form[hx-post="/login/password"] button[type="submit"]');
|
|
await page.waitForURL('**/manage/credentials', { timeout: 5000 });
|
|
|
|
// ---- Page structure ----
|
|
console.log('\n--- Credentials page structure ---');
|
|
const title = await page.title();
|
|
assert(title.includes('Credentials'), `Title contains "Credentials" (got: "${title}")`);
|
|
assert(title.includes('Porchlight'), `Title contains "Porchlight" (got: "${title}")`);
|
|
|
|
const h1 = await page.locator('h1').textContent();
|
|
assert(h1 === 'Credentials', `H1 says "Credentials" (got: "${h1}")`);
|
|
|
|
// Security keys section
|
|
const securityKeysH2 = page.locator('h2:has-text("Security keys")');
|
|
assert(await securityKeysH2.isVisible(), 'Security keys heading visible');
|
|
|
|
const registerBtn = page.locator('#webauthn-register-btn');
|
|
assert(await registerBtn.isVisible(), 'Add security key button visible');
|
|
|
|
// Password section
|
|
const passwordH2 = page.locator('h2:has-text("Password")');
|
|
assert(await passwordH2.isVisible(), 'Password heading visible');
|
|
|
|
const passwordSection = page.locator('#password-section');
|
|
assert(await passwordSection.isVisible(), 'Password section visible');
|
|
|
|
// ---- Password validation: mismatch ----
|
|
console.log('\n--- Password validation: mismatch ---');
|
|
await page.fill('#password', 'newpassword1');
|
|
await page.fill('#confirm', 'newpassword2');
|
|
await page.click('#password-section button[type="submit"]');
|
|
|
|
await page.waitForSelector('#password-section [role="alert"]', { timeout: 5000 });
|
|
const mismatchErr = await page.locator('#password-section [role="alert"]').textContent();
|
|
assert(
|
|
mismatchErr.includes('do not match'),
|
|
`Shows mismatch error (got: "${mismatchErr}")`
|
|
);
|
|
|
|
// ---- Password validation: minlength enforced client-side ----
|
|
console.log('\n--- Password validation: minlength attribute ---');
|
|
// Reload page to clear HTMX state (the form was replaced by the error div)
|
|
await page.goto(`${TARGET_URL}/manage/credentials`);
|
|
const pwMinlength = await page.locator('#password').getAttribute('minlength');
|
|
assert(pwMinlength === '8', `Password input has minlength="8" (got: "${pwMinlength}")`);
|
|
const confirmMinlength = await page.locator('#confirm').getAttribute('minlength');
|
|
assert(confirmMinlength === '8', `Confirm input has minlength="8" (got: "${confirmMinlength}")`);
|
|
|
|
// ---- Password change: success ----
|
|
console.log('\n--- Password change: success ---');
|
|
await page.goto(`${TARGET_URL}/manage/credentials`);
|
|
await page.fill('#password', 'newpassword123');
|
|
await page.fill('#confirm', 'newpassword123');
|
|
await page.click('#password-section button[type="submit"]');
|
|
|
|
await page.waitForSelector('#password-section [role="status"]', { timeout: 5000 });
|
|
const successMsg = await page.locator('#password-section [role="status"]').textContent();
|
|
assert(
|
|
successMsg.includes('Password updated'),
|
|
`Shows success message (got: "${successMsg}")`
|
|
);
|
|
});
|