63 tests across 8 spec files, all passing. Removes 2 stale stub files from backend/test/ that were incompatible with the current async EncryptionService and 3-argument AuthService constructor. New suite lives in src/ co-located with source files per NestJS convention. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
// 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();
|
|
});
|
|
});
|