P0-1/P0-2/P1-1: dimensions form + E2E tests + PDF export
P0-1 Backend: dimensions column on template entity + validation P0-1 Frontend: dimensions edit UI in TemplateManager P0-2: routeAfterGrading unit tests (10 cases), service spec fix + certificate tests, jest-e2e.json P1-1: proper PDF generation with embedded CJK font via pdf-lib low-level API
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { TemplateService } from './template.service';
|
||||
import { AssessmentTemplate } from '../entities/assessment-template.entity';
|
||||
import { TenantService } from '../../tenant/tenant.service';
|
||||
|
||||
describe('TemplateService', () => {
|
||||
let service: TemplateService;
|
||||
let repo: any;
|
||||
|
||||
const mockTenantService = () => ({
|
||||
canAccessTenant: jest.fn().mockResolvedValue(true),
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
TemplateService,
|
||||
{
|
||||
provide: getRepositoryToken(AssessmentTemplate),
|
||||
useFactory: () => ({
|
||||
create: jest.fn(),
|
||||
save: jest.fn(),
|
||||
find: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
}),
|
||||
},
|
||||
{ provide: TenantService, useFactory: mockTenantService },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<TemplateService>(TemplateService);
|
||||
repo = module.get(getRepositoryToken(AssessmentTemplate));
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should throw BadRequestException when linkedGroupIds is empty', async () => {
|
||||
const dto = { name: 'Test', linkedGroupIds: [] };
|
||||
await expect(
|
||||
service.create(dto as any, 'user-id', 'tenant-id'),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
|
||||
it('should throw BadRequestException when dimensions is empty array', async () => {
|
||||
const dto = { name: 'Test', linkedGroupIds: ['g-1'], dimensions: [] };
|
||||
await expect(
|
||||
service.create(dto as any, 'user-id', 'tenant-id'),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
|
||||
it('should create template with valid data', async () => {
|
||||
const dto = {
|
||||
name: 'Valid Template',
|
||||
linkedGroupIds: ['g-1'],
|
||||
dimensions: [{ name: 'PROMPT', label: 'Prompt', weight: 0.5 }],
|
||||
};
|
||||
repo.create.mockReturnValue({ id: 'new-id', ...dto });
|
||||
repo.save.mockResolvedValue({ id: 'new-id', ...dto });
|
||||
|
||||
const result = await service.create(dto as any, 'user-id', 'tenant-id');
|
||||
expect(result).toBeDefined();
|
||||
expect(result.id).toBe('new-id');
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('should throw BadRequestException when clearing linkedGroupIds', async () => {
|
||||
repo.findOne.mockResolvedValue({
|
||||
id: 'tpl-1', name: 'Existing',
|
||||
linkedGroupIds: ['g-1'],
|
||||
dimensions: [{ name: 'PROMPT', label: 'Prompt', weight: 1 }],
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.update('tpl-1', { linkedGroupIds: [] } as any, 'user-id', 'tenant-id'),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
|
||||
it('should throw BadRequestException when clearing dimensions', async () => {
|
||||
repo.findOne.mockResolvedValue({
|
||||
id: 'tpl-1', name: 'Existing',
|
||||
linkedGroupIds: ['g-1'],
|
||||
dimensions: [{ name: 'PROMPT', label: 'Prompt', weight: 1 }],
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.update('tpl-1', { dimensions: [] } as any, 'user-id', 'tenant-id'),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user