Files
fast-next-template/frontend/e2e/auth-password-reset.spec.ts
Felipe Cardoso 7b1bea2966 Refactor i18n integration and update tests for improved localization
- Updated test components (`PasswordResetConfirmForm`, `PasswordChangeForm`) to use i18n keys directly, ensuring accurate validation messages.
- Refined translations in `it.json` to standardize format and content.
- Replaced text-based labels with localized strings in `PasswordResetRequestForm` and `RegisterForm`.
- Introduced `generateLocalizedMetadata` utility and updated layout metadata generation for locale-aware SEO.
- Enhanced e2e tests with locale-prefixed routes and updated assertions for consistency.
- Added comprehensive i18n documentation (`I18N.md`) for usage, architecture, and testing.
2025-11-19 14:07:13 +01:00

238 lines
8.9 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Password Reset Request Flow', () => {
test.beforeEach(async ({ page }) => {
// Navigate to password reset page
await page.goto('/en/password-reset');
});
test('should display password reset request form', async ({ page }) => {
// Check page title
await expect(page.locator('h2')).toContainText('Reset your password');
// Check form elements
await expect(page.locator('input[name="email"]')).toBeVisible();
await expect(page.locator('button[type="submit"]')).toBeVisible();
// Check back to login link
await expect(page.getByRole('link', { name: 'Back to login' })).toBeVisible();
});
test('should show validation error for empty email', async ({ page }) => {
// Click submit without filling form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(1000);
// Should stay on password reset page (validation failed)
// URL might have query params, so use regex
await expect(page).toHaveURL(/\/en\/password-reset/);
});
test('should show validation error for invalid email', async ({ page }) => {
// Fill invalid email
await page.locator('input[name="email"]').fill('invalid-email');
// Submit form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(1000);
// Should stay on password reset page (validation failed)
await expect(page).toHaveURL('/en/password-reset');
});
test('should successfully submit password reset request', async ({ page }) => {
// Fill valid email
await page.locator('input[name="email"]').fill('test@example.com');
// Submit form
await page.locator('button[type="submit"]').click();
// Wait for success message (will likely fail without backend, that's ok)
await page.waitForTimeout(2000);
});
test('should navigate back to login page', async ({ page }) => {
// Click back to login link - use Promise.all to wait for navigation
const loginLink = page.getByRole('link', { name: 'Back to login' });
await Promise.all([page.waitForURL('/en/login'), loginLink.click()]);
// Should be on login page
await expect(page).toHaveURL('/en/login');
await expect(page.locator('h2')).toContainText('Sign in to your account');
});
test('should disable submit button while loading', async ({ page }) => {
// Fill form
await page.locator('input[name="email"]').fill('test@example.com');
const submitButton = page.locator('button[type="submit"]');
// Submit form
await submitButton.click();
await page.waitForTimeout(100);
// Check button state
const isDisabled = await submitButton.isDisabled().catch(() => false);
const buttonText = await submitButton.textContent();
// Accept either disabled state or loading text
expect(isDisabled || buttonText?.toLowerCase().includes('send')).toBeTruthy();
});
});
test.describe('Password Reset Confirm Flow', () => {
test('should display error for missing token', async ({ page }) => {
// Navigate without token
await page.goto('/en/password-reset/confirm');
// Should show error message
await expect(page.locator('h2')).toContainText(/Invalid/i);
// Should show link to request new reset - use specific link selector
await expect(page.getByRole('link', { name: 'Request new reset link' })).toBeVisible();
});
test('should display password reset confirm form with valid token', async ({ page }) => {
// Navigate with token (using a dummy token for UI testing)
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
// Check page title
await expect(page.locator('h2')).toContainText('Set new password');
// Check form elements
await expect(page.locator('input[name="new_password"]')).toBeVisible();
await expect(page.locator('input[name="confirm_password"]')).toBeVisible();
await expect(page.locator('button[type="submit"]')).toBeVisible();
});
test('should show validation errors for empty form', async ({ page }) => {
// Navigate with token
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
// Click submit without filling form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(1000);
// Should stay on password reset confirm page (validation failed)
await expect(page).toHaveURL(/\/en\/password-reset\/confirm/);
});
test('should show validation error for weak password', async ({ page }) => {
// Navigate with token
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
// Fill with weak password
await page.locator('input[name="new_password"]').fill('weak');
await page.locator('input[name="confirm_password"]').fill('weak');
// Submit form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(1000);
// Should stay on password reset confirm page (validation failed)
await expect(page).toHaveURL(/\/en\/password-reset\/confirm/);
});
test('should show validation error for mismatched passwords', async ({ page }) => {
// Navigate with token
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
// Fill with mismatched passwords
await page.locator('input[name="new_password"]').fill('Password123!');
await page.locator('input[name="confirm_password"]').fill('DifferentPassword123!');
// Submit form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(1000);
// Should stay on password reset confirm page (validation failed)
await expect(page).toHaveURL(/\/en\/password-reset\/confirm/);
});
test('should show error for invalid token', async ({ page }) => {
// Navigate with invalid token
await page.goto('/en/password-reset/confirm?token=invalid-token');
// Fill form with valid passwords
await page.locator('input[name="new_password"]').fill('NewPassword123!');
await page.locator('input[name="confirm_password"]').fill('NewPassword123!');
// Submit form
await page.locator('button[type="submit"]').click();
await page.waitForTimeout(2000);
// Without backend, just verify form is still functional
const currentUrl = page.url();
expect(currentUrl).toBeTruthy();
});
test('should successfully reset password with valid token', async ({ page }) => {
// Note: This test requires a valid reset token from backend
// In real scenario, you'd generate a token via API or use a test fixture
// For UI testing, we use a dummy token - backend will reject it
await page.goto('/en/password-reset/confirm?token=valid-test-token-from-backend');
// Fill form with valid passwords
await page.locator('input[name="new_password"]').fill('NewPassword123!');
await page.locator('input[name="confirm_password"]').fill('NewPassword123!');
// Submit form
await page.locator('button[type="submit"]').click();
// With a real token, should show success and redirect to login
// Without backend or valid token, will show error
await page.waitForTimeout(2000);
});
test('should navigate to request new reset link', async ({ page }) => {
// Navigate without token to trigger error state
await page.goto('/en/password-reset/confirm');
// Click request new reset link - use Promise.all to wait for navigation
const resetLink = page.getByRole('link', { name: 'Request new reset link' });
await Promise.all([page.waitForURL('/en/password-reset'), resetLink.click()]);
// Should be on password reset request page
await expect(page).toHaveURL('/en/password-reset');
await expect(page.locator('h2')).toContainText('Reset your password');
});
test('should toggle password visibility', async ({ page }) => {
// Navigate with token
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
const passwordInput = page.locator('input[name="new_password"]');
const confirmPasswordInput = page.locator('input[name="confirm_password"]');
// Passwords should start as hidden
await expect(passwordInput).toHaveAttribute('type', 'password');
await expect(confirmPasswordInput).toHaveAttribute('type', 'password');
// Note: If password toggle is implemented, test it here
});
test('should disable submit button while loading', async ({ page }) => {
// Navigate with token
await page.goto('/en/password-reset/confirm?token=dummy-test-token-123');
// Fill form
await page.locator('input[name="new_password"]').fill('NewPassword123!');
await page.locator('input[name="confirm_password"]').fill('NewPassword123!');
const submitButton = page.locator('button[type="submit"]');
// Submit form and verify it exists and can be clicked
await expect(submitButton).toBeVisible();
await submitButton.click();
// Wait for any response
await page.waitForTimeout(2000);
// Verify page is still functional (doesn't crash)
expect(page.url()).toBeTruthy();
});
});