fix(a11y,test): USelect placeholder contrast + auth logout hydration wait

a11y (main.css):
- Nuxt UI's default placeholder color (text-dimmed = #a6a09b) failed WCAG
  AA contrast on cream (2.43:1) and white (2.58:1) backgrounds, blocking
  axe checks on /member/profile (timezone) and /admin/events/create
  (tags). Override [data-slot="placeholder"] globally to var(--text-dim)
  (#5a5040), comfortably above 4.5:1 on both surfaces.

auth.spec.js (logout):
- Same hydration race as the board/admin-board-channels click tests:
  /admin's sidebar Sign-out @click handler isn't bound when Playwright
  fires the click immediately after admin-tag visibility, so the click
  no-ops and waitForResponse for /api/auth/logout times out.
- Add waitForLoadState('networkidle') after goto so hydration completes
  before the click.
This commit is contained in:
Jennie Robinson Faber 2026-04-26 18:30:32 +01:00
parent bb0dbfe53e
commit 521efb0890
2 changed files with 9 additions and 0 deletions

View file

@ -273,6 +273,14 @@ p a, blockquote a {
min-width: 0; min-width: 0;
} }
/* ---- Nuxt UI placeholder contrast ----
Default Nuxt UI placeholder uses `text-dimmed` (#a6a09b) which fails WCAG
AA on cream and white backgrounds (2.4:1). Override globally to --text-dim
so USelect/USelectMenu placeholders meet the 4.5:1 ratio. */
[data-slot="placeholder"] {
color: var(--text-dim);
}
/* ---- SHARED USelectMenu STYLES ---- /* ---- SHARED USelectMenu STYLES ----
Apply via: <USelectMenu class="zine-select" :ui="{ content: 'tz-content', item: 'tz-item', input: 'tz-input' }" /> Apply via: <USelectMenu class="zine-select" :ui="{ content: 'tz-content', item: 'tz-item', input: 'tz-input' }" />
Classes are global (not scoped) because Nuxt UI portals the popup content to body. */ Classes are global (not scoped) because Nuxt UI portals the popup content to body. */

View file

@ -44,6 +44,7 @@ test.describe('Authentication flows', () => {
test('logout clears auth', async ({ page }) => { test('logout clears auth', async ({ page }) => {
await loginAsAdmin(page) await loginAsAdmin(page)
await page.goto('/admin') await page.goto('/admin')
await page.waitForLoadState('networkidle')
await expect(page.locator('.admin-tag')).toBeVisible({ timeout: 15000 }) await expect(page.locator('.admin-tag')).toBeVisible({ timeout: 15000 })
// Set up response listener BEFORE clicking to avoid race // Set up response listener BEFORE clicking to avoid race