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/) }) })