canina/backend/src/settings/settings.controller.spec.ts
parsaaghayi 809c69f923
Some checks failed
Deploy Canina / deploy (push) Failing after 28s
feat(phase2): implement database optimization and RBAC enforcement
- 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.
2026-08-06 21:29:20 +03:30

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();
});
});