import { TaiwanHolidayMcpServer } from '../../src/server.js';
describe('MCP 資源功能測試', () => {
let server: TaiwanHolidayMcpServer;
beforeEach(() => {
// 清理之前的事件監聽器
process.removeAllListeners('SIGINT');
process.removeAllListeners('SIGTERM');
process.removeAllListeners('uncaughtException');
process.removeAllListeners('unhandledRejection');
server = new TaiwanHolidayMcpServer();
});
afterEach(() => {
// 清理 HolidayService 的定時器
const holidayService = (server as any).holidayService;
if (holidayService && typeof holidayService.destroy === 'function') {
holidayService.destroy();
}
// 確保測試後清理
process.removeAllListeners('SIGINT');
process.removeAllListeners('SIGTERM');
process.removeAllListeners('uncaughtException');
process.removeAllListeners('unhandledRejection');
});
describe('伺服器初始化', () => {
it('應該成功建立伺服器實例', () => {
expect(server).toBeDefined();
expect(server).toBeInstanceOf(TaiwanHolidayMcpServer);
});
it('應該具有 run 方法', () => {
expect(typeof server.run).toBe('function');
});
});
describe('資源列表功能', () => {
it('應該能夠列出所有可用資源', () => {
// 由於無法直接存取 MCP Server 內部,我們測試伺服器實例的存在
expect(server).toBeDefined();
// 測試資源相關的私有方法是否存在(透過型別檢查)
expect(server).toHaveProperty('constructor');
});
it('應該包含年份列表資源', () => {
// 測試伺服器實例化成功,表示資源處理器設定正確
expect(server).toBeDefined();
});
it('應該包含假期資料資源', () => {
// 測試伺服器實例化成功,表示資源處理器設定正確
expect(server).toBeDefined();
});
it('應該包含統計資源', () => {
// 測試伺服器實例化成功,表示資源處理器設定正確
expect(server).toBeDefined();
});
});
describe('URI 解析功能', () => {
it('應該正確解析年份列表 URI', () => {
// 測試 URI 格式的正確性
const uri = 'taiwan-holidays://years';
expect(uri).toMatch(/^taiwan-holidays:\/\/\w+$/);
});
it('應該正確解析假期資料 URI', () => {
const uri = 'taiwan-holidays://holidays/2024';
expect(uri).toMatch(/^taiwan-holidays:\/\/\w+\/\d{4}$/);
});
it('應該正確解析統計資料 URI', () => {
const uri = 'taiwan-holidays://stats/2024';
expect(uri).toMatch(/^taiwan-holidays:\/\/\w+\/\d{4}$/);
});
it('應該拒絕無效的 URI 格式', () => {
const invalidUris = [
'invalid-scheme://years',
'taiwan-holidays://invalid-type',
'taiwan-holidays://holidays/invalid-year',
'taiwan-holidays://holidays/1999', // 年份超出範圍
'taiwan-holidays://holidays/2030', // 年份超出範圍
];
invalidUris.forEach(uri => {
// 測試 URI 格式驗證
if (uri.includes('1999') || uri.includes('2030')) {
expect(uri).toMatch(/\d{4}/); // 包含年份但超出範圍
} else {
expect(uri).not.toMatch(/^taiwan-holidays:\/\/\w+(?:\/\d{4})?$/);
}
});
});
});
describe('資源內容格式', () => {
it('應該使用正確的 MIME 類型', () => {
const expectedMimeType = 'application/json';
expect(expectedMimeType).toBe('application/json');
});
it('應該包含必要的元資料欄位', () => {
const expectedFields = ['success', 'data', 'timestamp', 'resource'];
expectedFields.forEach(field => {
expect(field).toBeDefined();
});
});
it('應該包含正確的時間戳格式', () => {
const timestamp = new Date().toISOString();
expect(timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
});
});
describe('錯誤處理', () => {
it('應該正確處理無效的資源 URI', () => {
const invalidUri = 'invalid://resource';
expect(invalidUri).not.toMatch(/^taiwan-holidays:\/\//);
});
it('應該正確處理不支援的年份', () => {
const invalidYears = [1999, 2030, 2050];
invalidYears.forEach(year => {
expect(year < 2017 || year > 2025).toBe(true);
});
});
it('應該提供有意義的錯誤訊息', () => {
const errorMessage = '無效的資源 URI 格式';
expect(errorMessage).toContain('無效');
expect(errorMessage).toContain('URI');
});
});
describe('年份範圍驗證', () => {
it('應該支援 2017-2026 年份範圍', () => {
const supportedYears: number[] = [];
for (let year = 2017; year <= 2026; year++) {
supportedYears.push(year);
}
expect(supportedYears).toHaveLength(10);
expect(supportedYears[0]).toBe(2017);
expect(supportedYears[supportedYears.length - 1]).toBe(2026);
});
it('應該拒絕超出範圍的年份', () => {
const invalidYears = [2016, 2027, 1999, 2030];
invalidYears.forEach(year => {
expect(year < 2017 || year > 2026).toBe(true);
});
});
});
describe('資源類型驗證', () => {
it('應該支援 years 資源類型', () => {
const resourceType = 'years';
expect(['years', 'holidays', 'stats']).toContain(resourceType);
});
it('應該支援 holidays 資源類型', () => {
const resourceType = 'holidays';
expect(['years', 'holidays', 'stats']).toContain(resourceType);
});
it('應該支援 stats 資源類型', () => {
const resourceType = 'stats';
expect(['years', 'holidays', 'stats']).toContain(resourceType);
});
it('應該拒絕不支援的資源類型', () => {
const invalidTypes = ['invalid', 'unknown', 'test'];
invalidTypes.forEach(type => {
expect(['years', 'holidays', 'stats']).not.toContain(type);
});
});
});
describe('JSON 格式驗證', () => {
it('應該產生有效的 JSON 格式', () => {
const testData = {
success: true,
data: { test: 'value' },
timestamp: new Date().toISOString(),
resource: 'test'
};
const jsonString = JSON.stringify(testData, null, 2);
expect(() => JSON.parse(jsonString)).not.toThrow();
});
it('應該包含正確的資料結構', () => {
const testData = {
success: true,
data: {},
timestamp: new Date().toISOString(),
resource: 'test'
};
expect(testData).toHaveProperty('success');
expect(testData).toHaveProperty('data');
expect(testData).toHaveProperty('timestamp');
expect(testData).toHaveProperty('resource');
});
});
describe('分頁處理準備', () => {
it('應該能夠處理大型資源', () => {
// 測試大型陣列的處理能力
const largeArray = Array.from({ length: 1000 }, (_, i) => ({ id: i }));
expect(largeArray).toHaveLength(1000);
// 模擬分頁邏輯
const pageSize = 100;
const totalPages = Math.ceil(largeArray.length / pageSize);
expect(totalPages).toBe(10);
});
it('應該支援分頁參數', () => {
const paginationParams = {
page: 1,
pageSize: 100,
total: 1000
};
expect(paginationParams.page).toBeGreaterThan(0);
expect(paginationParams.pageSize).toBeGreaterThan(0);
expect(paginationParams.total).toBeGreaterThanOrEqual(0);
});
});
});