Adds schema-based input validation across helcim, events, members, series, admin, and updates API endpoints. Removes the peer-support debug test endpoint. Adds validation test coverage.
61 lines
2.1 KiB
JavaScript
61 lines
2.1 KiB
JavaScript
import { describe, it, expect } from 'vitest'
|
|
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
|
|
const createPostPath = resolve(
|
|
import.meta.dirname,
|
|
'../../../server/api/members/create.post.js'
|
|
)
|
|
|
|
describe('members/create.post.js response projection', () => {
|
|
const source = readFileSync(createPostPath, 'utf-8')
|
|
|
|
it('does NOT return the raw member object', () => {
|
|
// The old pattern: `return { success: true, member }`
|
|
// should be replaced with an explicit projection
|
|
expect(source).not.toMatch(/return\s*\{\s*success:\s*true,\s*member\s*\}/)
|
|
})
|
|
|
|
it('returns explicit member projection with id', () => {
|
|
expect(source).toContain('member._id')
|
|
})
|
|
|
|
it('returns explicit member projection with email', () => {
|
|
expect(source).toContain('member.email')
|
|
})
|
|
|
|
it('returns explicit member projection with name', () => {
|
|
expect(source).toContain('member.name')
|
|
})
|
|
|
|
it('returns explicit member projection with circle', () => {
|
|
expect(source).toContain('member.circle')
|
|
})
|
|
|
|
it('returns explicit member projection with status', () => {
|
|
expect(source).toContain('member.status')
|
|
})
|
|
|
|
it('does NOT expose helcimCustomerId in response', () => {
|
|
// helcimCustomerId should not appear in any return statement projection
|
|
// (it's OK if it appears elsewhere, e.g. in DB queries)
|
|
const returnBlocks = source.match(/return\s*\{[\s\S]*?\n\s*\}/g) || []
|
|
const successReturn = returnBlocks.find(b => b.includes('success: true'))
|
|
if (successReturn) {
|
|
expect(successReturn).not.toContain('helcimCustomerId')
|
|
}
|
|
})
|
|
|
|
it('does NOT expose role in response projection', () => {
|
|
const returnBlocks = source.match(/return\s*\{[\s\S]*?\n\s*\}/g) || []
|
|
const successReturn = returnBlocks.find(b => b.includes('success: true'))
|
|
if (successReturn) {
|
|
expect(successReturn).not.toContain('role')
|
|
}
|
|
})
|
|
|
|
it('does NOT forward error.message to client in catch block', () => {
|
|
// The outer catch should not use error.message as statusMessage
|
|
expect(source).not.toMatch(/statusMessage:\s*error\.message/)
|
|
})
|
|
})
|