Skip to main content
Glama
pshempel

MCP Time Server Node

by pshempel
config.test.ts8.58 kB
import { getConfig, resetConfigCache } from '../../src/utils/config'; import { getTimezoneOffset } from 'date-fns-tz'; // Mock date-fns-tz jest.mock('date-fns-tz', () => ({ getTimezoneOffset: jest.fn(), })); const mockedGetTimezoneOffset = getTimezoneOffset as jest.MockedFunction<typeof getTimezoneOffset>; describe('TimeServerConfig', () => { // Save original env vars const originalEnv = process.env; const originalTZ = process.env.TZ; const originalDefaultTimezone = process.env.DEFAULT_TIMEZONE; beforeEach(() => { // Reset environment process.env = { ...originalEnv }; delete process.env.TZ; delete process.env.DEFAULT_TIMEZONE; // Reset mocks jest.clearAllMocks(); // Mock timezone validation - valid timezones return a number, invalid return NaN mockedGetTimezoneOffset.mockImplementation((tz: string) => { const validTimezones = [ 'UTC', 'America/New_York', 'Asia/Tokyo', 'Europe/London', 'America/Indianapolis', ]; if (validTimezones.includes(tz) || tz === '') { return 0; // Simplified - just return 0 for valid } return NaN; // Invalid timezone }); // Reset config cache resetConfigCache(); }); afterEach(() => { // Restore environment process.env = originalEnv; if (originalTZ !== undefined) { process.env.TZ = originalTZ; } if (originalDefaultTimezone !== undefined) { process.env.DEFAULT_TIMEZONE = originalDefaultTimezone; } }); describe('System timezone detection', () => { it('should detect system timezone when no environment variables are set', () => { // Mock Intl.DateTimeFormat const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('America/Indianapolis'); }); it('should fall back to UTC if system timezone is invalid', () => { // Mock invalid system timezone const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'Invalid/Zone' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('UTC'); }); it('should handle missing Intl.DateTimeFormat gracefully', () => { // Mock missing Intl const originalIntl = global.Intl; (global as any).Intl = undefined; const config = getConfig(); expect(config.defaultTimezone).toBe('UTC'); // Restore global.Intl = originalIntl; }); }); describe('Environment variable precedence', () => { it('should use DEFAULT_TIMEZONE when set and valid', () => { process.env.DEFAULT_TIMEZONE = 'America/New_York'; const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('America/New_York'); }); it('should ignore DEFAULT_TIMEZONE if invalid', () => { process.env.DEFAULT_TIMEZONE = 'Invalid/Zone'; const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('America/Indianapolis'); }); it('should ignore empty DEFAULT_TIMEZONE', () => { process.env.DEFAULT_TIMEZONE = ''; const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('America/Indianapolis'); }); it('should respect TZ environment variable through Intl.DateTimeFormat', () => { // When TZ is set, Intl.DateTimeFormat returns it process.env.TZ = 'Asia/Tokyo'; const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'Asia/Tokyo' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('Asia/Tokyo'); }); it('should prioritize DEFAULT_TIMEZONE over TZ', () => { process.env.DEFAULT_TIMEZONE = 'Europe/London'; process.env.TZ = 'Asia/Tokyo'; const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'Asia/Tokyo' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('Europe/London'); }); }); describe('Caching behavior', () => { it('should cache the configuration', () => { const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; // First call const config1 = getConfig(); expect(config1.defaultTimezone).toBe('America/Indianapolis'); expect(mockResolvedOptions).toHaveBeenCalledTimes(1); // Second call should use cache const config2 = getConfig(); expect(config2).toBe(config1); // Same object reference expect(mockResolvedOptions).toHaveBeenCalledTimes(1); // Not called again }); it('should allow cache reset', () => { const mockResolvedOptions = jest.fn().mockReturnValue({ timeZone: 'America/Indianapolis' }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; // First call const config1 = getConfig(); // Change environment process.env.DEFAULT_TIMEZONE = 'UTC'; // Without reset, should still return cached const config2 = getConfig(); expect(config2).toBe(config1); // After reset, should recompute resetConfigCache(); const config3 = getConfig(); expect(config3).not.toBe(config1); expect(config3.defaultTimezone).toBe('UTC'); }); }); describe('Edge cases', () => { it('should handle Intl.DateTimeFormat throwing an error', () => { global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => { throw new Error('DateTimeFormat error'); }) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('UTC'); }); it('should handle resolvedOptions() throwing an error', () => { const mockResolvedOptions = jest.fn().mockImplementation(() => { throw new Error('resolvedOptions error'); }); global.Intl.DateTimeFormat = jest.fn().mockImplementation(() => ({ resolvedOptions: mockResolvedOptions, })) as any; const config = getConfig(); expect(config.defaultTimezone).toBe('UTC'); }); it('should handle unusual but valid timezone strings', () => { // Based on our research, these are technically valid mockedGetTimezoneOffset.mockImplementation((tz: string) => { if (tz === 'undefined' || tz === 'null') { return 0; // These weird strings are valid } return NaN; }); process.env.DEFAULT_TIMEZONE = 'undefined'; const config = getConfig(); expect(config.defaultTimezone).toBe('undefined'); // Weird but valid }); }); describe('Configuration object', () => { it('should return a complete TimeServerConfig object', () => { const config = getConfig(); expect(config).toHaveProperty('defaultTimezone'); expect(typeof config.defaultTimezone).toBe('string'); }); it('should be immutable', () => { const config = getConfig(); // Attempt to modify should throw expect(() => { (config as any).defaultTimezone = 'Modified'; }).toThrow(TypeError); // Verify it's still the same expect(config.defaultTimezone).not.toBe('Modified'); }); }); });

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