Some checks failed
Deploy Canina / deploy (push) Failing after 28s
- TASK-FIN-001: Eliminate N+1 query loop in OrdersService.create with batched findMany query.
- Perform monetary calculations strictly using Prisma.Decimal methods (.add(), .mul(), .sub()).
- Add validation for duplicate product IDs and invalid quantities in order items.
- Implement global DecimalInterceptor registered in main.ts to serialize Prisma.Decimal values into exact string representations in API responses.
- TASK-SEC-003: Create roles.decorator.ts and roles.guard.ts in common directory with backward-compatible re-exports in auth directory.
- Enforce RBAC on SettingsController with @UseGuards(JwtAuthGuard, RolesGuard) and @Roles('Admin').
- Add unit specs for DecimalInterceptor, RolesGuard, SettingsController, and OrdersService Decimal batch operations.
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { SettingsController } from './settings.controller';
|
|
import { SettingsService } from './settings.service';
|
|
import { GUARDS_METADATA } from '@nestjs/common/constants';
|
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
|
import { RolesGuard } from '../common/guards/roles.guard';
|
|
import { ROLES_KEY } from '../common/decorators/roles.decorator';
|
|
import { Reflector } from '@nestjs/core';
|
|
|
|
describe('SettingsController', () => {
|
|
let controller: SettingsController;
|
|
let service: SettingsService;
|
|
|
|
const mockSettingsService = {
|
|
getUiTexts: jest.fn().mockResolvedValue([{ key: 'k', value: 'v' }]),
|
|
updateUiText: jest.fn().mockResolvedValue({ key: 'k', value: 'v' }),
|
|
getScientificTerms: jest.fn().mockResolvedValue([{ key: 'k' }]),
|
|
upsertScientificTerm: jest.fn().mockResolvedValue({ key: 'k' }),
|
|
deleteScientificTerm: jest.fn().mockResolvedValue({ success: true }),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
controllers: [SettingsController],
|
|
providers: [{ provide: SettingsService, useValue: mockSettingsService }],
|
|
}).compile();
|
|
|
|
controller = module.get<SettingsController>(SettingsController);
|
|
service = module.get<SettingsService>(SettingsService);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
it('should be defined', () => {
|
|
expect(controller).toBeDefined();
|
|
});
|
|
|
|
it('should have JwtAuthGuard, RolesGuard and Admin role applied at controller level', () => {
|
|
const guards = Reflect.getMetadata(GUARDS_METADATA, SettingsController);
|
|
expect(guards).toBeDefined();
|
|
expect(guards).toContain(JwtAuthGuard);
|
|
expect(guards).toContain(RolesGuard);
|
|
|
|
const roles = Reflect.getMetadata(ROLES_KEY, SettingsController);
|
|
expect(roles).toEqual(['Admin']);
|
|
});
|
|
|
|
it('should getUiTexts', async () => {
|
|
const result = await controller.getUiTexts();
|
|
expect(service.getUiTexts).toHaveBeenCalled();
|
|
expect(result).toHaveLength(1);
|
|
});
|
|
|
|
it('should updateUiText', async () => {
|
|
const result = await controller.updateUiText('k', 'v');
|
|
expect(service.updateUiText).toHaveBeenCalledWith('k', 'v');
|
|
expect(result.key).toBe('k');
|
|
});
|
|
|
|
it('should getScientificTerms', async () => {
|
|
const result = await controller.getScientificTerms();
|
|
expect(service.getScientificTerms).toHaveBeenCalled();
|
|
expect(result).toHaveLength(1);
|
|
});
|
|
|
|
it('should upsertScientificTerm', async () => {
|
|
const data = { term: 't', definition: 'd' };
|
|
const result = await controller.upsertScientificTerm('k', data);
|
|
expect(service.upsertScientificTerm).toHaveBeenCalledWith('k', data);
|
|
expect(result.key).toBe('k');
|
|
});
|
|
|
|
it('should deleteScientificTerm', async () => {
|
|
const result = await controller.deleteScientificTerm('k');
|
|
expect(service.deleteScientificTerm).toHaveBeenCalledWith('k');
|
|
expect(result).toBeDefined();
|
|
});
|
|
});
|
|
|