Spaces:
Sleeping
Sleeping
File size: 4,097 Bytes
b6ecafa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | import { describe, it, expect } from 'vitest'
import { describeCronFrequency, validateCronExpression, generateCloneName } from '../cron-utils'
describe('describeCronFrequency', () => {
it('returns "every minute" for * * * * *', () => {
expect(describeCronFrequency('* * * * *')).toBe('every minute')
})
it('returns "every 5m" for */5 * * * *', () => {
expect(describeCronFrequency('*/5 * * * *')).toBe('every 5m')
})
it('returns "hourly at :00" for 0 * * * *', () => {
expect(describeCronFrequency('0 * * * *')).toBe('hourly at :00')
})
it('returns "daily at 14:30" for 30 14 * * *', () => {
expect(describeCronFrequency('30 14 * * *')).toBe('daily at 14:30')
})
it('returns "monthly" for 0 0 1 * *', () => {
expect(describeCronFrequency('0 0 1 * *')).toBe('monthly')
})
it('returns time with select days for 0 0 * * 1 (specific hour+dow)', () => {
expect(describeCronFrequency('0 0 * * 1')).toBe('00:00 (select days)')
})
it('returns "weekly" when dow is set and no earlier branch matches', () => {
expect(describeCronFrequency('1-30 * * * 1')).toBe('weekly')
})
it('falls through to raw schedule for */10 */2 * * *', () => {
expect(describeCronFrequency('*/10 */2 * * *')).toBe('*/10 */2 * * *')
})
it('returns "every 2h" for 0 */2 * * *', () => {
expect(describeCronFrequency('0 */2 * * *')).toBe('every 2h')
})
it('returns the raw schedule for non-standard expressions', () => {
expect(describeCronFrequency('invalid')).toBe('invalid')
})
it('strips trailing parenthetical comments', () => {
expect(describeCronFrequency('*/5 * * * * (some note)')).toBe('every 5m')
})
it('handles time with select days', () => {
expect(describeCronFrequency('0 9 * * 1,3,5')).toBe('09:00 (select days)')
})
})
describe('validateCronExpression', () => {
it('returns null for valid expression * * * * *', () => {
expect(validateCronExpression('* * * * *')).toBeNull()
})
it('returns null for valid step expression */5 * * * *', () => {
expect(validateCronExpression('*/5 * * * *')).toBeNull()
})
it('returns error for minute > 59', () => {
const result = validateCronExpression('60 * * * *')
expect(result).not.toBeNull()
expect(result).toContain('minute')
})
it('returns error for hour > 23', () => {
const result = validateCronExpression('* 25 * * *')
expect(result).not.toBeNull()
expect(result).toContain('hour')
})
it('returns error for wrong number of fields', () => {
const result = validateCronExpression('invalid')
expect(result).not.toBeNull()
expect(result).toContain('Expected 5 fields')
})
it('returns error for empty string', () => {
const result = validateCronExpression('')
expect(result).not.toBeNull()
})
it('returns null for valid range expression 1-5 * * * *', () => {
expect(validateCronExpression('1-5 * * * *')).toBeNull()
})
it('returns null for valid comma-separated values', () => {
expect(validateCronExpression('0,15,30,45 * * * *')).toBeNull()
})
it('returns error for day-of-month 0', () => {
const result = validateCronExpression('0 0 0 * *')
expect(result).not.toBeNull()
expect(result).toContain('day of month')
})
it('returns error for month > 12', () => {
const result = validateCronExpression('0 0 1 13 *')
expect(result).not.toBeNull()
expect(result).toContain('month')
})
})
describe('generateCloneName', () => {
it('returns "Name (copy)" when no conflicts', () => {
expect(generateCloneName('My Job', [])).toBe('My Job (copy)')
})
it('returns "Name (copy 2)" when "(copy)" exists', () => {
expect(generateCloneName('My Job', ['My Job (copy)'])).toBe('My Job (copy 2)')
})
it('returns "Name (copy 3)" when "(copy)" and "(copy 2)" exist', () => {
expect(generateCloneName('My Job', ['My Job (copy)', 'My Job (copy 2)'])).toBe('My Job (copy 3)')
})
it('is case-insensitive when checking existing names', () => {
expect(generateCloneName('My Job', ['my job (copy)'])).toBe('My Job (copy 2)')
})
})
|