diff --git a/package-lock.json b/package-lock.json index 71ace9e..6f5b184 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/register": "^7.25.9", + "axios-mock-adapter": "^2.1.0", "babel-jest": "^29.7.0", "jest": "^29.7.0", "rewire": "^7.0.0" @@ -2679,6 +2680,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-mock-adapter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-2.1.0.tgz", + "integrity": "sha512-AZUe4OjECGCNNssH8SOdtneiQELsqTsat3SQQCWLPjN436/H+L9AjWfV7bF+Zg/YL9cgbhrz5671hoh+Tbn98w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -4502,6 +4517,30 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/is-core-module": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", diff --git a/package.json b/package.json index 912361d..5c4dc8b 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/register": "^7.25.9", + "axios-mock-adapter": "^2.1.0", "babel-jest": "^29.7.0", "jest": "^29.7.0", "rewire": "^7.0.0" diff --git a/test/calendar.test.js b/test/calendar.test.js index 79c48a2..45996e5 100644 --- a/test/calendar.test.js +++ b/test/calendar.test.js @@ -2,12 +2,15 @@ import request from 'supertest'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { fetchCalendarData } from '../src/calendarUtil.js'; // ESM equivalent of __dirname const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const CALENDARS_DIR = path.join(__dirname, 'calendar'); +const CALENDARS_DIR = path.join(process.cwd(), 'calendar'); const TEST_CALENDARS_DIR = path.join(__dirname, 'test_calendars'); const EXPECTED_OUTPUTS_DIR = path.join(__dirname, 'expected_outputs'); @@ -26,9 +29,8 @@ describe('Calendar Merging API', () => { await new Promise(resolve => server.close(resolve)); // Clean up the merged calendars directory after tests - fs.rmdirSync(CALENDARS_DIR, { recursive: true }); if (fs.existsSync(CALENDARS_DIR)) { - fs.rmdirSync(CALENDARS_DIR, { recursive: true }); + fs.rmSync(CALENDARS_DIR, { recursive: true, force: true }); } // Optional: Add a delay to ensure all handles are released @@ -280,4 +282,60 @@ describe('Calendar Merging API', () => { expect(actualOutput).toBe(expectedOutput); }); + describe('Smart URL Handling', () => { + let mockAxios; + + beforeAll(() => { + mockAxios = new MockAdapter(axios); + }); + + afterEach(() => { + mockAxios.reset(); + }); + + afterAll(() => { + mockAxios.restore(); + }); + + test('should use original URL when valid without .ics', async () => { + const validUrl = 'https://cals.ftt.gmbh/calendar/germanholithunder'; + mockAxios.onGet(validUrl).reply(200, 'VALID_CALENDAR'); + + const result = await fetchCalendarData({ url: validUrl }); + expect(result.data).toBe('VALID_CALENDAR'); + }); + + test('should try .ics version when original fails', async () => { + const invalidUrl = 'https://cals.ftt.gmbh/calendar/germanholithunder.ics'; + const validUrl = invalidUrl.slice(0, -4); + + mockAxios + .onGet(invalidUrl).reply(404) + .onGet(validUrl).reply(200, 'VALID_CALENDAR'); + + const result = await fetchCalendarData({ url: invalidUrl }); + expect(result.data).toBe('VALID_CALENDAR'); + }); + + test('should preserve valid .ics URLs', async () => { + const googleUrl = 'https://calendar.google.com/.../basic.ics'; + mockAxios.onGet(googleUrl).reply(200, 'GOOGLE_CALENDAR'); + + const result = await fetchCalendarData({ url: googleUrl }); + expect(result.data).toBe('GOOGLE_CALENDAR'); + }); + + test('should try both versions for ambiguous URLs', async () => { + const baseUrl = 'https://example.com/calendar'; + const icsUrl = baseUrl + '.ics'; + + mockAxios + .onGet(baseUrl).reply(404) + .onGet(icsUrl).reply(200, 'ICS_CALENDAR'); + + const result = await fetchCalendarData({ url: baseUrl }); + expect(result.data).toBe('ICS_CALENDAR'); + }); + }); }); +