import { ForbiddenException } from '@nestjs/common'; import { describe, expect, it } from 'vitest'; import { TenantGuard } from './tenant.guard'; /** * TenantGuard.canActivate — legt die Testlage fuer diesen Bereich aus dem * Nichts an (260911-e2s, Aufgabe 2, Befund I: es gab vorher KEINE Testdatei * fuer Guard oder Middleware). Muster fuer `makeContext` wie in * `../module-registry/module.guard.spec.ts`. * * Der Guard wird OHNE Argumente konstruiert (`new TenantGuard()`) — das ist * zugleich die Typpruefungs-Aussage, dass er keine Prisma-Abhaengigkeit mehr * hat (260911-e2s, Aufgabe 2). * * Jeder durchlassende Fall prueft zusaetzlich, dass die alte * Anfrageobjekt-Eigenschaft NICHT als Schluessel auf dem Anfrageobjekt * vorhanden ist (`'tenantPrisma' in req`) — ueber den `in`-Operator, nicht * ueber einen Property-Zugriff mit Punkt, weil das Gate dieser Aufgabe den * Punkt-Zugriff im gesamten apps/api/src auf null zaehlt, Kommentare * eingeschlossen. */ function makeContext(request: any) { return { switchToHttp: () => ({ getRequest: () => request, }), } as any; } describe('TenantGuard.canActivate', () => { it('kein req.user (oeffentliche Route): liefert true, weder tenantId noch die alte Anfrageobjekt-Eigenschaft sind gesetzt', () => { const guard = new TenantGuard(); const req: any = {}; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect('tenantId' in req).toBe(false); expect('tenantPrisma' in req).toBe(false); }); it('Nutzer der Rolle USER mit tenantId, keine Kopfzeile: true, req.tenantId === die eigene Kennung', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'USER', tenantId: 't1' }, headers: {} }; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect(req.tenantId).toBe('t1'); expect('tenantPrisma' in req).toBe(false); }); it('Nutzer der Rolle ADMIN mit tenantId UND x-tenant-id-Kopfzeile: die Kopfzeile wird IGNORIERT, req.tenantId bleibt die eigene Kennung (T-04-03)', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'ADMIN', tenantId: 't1' }, headers: { 'x-tenant-id': 't2' }, }; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect(req.tenantId).toBe('t1'); expect('tenantPrisma' in req).toBe(false); }); it('SUPER_ADMIN mit tenantId und x-tenant-id-Kopfzeile: der Wechsel gelingt, req.tenantId === der Header-Wert (D-10)', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'SUPER_ADMIN', tenantId: 't1' }, headers: { 'x-tenant-id': 't2' }, }; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect(req.tenantId).toBe('t2'); expect('tenantPrisma' in req).toBe(false); }); it('SUPER_ADMIN mit tenantId, ohne Kopfzeile: req.tenantId === die eigene Kennung', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'SUPER_ADMIN', tenantId: 't1' }, headers: {} }; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect(req.tenantId).toBe('t1'); expect('tenantPrisma' in req).toBe(false); }); it('SUPER_ADMIN ohne tenantId und ohne Kopfzeile: true, req.tenantId === null (heutiges Verhalten, mit dem heutigen Sitzungsnachweis unerreichbar, trotzdem festgenagelt)', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'SUPER_ADMIN' }, headers: {} }; const result = guard.canActivate(makeContext(req)); expect(result).toBe(true); expect(req.tenantId).toBeNull(); expect('tenantPrisma' in req).toBe(false); }); it('Nutzer der Rolle USER ohne tenantId: wirft ForbiddenException("No tenant context")', () => { const guard = new TenantGuard(); const req: any = { user: { role: 'USER' }, headers: {} }; expect(() => guard.canActivate(makeContext(req))).toThrow( new ForbiddenException('No tenant context'), ); }); });