merge: worktree-a11y-fixes into main
Some checks failed
Test / vitest (push) Successful in 12m45s
Test / playwright (push) Failing after 10m5s
Test / visual (push) Failing after 9m16s

Accessibility fixes (aria-labels, color contrast, html lang, inline link
underlines), atomic dev login endpoints, and E2E test hardening.
This commit is contained in:
Jennie Robinson Faber 2026-04-05 22:04:54 +01:00
commit bab53cec9e
31 changed files with 792 additions and 162 deletions

View file

@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
vi.mock('../../../server/models/member.js', () => ({
default: { findOne: vi.fn(), create: vi.fn() }
default: { findOne: vi.fn(), create: vi.fn(), findOneAndUpdate: vi.fn() }
}))
vi.mock('../../../server/utils/mongoose.js', () => ({
@ -49,15 +49,15 @@ describe('dev endpoints', () => {
it('test-login.get.js first conditional is NODE_ENV production check', () => {
const source = readFileSync(resolve(devDir, 'test-login.get.js'), 'utf-8')
const handlerBody = source.slice(source.indexOf('defineEventHandler'))
const firstIf = handlerBody.match(/if\s*\([^)]+\)/)?.[0]
expect(firstIf).toContain("process.env.NODE_ENV === 'production'")
const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0]
expect(firstIf).toContain('process.env.NODE_ENV === "production"')
})
it('member-login.get.js first conditional is NODE_ENV production check', () => {
const source = readFileSync(resolve(devDir, 'member-login.get.js'), 'utf-8')
const handlerBody = source.slice(source.indexOf('defineEventHandler'))
const firstIf = handlerBody.match(/if\s*\([^)]+\)/)?.[0]
expect(firstIf).toContain("process.env.NODE_ENV === 'production'")
const firstIf = handlerBody.match(/if\s*\([\s\S]*?\)\s*\{/)?.[0]
expect(firstIf).toContain('process.env.NODE_ENV === "production"')
})
})
@ -74,34 +74,38 @@ describe('dev endpoints', () => {
})
it('creates admin user when none exists', async () => {
Member.findOne.mockResolvedValue(null)
Member.create.mockResolvedValue(mockMember)
Member.findOneAndUpdate.mockResolvedValue(mockMember)
const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
await testLoginHandler(event)
expect(Member.findOne).toHaveBeenCalledWith({ email: 'test-admin@ghostguild.dev' })
expect(Member.create).toHaveBeenCalledWith(
expect(Member.findOneAndUpdate).toHaveBeenCalledWith(
{ email: 'test-admin@ghostguild.dev' },
expect.objectContaining({
email: 'test-admin@ghostguild.dev',
role: 'admin',
circle: 'founder'
})
$setOnInsert: expect.objectContaining({
role: 'admin',
circle: 'founder'
})
}),
{ upsert: true, new: true }
)
})
it('uses existing admin when found', async () => {
Member.findOne.mockResolvedValue(mockMember)
Member.findOneAndUpdate.mockResolvedValue(mockMember)
const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
await testLoginHandler(event)
expect(Member.findOne).toHaveBeenCalledWith({ email: 'test-admin@ghostguild.dev' })
expect(Member.create).not.toHaveBeenCalled()
expect(Member.findOneAndUpdate).toHaveBeenCalledWith(
{ email: 'test-admin@ghostguild.dev' },
expect.any(Object),
{ upsert: true, new: true }
)
})
it('sets auth cookie', async () => {
Member.findOne.mockResolvedValue(mockMember)
Member.findOneAndUpdate.mockResolvedValue(mockMember)
const event = createMockEvent({ method: 'GET', path: '/api/dev/test-login' })
await testLoginHandler(event)