feat: add testing infrastructure — Vitest, Playwright, CI, git hooks
Add comprehensive testing covering 420 unit/handler tests across 24 Vitest files, 9 Playwright E2E specs, accessibility scans, and visual regression. Includes GitHub Actions CI, Husky pre-push hook, and TESTING.md docs.
This commit is contained in:
parent
036af95e00
commit
1e30ba23cd
35 changed files with 3637 additions and 5 deletions
89
tests/server/api/event-registration.test.js
Normal file
89
tests/server/api/event-registration.test.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { describe, it, expect } from 'vitest'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const eventsDir = resolve(import.meta.dirname, '../../../server/api/events/[id]')
|
||||
|
||||
describe('register.post.js', () => {
|
||||
const source = readFileSync(resolve(eventsDir, 'register.post.js'), 'utf-8')
|
||||
|
||||
it('uses validateBody for input validation', () => {
|
||||
expect(source).toContain('validateBody(event')
|
||||
})
|
||||
|
||||
it('checks for duplicate registration with case-insensitive email', () => {
|
||||
expect(source).toContain('email.toLowerCase()')
|
||||
})
|
||||
|
||||
it('checks membersOnly restriction', () => {
|
||||
expect(source).toContain('membersOnly')
|
||||
})
|
||||
|
||||
it('checks capacity via maxAttendees', () => {
|
||||
expect(source).toContain('maxAttendees')
|
||||
})
|
||||
|
||||
it('does not let email failure block registration', () => {
|
||||
// The await call (not the import) must be wrapped in try/catch
|
||||
const emailCallIndex = source.indexOf('await sendEventRegistrationEmail')
|
||||
expect(emailCallIndex).toBeGreaterThan(-1)
|
||||
|
||||
// A try block immediately precedes the email call
|
||||
const precedingSource = source.slice(0, emailCallIndex)
|
||||
const lastTryIndex = precedingSource.lastIndexOf('try')
|
||||
expect(lastTryIndex).toBeGreaterThan(-1)
|
||||
|
||||
// The catch after the email call should log but not re-throw
|
||||
const afterEmail = source.slice(emailCallIndex)
|
||||
const catchBlock = afterEmail.match(/catch\s*\(\w+\)\s*\{[^}]*\}/s)
|
||||
expect(catchBlock).not.toBeNull()
|
||||
expect(catchBlock[0]).toContain('console.error')
|
||||
})
|
||||
})
|
||||
|
||||
describe('guest-register.post.js', () => {
|
||||
const source = readFileSync(resolve(eventsDir, 'guest-register.post.js'), 'utf-8')
|
||||
|
||||
it('uses validateBody for input validation', () => {
|
||||
expect(source).toContain('validateBody(event')
|
||||
})
|
||||
|
||||
it('checks membersOnly restriction with 403', () => {
|
||||
expect(source).toContain('membersOnly')
|
||||
expect(source).toContain('403')
|
||||
})
|
||||
|
||||
it('checks payment requirement with 402', () => {
|
||||
expect(source).toContain('paymentRequired')
|
||||
expect(source).toContain('402')
|
||||
})
|
||||
|
||||
it('checks capacity via maxAttendees', () => {
|
||||
expect(source).toContain('maxAttendees')
|
||||
})
|
||||
|
||||
it('does not require auth', () => {
|
||||
expect(source).not.toContain('requireAuth')
|
||||
})
|
||||
})
|
||||
|
||||
describe('cancel-registration.post.js', () => {
|
||||
const source = readFileSync(resolve(eventsDir, 'cancel-registration.post.js'), 'utf-8')
|
||||
|
||||
it('uses validateBody for input validation', () => {
|
||||
expect(source).toContain('validateBody(event')
|
||||
})
|
||||
|
||||
it('finds registration by email', () => {
|
||||
expect(source).toContain('email.toLowerCase()')
|
||||
})
|
||||
|
||||
it('notifies waitlist after cancellation', () => {
|
||||
expect(source).toContain('waitlist')
|
||||
expect(source).toContain('sendWaitlistNotificationEmail')
|
||||
})
|
||||
|
||||
it('does not require auth', () => {
|
||||
expect(source).not.toContain('requireAuth')
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue