99 lines
4.3 KiB
JavaScript
99 lines
4.3 KiB
JavaScript
// @ts-check
|
|
import { test, expect } from '@playwright/test';
|
|
import { loadTestUser } from '../utils/testUser.js';
|
|
|
|
test.describe('@p0 Profile — ChangePasswordForm submit', () => {
|
|
test.setTimeout(20000);
|
|
|
|
test('success path closes the form; 429 path shows error and stays open', async ({ page }) => {
|
|
const u = loadTestUser();
|
|
|
|
// First POST => 200; second => 429 (no endpoint guessing needed)
|
|
let calls = 0;
|
|
await page.route('**/api/**password**', async (route) => {
|
|
calls += 1;
|
|
if (calls === 1) return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
|
if (calls === 2) return route.fulfill({ status: 429, contentType: 'application/json', body: JSON.stringify({ error: 'Too many attempts' }) });
|
|
return route.fallback();
|
|
});
|
|
|
|
// Sign in (your existing flow)
|
|
await page.context().clearCookies();
|
|
await page.goto('/signin', { waitUntil: 'networkidle' });
|
|
await page.getByPlaceholder('Username', { exact: true }).fill(u.username);
|
|
await page.getByPlaceholder('Password', { exact: true }).fill(u.password);
|
|
await page.getByRole('button', { name: /^Sign In$/ }).click();
|
|
await page.waitForURL('**/signin-landing**', { timeout: 15000 });
|
|
|
|
await page.goto('/profile', { waitUntil: 'networkidle' });
|
|
|
|
// If already open, close to make deterministic
|
|
const cancelIfOpen = page.getByRole('button', { name: /^Cancel password change$/i });
|
|
if (await cancelIfOpen.isVisible().catch(() => false)) {
|
|
await cancelIfOpen.click();
|
|
await expect(cancelIfOpen).toBeHidden({ timeout: 5000 });
|
|
}
|
|
|
|
// Open (use exact text; fresh locator)
|
|
await page.getByRole('button', { name: /^Change Password$/i }).click();
|
|
|
|
// 3 password inputs: current / new / confirm
|
|
const pwInputs = page.locator('input[type="password"]');
|
|
await expect(pwInputs.first()).toBeVisible({ timeout: 5000 });
|
|
|
|
// 1) Success submit — form should close
|
|
await pwInputs.nth(0).fill('OldPass!1');
|
|
await pwInputs.nth(1).fill('NewPass!1');
|
|
await pwInputs.nth(2).fill('NewPass!1');
|
|
const submit = page.getByRole('button', { name: /^Update Password$/i });
|
|
await submit.click();
|
|
|
|
// Form closes => Update button disappears
|
|
await expect(submit).toBeHidden({ timeout: 7000 });
|
|
|
|
// Reopen deterministically (works whether trigger is a button or link,
|
|
// or if the section needs a refresh)
|
|
async function reopenChangePassword(page) {
|
|
// If somehow still open, close first
|
|
const update = page.getByRole('button', { name: /^Update Password$/i }).first();
|
|
if (await update.isVisible().catch(() => false)) {
|
|
const cancel = page.getByRole('button', { name: /^Cancel password change$/i }).first();
|
|
if (await cancel.isVisible().catch(() => false)) {
|
|
await cancel.click();
|
|
await expect(update).toBeHidden({ timeout: 7000 });
|
|
}
|
|
}
|
|
// Try common triggers
|
|
const triggers = [
|
|
page.getByRole('button', { name: /^Change Password$/i }).first(),
|
|
page.getByRole('link', { name: /^Change Password$/i }).first(),
|
|
page.locator('text=Change Password').first(),
|
|
];
|
|
for (const t of triggers) {
|
|
if (await t.isVisible().catch(() => false)) { await t.click(); return; }
|
|
}
|
|
// Fallback: reload the page section and try once more
|
|
await page.goto('/profile', { waitUntil: 'networkidle' });
|
|
for (const t of triggers) {
|
|
if (await t.isVisible().catch(() => false)) { await t.click(); return; }
|
|
}
|
|
throw new Error('Could not find Change Password trigger after success submit');
|
|
}
|
|
await reopenChangePassword(page);
|
|
|
|
await pwInputs.nth(0).fill('OldPass!1');
|
|
await pwInputs.nth(1).fill('NewPass!2');
|
|
await pwInputs.nth(2).fill('NewPass!2');
|
|
await page.getByRole('button', { name: /^Update Password$/i }).click();
|
|
|
|
// For 429: either see an error, OR the form remains open (Update/Cancel still visible)
|
|
const errText = page.getByText(/too many attempts|please wait|try again/i);
|
|
const sawError = await errText.isVisible({ timeout: 3000 }).catch(() => false);
|
|
const stillOpen =
|
|
(await page.getByRole('button', { name: /^Update Password$/i }).isVisible().catch(() => false)) ||
|
|
(await page.getByRole('button', { name: /^Cancel password change$/i }).isVisible().catch(() => false));
|
|
|
|
expect(sawError || stillOpen).toBeTruthy();
|
|
});
|
|
});
|