Files
fast-next-template/frontend/e2e/settings-navigation.spec.ts
Felipe Cardoso 10ff6a1a96 Add comprehensive E2E tests for settings pages (Profile, Password, Sessions)
- Implemented Playwright tests for profile settings, password change, and session management pages to validate user interactions, form handling, and navigation.
- Added `setupAuthenticatedMocks` helper to mock API interactions and improve test isolation.
- Verified edge cases like form validation, dirty states, session revocation, and navigation consistency.
2025-11-03 08:36:51 +01:00

162 lines
5.2 KiB
TypeScript

/**
* E2E Tests for Settings Navigation
* Tests navigation between different settings pages using mocked API
*/
import { test, expect } from '@playwright/test';
import { setupAuthenticatedMocks } from './helpers/auth';
test.describe('Settings Navigation', () => {
test.beforeEach(async ({ page }) => {
// Set up API mocks for authenticated user
await setupAuthenticatedMocks(page);
// Navigate to settings
await page.goto('/settings/profile');
await expect(page).toHaveURL('/settings/profile');
});
test('should display settings tabs', async ({ page }) => {
// Check all tabs are visible
await expect(page.locator('a:has-text("Profile")')).toBeVisible();
await expect(page.locator('a:has-text("Password")')).toBeVisible();
await expect(page.locator('a:has-text("Sessions")')).toBeVisible();
});
test('should highlight active tab', async ({ page }) => {
// Profile tab should be active (check for active styling)
const profileTab = page.locator('a:has-text("Profile")').first();
// Check if it has active state (could be via class or aria-current)
const hasActiveClass = await profileTab.evaluate((el) => {
return el.classList.contains('active') ||
el.getAttribute('aria-current') === 'page' ||
el.classList.contains('bg-muted') ||
el.getAttribute('data-state') === 'active';
});
expect(hasActiveClass).toBeTruthy();
});
test('should navigate from Profile to Password', async ({ page }) => {
// Click Password tab
const passwordTab = page.locator('a:has-text("Password")').first();
await Promise.all([
page.waitForURL('/settings/password', { timeout: 10000 }),
passwordTab.click(),
]);
await expect(page).toHaveURL('/settings/password');
await expect(page.locator('h2')).toContainText(/Change Password/i);
});
test('should navigate from Profile to Sessions', async ({ page }) => {
// Click Sessions tab
const sessionsTab = page.locator('a:has-text("Sessions")').first();
await Promise.all([
page.waitForURL('/settings/sessions', { timeout: 10000 }),
sessionsTab.click(),
]);
await expect(page).toHaveURL('/settings/sessions');
await expect(page.locator('h2')).toContainText(/Active Sessions/i);
});
test('should navigate from Password to Profile', async ({ page }) => {
// Go to password page first
await page.goto('/settings/password');
await expect(page).toHaveURL('/settings/password');
// Click Profile tab
const profileTab = page.locator('a:has-text("Profile")').first();
await Promise.all([
page.waitForURL('/settings/profile', { timeout: 10000 }),
profileTab.click(),
]);
await expect(page).toHaveURL('/settings/profile');
await expect(page.locator('h2')).toContainText(/Profile/i);
});
test('should navigate from Sessions to Password', async ({ page }) => {
// Go to sessions page first
await page.goto('/settings/sessions');
await expect(page).toHaveURL('/settings/sessions');
// Click Password tab
const passwordTab = page.locator('a:has-text("Password")').first();
await Promise.all([
page.waitForURL('/settings/password', { timeout: 10000 }),
passwordTab.click(),
]);
await expect(page).toHaveURL('/settings/password');
await expect(page.locator('h2')).toContainText(/Change Password/i);
});
test('should maintain layout when navigating between tabs', async ({ page }) => {
// Check header exists
await expect(page.locator('header')).toBeVisible();
// Navigate to different tabs
await page.goto('/settings/password');
await expect(page.locator('header')).toBeVisible();
await page.goto('/settings/sessions');
await expect(page.locator('header')).toBeVisible();
// Layout should be consistent
});
test('should have working back button navigation', async ({ page }) => {
// Navigate to password page
await page.goto('/settings/password');
await expect(page).toHaveURL('/settings/password');
// Go back
await page.goBack();
await expect(page).toHaveURL('/settings/profile');
// Go forward
await page.goForward();
await expect(page).toHaveURL('/settings/password');
});
test('should access settings from header dropdown', async ({ page }) => {
// Go to home page
await page.goto('/');
// Open user menu (avatar button)
const userMenuButton = page.locator('button[aria-label="User menu"], button:has([class*="avatar"])').first();
if (await userMenuButton.isVisible()) {
await userMenuButton.click();
// Click Settings option
const settingsLink = page.locator('a:has-text("Settings"), [role="menuitem"]:has-text("Settings")').first();
if (await settingsLink.isVisible()) {
await Promise.all([
page.waitForURL(/\/settings/, { timeout: 10000 }),
settingsLink.click(),
]);
// Should navigate to settings (probably profile as default)
await expect(page.url()).toMatch(/\/settings/);
}
}
});
test('should redirect /settings to /settings/profile', async ({ page }) => {
// Navigate to base settings URL
await page.goto('/settings');
// Should redirect to profile
await expect(page).toHaveURL('/settings/profile');
});
});