119 lines
4.2 KiB
TypeScript
119 lines
4.2 KiB
TypeScript
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('keeps exam-management scores read-only in the student archive', async () => {
|
|
const exam = {
|
|
findOne: jest.fn().mockResolvedValue({ id: 3, studentId: 7, examId: 8 }),
|
|
save: jest.fn(),
|
|
update: jest.fn(),
|
|
};
|
|
const service = createService({ exam });
|
|
|
|
await expect(service.updateExamScore(3, { score: 95 })).rejects.toBeInstanceOf(
|
|
BadRequestException,
|
|
);
|
|
await expect(service.deleteExamScore(3)).rejects.toBeInstanceOf(BadRequestException);
|
|
expect(exam.save).not.toHaveBeenCalled();
|
|
expect(exam.update).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);
|
|
});
|
|
});
|