Skip to main content
Glama

Timezone MCP Server

by sam-artuso
swagger.e2e.spec.tsβ€’9.96 kB
import { describe, it, expect, beforeAll, afterAll } from 'vitest' import { Test, TestingModule } from '@nestjs/testing' import { INestApplication } from '@nestjs/common' import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger' import { ConfigService } from '@nestjs/config' import { createMockConfigService, setupTestEnvironment } from './test-config.helper' describe('Swagger/OpenAPI (e2e)', () => { let app: INestApplication // eslint-disable-next-line @typescript-eslint/no-explicit-any let swaggerDocument: any beforeAll(async () => { try { // Set up environment variables BEFORE importing AppModule // This ensures McpAuthModule.forRoot() and TimezoneModule.forRoot() have correct env vars setupTestEnvironment() // Dynamic import to ensure setupTestEnvironment() runs first // (top-level imports are hoisted and run before module-level code) const { AppModule } = await import('../src/app/app.module') const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }) .overrideProvider(ConfigService) .useValue(createMockConfigService()) .compile() app = moduleFixture.createNestApplication() // Setup Swagger the same way as in main.test-helper.ts (development mode) const config = new DocumentBuilder() .setTitle('Timezone MCP Server API - Development') .setDescription( 'MCP (Model Context Protocol) server for timezone operations. ' + '\n\n**Development Mode**: This REST API is only available when NODE_ENV=development. ' + 'It provides unauthenticated endpoints for testing and development. ' + '\n\n**Production Mode**: Only the MCP endpoint at /mcp is available, protected by OAuth authentication. ' + '\n\nProvides endpoints to get available regions, cities, and current time in any timezone with ISO 8601 formatted timestamps.', ) .setVersion('1.0') .addServer('', 'Current server') .addTag('health', 'Health check endpoints') .addTag('timezones', 'Timezone information endpoints (development only)') .build() swaggerDocument = SwaggerModule.createDocument(app, config) await app.init() } catch (error) { console.error('Failed to initialize app in tests:', error) throw error } }) afterAll(async () => { if (app) { await app.close() } }) it('should generate a valid OpenAPI document', () => { expect(swaggerDocument).toBeDefined() expect(swaggerDocument.openapi).toBe('3.0.0') }) it('should have correct API info', () => { expect(swaggerDocument.info).toBeDefined() expect(swaggerDocument.info.title).toBe('Timezone MCP Server API - Development') expect(swaggerDocument.info.version).toBe('1.0') expect(swaggerDocument.info.description).toContain('MCP (Model Context Protocol)') expect(swaggerDocument.info.description).toContain('Development Mode') }) it('should have correct servers configuration', () => { expect(swaggerDocument.servers).toBeDefined() expect(Array.isArray(swaggerDocument.servers)).toBe(true) expect(swaggerDocument.servers.length).toBeGreaterThan(0) // Empty string means relative URL (current server) expect(swaggerDocument.servers[0].url).toBe('') }) it('should have correct tags', () => { expect(swaggerDocument.tags).toBeDefined() expect(Array.isArray(swaggerDocument.tags)).toBe(true) // eslint-disable-next-line @typescript-eslint/no-explicit-any const tagNames = swaggerDocument.tags.map((tag: any) => tag.name) expect(tagNames).toContain('health') expect(tagNames).toContain('timezones') }) describe('Paths', () => { it('should have health check endpoint documented', () => { expect(swaggerDocument.paths).toBeDefined() expect(swaggerDocument.paths['/health']).toBeDefined() expect(swaggerDocument.paths['/health'].get).toBeDefined() }) it('should have GET /timezones/regions endpoint documented', () => { expect(swaggerDocument.paths['/timezones/regions']).toBeDefined() expect(swaggerDocument.paths['/timezones/regions'].get).toBeDefined() }) it('should have GET /timezones/regions/{region}/cities endpoint documented', () => { expect(swaggerDocument.paths['/timezones/regions/{region}/cities']).toBeDefined() expect(swaggerDocument.paths['/timezones/regions/{region}/cities'].get).toBeDefined() }) it('should have GET /timezones/{region}/{city} endpoint documented', () => { expect(swaggerDocument.paths['/timezones/{region}/{city}']).toBeDefined() expect(swaggerDocument.paths['/timezones/{region}/{city}'].get).toBeDefined() }) }) describe('Schemas', () => { it('should have HealthResponseDto schema', () => { expect(swaggerDocument.components).toBeDefined() expect(swaggerDocument.components.schemas).toBeDefined() expect(swaggerDocument.components.schemas.HealthResponseDto).toBeDefined() const healthSchema = swaggerDocument.components.schemas.HealthResponseDto expect(healthSchema.properties).toBeDefined() expect(healthSchema.properties.status).toBeDefined() expect(healthSchema.properties.timestamp).toBeDefined() }) it('should have RegionsResponseDto schema', () => { expect(swaggerDocument.components.schemas.RegionsResponseDto).toBeDefined() const regionsSchema = swaggerDocument.components.schemas.RegionsResponseDto expect(regionsSchema.properties).toBeDefined() expect(regionsSchema.properties.regions).toBeDefined() expect(regionsSchema.properties.count).toBeDefined() }) it('should have CitiesResponseDto schema', () => { expect(swaggerDocument.components.schemas.CitiesResponseDto).toBeDefined() const citiesSchema = swaggerDocument.components.schemas.CitiesResponseDto expect(citiesSchema.properties).toBeDefined() expect(citiesSchema.properties.region).toBeDefined() expect(citiesSchema.properties.cities).toBeDefined() expect(citiesSchema.properties.count).toBeDefined() }) it('should have TimezoneResponseDto schema', () => { expect(swaggerDocument.components.schemas.TimezoneResponseDto).toBeDefined() const timezoneSchema = swaggerDocument.components.schemas.TimezoneResponseDto expect(timezoneSchema.properties).toBeDefined() expect(timezoneSchema.properties.timezone).toBeDefined() expect(timezoneSchema.properties.datetime_local).toBeDefined() expect(timezoneSchema.properties.datetime_utc).toBeDefined() expect(timezoneSchema.properties.timezone_offset).toBeDefined() expect(timezoneSchema.properties.timestamp).toBeDefined() }) }) describe('Health Endpoint Documentation', () => { it('should have correct operation details', () => { const operation = swaggerDocument.paths['/health'].get expect(operation.summary).toBe('Health check endpoint') expect(operation.description).toBe('Returns the health status of the service') expect(operation.tags).toContain('health') }) it('should have 200 response documented', () => { const operation = swaggerDocument.paths['/health'].get expect(operation.responses).toBeDefined() expect(operation.responses['200']).toBeDefined() expect(operation.responses['200'].description).toBe('Service is healthy') }) }) describe('Timezone Endpoints Documentation', () => { it('should have GET /timezones/regions with correct details', () => { const operation = swaggerDocument.paths['/timezones/regions'].get expect(operation.summary).toBe('Get all timezone regions') expect(operation.tags).toContain('timezones') expect(operation.responses['200']).toBeDefined() }) it('should have GET /timezones/regions/{region}/cities with parameters', () => { const operation = swaggerDocument.paths['/timezones/regions/{region}/cities'].get expect(operation.summary).toBe('Get cities in a region') expect(operation.tags).toContain('timezones') expect(operation.parameters).toBeDefined() expect(operation.parameters.length).toBeGreaterThan(0) // eslint-disable-next-line @typescript-eslint/no-explicit-any const regionParam = operation.parameters.find((p: any) => p.name === 'region') expect(regionParam).toBeDefined() expect(regionParam.in).toBe('path') expect(regionParam.required).toBe(true) }) it('should document 400 error responses', () => { const operation = swaggerDocument.paths['/timezones/regions/{region}/cities'].get expect(operation.responses['400']).toBeDefined() expect(operation.responses['400'].description).toBe('Invalid region name provided') }) it('should have GET /timezones/{region}/{city} with two path parameters', () => { const operation = swaggerDocument.paths['/timezones/{region}/{city}'].get expect(operation.summary).toBe('Get current time in timezone') expect(operation.parameters).toBeDefined() expect(operation.parameters.length).toBe(2) // eslint-disable-next-line @typescript-eslint/no-explicit-any const regionParam = operation.parameters.find((p: any) => p.name === 'region') // eslint-disable-next-line @typescript-eslint/no-explicit-any const cityParam = operation.parameters.find((p: any) => p.name === 'city') expect(regionParam).toBeDefined() expect(cityParam).toBeDefined() // Check that the parameters have examples (they might be in schema.example instead of example) const regionExample = regionParam.example || regionParam.schema?.example const cityExample = cityParam.example || cityParam.schema?.example expect(regionExample).toBe('America') expect(cityExample).toBe('New_York') }) }) })

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/sam-artuso/demo-mcp'

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