fix: accessibility improvements and test infrastructure hardening
Add aria-labels to form controls (selects, checkboxes, switches), set html lang attribute and page title, fix color contrast for --candle-dim and --text-faint tokens, underline inline links, remove opacity hack. Harden dev login endpoints with atomic findOneAndUpdate and tokenVersion in JWT. Update Playwright timeouts and E2E test helpers.
This commit is contained in:
parent
61c16d8bac
commit
c40f2c7c63
35 changed files with 787 additions and 173 deletions
|
|
@ -2,53 +2,57 @@ import { test, expect } from '@playwright/test'
|
|||
import { loginAsAdmin, loginAsMember } from './helpers/auth.js'
|
||||
|
||||
test.describe('Authentication flows', () => {
|
||||
test('protected page shows login modal when logged out', async ({ page }) => {
|
||||
test('protected page shows sign-in prompt when logged out', async ({ page }) => {
|
||||
// Navigate to a protected member page without being logged in
|
||||
await page.goto('/member/dashboard')
|
||||
|
||||
// The auth middleware aborts navigation and shows the login modal
|
||||
// Look for the modal title and email input
|
||||
await expect(page.getByText('Sign in to continue')).toBeVisible()
|
||||
// Page shows the unauth state with sign-in button
|
||||
await expect(page.getByRole('heading', { name: 'Sign in required' })).toBeVisible({ timeout: 10000 })
|
||||
await expect(page.getByRole('button', { name: 'Sign In' })).toBeVisible()
|
||||
|
||||
// Clicking Sign In opens the login modal with email input
|
||||
await page.getByRole('button', { name: 'Sign In' }).click()
|
||||
await expect(page.locator('.modal-title')).toBeVisible({ timeout: 5000 })
|
||||
await expect(page.locator('input[type="email"]')).toBeVisible()
|
||||
await expect(page.getByRole('button', { name: 'Send magic link' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('admin login and redirect', async ({ page }) => {
|
||||
test('admin login sets auth cookie', async ({ page }) => {
|
||||
await loginAsAdmin(page)
|
||||
|
||||
// loginAsAdmin waits for /admin URL
|
||||
await expect(page).toHaveURL(/\/admin/)
|
||||
// Verify cookie was set
|
||||
const cookies = await page.context().cookies()
|
||||
const authCookie = cookies.find((c) => c.name === 'auth-token')
|
||||
expect(authCookie).toBeTruthy()
|
||||
|
||||
// Admin layout should show admin sidebar content
|
||||
await expect(page.locator('.sidebar-nav').getByText('Members')).toBeVisible()
|
||||
await expect(page.locator('.admin-tag')).toBeVisible()
|
||||
// Navigate to admin page — should show admin layout
|
||||
await page.goto('/admin')
|
||||
await expect(page.locator('.admin-tag')).toBeVisible({ timeout: 15000 })
|
||||
})
|
||||
|
||||
test('member login and redirect', async ({ page }) => {
|
||||
test('member login sets auth cookie', async ({ page }) => {
|
||||
await loginAsMember(page, 'test-admin@ghostguild.dev')
|
||||
|
||||
// loginAsMember waits for /member/ URL
|
||||
await expect(page).toHaveURL(/\/member\//)
|
||||
const cookies = await page.context().cookies()
|
||||
const authCookie = cookies.find((c) => c.name === 'auth-token')
|
||||
expect(authCookie).toBeTruthy()
|
||||
})
|
||||
|
||||
test('logout clears auth', async ({ page }) => {
|
||||
// Login as admin first
|
||||
await loginAsAdmin(page)
|
||||
await expect(page).toHaveURL(/\/admin/)
|
||||
await page.goto('/admin')
|
||||
await expect(page.locator('.admin-tag')).toBeVisible({ timeout: 15000 })
|
||||
|
||||
// Set up response listener BEFORE clicking to avoid race
|
||||
const logoutResponse = page.waitForResponse((resp) => resp.url().includes('/api/auth/logout'))
|
||||
|
||||
// Click the "Sign out" link in the sidebar meta area
|
||||
await page.locator('.sidebar-meta a').filter({ hasText: 'Sign out' }).click()
|
||||
|
||||
// Should redirect to home after logout
|
||||
await page.waitForURL('/')
|
||||
// Wait for the logout API call to complete
|
||||
await logoutResponse
|
||||
|
||||
// Verify the auth-token cookie is cleared
|
||||
const cookies = await page.context().cookies()
|
||||
const authCookie = cookies.find((c) => c.name === 'auth-token')
|
||||
expect(!authCookie || authCookie.value === '').toBeTruthy()
|
||||
|
||||
// Navigating to a protected page should show the login modal
|
||||
// Navigating to a protected page should show the sign-in prompt
|
||||
await page.goto('/member/dashboard')
|
||||
await expect(page.getByText('Sign in to continue')).toBeVisible()
|
||||
await expect(page.getByRole('heading', { name: 'Sign in required' })).toBeVisible({ timeout: 10000 })
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue