mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
feat: add unit tests
This commit is contained in:
parent
10f36c2d48
commit
432193cad9
169
api/src/i18n/controllers/language.controller.spec.ts
Normal file
169
api/src/i18n/controllers/language.controller.spec.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -141,10 +141,13 @@ export class LanguageController extends BaseController<Language> {
|
|||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
@HttpCode(204)
|
@HttpCode(204)
|
||||||
async deleteOne(@Param('id') id: string): Promise<DeleteResult> {
|
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) {
|
if (result.deletedCount === 0) {
|
||||||
this.logger.warn(`Unable to delete Language by id ${id}`);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
31
api/src/utils/test/fixtures/language.ts
vendored
Normal file
31
api/src/utils/test/fixtures/language.ts
vendored
Normal 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);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user