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
85
tests/server/api/admin-auth-guards.test.js
Normal file
85
tests/server/api/admin-auth-guards.test.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { describe, it, expect } from 'vitest'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const adminDir = resolve(import.meta.dirname, '../../../server/api/admin')
|
||||
|
||||
// All admin routes grouped by directory
|
||||
const adminRoutes = {
|
||||
'admin/': [
|
||||
'dashboard.get.js',
|
||||
'events.get.js',
|
||||
'events.post.js',
|
||||
'members.get.js',
|
||||
'members.post.js',
|
||||
'series.get.js',
|
||||
'series.post.js',
|
||||
'series.put.js'
|
||||
],
|
||||
'admin/events/': [
|
||||
'events/[id].delete.js',
|
||||
'events/[id].get.js',
|
||||
'events/[id].put.js'
|
||||
],
|
||||
'admin/members/': [
|
||||
'members/[id].put.js',
|
||||
'members/[id]/role.patch.js',
|
||||
'members/import.post.js',
|
||||
'members/invite.post.js'
|
||||
],
|
||||
'admin/series/': [
|
||||
'series/[id].delete.js',
|
||||
'series/[id].put.js',
|
||||
'series/tickets.put.js'
|
||||
]
|
||||
}
|
||||
|
||||
// Business logic markers that must appear after requireAdmin
|
||||
const businessLogicPatterns = [
|
||||
'readBody(event)',
|
||||
'validateBody(event',
|
||||
'fetch(',
|
||||
'connectDB()',
|
||||
'Member.find',
|
||||
'Member.findOne',
|
||||
'Member.findById',
|
||||
'Member.countDocuments',
|
||||
'Event.find',
|
||||
'Event.findOne',
|
||||
'Event.findById',
|
||||
'Event.countDocuments',
|
||||
'Series.find',
|
||||
'Series.findOne',
|
||||
'Series.findById'
|
||||
]
|
||||
|
||||
describe('Admin endpoint auth guards', () => {
|
||||
for (const [group, files] of Object.entries(adminRoutes)) {
|
||||
describe(group, () => {
|
||||
for (const file of files) {
|
||||
describe(file, () => {
|
||||
const source = readFileSync(resolve(adminDir, file), 'utf-8')
|
||||
|
||||
it('calls requireAdmin', () => {
|
||||
expect(source).toContain('requireAdmin(event)')
|
||||
})
|
||||
|
||||
it('calls requireAdmin before any business logic', () => {
|
||||
const adminIndex = source.indexOf('requireAdmin(event)')
|
||||
expect(adminIndex).toBeGreaterThan(-1)
|
||||
|
||||
for (const pattern of businessLogicPatterns) {
|
||||
const patternIndex = source.indexOf(pattern)
|
||||
if (patternIndex > -1) {
|
||||
expect(
|
||||
adminIndex,
|
||||
`requireAdmin must appear before ${pattern} in ${file}`
|
||||
).toBeLessThan(patternIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue