27
loading...
This website collects cookies to deliver better user experience
mkdir getting-started-with-jest && cd $_
npm init -y
npm i jest --save-dev
Let's also configure an NPM script for running our tests from the command line. Open up package.json and configure a script named test for running Jest:
"scripts": {
"test": "jest"
},
Fakes
: an object with limited capabilities (for the purposes of testing), e.g. a fake web service. Fake has business behavior. You can drive a fake to behave in different ways by giving it different data. Fakes can be used when you can’t use a real implementation in your test.Mock
: an object on which you set expectations. A mock has expectations about the way it should be called, and a test should fail if it’s not called that way. Mocks are used to test interactions between objects.Stub
: an object that provides predefined answers to method calls. A stub has no logic and only returns what you tell it to return.Spy
: Spy, spies on the caller. Often used to make sure a particular method has been called.import { Test, TestingModule } from '@nestjs/testing';
import { ApiService } from './api.service';
import { HttpModule } from '@nestjs/common';
describe('ApiService', () => {
let service: ApiService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ApiService],
imports: [HttpModule],
}).compile();
service = module.get<ApiService>(ApiService);
});
it('ApiService - should be defined', () => {
expect(service).toBeDefined();
});
});
Test.createTestingModule
, once we have module we can get services and controllers from module and test their methods with mock already done while creating test modulebeforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ApiService],
imports: [HttpModule],
}).compile();
// getting service modue from main module
service = module.get<ApiService>(ApiService);
});
// now checking if service is available
it('ApiService - should be defined', () => {
expect(service).toBeDefined();
});
import {
Get,
Post,
Controller,
HttpCode,
HttpStatus,
Body,
Req,
Param,
ParamData,
Patch,
Delete,
ValidationPipe,
UsePipes,
} from '@nestjs/common';
import NoteService from '../services/note.service';
import { CreateNoteDto, GetNoteById } from '../dto/create-note.dto';
import { UpdateNoteDto } from '../dto/update-note-dto';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
@Controller('/api/v1/notes')
export class NoteController {
constructor(private readonly noteService: NoteService) {}
@Post()
@ApiTags('notes')
@ApiOperation({ description: 'Get All categories or sub-categories' })
@UsePipes(ValidationPipe)
@HttpCode(HttpStatus.CREATED)
async saveNote(@Body() dto: CreateNoteDto) {
return await this.noteService.saveNote(dto);
}
@ApiTags('notes')
@Get('/')
@ApiOperation({ description: 'Get All categories or sub-categories' })
@UsePipes(ValidationPipe)
@HttpCode(HttpStatus.OK)
async getAllNote() {
return await this.noteService.findAllNotes({});
}
@ApiTags('notes')
@ApiOperation({ description: 'Get All categories or sub-categories' })
@UsePipes(ValidationPipe)
@HttpCode(HttpStatus.OK)
@Get('/:id')
async getNoteById(@Param() dto: GetNoteById) {
return await this.noteService.findOneNote({
where: {
id: dto.id,
},
});
}
@ApiTags('notes')
@ApiOperation({ description: 'Get All categories or sub-categories' })
@UsePipes(ValidationPipe)
@HttpCode(HttpStatus.OK)
@Patch('/:id')
async updateNoteById(
@Param() param: GetNoteById,
@Body() dto: UpdateNoteDto,
) {
return await this.noteService.updateNote(param.id, dto);
}
@ApiTags('notes')
@ApiOperation({ description: 'delete notes' })
@UsePipes(ValidationPipe)
@HttpCode(HttpStatus.OK)
@Delete('/:id')
async deleteNoteById(@Param() param: GetNoteById,) {
return await this.noteService.deleteNote(param.id);
}
}
import { Test, TestingModule } from '@nestjs/testing';
import { NoteController } from './note.controller';
import NoteService from '../services/note.service';
import { CreateNoteDto, GetNoteById } from '../dto/create-note.dto';
describe("NoteController Unit Tests", () => {
let noteController: NoteController;
let spyService: NoteService
beforeAll(async () => {
const ApiServiceProvider = {
provide: NoteService,
useFactory: () => ({
saveNote: jest.fn(() => []),
findAllNotes: jest.fn(() => []),
findOneNote: jest.fn(() => { }),
updateNote: jest.fn(() => { }),
deleteNote: jest.fn(() => { })
})
}
const app: TestingModule = await Test.createTestingModule({
controllers: [NoteController],
providers: [NoteService, ApiServiceProvider],
}).compile();
noteController = app.get<NoteController>(NoteController);
spyService = app.get<NoteService>(NoteService);
})
it("calling saveNotes method", () => {
const dto = new CreateNoteDto();
expect(noteController.saveNote(dto)).not.toEqual(null);
})
it("calling saveNotes method", () => {
const dto = new CreateNoteDto();
noteController.saveNote(dto);
expect(spyService.saveNote).toHaveBeenCalled();
expect(spyService.saveNote).toHaveBeenCalledWith(dto);
})
it("calling getAllNote method", () => {
noteController.getAllNote();
expect(spyService.findAllNotes).toHaveBeenCalled();
})
it("calling find NoteById method", () => {
const dto = new GetNoteById();
dto.id = '3789';
noteController.getNoteById(dto);
expect(spyService.findOneNote).toHaveBeenCalled();
})
});
const ApiServiceProvider = {
provide: NoteService,
useFactory: () => ({
saveNote: jest.fn(() => []),
findAllNotes: jest.fn(() => []),
findOneNote: jest.fn(() => { }),
updateNote: jest.fn(() => { }),
deleteNote: jest.fn(() => { })
})
}
const app: TestingModule = await Test.createTestingModule({
controllers: [NoteController],
providers: [NoteService, ApiServiceProvider],
}).compile();
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, FindOneOptions, FindManyOptions } from 'typeorm';
import Note from '../entity/note.entity';
import * as _ from 'lodash';
import { CreateNoteDto } from '../dto/create-note.dto';
import { UpdateNoteDto } from '../dto/update-note-dto';
@Injectable()
export default class NoteService {
constructor(
@InjectRepository(Note) private readonly noteRepository: Repository<Note>,
) {}
async saveNote(dto: CreateNoteDto) {
const note = new Note();
note.text = dto.text;
note.is_completed = dto.is_completed;
return await this.noteRepository.save(note);
}
async findAllNotes(findAllOptions: FindManyOptions<Note>) {
return await this.noteRepository.find(findAllOptions);
}
async findOneNote(findOneOptions: FindOneOptions<Note>) {
return await this.noteRepository.findOne(findOneOptions);
}
async updateNote(noteId: string, dto: UpdateNoteDto) {
const foundNote = await this.findOneNote({
where: { id: noteId },
});
return await this.noteRepository.save(_.merge(foundNote, dto));
}
async deleteNote(noteId: string) {
const foundNote = await this.findOneNote({
where: { id: noteId },
});
if(foundNote) {
await this.noteRepository.delete(foundNote);
return foundNote;
}
return null;
}
}
import { Test, TestingModule } from '@nestjs/testing';
import NoteService from './note.service';
import { Repository, FindOneOptions, FindManyOptions } from 'typeorm';
import { CreateNoteDto } from '../dto/create-note.dto';
import { UpdateNoteDto } from '../dto/update-note-dto';
class ApiServiceMock {
saveNote(dto: any) {
return [];
}
findOneNote() {
return [];
}
deleteNote(id: string) {
return null;
}
updateNote(id: string, dto: any) {
return [];
}
}
describe.only("NoteService", () => {
let noteService: NoteService;
beforeAll(async () => {
const ApiServiceProvider = {
provide: NoteService,
useClass: ApiServiceMock,
}
const module: TestingModule = await Test.createTestingModule({
providers: [
NoteService, ApiServiceProvider
],
}).compile();
noteService = module.get<NoteService>(NoteService);
})
it('should call saveNote method with expected params', async () => {
const createNoteSpy = jest.spyOn(noteService, 'saveNote');
const dto = new CreateNoteDto();
noteService.saveNote(dto);
expect(createNoteSpy).toHaveBeenCalledWith(dto);
});
it('should call findOneNote method with expected param', async () => {
const findOneNoteSpy = jest.spyOn(noteService, 'findOneNote');
const findOneOptions: FindOneOptions = {};
noteService.findOneNote(findOneOptions);
expect(findOneNoteSpy).toHaveBeenCalledWith(findOneOptions);
});
it('should call updateNote method with expected params', async () => {
const updateNoteSpy = jest.spyOn(noteService, 'updateNote');
const noteId = 'noteId';
const dto = new UpdateNoteDto();
noteService.updateNote(noteId, dto);
expect(updateNoteSpy).toHaveBeenCalledWith(noteId, dto);
});
it('should call deleteNote method with expected param', async () => {
const deleteNoteSpy = jest.spyOn(noteService, 'deleteNote');
const noteId = 'noteId';
noteService.deleteNote(noteId);
expect(deleteNoteSpy).toHaveBeenCalledWith(noteId);
});
})
const ApiServiceProvider = {
provide: NoteService,
useClass: ApiServiceMock,
}
import { getRepositoryToken } from '@nestjs/typeorm';
providers: [
{
provide: getRepositoryToken(User),
useValue: {},
}
],
import {Test, TestingModule} from '@nestjs/testing';
import NoteService from './note.service';
import * as sinon from 'sinon';
import { getRepositoryToken } from '@nestjs/typeorm';
import Note from '../entity/note.entity';
import { Repository, FindOneOptions, FindManyOptions } from 'typeorm';
import { CreateNoteDto } from '../dto/create-note.dto';
import { UpdateNoteDto } from '../dto/update-note-dto';
describe("NoteService", () => {
let noteService: NoteService;
let sandbox : sinon.SinonSandbox;
beforeAll(async() => {
sandbox = sinon.createSandbox();
const module: TestingModule = await Test.createTestingModule({
providers: [
NoteService,
{
provide: getRepositoryToken(Note),
useValue: sinon.createStubInstance(Repository),
},
],
}).compile();
noteService = module.get<NoteService>(NoteService);
})
it('should call saveNote method with expected params', async () => {
const createNoteSpy = jest.spyOn(noteService, 'saveNote');
const dto = new CreateNoteDto();
noteService.saveNote(dto);
expect(createNoteSpy).toHaveBeenCalledWith(dto);
});
it('should call findOneNote method with expected param', async () => {
const findOneNoteSpy = jest.spyOn(noteService, 'findOneNote');
const findOneOptions: FindOneOptions = {};
noteService.findOneNote(findOneOptions);
expect(findOneNoteSpy).toHaveBeenCalledWith(findOneOptions);
});
it('should call updateNote method with expected params', async () => {
const updateNoteSpy = jest.spyOn(noteService, 'updateNote');
const noteId = 'noteId';
const dto = new UpdateNoteDto();
noteService.updateNote(noteId, dto);
expect(updateNoteSpy).toHaveBeenCalledWith(noteId, dto);
});
it('should call deleteNote method with expected param', async () => {
const deleteNoteSpy = jest.spyOn(noteService, 'deleteNote');
const noteId = 'noteId';
noteService.deleteNote(noteId);
expect(deleteNoteSpy).toHaveBeenCalledWith(noteId);
});
afterAll(async () => {
sandbox.restore();
});
})
src/users/tests/users.service.spec.ts
import { Test } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import User from '../../users/user.entity';
import { UsersService } from '../../users/users.service';
describe('The UsersService', () => {
let usersService: UsersService;
let findOne: jest.Mock;
beforeEach(async () => {
findOne = jest.fn();
const module = await Test.createTestingModule({
providers: [
UsersService,
{
provide: getRepositoryToken(User),
useValue: {
findOne
}
}
],
})
.compile();
usersService = await module.get(UsersService);
})
describe('when getting a user by email', () => {
describe('and the user is matched', () => {
let user: User;
beforeEach(() => {
user = new User();
findOne.mockReturnValue(Promise.resolve(user));
})
it('should return the user', async () => {
const fetchedUser = await usersService.getByEmail('[email protected]');
expect(fetchedUser).toEqual(user);
})
})
describe('and the user is not matched', () => {
beforeEach(() => {
findOne.mockReturnValue(undefined);
})
it('should throw an error', async () => {
await expect(usersService.getByEmail('[email protected]')).rejects.toThrow();
})
})
})
});
overrideProvider
method from nestjs uploadToAzure
which will return upload file linkdescribe('testing', () => {
let app: INestApplication;
let testUtils: TestUtils;
let moduleRef: TestingModule;
beforeEach(async () => {
moduleRef = await Test.createTestingModule({
imports: [AppModule],
providers: [TestUtils, DatabaseService],
})
.overrideProvider(AuthService)
.useValue({
init: (token: string) => testUtils.getRandomUser(token),
})
.overrideProvider(BlobUploadService)
.useValue({ uploadToAzure: () => 'http://test__link_logo.com' })
.compile();
app = moduleRef.createNestApplication();
testUtils = moduleRef.get<TestUtils>(TestUtils);
await testUtils.reloadFixtures();
await app.init();
});
27