Skip to main content
Glama
pshempel

MCP Time Server Node

by pshempel
RecurrenceValidator.test.ts9.85 kB
import { describe, it, expect } from '@jest/globals'; import { RecurrenceValidator } from '../../../src/tools/recurrence/RecurrenceValidator'; import { ValidationError, TimezoneError } from '../../../src/adapters/mcp-sdk/errors'; import type { DailyParams, WeeklyParams, MonthlyParams, YearlyParams, } from '../../../src/types/recurrence'; describe('RecurrenceValidator', () => { const validator = new RecurrenceValidator(); describe('pattern validation', () => { it('should accept valid patterns', () => { // Test each pattern with minimal valid params expect(() => validator.validate({ pattern: 'daily' })).not.toThrow(); expect(() => validator.validate({ pattern: 'weekly' })).not.toThrow(); expect(() => validator.validate({ pattern: 'monthly', dayOfMonth: 15 })).not.toThrow(); expect(() => validator.validate({ pattern: 'yearly' })).not.toThrow(); }); it('should reject invalid patterns', () => { const invalidPatterns = ['hourly', 'invalid', 'DAILY']; invalidPatterns.forEach((pattern) => { expect(() => validator.validate({ pattern } as any)).toThrow(); try { validator.validate({ pattern } as any); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Invalid pattern'); } }); }); it('should reject missing pattern', () => { expect(() => validator.validate({} as any)).toThrow(); try { validator.validate({} as any); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Pattern is required'); } }); }); describe('timezone validation', () => { it('should accept undefined timezone (system default)', () => { const params: DailyParams = { pattern: 'daily' }; expect(() => validator.validate(params)).not.toThrow(); }); it('should accept empty string timezone (UTC)', () => { const params: DailyParams = { pattern: 'daily', timezone: '' }; expect(() => validator.validate(params)).not.toThrow(); }); it('should accept valid timezones', () => { const validTimezones = ['UTC', 'America/New_York', 'Europe/London', 'Asia/Tokyo']; validTimezones.forEach((timezone) => { const params: DailyParams = { pattern: 'daily', timezone }; expect(() => validator.validate(params)).not.toThrow(); }); }); it('should reject invalid timezones', () => { const params: DailyParams = { pattern: 'daily', timezone: 'Invalid/Zone' }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(TimezoneError); expect(error.code).toBe('TIMEZONE_ERROR'); expect(error.message).toContain('Invalid timezone'); } }); }); describe('time validation', () => { it('should accept valid time formats', () => { const validTimes = ['00:00', '14:30', '23:59', '9:45']; validTimes.forEach((time) => { const params: DailyParams = { pattern: 'daily', time }; expect(() => validator.validate(params)).not.toThrow(); }); }); it('should accept undefined time', () => { const params: DailyParams = { pattern: 'daily' }; expect(() => validator.validate(params)).not.toThrow(); }); it('should reject invalid time formats', () => { const invalidTimes = ['24:00', '12:60', '14:30:00', '14', '14:3', 'invalid']; invalidTimes.forEach((time) => { const params: DailyParams = { pattern: 'daily', time }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Invalid time format'); } }); }); }); describe('weekly pattern validation', () => { it('should accept valid day of week', () => { const validDays = [0, 1, 2, 3, 4, 5, 6]; validDays.forEach((dayOfWeek) => { const params: WeeklyParams = { pattern: 'weekly', dayOfWeek }; expect(() => validator.validate(params)).not.toThrow(); }); }); it('should accept undefined day of week', () => { const params: WeeklyParams = { pattern: 'weekly' }; expect(() => validator.validate(params)).not.toThrow(); }); it('should reject invalid day of week', () => { const invalidDays = [-1, 7, 0.5, NaN]; invalidDays.forEach((dayOfWeek) => { const params: WeeklyParams = { pattern: 'weekly', dayOfWeek }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Invalid day_of_week'); } }); }); }); describe('monthly pattern validation', () => { it('should accept valid day of month', () => { const validDays = [1, 15, 28, 31, -1]; // -1 is special for last day validDays.forEach((dayOfMonth) => { const params: MonthlyParams = { pattern: 'monthly', dayOfMonth }; expect(() => validator.validate(params)).not.toThrow(); }); }); it('should reject missing day of month', () => { const params = { pattern: 'monthly' } as MonthlyParams; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('dayOfMonth is required'); } }); it('should reject invalid day of month', () => { const invalidDays = [-2, 0, 32, 1.5, NaN]; invalidDays.forEach((dayOfMonth) => { const params: MonthlyParams = { pattern: 'monthly', dayOfMonth }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Invalid day_of_month'); } }); }); }); describe('yearly pattern validation', () => { it('should accept undefined month and dayOfMonth', () => { const params: YearlyParams = { pattern: 'yearly' }; expect(() => validator.validate(params)).not.toThrow(); }); it('should accept valid month', () => { const validMonths = [0, 1, 5, 11]; validMonths.forEach((month) => { const params: YearlyParams = { pattern: 'yearly', month, dayOfMonth: 15 }; expect(() => validator.validate(params)).not.toThrow(); }); }); it('should reject invalid month', () => { const invalidMonths = [-1, 12, 0.5, NaN]; invalidMonths.forEach((month) => { const params: YearlyParams = { pattern: 'yearly', month, dayOfMonth: 15 }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Invalid month'); } }); }); it('should reject month without dayOfMonth', () => { const params: YearlyParams = { pattern: 'yearly', month: 5 }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Both month and dayOfMonth'); } }); it('should reject dayOfMonth without month', () => { const params: YearlyParams = { pattern: 'yearly', dayOfMonth: 15 }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('Both month and dayOfMonth'); } }); }); describe('string length validation', () => { it('should reject excessively long timezone strings', () => { const params: DailyParams = { pattern: 'daily', timezone: 'A'.repeat(101), // Over 100 char limit }; expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(ValidationError); expect(error.code).toBe('VALIDATION_ERROR'); expect(error.message).toContain('exceeds maximum length'); } }); it('should accept timezone at max length', () => { const params: DailyParams = { pattern: 'daily', timezone: 'A'.repeat(100), // At 100 char limit }; // Will fail timezone validation but not length validation expect(() => validator.validate(params)).toThrow(); try { validator.validate(params); } catch (error: any) { expect(error).toBeInstanceOf(TimezoneError); expect(error.code).toBe('TIMEZONE_ERROR'); // should be timezone error for invalid timezone expect(error.message).toContain('Invalid timezone'); } }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pshempel/mcp-time-server-node'

If you have feedback or need assistance with the MCP directory API, please join our Discord server