admin/validation/eventWizard.test.ts

232 lines
7.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
ConsumerEventWizardStep2Validation,
EventWizardFaqFormValidation,
EventWizardStep1Validation,
EventWizardStep2Validation,
EventWizardStep3Validation,
} from '@/validation/eventWizard'
describe('event wizard validation', () => {
it('requires title, slug, and category on step 1', () => {
expect(EventWizardStep1Validation.safeParse({ title: '', slug: '', categoryId: '' }).success).toBe(false)
expect(
EventWizardStep1Validation.parse({
title: 'رویداد تست',
slug: 'test-event',
categoryId: '1',
shortDescription: '',
description: '',
})
).toMatchObject({ title: 'رویداد تست', slug: 'test-event', categoryId: '1' })
})
it('rejects invalid slug patterns', () => {
expect(
EventWizardStep1Validation.safeParse({
title: 'عنوان',
slug: 'Bad_Slug',
categoryId: '1',
}).success
).toBe(false)
})
it.each(['new', '462f10ff-7466-4a58-9631-d09f02b76eaf'])('rejects the reserved event slug %s', (slug) => {
expect(
EventWizardStep1Validation.safeParse({
title: 'عنوان',
slug,
categoryId: '1',
}).success
).toBe(false)
})
it('requires schedule and location on step 2 and enforces end after start', () => {
const base = {
startDate: '2026-07-19T00:00:00.000Z',
startTime: 600,
endDate: '2026-07-19T00:00:00.000Z',
endTime: 720,
cityId: '10',
address: 'تهران',
addressVisibility: 'public' as const,
}
expect(EventWizardStep2Validation.parse(base)).toMatchObject({ cityId: '10', address: 'تهران' })
expect(EventWizardStep2Validation.safeParse({ ...base, endTime: 600 }).success).toBe(false)
expect(EventWizardStep2Validation.safeParse({ ...base, cityId: '' }).success).toBe(false)
})
it('validates consumer step 2 without city selection (city comes from host profile)', () => {
const base = {
startDate: '2026-07-19T00:00:00.000Z',
startTime: 600,
endDate: '2026-07-19T00:00:00.000Z',
endTime: 720,
address: 'تهران',
addressVisibility: 'public' as const,
}
expect(ConsumerEventWizardStep2Validation.parse(base)).toMatchObject({ address: 'تهران' })
expect(ConsumerEventWizardStep2Validation.safeParse({ ...base, endTime: 600 }).success).toBe(false)
expect(ConsumerEventWizardStep2Validation.safeParse({ ...base, address: '' }).success).toBe(false)
})
it('requires generalArea when addressVisibility is attendees_only', () => {
const base = {
startDate: '2026-07-19T00:00:00.000Z',
startTime: 600,
endDate: '2026-07-19T00:00:00.000Z',
endTime: 720,
cityId: '10',
address: 'تهران',
}
expect(EventWizardStep2Validation.safeParse({ ...base, addressVisibility: 'attendees_only', generalArea: '' }).success).toBe(false)
expect(
EventWizardStep2Validation.safeParse({
...base,
addressVisibility: 'attendees_only',
generalArea: 'مشهد، خیابان هفت‌تیر',
}).success
).toBe(true)
const consumerBase = {
startDate: '2026-07-19T00:00:00.000Z',
startTime: 600,
endDate: '2026-07-19T00:00:00.000Z',
endTime: 720,
address: 'تهران',
}
expect(
ConsumerEventWizardStep2Validation.safeParse({
...consumerBase,
addressVisibility: 'attendees_only',
generalArea: '',
}).success
).toBe(false)
})
it('requires positive price for paid events and capacity of at least 1', () => {
expect(
EventWizardStep3Validation.parse({
isFree: true,
price: 0,
capacity: 20,
reservedCapacity: 0,
genderRestriction: 'open',
ageRestriction: 'open',
cancellationFeePercent: 0,
cancellationFeePercent12To24Hours: 0,
cancellationFeePercentMoreThan24Hours: 0,
isDiscoverable: true,
autoCreateGroup: true,
waitlistAutoOffer: true,
sendReviewRequestSms: false,
})
).toMatchObject({ isFree: true, price: 0, capacity: 20 })
expect(
EventWizardStep3Validation.safeParse({
isFree: false,
price: 0,
capacity: 20,
reservedCapacity: 0,
genderRestriction: 'open',
ageRestriction: 'open',
cancellationFeePercent: 0,
cancellationFeePercent12To24Hours: 0,
cancellationFeePercentMoreThan24Hours: 0,
isDiscoverable: true,
autoCreateGroup: true,
waitlistAutoOffer: true,
sendReviewRequestSms: false,
}).success
).toBe(false)
expect(
EventWizardStep3Validation.safeParse({
isFree: false,
price: 100000,
capacity: 0,
reservedCapacity: 0,
genderRestriction: 'open',
ageRestriction: 'open',
cancellationFeePercent: 0,
cancellationFeePercent12To24Hours: 0,
cancellationFeePercentMoreThan24Hours: 0,
isDiscoverable: true,
autoCreateGroup: true,
waitlistAutoOffer: true,
sendReviewRequestSms: false,
}).success
).toBe(false)
})
it('rejects unknown gender and age restriction values', () => {
const base = {
isFree: true,
price: 0,
capacity: 20,
reservedCapacity: 0,
genderRestriction: 'open',
ageRestriction: 'open',
cancellationFeePercent: 0,
cancellationFeePercent12To24Hours: 0,
cancellationFeePercentMoreThan24Hours: 0,
isDiscoverable: true,
autoCreateGroup: true,
waitlistAutoOffer: true,
sendReviewRequestSms: false,
}
expect(EventWizardStep3Validation.safeParse({ ...base, genderRestriction: 'women' }).success).toBe(false)
expect(EventWizardStep3Validation.safeParse({ ...base, ageRestriction: 'age_15_20' }).success).toBe(false)
expect(EventWizardStep3Validation.safeParse({ ...base, ageRestriction: 'age_15_19' }).success).toBe(true)
})
it('requires cancellation penalties to decrease as cancellation gets earlier', () => {
const base = {
isFree: false,
price: 100_000,
capacity: 20,
reservedCapacity: 0,
genderRestriction: 'open',
ageRestriction: 'open',
cancellationFeePercent: 30,
cancellationFeePercent12To24Hours: 20,
cancellationFeePercentMoreThan24Hours: 10,
isDiscoverable: true,
autoCreateGroup: true,
waitlistAutoOffer: true,
sendReviewRequestSms: false,
}
expect(EventWizardStep3Validation.safeParse(base).success).toBe(true)
expect(
EventWizardStep3Validation.safeParse({
...base,
cancellationFeePercentMoreThan24Hours: 25,
}).success
).toBe(false)
expect(
EventWizardStep3Validation.safeParse({
...base,
cancellationFeePercent: 0,
cancellationFeePercent12To24Hours: 0,
cancellationFeePercentMoreThan24Hours: 0,
}).success
).toBe(true)
})
it('requires both question and answer for FAQ rows', () => {
expect(EventWizardFaqFormValidation.safeParse({ question: '', answer: 'پاسخ' }).success).toBe(false)
expect(EventWizardFaqFormValidation.parse({ question: 'سوال؟', answer: 'پاسخ' })).toEqual({
question: 'سوال؟',
answer: 'پاسخ',
})
})
})