Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions src/todo/todo.controller.spec.ts

This file was deleted.

174 changes: 173 additions & 1 deletion src/todo/todo.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,190 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TodoService } from './todo.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Todo, TodoState } from './../entities/todo.entity';
import { User } from './../entities/user.entity';
import { Repository } from 'typeorm';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this import to top

import {
InternalServerErrorException,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { plainToClass } from 'class-transformer';
import { CreateTodoDto } from './dto/create-todo.dto';

describe('TodoService', () => {
let service: TodoService;
let todoRepository: Repository<Todo>;
let userRepository: Repository<User>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TodoService],
providers: [
TodoService,
{
provide: getRepositoryToken(Todo),
useValue: {
findOne: jest.fn(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store them in a variable at the top and assign here, so that u can directly use it later

save: jest.fn(),
create: jest.fn(),
},
},
{
provide: getRepositoryToken(User),
useValue: {
findOne: jest.fn(),
},
},
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clear all mocks before each run

}).compile();

service = module.get<TodoService>(TodoService);
todoRepository = module.get<Repository<Todo>>(getRepositoryToken(Todo));
userRepository = module.get<Repository<User>>(getRepositoryToken(User));
jest.clearAllMocks();
});

it('should be defined', () => {
expect(service).toBeDefined();
expect(todoRepository).toBeDefined();
expect(userRepository).toBeDefined();
});

describe('find', () => {
it('should return a todo if it exists and belongs to the user', async () => {
const mockTodo = {
id: 1,
title: 'Test Todo',
description: 'Description of the test todo',
state: 'pending',
userId: 1,
};

(todoRepository.findOne as jest.Mock).mockResolvedValue(mockTodo);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use mockResolvedValueOnce instead of this


const userID = 1;
const todoID = 1;

const result = await service.find(todoID, userID);

const sanitizedTodo = plainToClass(Todo, mockTodo, {
excludeExtraneousValues: true,
});
expect(result).toEqual(sanitizedTodo);

expect(todoRepository.findOne).toHaveBeenCalledWith({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also check how many times its been called

where: { id: todoID },
});
});

it('should throw NotFoundException if the todo is not found', async () => {
const todoID = 1;
const userID = 1;

(todoRepository.findOne as jest.Mock).mockResolvedValue(null);

await expect(service.find(todoID, userID)).rejects.toThrow(
NotFoundException,
);
});

it('should throw UnauthorizedException if the user does not own the todo', async () => {
const mockTodo = {
id: 1,
title: 'Test Todo',
description: 'Description of todo',
state: 'pending',
userId: 2,
};

const todoID = 1;
const userID = 1;

(todoRepository.findOne as jest.Mock).mockResolvedValue(mockTodo);

await expect(service.find(todoID, userID)).rejects.toThrow(
UnauthorizedException,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should return forbidden error instead of unauthorized

);
await expect(service.find(todoID, userID)).rejects.toThrow(
`You don't have access to this todo`,
);
});
});

describe('create', () => {
const mockUser: User = {
id: 1,
email: 'test@email.com',
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
password: 'password123',
todos: [],
};

const mockCreateTodoPayload: CreateTodoDto = {
title: 'test todo',
state: TodoState.PENDING,
userId: 1,
description: 'test description',
};

const unsanitizedTodo: Todo = {
id: 1,
title: 'test todo',
state: TodoState.PENDING,
userId: 1,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
description: 'test description',
user: mockUser,
};

const mockTodo = {
title: 'test todo',
description: 'test description',
state: TodoState.PENDING,
userId: 1,
user: mockUser,
};

const mockSanitizedTodo = plainToClass(Todo, unsanitizedTodo, {
excludeExtraneousValues: true,
});

it('should throw NotFoundException if the user is not found', async () => {
(userRepository.findOne as jest.Mock).mockResolvedValue(null);

await expect(service.create(mockCreateTodoPayload)).rejects.toThrow(
NotFoundException,
);
});

it('should throw internal server error when saving', async () => {
(userRepository.findOne as jest.Mock).mockResolvedValue(mockUser);

(todoRepository.save as jest.Mock).mockRejectedValue(
new Error('Database error'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use typeorm QueryFailedError

);

await expect(service.create(mockCreateTodoPayload)).rejects.toThrow(
InternalServerErrorException,
);
await expect(service.create(mockCreateTodoPayload)).rejects.toThrow(
'An error occurred while saving the todo',
);
});

it('successfully create the todo', async () => {
(userRepository.findOne as jest.Mock).mockResolvedValue(mockUser);

(todoRepository.save as jest.Mock).mockResolvedValue(unsanitizedTodo);
(todoRepository.create as jest.Mock).mockResolvedValue(mockTodo);

const result = await service.create(mockCreateTodoPayload);

expect(result).toEqual(mockSanitizedTodo);
});
});
});
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"compilerOptions": {
"paths": {
"src/*": ["src/*"]
},
"module": "commonjs",
"declaration": true,
"removeComments": true,
Expand Down