mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
7f5c537ad6
The all-trips feed merges many trips into one calendar. It did that by generating each trip's finished ICS and then scanning the text back apart: one pass for the VEVENTs, one for the VTIMEZONEs, plus a string replace to splice the refresh hints into the header. The scans had to be structural rather than regexes, because a user-supplied SUMMARY can legitimately contain the literal 'END:VEVENT' and a lazy match would truncate the event there. CalendarService now returns the parts - calendar name, filename, VTIMEZONE blocks keyed by TZID, and the VEVENT blocks - and exportICS serialises them. Both scanners are gone. CAL-010 pins the whole serialised document as a snapshot, with DTSTAMP and the UID counter normalised so it pins the calendar rather than the minute it ran in. It is what proves this changed no bytes: it was taken before the model went in and still matches. Two tests still pointed at the health controller deleted in d37af204: health.di.test.ts loses its only subject, and the AppModule wiring test now resolves FeaturesController instead - it is the one test that builds the whole container, so it should resolve something that still exists.
44 lines
1.8 KiB
TypeScript
44 lines
1.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { HttpException } from '@nestjs/common';
|
|
import { Test } from '@nestjs/testing';
|
|
import { db } from '../../../src/db/database';
|
|
import { AppModule } from '../../../src/nest/app.module';
|
|
import { FeaturesController } from '../../../src/nest/health/features.controller';
|
|
import { DatabaseService } from '../../../src/nest/database/database.service';
|
|
import { AdminGuard } from '../../../src/nest/auth/admin.guard';
|
|
|
|
function ctx(user: unknown) {
|
|
return { switchToHttp: () => ({ getRequest: () => ({ user }) }) } as never;
|
|
}
|
|
|
|
describe('AppModule wiring', () => {
|
|
it('compiles with the global filter + DB provider and resolves the controller', async () => {
|
|
const moduleRef = await Test.createTestingModule({ imports: [AppModule] })
|
|
.overrideProvider(DatabaseService)
|
|
.useValue({ get: () => ({ n: 0 }) })
|
|
.compile();
|
|
// The one test that builds the whole AppModule: resolving a controller out of
|
|
// it proves every module in the graph compiled, not just this one.
|
|
expect(moduleRef.get(FeaturesController)).toBeInstanceOf(FeaturesController);
|
|
});
|
|
});
|
|
|
|
describe('AdminGuard', () => {
|
|
const guard = new AdminGuard();
|
|
it('allows admins', () => {
|
|
expect(guard.canActivate(ctx({ role: 'admin' }))).toBe(true);
|
|
});
|
|
it('blocks non-admins and anonymous with 403 { error }', () => {
|
|
expect(() => guard.canActivate(ctx({ role: 'user' }))).toThrow(HttpException);
|
|
expect(() => guard.canActivate(ctx(undefined))).toThrow(HttpException);
|
|
});
|
|
});
|
|
|
|
describe('DatabaseService (shared connection)', () => {
|
|
it('runs real queries against the existing SQLite connection', () => {
|
|
const svc = new DatabaseService(db);
|
|
expect(svc.get('SELECT 1 AS one')).toEqual({ one: 1 });
|
|
expect(svc.all('SELECT 1 AS one')).toEqual([{ one: 1 }]);
|
|
});
|
|
});
|