128 lines
3.5 KiB
TypeScript
128 lines
3.5 KiB
TypeScript
|
|
import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
|
||
|
|
import type { Server } from 'bun';
|
||
|
|
import { createPlugin } from './plugins';
|
||
|
|
|
||
|
|
// --- Synthetic ICS ---
|
||
|
|
|
||
|
|
const pad = (n: number) => n.toString().padStart(2, '0');
|
||
|
|
const icsDate = (d: Date) =>
|
||
|
|
`${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}T${pad(d.getHours())}${pad(d.getMinutes())}00`;
|
||
|
|
|
||
|
|
const now = new Date();
|
||
|
|
const currentStart = new Date(now.getTime() - 30 * 60_000);
|
||
|
|
const currentEnd = new Date(now.getTime() + 30 * 60_000);
|
||
|
|
const nextStart = new Date(now.getTime() + 60 * 60_000);
|
||
|
|
const nextEnd = new Date(now.getTime() + 120 * 60_000);
|
||
|
|
const laterStart = new Date(now.getTime() + 180 * 60_000);
|
||
|
|
const laterEnd = new Date(now.getTime() + 240 * 60_000);
|
||
|
|
|
||
|
|
const ics = `BEGIN:VCALENDAR
|
||
|
|
VERSION:2.0
|
||
|
|
PRODID:-//Test//Test//EN
|
||
|
|
BEGIN:VEVENT
|
||
|
|
DTSTART:${icsDate(currentStart)}
|
||
|
|
DTEND:${icsDate(currentEnd)}
|
||
|
|
SUMMARY:Current Meeting
|
||
|
|
UID:test-current@test
|
||
|
|
END:VEVENT
|
||
|
|
BEGIN:VEVENT
|
||
|
|
DTSTART:${icsDate(nextStart)}
|
||
|
|
DTEND:${icsDate(nextEnd)}
|
||
|
|
SUMMARY:Next Meeting
|
||
|
|
UID:test-next@test
|
||
|
|
END:VEVENT
|
||
|
|
BEGIN:VEVENT
|
||
|
|
DTSTART:${icsDate(laterStart)}
|
||
|
|
DTEND:${icsDate(laterEnd)}
|
||
|
|
SUMMARY:Later Meeting
|
||
|
|
UID:test-later@test
|
||
|
|
END:VEVENT
|
||
|
|
END:VCALENDAR`;
|
||
|
|
|
||
|
|
const fakeModel = {
|
||
|
|
width: 800,
|
||
|
|
height: 480,
|
||
|
|
css: { classes: { device: 'device', size: 'size', density: 'density' } },
|
||
|
|
} as any;
|
||
|
|
|
||
|
|
// --- ICS server ---
|
||
|
|
|
||
|
|
let icsServer: Server;
|
||
|
|
let icsUrl: string;
|
||
|
|
|
||
|
|
beforeAll(() => {
|
||
|
|
icsServer = Bun.serve({
|
||
|
|
port: 0,
|
||
|
|
hostname: '127.0.0.1',
|
||
|
|
routes: {
|
||
|
|
'/cal.ics': () =>
|
||
|
|
new Response(ics, {
|
||
|
|
headers: { 'Content-Type': 'text/calendar' },
|
||
|
|
}),
|
||
|
|
},
|
||
|
|
});
|
||
|
|
icsUrl = `http://127.0.0.1:${icsServer.port}/cal.ics`;
|
||
|
|
});
|
||
|
|
|
||
|
|
afterAll(() => {
|
||
|
|
icsServer.stop();
|
||
|
|
});
|
||
|
|
|
||
|
|
// --- Tests ---
|
||
|
|
|
||
|
|
describe('plugin registry', () => {
|
||
|
|
test('unknown plugin throws', () => {
|
||
|
|
expect(() => createPlugin('nonexistent', {})).toThrow(
|
||
|
|
'Unknown plugin: nonexistent'
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('calendar plugin creates an ICSRenderable', () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [] });
|
||
|
|
expect(plugin.hash).toBe('');
|
||
|
|
expect(plugin.nextEvent).toBeUndefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('calendar plugin rendering', () => {
|
||
|
|
test('renders events from ICS feed', async () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [icsUrl] });
|
||
|
|
const html = await plugin.render('full', fakeModel);
|
||
|
|
|
||
|
|
expect(html).toContain('Current Meeting');
|
||
|
|
expect(html).toContain('Next Meeting');
|
||
|
|
expect(html).toContain('Later Meeting');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('shows BEZET when there is a current event', async () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [icsUrl] });
|
||
|
|
const html = await plugin.render('full', fakeModel);
|
||
|
|
|
||
|
|
expect(html).toContain('BEZET');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('computes hash after render', async () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [icsUrl] });
|
||
|
|
await plugin.render('full', fakeModel);
|
||
|
|
|
||
|
|
expect(plugin.hash).toBeTruthy();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('sets nextEvent to upcoming event start', async () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [icsUrl] });
|
||
|
|
await plugin.render('full', fakeModel);
|
||
|
|
|
||
|
|
expect(plugin.nextEvent).toBeInstanceOf(Date);
|
||
|
|
const diff = Math.abs(plugin.nextEvent!.getTime() - nextStart.getTime());
|
||
|
|
expect(diff).toBeLessThan(120_000);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('renders VRIJ with no events', async () => {
|
||
|
|
const plugin = createPlugin('calendar', { urls: [] });
|
||
|
|
const html = await plugin.render('full', fakeModel);
|
||
|
|
|
||
|
|
expect(html).toContain('VRIJ');
|
||
|
|
expect(html).not.toContain('BEZET');
|
||
|
|
});
|
||
|
|
});
|