diff --git a/src/porchlight/templates/manage/credentials.html b/src/porchlight/templates/manage/credentials.html index 6d4c269..a37221e 100644 --- a/src/porchlight/templates/manage/credentials.html +++ b/src/porchlight/templates/manage/credentials.html @@ -38,7 +38,8 @@ {% else %}

No password set.

{% endif %} -
+
+ {% if has_password %}
diff --git a/tests/e2e/credentials.spec.js b/tests/e2e/credentials.spec.js index 0270822..bc5fd3f 100644 --- a/tests/e2e/credentials.spec.js +++ b/tests/e2e/credentials.spec.js @@ -42,6 +42,7 @@ test.describe('Credentials page', () => { test.describe('Password validation', () => { test('shows mismatch error', async ({ page }) => { + await page.fill('#current_password', fixtures.cred_password); await page.fill('#password', 'newpassword1'); await page.fill('#confirm', 'newpassword2'); await page.click('#password-section button[type="submit"]'); @@ -51,6 +52,23 @@ test.describe('Credentials page', () => { await expect(alert).toContainText('do not match'); }); + test('keeps the password form visible after a validation error', async ({ page }) => { + await page.fill('#current_password', fixtures.cred_password); + await page.fill('#password', 'newpassword1'); + await page.fill('#confirm', 'newpassword2'); + await page.click('#password-section button[type="submit"]'); + + const alert = page.locator('#password-section [role="alert"]'); + await expect(alert).toBeVisible({ timeout: 5000 }); + + // Regression: the form and its inputs must NOT disappear on error. + await expect(page.locator('#password')).toBeVisible(); + await expect(page.locator('#confirm')).toBeVisible(); + await expect( + page.locator('#password-section button[type="submit"]'), + ).toBeVisible(); + }); + test('password input has minlength="8"', async ({ page }) => { await expect(page.locator('#password')).toHaveAttribute('minlength', '8'); }); @@ -62,8 +80,9 @@ test.describe('Credentials page', () => { test.describe('Password change', () => { test('succeeds with matching passwords', async ({ page }) => { - await page.fill('#password', 'newpassword123'); - await page.fill('#confirm', 'newpassword123'); + await page.fill('#current_password', fixtures.cred_password); + await page.fill('#password', 'purple-tiger-mountain-42'); + await page.fill('#confirm', 'purple-tiger-mountain-42'); await page.click('#password-section button[type="submit"]'); const status = page.locator('#password-section [role="status"]'); diff --git a/tests/e2e/full-flow.spec.js b/tests/e2e/full-flow.spec.js index 5d472f6..be797d2 100644 --- a/tests/e2e/full-flow.spec.js +++ b/tests/e2e/full-flow.spec.js @@ -30,8 +30,8 @@ test.describe('Full user journey', () => { await expect(passwordInput).toBeVisible(); await expect(confirmInput).toBeVisible(); - await passwordInput.fill('mypassword123'); - await confirmInput.fill('mypassword123'); + await passwordInput.fill('purple-tiger-mountain-42'); + await confirmInput.fill('purple-tiger-mountain-42'); await page.click('#password-section button[type="submit"]'); // Wait for success message @@ -51,7 +51,7 @@ test.describe('Full user journey', () => { // ---- Step 4: Login with the password we just set ---- await page.fill('#username', fixtures.register_username); - await page.fill('#password', 'mypassword123'); + await page.fill('#password', 'purple-tiger-mountain-42'); await page.click('form[hx-post="/login/password"] button[type="submit"]'); // Wait for redirect to credentials page