// backend/src/auth/ws-auth.guard.spec.ts import { WsAuthGuard } from './ws-auth.guard'; import { AuthController } from './auth.controller'; describe('WsAuthGuard', () => { let guard: WsAuthGuard; let jwt: any; beforeEach(() => { jwt = { verify: jest.fn().mockReturnValue({ sub: 1, email: 'test@test.com' }), }; guard = new WsAuthGuard(jwt as any); }); it('should authenticate via httpOnly cookie', () => { const req = { headers: { cookie: 'wraith_token=valid-jwt; other=stuff' }, url: '/ws' }; const result = guard.validateClient({}, req); expect(jwt.verify).toHaveBeenCalledWith('valid-jwt'); expect(result).toEqual({ sub: 1, email: 'test@test.com' }); }); it('should authenticate via single-use WS ticket', () => { const originalConsume = AuthController.consumeWsTicket; AuthController.consumeWsTicket = jest.fn().mockReturnValue({ sub: 42, email: 'ticket@test.com', role: 'user', }); const req = { url: '/api/ws/terminal?ticket=abc123', headers: {} }; const result = guard.validateClient({}, req); expect(AuthController.consumeWsTicket).toHaveBeenCalledWith('abc123'); expect(result).toEqual({ sub: 42, email: 'ticket@test.com' }); // Restore AuthController.consumeWsTicket = originalConsume; }); it('should fall back to legacy URL token when no cookie or ticket', () => { const req = { url: '/api/ws/terminal?token=legacy-jwt', headers: {} }; guard.validateClient({}, req); expect(jwt.verify).toHaveBeenCalledWith('legacy-jwt'); }); it('should return null when no credentials are present', () => { const req = { url: '/api/ws/terminal', headers: {} }; const result = guard.validateClient({}, req); expect(result).toBeNull(); }); it('should return null when JWT verification fails', () => { jwt.verify.mockImplementation(() => { throw new Error('invalid signature'); }); const req = { headers: { cookie: 'wraith_token=bad-jwt' }, url: '/ws' }; const result = guard.validateClient({}, req); expect(result).toBeNull(); }); });