Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
190 lines
5.9 KiB
TypeScript
190 lines
5.9 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,
|
|
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,
|
|
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,
|
|
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,
|
|
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 both question and answer for FAQ rows', () => {
|
|
expect(EventWizardFaqFormValidation.safeParse({ question: '', answer: 'پاسخ' }).success).toBe(false)
|
|
expect(EventWizardFaqFormValidation.parse({ question: 'سوال؟', answer: 'پاسخ' })).toEqual({
|
|
question: 'سوال؟',
|
|
answer: 'پاسخ',
|
|
})
|
|
})
|
|
})
|