import { describe, expect, it } from 'vitest' import { EVENT_SENSITIVE_FIELDS, isEventEnded, isEventSlugLocked, isFieldLocked, resolveEventEditPolicy, } from '@/features/events/eventEditPolicy' describe('resolveEventEditPolicy', () => { it('allows full edits for draft events', () => { const policy = resolveEventEditPolicy('draft', 0) expect(policy).toMatchObject({ canEdit: true, hasActiveBookings: false, minCapacity: 1, lockBehavioralSettings: false, }) expect(policy.lockedFields.size).toBe(0) }) it('allows full edits for published events without bookings', () => { const policy = resolveEventEditPolicy('published', 0) expect(policy.canEdit).toBe(true) expect(policy.hasActiveBookings).toBe(false) expect(policy.minCapacity).toBe(1) expect(policy.lockedFields.size).toBe(0) expect(policy.lockBehavioralSettings).toBe(false) }) it('does not lock the public slug on live statuses (revision path)', () => { expect(isEventSlugLocked('draft')).toBe(false) expect(isEventSlugLocked('pending_review')).toBe(false) expect(isEventSlugLocked('published')).toBe(false) expect(isEventSlugLocked('full')).toBe(false) expect(isEventSlugLocked('completed')).toBe(true) }) it('floors capacity at booked plus reserved seats', () => { const policy = resolveEventEditPolicy('published', 2, 3) expect(policy.minCapacity).toBe(5) }) it('locks sensitive fields when a live event has active bookings', () => { const policy = resolveEventEditPolicy('published', 3) expect(policy).toMatchObject({ canEdit: true, hasActiveBookings: true, minCapacity: 3, lockBehavioralSettings: true, }) expect([...policy.lockedFields]).toEqual([...EVENT_SENSITIVE_FIELDS]) expect(isFieldLocked(policy, 'startsAt')).toBe(true) expect(isFieldLocked(policy, 'price')).toBe(true) expect(isFieldLocked(policy, 'cancellationFeePercent')).toBe(true) expect(isFieldLocked(policy, 'genderRestriction')).toBe(true) expect(isFieldLocked(policy, 'ageRestriction')).toBe(true) }) it('locks the same fields for full events with bookings', () => { const policy = resolveEventEditPolicy('full', 5) expect(policy.minCapacity).toBe(5) expect(policy.lockedFields.has('address')).toBe(true) }) it('blocks edits for terminal statuses', () => { for (const status of ['cancelled', 'completed']) { const policy = resolveEventEditPolicy(status, 2) expect(policy.canEdit).toBe(false) expect(policy.minCapacity).toBe(2) expect(policy.lockedFields.size).toBe(EVENT_SENSITIVE_FIELDS.length) } }) it('treats pending_review like draft for lock purposes', () => { const policy = resolveEventEditPolicy('pending_review', 0) expect(policy.canEdit).toBe(true) expect(policy.hasActiveBookings).toBe(false) expect(policy.lockedFields.size).toBe(0) }) }) describe('isEventEnded', () => { const future = new Date(Date.now() + 60 * 60 * 1000).toISOString() const past = new Date(Date.now() - 60 * 60 * 1000).toISOString() it('is true for terminal statuses even when endsAt is still in the future', () => { expect(isEventEnded('completed', future)).toBe(true) expect(isEventEnded('cancelled', future)).toBe(true) }) it('is true when endsAt has passed on a live event', () => { expect(isEventEnded('published', past)).toBe(true) }) it('is false for a live event that has not ended yet', () => { expect(isEventEnded('published', future)).toBe(false) }) })