-
Notifications
You must be signed in to change notification settings - Fork 5
Tests
Important
Tests will need to be updated / added when you update/create a new endpoint
All tests need to cover all the endpoints, and all possible responses. They should be organized like the below example
Tip
describe for each endpoint should include - METHOD /route optionally a short description of the route
- it should contain the expected return, and the action,
- arrange in ascending statuscode i.e. 200, 201, 400, 401,404 etc
- use additional describe if needed
Example: Auth Controller e2e tests
There are 2 unit tests for each module, the controller, and service unit tests (.controller.spec.ts, .service.spec.ts)
Tests required
- expect controller to be defined
- expect services to be defined
- expect (mocked) functions to be defined
- mocked functions to be called
- All functions need to be tested ( 1 describe block per function)
- All dependencies and functions inside the each main controller/service function should be mocked and tested with tobecalledWith() or tobeCalled()
Anything already tested in e2e will not need to be tested here, e.g different responses (401, 403, etc)
Note
In the service unit tests we use prisma mock
Sample controller unit test
describe("VoyagesController", () => {
let controller: VoyagesController;
const requestMock = {} as unknown as CustomRequest;
const dtoMock = {
voyageTeamId: 1,
responses: [
{ questionId: 26, text: "All" },
{ questionId: 27, text: "Deploy app" },
],
} as CreateVoyageProjectSubmissionDto;
const mockVoyagesService = {
submitVoyageProject: jest.fn((_requestMock, _dtoMock) => {
return {
id: 1,
voyageTeamId: 1,
responseGroupId: 1,
createdAt: new Date(Date.now()),
};
}),
getVoyageProjects: jest.fn(() => {
return [
{
id: 1,
voyageTeamId: 1,
responseGroupId: 1,
createdAt: new Date(Date.now()),
},
{
id: 2,
voyageTeamId: 2,
responseGroupId: 1,
createdAt: new Date(Date.now()),
},
];
}),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [VoyagesController],
providers: [VoyagesService],
})
.overrideProvider(VoyagesService)
.useValue(mockVoyagesService)
.compile();
controller = module.get<VoyagesController>(VoyagesController);
});
it("voyages controller should be defined", () => {
expect(controller).toBeDefined();
});
it("voyages service should be defined", () => {
expect(controller.submitVoyageProject).toBeDefined();
});
describe("createVoyageProjectSubmission", () => {
it("should be defined", () => {
expect(controller.submitVoyageProject).toBeDefined();
});
it("should submit a voyage project", async () => {
expect(
await controller.submitVoyageProject(requestMock, dtoMock),
).toEqual({
id: expect.any(Number),
voyageTeamId: expect.any(Number),
responseGroupId: expect.any(Number),
createdAt: expect.any(Date),
});
expect(mockVoyagesService.submitVoyageProject).toHaveBeenCalledWith(
requestMock,
dtoMock,
);
});
});
describe("should get all voyage project submissions", () => {
it("should be defined", () => {
expect(controller.getAllVoyageProjects).toBeDefined();
});
it("should get all voyage project submissions", async () => {
const projects = await controller.getAllVoyageProjects();
expect(projects).toHaveLength(2);
expect(projects).toBeArray();
expect(projects).toContainEqual({
id: expect.any(Number),
voyageTeamId: expect.any(Number),
responseGroupId: expect.any(Number),
createdAt: expect.any(Date),
});
expect(mockVoyagesService.getVoyageProjects).toHaveBeenCalledWith();
});
});
});
Sample service unit test
describe("VoyagesService", () => {
let service: VoyagesService;
const requestMock = {
user: {
userId: "d31315ef-93c8-488f-a3f6-cb2df0016738",
email: "[email protected]",
role: ["voyager"],
voyageTeams: [
{
teamId: 1,
memberId: 1,
},
],
},
} as unknown as CustomRequest;
const dtoMock = {
voyageTeamId: 1,
responses: [
{ questionId: 26, text: "All" },
{ questionId: 27, text: "Deploy app" },
],
} as CreateVoyageProjectSubmissionDto;
const mockGlobalService = {
responseDtoToArray: jest.fn((_dtoMock) => {
return [_dtoMock.responses];
}),
checkQuestionsInFormByTitle: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
VoyagesService,
{
provide: PrismaService,
useValue: prismaMock,
},
GlobalService,
{
provide: GlobalService,
useValue: mockGlobalService,
},
],
}).compile();
service = module.get<VoyagesService>(VoyagesService);
});
it("should be defined", () => {
expect(service).toBeDefined();
});
it("should be able to submit a voyage project", async () => {
prismaMock.$transaction.mockResolvedValueOnce({
id: 1,
voyageTeamId: 1,
responseGroupId: 1,
createdAt: new Date(Date.now()),
});
expect(await service.submitVoyageProject(requestMock, dtoMock)).toEqual(
{
id: expect.any(Number),
voyageTeamId: expect.any(Number),
responseGroupId: expect.any(Number),
createdAt: expect.any(Date),
},
);
expect(mockGlobalService.responseDtoToArray).toHaveBeenCalledWith(
dtoMock,
);
expect(
mockGlobalService.checkQuestionsInFormByTitle,
).toHaveBeenCalled();
});
it("should get all voyage projects ", async () => {
prismaMock.formResponseVoyageProject.findMany.mockResolvedValue([
{
id: 1,
voyageTeamId: 1,
responseGroupId: 1,
createdAt: new Date(Date.now()),
updatedAt: new Date(Date.now()),
},
{
id: 2,
voyageTeamId: 1,
responseGroupId: 2,
createdAt: new Date(Date.now()),
updatedAt: new Date(Date.now()),
},
]);
const projects = await service.getVoyageProjects();
expect(projects).toHaveLength(2);
expect(projects).toBeArray();
expect(projects).toContainEqual({
id: expect.any(Number),
voyageTeamId: expect.any(Number),
responseGroupId: expect.any(Number),
createdAt: expect.any(Date),
updatedAt: expect.any(Date),
});
});
});
Note
Both Marius and Anson have e2e tests video on NestJS which are worth looking at
NestJS Testing Tutorial | Unit and Integration Testing (Marius Espejo)
Anson the developer
https://github.com/prisma/prisma/discussions/14435
https://github.com/prisma/prisma/discussions/22865
https://stackoverflow.com/questions/73007221/how-to-unit-test-a-transaction-wrapped-function-in-prisma
NestJS - Unit and E2E Testing
Build Complete REST API Feature with Nest JS (Using Prisma and Postgresql) from Scratch - Beginner-friendly - PART 5
API with NestJS #102. Writing unit tests with Prisma
NestJS Testing Recipe: Mocking Prisma
NestJS unit testing: A how-to guide with examples
fn vs spyOn