mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
0b218d53b2
Co-hosted NestJS app behind the existing Express server via a strangler-fig dispatcher, sharing the same better-sqlite3 connection and JWT httpOnly cookie. Additive and dormant: default routing stays on Express, Nest only serves its own /api/_nest diagnostics until a module opts in. F1 @trek/shared Zod contract package; F2 Nest bootstrap co-hosted (fall-through, single Dockerfile/port); F3 shared better-sqlite3 provider; F4 JWT cookie auth guard (+ @CurrentUser, admin guard); F5 Zod validation pipe + error-envelope parity; F6 Nest test + coverage gates; F7 per-prefix strangler toggle (env, default Express); F8 CI build/typecheck/test/coverage. Remaining F4/F6/F8 checklist items (trip-access + permission levels + MFA policy, e2e harness/seed + 80% gate, Nest↔Express parity test, Playwright PR-comment workflow) are tracked on the first consuming module cards (L1/A1/C1).
41 lines
1.6 KiB
TypeScript
41 lines
1.6 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { HttpException } from '@nestjs/common';
|
|
import { Test } from '@nestjs/testing';
|
|
import { AppModule } from '../../../src/nest/app.module';
|
|
import { HealthController } from '../../../src/nest/health/health.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();
|
|
expect(moduleRef.get(HealthController)).toBeInstanceOf(HealthController);
|
|
});
|
|
});
|
|
|
|
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();
|
|
expect(svc.get('SELECT 1 AS one')).toEqual({ one: 1 });
|
|
expect(svc.all('SELECT 1 AS one')).toEqual([{ one: 1 }]);
|
|
});
|
|
});
|