feat(validation): rename contributionTier → contributionAmount in Zod schemas

This commit is contained in:
Jennie Robinson Faber 2026-04-19 18:16:47 +01:00
parent 55af652263
commit e4dade18b9
3 changed files with 49 additions and 35 deletions

View file

@ -9,7 +9,7 @@ export const memberCreateSchema = z.object({
email: z.string().trim().toLowerCase().email(),
name: z.string().min(1).max(200),
circle: z.enum(['community', 'founder', 'practitioner']),
contributionTier: z.enum(['0', '5', '15', '30', '50'])
contributionAmount: z.number().int().min(0)
})
export const memberProfileUpdateSchema = z.object({
@ -57,7 +57,7 @@ export const helcimCustomerSchema = z.object({
name: z.string().min(1).max(200),
email: z.string().trim().toLowerCase().email(),
circle: z.enum(['community', 'founder', 'practitioner']).optional(),
contributionTier: z.enum(['0', '5', '15', '30', '50']).optional(),
contributionAmount: z.number().int().min(0).optional(),
agreedToGuidelines: z.literal(true)
})
@ -73,7 +73,7 @@ export const helcimInitializePaymentSchema = z.object({
export const helcimSubscriptionSchema = z.object({
customerId: z.union([z.string().min(1), z.number()]),
contributionTier: z.enum(['0', '5', '15', '30', '50']),
contributionAmount: z.number().int().min(0),
customerCode: z.union([z.string().min(1).max(200), z.number()]).transform(String),
cardToken: z.string().max(500).optional().nullable(),
cadence: z.enum(['monthly', 'annual']).default('monthly')
@ -140,7 +140,7 @@ export const eventPaymentSchema = z.object({
// --- Member schemas ---
export const updateContributionSchema = z.object({
contributionTier: z.enum(['0', '5', '15', '30', '50']),
contributionAmount: z.number().int().min(0),
cadence: z.enum(['monthly', 'annual']).default('monthly')
})
@ -294,14 +294,14 @@ export const adminMemberCreateSchema = z.object({
name: z.string().min(1).max(200),
email: z.string().trim().toLowerCase().email(),
circle: z.enum(['community', 'founder', 'practitioner']),
contributionTier: z.enum(['0', '5', '15', '30', '50'])
contributionAmount: z.number().int().min(0)
})
export const adminMemberUpdateSchema = z.object({
name: z.string().min(1).max(200),
email: z.string().trim().toLowerCase().email(),
circle: z.enum(['community', 'founder', 'practitioner']),
contributionTier: z.enum(['0', '5', '15', '30', '50']),
contributionAmount: z.number().int().min(0),
status: z.enum(['pending_payment', 'active', 'suspended', 'cancelled'])
})
@ -314,7 +314,7 @@ export const bulkMemberImportSchema = z.object({
name: z.string().min(1).max(200),
email: z.string().trim().toLowerCase().email(),
circle: z.enum(['community', 'founder', 'practitioner']),
contributionTier: z.enum(['0', '5', '15', '30', '50'])
contributionAmount: z.number().int().min(0)
})).min(1).max(100)
})
@ -351,7 +351,7 @@ export const inviteAcceptSchema = z.object({
location: z.string().max(200).optional(),
circle: z.enum(['community', 'founder', 'practitioner']),
motivation: z.string().max(5000).optional(),
contributionTier: z.enum(['0', '5', '15', '30', '50']),
contributionAmount: z.number().int().min(0),
agreedToGuidelines: z.literal(true),
token: z.string().min(1)
})

View file

@ -138,16 +138,16 @@ describe('helcimSubscriptionSchema', () => {
it('accepts valid subscription data', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15',
contributionAmount: 15,
customerCode: 'CST123'
})
expect(result.success).toBe(true)
})
it('rejects invalid contribution tier', () => {
it('rejects negative contributionAmount', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '999',
contributionAmount: -1,
customerCode: 'CST123'
})
expect(result.success).toBe(false)
@ -156,7 +156,7 @@ describe('helcimSubscriptionSchema', () => {
it('rejects missing customerCode', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15'
contributionAmount: 15
})
expect(result.success).toBe(false)
})
@ -164,7 +164,7 @@ describe('helcimSubscriptionSchema', () => {
it('accepts cadence: monthly', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15',
contributionAmount: 15,
customerCode: 'CST123',
cadence: 'monthly'
})
@ -175,7 +175,7 @@ describe('helcimSubscriptionSchema', () => {
it('accepts cadence: annual', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15',
contributionAmount: 15,
customerCode: 'CST123',
cadence: 'annual'
})
@ -186,7 +186,7 @@ describe('helcimSubscriptionSchema', () => {
it('rejects cadence: weekly', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15',
contributionAmount: 15,
customerCode: 'CST123',
cadence: 'weekly'
})
@ -196,7 +196,7 @@ describe('helcimSubscriptionSchema', () => {
it('defaults cadence to monthly when omitted', () => {
const result = helcimSubscriptionSchema.safeParse({
customerId: '12345',
contributionTier: '15',
contributionAmount: 15,
customerCode: 'CST123'
})
expect(result.success).toBe(true)
@ -334,19 +334,26 @@ describe('eventPaymentSchema', () => {
// --- Member schemas ---
describe('updateContributionSchema', () => {
it('accepts valid contribution tier', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '15' })
it('accepts valid contributionAmount', () => {
const result = updateContributionSchema.safeParse({ contributionAmount: 15 })
expect(result.success).toBe(true)
})
it('rejects invalid tier', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '100' })
expect(result.success).toBe(false)
it('accepts contributionAmount: 0, 7, 9999', () => {
expect(updateContributionSchema.safeParse({ contributionAmount: 0 }).success).toBe(true)
expect(updateContributionSchema.safeParse({ contributionAmount: 7 }).success).toBe(true)
expect(updateContributionSchema.safeParse({ contributionAmount: 9999 }).success).toBe(true)
})
it('rejects invalid contributionAmount values', () => {
expect(updateContributionSchema.safeParse({ contributionAmount: -1 }).success).toBe(false)
expect(updateContributionSchema.safeParse({ contributionAmount: 1.5 }).success).toBe(false)
expect(updateContributionSchema.safeParse({ contributionAmount: '15' }).success).toBe(false)
})
it('strips unknown fields', () => {
const result = updateContributionSchema.safeParse({
contributionTier: '15',
contributionAmount: 15,
role: 'admin'
})
expect(result.success).toBe(true)
@ -354,24 +361,24 @@ describe('updateContributionSchema', () => {
})
it('accepts cadence: monthly', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '15', cadence: 'monthly' })
const result = updateContributionSchema.safeParse({ contributionAmount: 15, cadence: 'monthly' })
expect(result.success).toBe(true)
expect(result.data.cadence).toBe('monthly')
})
it('accepts cadence: annual', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '15', cadence: 'annual' })
const result = updateContributionSchema.safeParse({ contributionAmount: 15, cadence: 'annual' })
expect(result.success).toBe(true)
expect(result.data.cadence).toBe('annual')
})
it('rejects cadence: weekly', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '15', cadence: 'weekly' })
const result = updateContributionSchema.safeParse({ contributionAmount: 15, cadence: 'weekly' })
expect(result.success).toBe(false)
})
it('defaults cadence to monthly when omitted', () => {
const result = updateContributionSchema.safeParse({ contributionTier: '15' })
const result = updateContributionSchema.safeParse({ contributionAmount: 15 })
expect(result.success).toBe(true)
expect(result.data.cadence).toBe('monthly')
})
@ -425,7 +432,7 @@ describe('adminMemberCreateSchema', () => {
name: 'Admin Created',
email: 'admin-created@example.com',
circle: 'founder',
contributionTier: '30'
contributionAmount: 30
})
expect(result.success).toBe(true)
})
@ -435,7 +442,7 @@ describe('adminMemberCreateSchema', () => {
name: 'Admin Created',
email: 'admin-created@example.com',
circle: 'founder',
contributionTier: '30',
contributionAmount: 30,
role: 'admin'
})
expect(result.success).toBe(true)
@ -447,7 +454,7 @@ describe('adminMemberCreateSchema', () => {
name: 'Admin Created',
email: 'admin-created@example.com',
circle: 'founder',
contributionTier: '30',
contributionAmount: 30,
status: 'active'
})
expect(result.success).toBe(true)
@ -459,7 +466,7 @@ describe('adminMemberCreateSchema', () => {
name: 'Admin Created',
email: 'admin-created@example.com',
circle: 'superadmin',
contributionTier: '30'
contributionAmount: 30
})
expect(result.success).toBe(false)
})

View file

@ -42,7 +42,7 @@ describe('memberCreateSchema', () => {
email: 'new@example.com',
name: 'Test User',
circle: 'community',
contributionTier: '0'
contributionAmount: 0
}
it('accepts valid member data', () => {
@ -80,9 +80,16 @@ describe('memberCreateSchema', () => {
expect(result.success).toBe(false)
})
it('rejects invalid contributionTier enum', () => {
const result = memberCreateSchema.safeParse({ ...validMember, contributionTier: '999' })
expect(result.success).toBe(false)
it('accepts contributionAmount: 0, 7, 9999', () => {
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: 0 }).success).toBe(true)
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: 7 }).success).toBe(true)
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: 9999 }).success).toBe(true)
})
it('rejects invalid contributionAmount values', () => {
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: -1 }).success).toBe(false)
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: 1.5 }).success).toBe(false)
expect(memberCreateSchema.safeParse({ ...validMember, contributionAmount: '15' }).success).toBe(false)
})
it('rejects missing required fields', () => {
@ -246,7 +253,7 @@ describe('validateBody', () => {
it('strips unknown fields from output', async () => {
const event = createMockEvent({
method: 'POST',
body: { email: 'test@example.com', name: 'Test', circle: 'community', contributionTier: '0', role: 'admin', _id: 'fake' }
body: { email: 'test@example.com', name: 'Test', circle: 'community', contributionAmount: 0, role: 'admin', _id: 'fake' }
})
const data = await validateBody(event, memberCreateSchema)
expect(data).not.toHaveProperty('role')