From 6d1368d7611840c6e2cd41ed9049d41cd7b84a4d Mon Sep 17 00:00:00 2001 From: Cagatay Uslu Date: Wed, 21 May 2025 16:57:59 +0200 Subject: [PATCH] testing: add tests for auth.controller --- src/auth/auth.controller.spec.ts | 241 ++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 6 deletions(-) diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts index c70a6cf..5599a24 100644 --- a/src/auth/auth.controller.spec.ts +++ b/src/auth/auth.controller.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/unbound-method */ import { Test, TestingModule } from '@nestjs/testing'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; @@ -8,6 +10,13 @@ import { PasskeyEntity } from './entities/passkey.entity'; import { Challenge } from './entities/challenge.entity'; import { ConfigService } from '@nestjs/config'; import { RegisterUserDto } from './dto/register-user.input'; +import { BadRequestException, UnauthorizedException } from '@nestjs/common'; +import { ChallengeDTO } from './dto/challenge.dto'; +import { + AuthenticationResponseJSON, + RegistrationResponseJSON, +} from '@simplewebauthn/server/script/deps'; +import { VerifiedAuthenticationResponse } from '@simplewebauthn/server'; describe('AuthController', () => { let controller: AuthController; @@ -29,7 +38,6 @@ describe('AuthController', () => { RP_NAME: 'Motimate', RP_ORIGIN: 'https://motiemate.com', }; - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return envVariables[key]; }), }; @@ -72,7 +80,37 @@ describe('AuthController', () => { }); describe('register', () => { - it('should not throw on correct input', () => { + it('should register a user successfully', async () => { + const mockUser = { + user_id: '1', + name: 'TestUser', + email: 'test@example.com', + password: 'hashedPassword123', + } as jest.Mocked; + + const createUserSpy = jest + .spyOn(controller['authService'], 'createUser') + .mockResolvedValue(mockUser); + + const input: RegisterUserDto = { + username: 'TestUser', + email: 'test@example.com', + password: 'password123', + }; + + const result = await controller.register(input); + + expect(createUserSpy).toHaveBeenCalledWith( + input.username, + input.password, + ); + expect(result).toEqual({ + message: 'User registered successfully', + user: mockUser, + }); + }); + + it('should not throw on correct input', async () => { // GIVEN const input: RegisterUserDto = { username: 'TestUser', @@ -80,11 +118,13 @@ describe('AuthController', () => { password: '1m2m3n4b5b7', }; - // WHEN - const test = () => controller.register(input); + jest.spyOn( + controller['authService'], + 'createUser', + ).mockResolvedValue({} as User); - // THEN - expect(test).not.toThrow(); + // WHEN & THEN + await expect(controller.register(input)).resolves.not.toThrow(); }); }); @@ -93,4 +133,193 @@ describe('AuthController', () => { expect(controller.login()).toBeUndefined(); }); }); + + describe('logout', () => { + it('should call request.logout', () => { + const mockRequest = { + logout: jest.fn((callback: () => void): void => { + callback(); + }), + }; + + controller.logout(mockRequest as any); + + expect(mockRequest.logout).toHaveBeenCalled(); + }); + }); + describe('changePassword', () => { + it('should change password successfully', async () => { + jest.spyOn( + controller['authService'], + 'changePassword', + ).mockResolvedValue(undefined); + const userId = 1; + const newPassword = 'newPassword123'; + + const result = await controller.changePassword(userId, newPassword); + + expect( + controller['authService'].changePassword, + ).toHaveBeenCalledWith(userId, newPassword); + expect(result).toEqual({ + message: 'Password changed successfully', + }); + }); + + it('should throw BadRequestException when changePassword fails', async () => { + jest.spyOn( + controller['authService'], + 'changePassword', + ).mockRejectedValue(new Error('Failed')); + const userId = 1; + const newPassword = 'newPassword123'; + + await expect( + controller.changePassword(userId, newPassword), + ).rejects.toThrow(BadRequestException); + }); + }); + describe('webauthnRegister', () => { + it('should generate registration options successfully', async () => { + const mockChallenge = { + challenge: 'test-challenge', + user: { id: 'user-id' }, + } as unknown as jest.Mocked; + jest.spyOn( + controller['authService'], + 'generateRegistrationOptions', + ).mockResolvedValue(mockChallenge); + const userId = 'user-id'; + + const result = await controller.webauthnRegister(userId); + + expect( + controller['authService'].generateRegistrationOptions, + ).toHaveBeenCalledWith(userId); + expect(result).toBeInstanceOf(ChallengeDTO); + expect(result).toEqual(new ChallengeDTO(mockChallenge)); + }); + + it('should throw BadRequestException when generateRegistrationOptions fails', async () => { + jest.spyOn( + controller['authService'], + 'generateRegistrationOptions', + ).mockRejectedValue(new Error('Failed')); + const userId = 'user-id'; + + await expect(controller.webauthnRegister(userId)).rejects.toThrow( + BadRequestException, + ); + }); + }); + describe('webauthnRegisterVerify', () => { + it('should verify registration response successfully', async () => { + const mockResponse = { + id: 'credential-id', + } as RegistrationResponseJSON; + const mockVerification = { verified: true }; + jest.spyOn( + controller['authService'], + 'verifyRegistrationResponse', + ).mockResolvedValue(mockVerification); + const userId = 'user-id'; + + const result = await controller.webauthnRegisterVerify( + mockResponse, + userId, + ); + + expect( + controller['authService'].verifyRegistrationResponse, + ).toHaveBeenCalledWith(mockResponse, userId); + expect(result).toEqual({ verification: mockVerification }); + }); + + it('should throw UnauthorizedException when verifyRegistrationResponse fails', async () => { + const mockResponse = { + id: 'credential-id', + } as RegistrationResponseJSON; + jest.spyOn( + controller['authService'], + 'verifyRegistrationResponse', + ).mockRejectedValue(new Error('Failed')); + const userId = 'user-id'; + + await expect( + controller.webauthnRegisterVerify(mockResponse, userId), + ).rejects.toThrow(UnauthorizedException); + }); + }); + describe('webauthnAuthenticate', () => { + it('should generate authentication options successfully', async () => { + const mockChallenge = { + challenge: 'test-challenge', + } as unknown as jest.Mocked; + jest.spyOn( + controller['authService'], + 'generateAuthenticationOptions', + ).mockResolvedValue(mockChallenge); + const userId = 'user-id'; + + const result = await controller.webauthnAuthenticate(userId); + + expect( + controller['authService'].generateAuthenticationOptions, + ).toHaveBeenCalledWith(userId); + expect(result).toBeInstanceOf(ChallengeDTO); + expect(result).toEqual(new ChallengeDTO(mockChallenge)); + }); + + it('should throw BadRequestException when generateAuthenticationOptions fails', async () => { + jest.spyOn( + controller['authService'], + 'generateAuthenticationOptions', + ).mockRejectedValue(new Error('Failed')); + const userId = 'user-id'; + + await expect( + controller.webauthnAuthenticate(userId), + ).rejects.toThrow(BadRequestException); + }); + }); + describe('webauthnAuthenticateVerify', () => { + it('should verify authentication response successfully', async () => { + const mockResponse = { + id: 'credential-id', + } as AuthenticationResponseJSON; + const mockVerification = { + verified: true, + } as VerifiedAuthenticationResponse; + jest.spyOn( + controller['authService'], + 'verifyAuthenticationResponse', + ).mockResolvedValue(mockVerification); + const userId = 'user-id'; + + const result = await controller.webauthnAuthenticateVerify( + mockResponse, + userId, + ); + + expect( + controller['authService'].verifyAuthenticationResponse, + ).toHaveBeenCalledWith(mockResponse, userId); + expect(result).toEqual({ verification: mockVerification }); + }); + + it('should throw UnauthorizedException when verifyAuthenticationResponse fails', async () => { + const mockResponse = { + id: 'credential-id', + } as AuthenticationResponseJSON; + jest.spyOn( + controller['authService'], + 'verifyAuthenticationResponse', + ).mockRejectedValue(new Error('Failed')); + const userId = 'user-id'; + + await expect( + controller.webauthnAuthenticateVerify(mockResponse, userId), + ).rejects.toThrow(UnauthorizedException); + }); + }); });