feat: add unit tests

This commit is contained in:
Mohamed Marrouchi 2024-09-22 19:03:53 +01:00
parent 10f36c2d48
commit 432193cad9
3 changed files with 205 additions and 2 deletions

View File

@ -0,0 +1,169 @@
/*
* Copyright © 2024 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
* 3. SaaS Restriction: This software, or any derivative of it, may not be used to offer a competing product or service (SaaS) without prior written consent from Hexastack. Offering the software as a service or using it in a commercial cloud environment without express permission is strictly prohibited.
*/
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { BadRequestException, NotFoundException } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Test } from '@nestjs/testing';
import { I18nService } from '@/i18n/services/i18n.service';
import { LoggerService } from '@/logger/logger.service';
import { NOT_FOUND_ID } from '@/utils/constants/mock';
import {
installLanguageFixtures,
languageFixtures,
} from '@/utils/test/fixtures/language';
import { getPageQuery } from '@/utils/test/pagination';
import {
closeInMongodConnection,
rootMongooseTestModule,
} from '@/utils/test/test';
import { LanguageController } from './language.controller';
import { LanguageUpdateDto } from '../dto/language.dto';
import { LanguageRepository } from '../repositories/language.repository';
import { Language, LanguageModel } from '../schemas/language.schema';
import { LanguageService } from '../services/language.service';
describe('LanguageController', () => {
let languageController: LanguageController;
let languageService: LanguageService;
let language: Language;
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [
rootMongooseTestModule(installLanguageFixtures),
MongooseModule.forFeature([LanguageModel]),
],
providers: [
LanguageController,
LanguageService,
LanguageRepository,
LoggerService,
{
provide: I18nService,
useValue: {
t: jest.fn().mockImplementation((t) => t),
initDynamicLanguages: jest.fn(),
},
},
{
provide: CACHE_MANAGER,
useValue: {
del: jest.fn(),
get: jest.fn(),
set: jest.fn(),
},
},
LoggerService,
],
}).compile();
languageService = module.get<LanguageService>(LanguageService);
languageController = module.get<LanguageController>(LanguageController);
language = await languageService.findOne({ code: 'en' });
});
afterEach(jest.clearAllMocks);
afterAll(closeInMongodConnection);
describe('count', () => {
it('should count languages', async () => {
jest.spyOn(languageService, 'count');
const result = await languageController.filterCount();
expect(languageService.count).toHaveBeenCalled();
expect(result).toEqual({ count: languageFixtures.length });
});
});
describe('findOne', () => {
it('should find one translation by id', async () => {
jest.spyOn(languageService, 'findOne');
const result = await languageController.findOne(language.id);
expect(languageService.findOne).toHaveBeenCalledWith(language.id);
expect(result).toEqualPayload(
languageFixtures.find(({ code }) => code === language.code),
);
});
});
describe('findPage', () => {
const pageQuery = getPageQuery<Language>();
it('should find languages', async () => {
jest.spyOn(languageService, 'findPage');
const result = await languageController.findPage(pageQuery, {});
expect(languageService.findPage).toHaveBeenCalledWith({}, pageQuery);
expect(result).toEqualPayload(languageFixtures);
});
});
describe('updateOne', () => {
const translationUpdateDto: LanguageUpdateDto = {
title: 'English (US)',
};
it('should update one language by id', async () => {
jest.spyOn(languageService, 'updateOne');
const result = await languageController.updateOne(
language.id,
translationUpdateDto,
);
expect(languageService.updateOne).toHaveBeenCalledWith(
language.id,
translationUpdateDto,
);
expect(result).toEqualPayload({
...languageFixtures.find(({ code }) => code === language.code),
...translationUpdateDto,
});
});
it('should mark a language as default', async () => {
jest.spyOn(languageService, 'updateOne');
const translationUpdateDto = { default: true };
const frLang = await languageService.findOne({ code: 'fr' });
const result = await languageController.updateOne(
frLang.id,
translationUpdateDto,
);
expect(languageService.updateOne).toHaveBeenCalledWith(
frLang.id,
translationUpdateDto,
);
expect(result).toEqualPayload({
...languageFixtures.find(({ code }) => code === frLang.code),
...translationUpdateDto,
});
const enLang = await languageService.findOne({ code: 'en' });
expect(enLang.default).toBe(false);
});
it('should throw a NotFoundException when attempting to update a translation by id', async () => {
jest.spyOn(languageService, 'updateOne');
await expect(
languageController.updateOne(NOT_FOUND_ID, translationUpdateDto),
).rejects.toThrow(NotFoundException);
});
});
describe('deleteOne', () => {
it('should throw when attempting to delete the default language', async () => {
const defaultLang = await languageService.findOne({ default: true });
await expect(
languageController.deleteOne(defaultLang.id),
).rejects.toThrow(BadRequestException);
});
});
});

View File

@ -141,10 +141,13 @@ export class LanguageController extends BaseController<Language> {
@Delete(':id')
@HttpCode(204)
async deleteOne(@Param('id') id: string): Promise<DeleteResult> {
const result = await this.languageService.deleteOne(id);
const result = await this.languageService.deleteOne({
default: false, // Prevent deleting the default language
_id: id,
});
if (result.deletedCount === 0) {
this.logger.warn(`Unable to delete Language by id ${id}`);
throw new NotFoundException(`Language with ID ${id} not found`);
throw new BadRequestException(`Unable to delete Language with ID ${id}`);
}
return result;
}

31
api/src/utils/test/fixtures/language.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright © 2024 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
* 3. SaaS Restriction: This software, or any derivative of it, may not be used to offer a competing product or service (SaaS) without prior written consent from Hexastack. Offering the software as a service or using it in a commercial cloud environment without express permission is strictly prohibited.
*/
import mongoose from 'mongoose';
import { LanguageUpdateDto } from '@/i18n/dto/language.dto';
import { LanguageModel } from '@/i18n/schemas/language.schema';
export const languageFixtures: LanguageUpdateDto[] = [
{
title: 'English',
code: 'en',
default: true,
},
{
title: 'Français',
code: 'fr',
default: false,
},
];
export const installLanguageFixtures = async () => {
const Language = mongoose.model(LanguageModel.name, LanguageModel.schema);
return await Language.insertMany(languageFixtures);
};