cms.c2sgmbh/tests/unit/youtube/conflict-detection.unit.spec.ts
Martin Porwoll 2466745e7f feat(youtube): add conflict detection service
Detect scheduling conflicts in the content calendar including same-day
longform collisions, weekly frequency limit violations, and weekend
scheduling warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:50:24 +00:00

152 lines
5.8 KiB
TypeScript

/**
* Conflict Detection Service Unit Tests
*
* Tests scheduling conflict detection for same-day collisions,
* weekly frequency limits, and weekend warnings.
*/
import { describe, it, expect } from 'vitest'
import { detectConflicts, type CalendarEvent } from '@/lib/youtube/ConflictDetectionService'
const defaultSchedule = { longformPerWeek: 1, shortsPerWeek: 4 }
describe('ConflictDetectionService', () => {
describe('same-day conflicts', () => {
it('should detect two longform videos on the same day for the same channel', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-03', contentType: 'longform' },
{ id: 2, channelId: 1, scheduledDate: '2026-03-03', contentType: 'longform' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const sameDay = conflicts.find((c) => c.type === 'same_day')
expect(sameDay).toBeDefined()
expect(sameDay!.severity).toBe('error')
expect(sameDay!.eventIds).toContain(1)
expect(sameDay!.eventIds).toContain(2)
})
it('should not flag conflicts for different channels on the same day', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-03', contentType: 'longform' },
{ id: 2, channelId: 2, scheduledDate: '2026-03-03', contentType: 'longform' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const sameDayConflicts = conflicts.filter((c) => c.type === 'same_day')
expect(sameDayConflicts).toHaveLength(0)
})
it('should not flag shorts on the same day as a same-day conflict', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-03', contentType: 'short' },
{ id: 2, channelId: 1, scheduledDate: '2026-03-03', contentType: 'short' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const sameDayConflicts = conflicts.filter((c) => c.type === 'same_day')
expect(sameDayConflicts).toHaveLength(0)
})
})
describe('weekly frequency', () => {
it('should detect weekly frequency exceeded for longform', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-02', contentType: 'longform' },
{ id: 2, channelId: 1, scheduledDate: '2026-03-04', contentType: 'longform' },
{ id: 3, channelId: 1, scheduledDate: '2026-03-06', contentType: 'longform' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const frequency = conflicts.find((c) => c.type === 'frequency_exceeded')
expect(frequency).toBeDefined()
expect(frequency!.severity).toBe('warning')
expect(frequency!.eventIds).toHaveLength(3)
})
it('should detect weekly frequency exceeded for shorts', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-02', contentType: 'short' },
{ id: 2, channelId: 1, scheduledDate: '2026-03-03', contentType: 'short' },
{ id: 3, channelId: 1, scheduledDate: '2026-03-04', contentType: 'short' },
{ id: 4, channelId: 1, scheduledDate: '2026-03-05', contentType: 'short' },
{ id: 5, channelId: 1, scheduledDate: '2026-03-06', contentType: 'short' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const frequency = conflicts.find(
(c) => c.type === 'frequency_exceeded' && c.message.includes('Shorts'),
)
expect(frequency).toBeDefined()
expect(frequency!.eventIds).toHaveLength(5)
})
it('should not flag frequency when within limits', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-02', contentType: 'longform' },
]
const conflicts = detectConflicts(events, defaultSchedule)
const frequencyConflicts = conflicts.filter((c) => c.type === 'frequency_exceeded')
expect(frequencyConflicts).toHaveLength(0)
})
})
describe('weekend warnings', () => {
it('should detect weekend scheduling on Saturday', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-07', contentType: 'longform' },
]
const conflicts = detectConflicts(events, { longformPerWeek: 2, shortsPerWeek: 7 })
const weekend = conflicts.find((c) => c.type === 'weekend')
expect(weekend).toBeDefined()
expect(weekend!.severity).toBe('warning')
})
it('should detect weekend scheduling on Sunday', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-08', contentType: 'short' },
]
const conflicts = detectConflicts(events, { longformPerWeek: 2, shortsPerWeek: 7 })
const weekend = conflicts.find((c) => c.type === 'weekend')
expect(weekend).toBeDefined()
})
it('should not flag weekday scheduling', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-02', contentType: 'longform' },
]
const conflicts = detectConflicts(events, { longformPerWeek: 2, shortsPerWeek: 7 })
const weekendConflicts = conflicts.filter((c) => c.type === 'weekend')
expect(weekendConflicts).toHaveLength(0)
})
})
describe('edge cases', () => {
it('should return no conflicts for an empty event list', () => {
const conflicts = detectConflicts([], defaultSchedule)
expect(conflicts).toHaveLength(0)
})
it('should return no conflicts for a single weekday event within limits', () => {
const events: CalendarEvent[] = [
{ id: 1, channelId: 1, scheduledDate: '2026-03-02', contentType: 'longform' },
]
const conflicts = detectConflicts(events, defaultSchedule)
expect(conflicts).toHaveLength(0)
})
})
})