-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added unit tests admin, home, focus areas & health
- Loading branch information
1 parent
40d9695
commit b305dad
Showing
13 changed files
with
1,191 additions
and
299 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { AdminController } from './admin.controller'; | ||
import { ParticipantsRequestService } from '../participants-request/participants-request.service'; | ||
import { AdminService } from './admin.service'; | ||
import { ForbiddenException, UnauthorizedException } from '@nestjs/common'; | ||
import { ParticipantType, ApprovalStatus } from '@prisma/client'; | ||
import { JwtService } from '../utils/jwt/jwt.service'; | ||
import { ParticipantProcessRequestSchema, ParticipantRequestMemberSchema, ParticipantRequestTeamSchema } from 'libs/contracts/src/schema/participants-request'; | ||
|
||
// Mock schemas | ||
jest.mock('libs/contracts/src/schema/participants-request', () => ({ | ||
ParticipantRequestMemberSchema: { | ||
safeParse: jest.fn().mockReturnValue({ success: true }), // Mock success for MEMBER schema | ||
}, | ||
ParticipantRequestTeamSchema: { | ||
safeParse: jest.fn().mockReturnValue({ success: true }), // Mock success for TEAM schema | ||
}, | ||
ParticipantProcessRequestSchema: { | ||
safeParse: jest.fn().mockReturnValue({ success: true }), // Mock success for process request schema | ||
}, | ||
})); | ||
|
||
describe('AdminController', () => { | ||
let controller: AdminController; | ||
let participantsRequestService: ParticipantsRequestService; | ||
let adminService: AdminService; | ||
|
||
const mockParticipantsRequestService = { | ||
getAll: jest.fn(), | ||
getByUid: jest.fn(), | ||
addRequest: jest.fn(), | ||
updateRequest: jest.fn(), | ||
processRejectRequest: jest.fn(), | ||
processTeamCreateRequest: jest.fn(), | ||
processMemberCreateRequest: jest.fn(), | ||
processTeamEditRequest: jest.fn(), | ||
processMemberEditRequest: jest.fn(), | ||
}; | ||
|
||
const mockAdminService = { | ||
signIn: jest.fn(), | ||
}; | ||
|
||
beforeEach(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
controllers: [AdminController], | ||
providers: [ | ||
{ provide: ParticipantsRequestService, useValue: mockParticipantsRequestService }, | ||
{ provide: AdminService, useValue: mockAdminService }, | ||
{ provide: JwtService, useValue: {} }, | ||
], | ||
}).compile(); | ||
|
||
controller = module.get<AdminController>(AdminController); | ||
participantsRequestService = module.get<ParticipantsRequestService>(ParticipantsRequestService); | ||
adminService = module.get<AdminService>(AdminService); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('signIn', () => { | ||
it('should return a signed JWT token if credentials are valid', async () => { | ||
const body = { username: 'admin', password: 'password' }; | ||
const token = { code: 1, accessToken: 'testToken' }; | ||
jest.spyOn(adminService, 'signIn').mockResolvedValue(token); | ||
|
||
const result = await controller.signIn(body); | ||
expect(result).toEqual(token); | ||
}); | ||
}); | ||
|
||
describe('findAll', () => { | ||
it('should return all participants', async () => { | ||
const query = {}; | ||
const mockResponse: any = [{ id: '1', name: 'Participant' }]; | ||
jest.spyOn(participantsRequestService, 'getAll').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.findAll(query); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.getAll).toHaveBeenCalledWith(query); | ||
}); | ||
}); | ||
|
||
describe('findOne', () => { | ||
it('should return a participant by UID', async () => { | ||
const params = { uid: '123' }; | ||
const mockResponse: any = { id: '123', name: 'Participant' }; | ||
jest.spyOn(participantsRequestService, 'getByUid').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.findOne(params); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.getByUid).toHaveBeenCalledWith(params.uid); | ||
}); | ||
}); | ||
|
||
describe('addRequest', () => { | ||
it('should call addRequest with valid MEMBER schema', async () => { | ||
const body = { participantType: ParticipantType.MEMBER, name: 'John Doe' }; | ||
const mockResponse: any = { id: '1', ...body }; | ||
jest.spyOn(participantsRequestService, 'addRequest').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.addRequest(body); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.addRequest).toHaveBeenCalledWith(body); | ||
}); | ||
|
||
it('should call addRequest with valid TEAM schema', async () => { | ||
const body = { participantType: ParticipantType.TEAM, name: 'Team A' }; | ||
const mockResponse: any = { id: '2', ...body }; | ||
jest.spyOn(participantsRequestService, 'addRequest').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.addRequest(body); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.addRequest).toHaveBeenCalledWith(body); | ||
}); | ||
}); | ||
|
||
describe('updateRequest', () => { | ||
it('should call updateRequest with valid MEMBER schema', async () => { | ||
const body = { participantType: ParticipantType.MEMBER, name: 'Updated Name' }; | ||
const params = { uid: '123' }; | ||
const mockResponse: any = { id: '123', ...body }; | ||
jest.spyOn(participantsRequestService, 'updateRequest').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.updateRequest(body, params); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.updateRequest).toHaveBeenCalledWith(body, params.uid); | ||
}); | ||
|
||
it('should call updateRequest with valid TEAM schema', async () => { | ||
const body = { participantType: ParticipantType.TEAM, name: 'Updated Team' }; | ||
const params = { uid: '123' }; | ||
const mockResponse: any = { id: '123', ...body }; | ||
jest.spyOn(participantsRequestService, 'updateRequest').mockResolvedValue(mockResponse); | ||
|
||
const result = await controller.updateRequest(body, params); | ||
expect(result).toEqual(mockResponse); | ||
expect(participantsRequestService.updateRequest).toHaveBeenCalledWith(body, params.uid); | ||
}); | ||
}); | ||
|
||
describe('processRequest', () => { | ||
it('should call processRejectRequest when status is REJECTED', async () => { | ||
const body = { participantType: 'MEMBER', status: ApprovalStatus.REJECTED }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(participantsRequestService, 'processRejectRequest').mockResolvedValue('success' as any); | ||
|
||
const result = await controller.processRequest(body, params); | ||
expect(result).toEqual('success'); | ||
expect(participantsRequestService.processRejectRequest).toHaveBeenCalledWith(params.uid); | ||
}); | ||
|
||
it('should call processTeamCreateRequest when status is APPROVED for TEAM without referenceUid', async () => { | ||
const body = { participantType: 'TEAM', status: ApprovalStatus.APPROVED }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(participantsRequestService, 'processTeamCreateRequest').mockResolvedValue('success' as any); | ||
|
||
const result = await controller.processRequest(body, params); | ||
expect(result).toEqual('success'); | ||
expect(participantsRequestService.processTeamCreateRequest).toHaveBeenCalledWith(params.uid); | ||
}); | ||
|
||
it('should call processMemberCreateRequest when status is APPROVED for MEMBER without referenceUid', async () => { | ||
const body = { participantType: 'MEMBER', status: ApprovalStatus.APPROVED }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(participantsRequestService, 'processMemberCreateRequest').mockResolvedValue('success' as any); | ||
|
||
const result = await controller.processRequest(body, params); | ||
expect(result).toEqual('success'); | ||
expect(participantsRequestService.processMemberCreateRequest).toHaveBeenCalledWith(params.uid); | ||
}); | ||
|
||
it('should call processTeamEditRequest when status is APPROVED for TEAM with referenceUid', async () => { | ||
const body = { participantType: 'TEAM', status: ApprovalStatus.APPROVED, referenceUid: '456' }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(participantsRequestService, 'processTeamEditRequest').mockResolvedValue('success' as any); | ||
|
||
const result = await controller.processRequest(body, params); | ||
expect(result).toEqual('success'); | ||
expect(participantsRequestService.processTeamEditRequest).toHaveBeenCalledWith(params.uid); | ||
}); | ||
|
||
it('should call processMemberEditRequest when status is APPROVED for MEMBER with referenceUid', async () => { | ||
const body = { participantType: 'MEMBER', status: ApprovalStatus.APPROVED, referenceUid: '456' }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(participantsRequestService, 'processMemberEditRequest').mockResolvedValue('success' as any); | ||
|
||
const result = await controller.processRequest(body, params); | ||
expect(result).toEqual('success'); | ||
expect(participantsRequestService.processMemberEditRequest).toHaveBeenCalledWith(params.uid); | ||
}); | ||
}); | ||
|
||
describe('AdminController - ForbiddenException Scenarios', () => { | ||
|
||
|
||
describe('addRequest - ForbiddenException cases', () => { | ||
it('should throw ForbiddenException for invalid MEMBER schema', async () => { | ||
const body = { participantType: ParticipantType.MEMBER, invalidField: 'error' }; | ||
jest.spyOn(ParticipantRequestMemberSchema, 'safeParse').mockReturnValueOnce({ success: false } as any); | ||
|
||
await expect(controller.addRequest(body)).rejects.toThrow(ForbiddenException); | ||
}); | ||
|
||
it('should throw ForbiddenException for invalid TEAM schema', async () => { | ||
const body = { participantType: ParticipantType.TEAM, invalidField: 'error' }; | ||
jest.spyOn(ParticipantRequestTeamSchema, 'safeParse').mockReturnValueOnce({ success: false } as any); | ||
|
||
await expect(controller.addRequest(body)).rejects.toThrow(ForbiddenException); | ||
}); | ||
|
||
it('should throw ForbiddenException for unknown participant type', async () => { | ||
const body = { participantType: 'UNKNOWN_TYPE' }; | ||
|
||
await expect(controller.addRequest(body)).rejects.toThrow(ForbiddenException); | ||
}); | ||
}); | ||
|
||
describe('updateRequest - ForbiddenException cases', () => { | ||
it('should throw ForbiddenException for invalid MEMBER schema on update', async () => { | ||
const body = { participantType: ParticipantType.MEMBER, invalidField: 'error' }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(ParticipantRequestMemberSchema, 'safeParse').mockReturnValueOnce({ success: false } as any); | ||
|
||
await expect(controller.updateRequest(body, params)).rejects.toThrow(ForbiddenException); | ||
}); | ||
|
||
it('should throw ForbiddenException for invalid TEAM schema on update', async () => { | ||
const body = { participantType: ParticipantType.TEAM, invalidField: 'error' }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(ParticipantRequestTeamSchema, 'safeParse').mockReturnValueOnce({ success: false } as any); | ||
|
||
await expect(controller.updateRequest(body, params)).rejects.toThrow(ForbiddenException); | ||
}); | ||
}); | ||
|
||
describe('processRequest - ForbiddenException case', () => { | ||
it('should throw ForbiddenException for invalid process request schema', async () => { | ||
const body = { status: 'INVALID_STATUS' }; | ||
const params = { uid: '123' }; | ||
jest.spyOn(ParticipantProcessRequestSchema, 'safeParse').mockReturnValueOnce({ success: false } as any); | ||
|
||
await expect(controller.processRequest(body, params)).rejects.toThrow(ForbiddenException); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { AdminService } from './admin.service'; | ||
import { UnauthorizedException } from '@nestjs/common'; | ||
import { JwtService } from '../utils/jwt/jwt.service'; | ||
|
||
describe('AdminService', () => { | ||
let adminService: AdminService; | ||
let jwtService: JwtService; | ||
|
||
beforeEach(() => { | ||
// Mock JwtService | ||
jwtService = { | ||
getSignedToken: jest.fn().mockResolvedValue('mockedToken'), | ||
} as unknown as JwtService; | ||
|
||
adminService = new AdminService(jwtService); | ||
|
||
// Mock environment variables | ||
process.env.ADMIN_USERNAME = 'admin'; | ||
process.env.ADMIN_PASSWORD = 'password'; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should return a signed JWT token if credentials are valid', async () => { | ||
const username = 'admin'; | ||
const password = 'password'; | ||
|
||
const result = await adminService.signIn(username, password); | ||
|
||
expect(result).toEqual({ code: 1, accessToken: 'mockedToken' }); | ||
expect(jwtService.getSignedToken).toHaveBeenCalledWith(['DIRECTORYADMIN']); | ||
}); | ||
|
||
it('should throw UnauthorizedException if username is invalid', async () => { | ||
const username = 'invalidAdmin'; | ||
const password = 'password'; | ||
|
||
await expect(adminService.signIn(username, password)).rejects.toThrow(UnauthorizedException); | ||
expect(jwtService.getSignedToken).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should throw UnauthorizedException if password is invalid', async () => { | ||
const username = 'admin'; | ||
const password = 'wrongPassword'; | ||
|
||
await expect(adminService.signIn(username, password)).rejects.toThrow(UnauthorizedException); | ||
expect(jwtService.getSignedToken).not.toHaveBeenCalled(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; | ||
|
||
// Define the RequestIp decorator | ||
export const RequestIp = createParamDecorator((data: unknown, context: ExecutionContext) => { | ||
const req = context.switchToHttp().getRequest(); | ||
return req.headers['x-forwarded-for'] || req.connection.remoteAddress; | ||
}); | ||
|
||
describe('RequestIp Decorator', () => { | ||
it('should return the x-forwarded-for header if it exists', () => { | ||
const mockRequest = { | ||
headers: { | ||
'x-forwarded-for': '123.45.67.89', | ||
}, | ||
connection: { | ||
remoteAddress: '98.76.54.32', // This should not be returned | ||
}, | ||
}; | ||
|
||
const mockContext = { | ||
switchToHttp: () => ({ | ||
getRequest: () => mockRequest, | ||
}), | ||
} as unknown as ExecutionContext; // Type assertion to satisfy TypeScript | ||
|
||
// Call the decorator as it would be called in a real scenario | ||
const result = RequestIp('', mockContext); // Provide an empty string | ||
expect(result).toBe('123.45.67.89'); // Check the returned value | ||
}); | ||
|
||
it('should return remoteAddress if x-forwarded-for header does not exist', () => { | ||
const mockRequest = { | ||
headers: {}, | ||
connection: { | ||
remoteAddress: '98.76.54.32', | ||
}, | ||
}; | ||
|
||
const mockContext = { | ||
switchToHttp: () => ({ | ||
getRequest: () => mockRequest, | ||
}), | ||
} as unknown as ExecutionContext; // Type assertion to satisfy TypeScript | ||
|
||
// Call the decorator as it would be called in a real scenario | ||
const result = RequestIp('', mockContext); // Provide an empty string | ||
expect(result).toBe('98.76.54.32'); // Check the returned value | ||
}); | ||
}); |
Oops, something went wrong.