Skip to content

Commit

Permalink
test: add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yxuo committed Sep 22, 2023
1 parent cc6354c commit f9b850b
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 3 deletions.
67 changes: 67 additions & 0 deletions src/users/users.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { HttpStatus, Provider } from '@nestjs/common';

describe('UsersController', () => {
let usersController: UsersController;
let usersService: UsersService;

beforeEach(async () => {
const usersServiceMock = {
provide: UsersService,
useValue: {
createFromFile: jest.fn(),
},
} as Provider;
const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [usersServiceMock],
}).compile();

usersController = module.get<UsersController>(UsersController);
usersService = module.get<UsersService>(UsersService);
});

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

describe('uploadFile', () => {
it('should upload a valid file', async () => {
// Arrange
const fileMock = {
originalname: 'test.csv',
mimetype: 'text/csv',
path: 'something',
buffer: Buffer.from('mock file content'),
} as Express.Multer.File;
const expectedResult = HttpStatus.CREATED;

jest
.spyOn(usersService, 'createFromFile')
.mockResolvedValue(expectedResult);

// Act
const result = await usersController.uploadFile(fileMock);

// Assert
expect(usersService.createFromFile).toHaveBeenCalledWith(fileMock);
expect(result).toBe(expectedResult);
});
it('should throw error when file is invalid', async () => {
// Arrange
const fileMock = {
originalname: 'test.csv',
mimetype: 'text/csv',
path: 'something',
buffer: Buffer.from('invalid file'),
} as Express.Multer.File;

jest.spyOn(usersService, 'createFromFile').mockRejectedValue(new Error());

// Assert
await expect(usersController.uploadFile(fileMock)).rejects.toThrowError();
});
});
});
161 changes: 161 additions & 0 deletions src/users/users.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { Provider } from '@nestjs/common';
import { Repository } from 'typeorm';
import { FileUserInterface } from './interfaces/file-user.interface';
import { CreateUserExcelDto } from './dto/create-user-excel.dto';
import * as CLASS_VALIDATOR from 'class-validator';
import * as XLSX from 'xlsx';

describe('UsersService', () => {
let usersService: UsersService;
let usersRepository: Repository<User>;
const USER_REPOSITORY_TOKEN = getRepositoryToken(User);
const usersRepositoryMock = {
provide: USER_REPOSITORY_TOKEN,
useValue: {
create: jest.fn(),
save: jest.fn(),
find: jest.fn(),
findOne: jest.fn(),
},
} as Provider;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService, usersRepositoryMock],
}).compile();

usersService = module.get<UsersService>(UsersService);
usersRepository = module.get<Repository<User>>(USER_REPOSITORY_TOKEN);
});

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

describe('create', () => {
it('should create a user', async () => {
// Arrange
const createUserDto = {
email: '[email protected]',
} as CreateUserDto;
const user = {
email: createUserDto.email,
} as User;

jest.spyOn(usersRepository, 'save').mockResolvedValue(user);

// Act
const result = await usersService.create(createUserDto);

// Assert
expect(usersRepository.save).toBeCalled();
expect(result).toEqual(user);
});
});

describe('createFromFile', () => {
it('should create users from a valid file', async () => {
// Arrange
const fileMock = {
buffer: {},
} as Express.Multer.File;

const expectedFileUsers = [] as FileUserInterface[];
for (let i = 0; i < 3; i++) {
expectedFileUsers.push({
row: i + 2,
user: {
email: `email_${i}@example.com`,
},
errors: {},
} as FileUserInterface);
}
jest
.spyOn(usersService, 'getExcelUsersFromWorksheet')
.mockResolvedValue(expectedFileUsers);

// Act
await usersService.createFromFile(fileMock);

// Assert
expect(usersService.getExcelUsersFromWorksheet).toHaveBeenCalledWith(
expect.any(Object),
expect.any(Array),
expect.any(Function),
);
expect(usersRepository.save).toBeCalledTimes(expectedFileUsers.length);
});

it('should throw error if file content has errors', async () => {
// Arrange
const fileMock = {
buffer: {},
} as Express.Multer.File;

const expectedFileUsers = [] as FileUserInterface[];
for (let i = 0; i < 3; i++) {
expectedFileUsers.push({
row: i + 2,
user: {
email: `invalidEmail_${i} example.com`,
},
errors: {
email: 'invalid',
},
} as FileUserInterface);
}
jest
.spyOn(usersService, 'getExcelUsersFromWorksheet')
.mockResolvedValue(expectedFileUsers);

// Assert
await expect(
usersService.createFromFile(fileMock),
).rejects.toThrowError();
});
});

describe('getExcelUsersFromWorksheet', () => {
it('should extract users from a valid worksheet', async () => {
// Arrange
const worksheetMock = {};
const expectedUserFields = ['permitCode', 'email'];
jest.spyOn(XLSX.utils, 'sheet_to_json').mockReturnValue([
{
codigo_permissionario: 'permitCode1',
email: '[email protected]',
},
]);
jest.spyOn(CLASS_VALIDATOR, 'validate').mockReturnValue([]);
const expectedResult = [
{
row: 2,
user: {
permitCode: 'permitCode1',
email: '[email protected]',
},
errors: {},
},
] as FileUserInterface[];

// Act
const result = await usersService.getExcelUsersFromWorksheet(
worksheetMock,
expectedUserFields,
CreateUserExcelDto,
);

// Assert
expect(result).toEqual(expectedResult);
});
});

afterEach(() => {
jest.clearAllMocks();
});
});
7 changes: 4 additions & 3 deletions src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ export class UsersService {
async createFromFile(file: Express.Multer.File): Promise<any> {
const worksheet = this.getWorksheetFromFile(file);
const expectedUserFields = ['permitCode', 'email'];
const excelUsers = await this.getExcelUsersFromWorksheet(
const fileUsers = await this.getExcelUsersFromWorksheet(
worksheet,
expectedUserFields,
CreateUserExcelDto,
);
const invalidUsers = excelUsers.filter(
const invalidUsers = fileUsers.filter(
(i) => Object.keys(i.errors).length > 0,
);
if (invalidUsers.length > 0) {
Expand All @@ -203,10 +203,11 @@ export class UsersService {
);
}

for (const excelUser of excelUsers) {
for (const excelUser of fileUsers) {
await this.usersRepository.save(
this.usersRepository.create(excelUser.user),
);
}
return HttpStatus.CREATED;
}
}

0 comments on commit f9b850b

Please sign in to comment.