test: harden business boundary conditions
This commit is contained in:
102
apps/server/src/archive/archive.boundaries.spec.ts
Normal file
102
apps/server/src/archive/archive.boundaries.spec.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { ArchiveService } from './archive.service';
|
||||
|
||||
function createService(repos: Partial<Record<string, Record<string, jest.Mock>>> = {}) {
|
||||
return new ArchiveService(
|
||||
(repos.student ?? {}) as never,
|
||||
(repos.profile ?? {}) as never,
|
||||
(repos.enrollment ?? {}) as never,
|
||||
(repos.exam ?? {}) as never,
|
||||
(repos.learning ?? {}) as never,
|
||||
(repos.result ?? {}) as never,
|
||||
(repos.attachment ?? {}) as never,
|
||||
(repos.attendance ?? {}) as never,
|
||||
{} as never,
|
||||
);
|
||||
}
|
||||
|
||||
describe('ArchiveService — resource and relationship boundaries', () => {
|
||||
it('rejects adding archive records for a missing student', async () => {
|
||||
const student = { findOne: jest.fn().mockResolvedValue(null) };
|
||||
const service = createService({ student });
|
||||
|
||||
await expect(
|
||||
service.addEnrollment(404, { courseCategory: '文化', classType: '冲刺' }),
|
||||
).rejects.toBeInstanceOf(NotFoundException);
|
||||
await expect(
|
||||
service.addLearningRecord(404, {
|
||||
recordDate: '2026-07-14',
|
||||
recordType: '沟通',
|
||||
content: '内容',
|
||||
}),
|
||||
).rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
|
||||
it('rejects linking an exam score to another student enrollment', async () => {
|
||||
const exam = { create: jest.fn(), save: jest.fn() };
|
||||
const service = createService({
|
||||
student: { findOne: jest.fn().mockResolvedValue({ id: 7 }) },
|
||||
enrollment: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
exam,
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.addExamScore(7, {
|
||||
examType: '月考',
|
||||
subject: '语文',
|
||||
score: 90,
|
||||
enrollmentId: 99,
|
||||
}),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
expect(exam.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects moving an existing exam score to another student enrollment', async () => {
|
||||
const exam = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 3, studentId: 7, enrollmentId: 1 }),
|
||||
save: jest.fn(),
|
||||
};
|
||||
const service = createService({
|
||||
enrollment: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
exam,
|
||||
});
|
||||
|
||||
await expect(service.updateExamScore(3, { enrollmentId: 99 })).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
expect(exam.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects a missing attachment upload before writing to disk', async () => {
|
||||
const service = createService({ student: { findOne: jest.fn() } });
|
||||
await expect(service.addAttachment(7, undefined as never, 'other')).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects attachment path traversal', async () => {
|
||||
const service = createService({
|
||||
attachment: {
|
||||
findOne: jest.fn().mockResolvedValue({
|
||||
id: 1,
|
||||
studentId: 7,
|
||||
filePath: '../../etc/passwd',
|
||||
}),
|
||||
},
|
||||
});
|
||||
await expect(service.getAttachmentFile(7, 1)).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
|
||||
it('returns not found for update/delete of absent child records', async () => {
|
||||
const service = createService({
|
||||
enrollment: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
exam: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
learning: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
attachment: { findOne: jest.fn().mockResolvedValue(null) },
|
||||
});
|
||||
await expect(service.updateEnrollment(1, {})).rejects.toBeInstanceOf(NotFoundException);
|
||||
await expect(service.deleteExamScore(1)).rejects.toBeInstanceOf(NotFoundException);
|
||||
await expect(service.deleteLearningRecord(1)).rejects.toBeInstanceOf(NotFoundException);
|
||||
await expect(service.deleteAttachment(1)).rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user