CalMerger/test/calendar.test.js

341 lines
13 KiB
JavaScript

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(process.cwd(), 'calendar');
const TEST_CALENDARS_DIR = path.join(__dirname, 'test_calendars');
const EXPECTED_OUTPUTS_DIR = path.join(__dirname, 'expected_outputs');
let server;
process.chdir(__dirname)
const app = await import('../src/server');
describe('Calendar Merging API', () => {
beforeAll(async () => {
// Start the server
server = app.default.listen(0);
});
afterAll(async () => {
// Ensure the server is closed before cleanup
await new Promise(resolve => server.close(resolve));
// Clean up the merged calendars directory after tests
if (fs.existsSync(CALENDARS_DIR)) {
fs.rmSync(CALENDARS_DIR, { recursive: true, force: true });
}
// Optional: Add a delay to ensure all handles are released
await new Promise(resolve => setTimeout(resolve, 100));
});
const getTestCalendarFilename = (filename) => {
return path.join(TEST_CALENDARS_DIR, filename);
};
const loadExpectedOutput = (filename) => {
return fs.readFileSync(path.join(EXPECTED_OUTPUTS_DIR, filename), 'utf8');
};
test('Preserve nextcloud calendar', async () => {
const input = getTestCalendarFilename('nextcloud-minimal.ics');
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'nextcloud-minimal',
calendars: [
{
url: input,
prefix: '',
override: false,
},
],
});
expect(response.status).toBe(200);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'nextcloud-minimal.ics');
console.log('Checking if file exists at:', filePath);
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output
const expectedOutput = fs.readFileSync(input, 'utf8');
const actualOutput = fs.readFileSync(filePath, 'utf8');
//compare
expect(actualOutput).toBe(expectedOutput);
});
test('Preserve google calendar', async () => {
const input = getTestCalendarFilename('google-calendar-minimal.ics');
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'google-calendar-minimal',
calendars: [
{
url: input,
prefix: '',
override: false,
},
],
});
expect(response.status).toBe(200);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'google-calendar-minimal.ics');
console.log('Checking if file exists at:', filePath);
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output
const expectedOutput = fs.readFileSync(input, 'utf8');
const actualOutput = fs.readFileSync(filePath, 'utf8');
//compare
expect(actualOutput).toBe(expectedOutput);
});
test('Preserve date-based calendar', async () => {
const input = getTestCalendarFilename('US_Holidays.ics');
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'US Holidays',
calendars: [
{
url: input,
prefix: '',
override: false,
},
],
});
expect(response.status).toBe(200);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'US_Holidays.ics');
console.log('Checking if file exists at:', filePath);
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = fs.readFileSync(input, 'utf8');
const actualOutput = fs.readFileSync(filePath, 'utf8');
expect(actualOutput).toBe(expectedOutput);
});
test('Merge date-based calendar', async () => {
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'Date Based Calendar',
calendars: [
{
url: getTestCalendarFilename('holiday_calendar_2023.ics'),
prefix: 'holiday_calendar_2023',
override: false,
},
{
url: getTestCalendarFilename('US_Holidays.ics'),
prefix: 'US_holidays',
override: false,
},
],
});
expect(response.status).toBe(200);
expect(response.body.url).toMatch(new RegExp(`calendar/Date_Based_Calendar`));
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'Date_Based_Calendar.ics');
console.log('Checking if file exists at:', filePath);
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = loadExpectedOutput('Date_Based_Calendar.ics');
const actualOutput = fs.readFileSync(filePath, 'utf8');
expect(actualOutput).toBe(expectedOutput);
});
//test Merge time-based calendar
test('Merge time-based calendar', async () => {
const input = getTestCalendarFilename('work_task_calendar.ics');
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'Time Based Calendar',
calendars: [
{
url: getTestCalendarFilename('team_meeting_calendar.ics'), // Time-based calendar
prefix: 'team_meeting_calendar',
override: false,
},
{
url: getTestCalendarFilename('work_task_calendar.ics'), // Time-based calendar
prefix: 'Work_Task',
override: false,
},
],
});
expect(response.status).toBe(200);
expect(response.body.url).toMatch(/calendar\/Time_Based_Calendar/);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'Time_Based_Calendar.ics');
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = loadExpectedOutput('Time_Based_Calendar.ics');
const actualOutput = fs.readFileSync(filePath, 'utf8');
expect(actualOutput).toBe(expectedOutput);
});
//test Merge calendar without prefix
test('Merge calendar without prefix', async () => {
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'No Prefix Calendar',
calendars: [
{
url: getTestCalendarFilename('sf_public_holidays.ics'),
prefix: '',
override: false,
},
],
});
expect(response.status).toBe(200);
expect(response.body.url).toMatch(/calendar\/No_Prefix_Calendar/);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'No_Prefix_Calendar.ics');
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = loadExpectedOutput('No_Prefix_Calendar.ics');
const actualOutput = fs.readFileSync(filePath, 'utf8');
expect(actualOutput).toBe(expectedOutput);
});
//test Merge calendar with override
test('Merge calendar with override', async () => {
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'Override Calendar',
calendars: [
{
url: getTestCalendarFilename('sf_public_holidays.ics'),
prefix: 'Override Event',
override: true,
},
],
});
expect(response.status).toBe(200);
expect(response.body.url).toMatch(/calendar\/Override_Calendar/);
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'Override_Calendar.ics');
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = loadExpectedOutput('Override_Calendar.ics');
const actualOutput = fs.readFileSync(filePath, 'utf8');
expect(actualOutput).toBe(expectedOutput);
});
//test Merge date-based and time-based calendars
test('Merge date-based and time-based calendars', async () => {
const response = await request(server)
.post('/merge')
.send({
linkGroupName: 'Merged Date and Time Based Calendar',
calendars: [
{
url: getTestCalendarFilename('holiday_calendar_2023.ics'), // Date-based calendar
prefix: 'Holiday_2023',
override: false,
},
{
url: getTestCalendarFilename('work_task_calendar.ics'), // Time-based calendar
prefix: 'Work_Task',
override: false,
},
],
});
expect(response.status).toBe(200);
expect(response.body.url).toMatch(new RegExp('calendar/Merged_Date_and_Time_Based_Calendar'));
// Check if the file was created in the test directory
const filePath = path.join(CALENDARS_DIR, 'Merged_Date_and_Time_Based_Calendar.ics');
expect(fs.existsSync(filePath)).toBe(true);
// Load expected output and compare
const expectedOutput = loadExpectedOutput('Merged_Date_and_Time_Based_Calendar.ics');
const actualOutput = fs.readFileSync(filePath, 'utf8');
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');
});
});
});