test: add unit tests for Schedules, Bills, and Attendance services

This commit is contained in:
2026-07-05 20:51:24 +08:00
parent 09580e4a4e
commit a7a1969d79
3 changed files with 396 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ConflictException } from '@nestjs/common';
import { Repository } from 'typeorm';
import { SchedulesService } from './schedules.service';
import { ClassSchedule } from '../entities/class-schedule.entity';
/** Build a mock query-builder where each chain method returns `this`. */
function mockQueryBuilder<T>(results: T[] = []) {
const qb = {
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
getMany: jest.fn().mockResolvedValue(results),
};
return qb;
}
describe('SchedulesService — checkConflict', () => {
let service: SchedulesService;
let scheduleRepo: jest.Mocked<Pick<Repository<ClassSchedule>, 'createQueryBuilder'>>;
beforeEach(async () => {
const mockRepo = {
createQueryBuilder: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
SchedulesService,
{ provide: getRepositoryToken(ClassSchedule), useValue: mockRepo },
],
}).compile();
service = module.get<SchedulesService>(SchedulesService);
scheduleRepo = module.get(getRepositoryToken(ClassSchedule));
});
it('same classroom + same weekday + overlapping times → ConflictException', async () => {
const qb = mockQueryBuilder<ClassSchedule>([
{ id: 1, subject: '数学', startTime: '08:00', endTime: '10:00' } as ClassSchedule,
]);
(scheduleRepo.createQueryBuilder as jest.Mock).mockReturnValue(qb);
await expect(
service.checkConflict(1, 3, '09:00', '11:00', '2026-03-01', '2026-06-30'),
).rejects.toThrow(ConflictException);
});
it('same classroom + same weekday + non-overlapping times → no conflict', async () => {
const qb = mockQueryBuilder<ClassSchedule>([]);
(scheduleRepo.createQueryBuilder as jest.Mock).mockReturnValue(qb);
await expect(
service.checkConflict(1, 3, '10:00', '12:00', '2026-03-01', '2026-06-30'),
).resolves.toEqual([]);
});
it('same classroom + same weekday + overlapping times but disjoint date ranges → no conflict', async () => {
const qb = mockQueryBuilder<ClassSchedule>([]);
(scheduleRepo.createQueryBuilder as jest.Mock).mockReturnValue(qb);
await expect(
service.checkConflict(1, 3, '09:00', '11:00', '2026-07-01', '2026-08-31'),
).resolves.toEqual([]);
});
it('different classroom → no conflict', async () => {
const qb = mockQueryBuilder<ClassSchedule>([]);
(scheduleRepo.createQueryBuilder as jest.Mock).mockReturnValue(qb);
await expect(
service.checkConflict(2, 3, '09:00', '11:00', '2026-03-01', '2026-06-30'),
).resolves.toEqual([]);
});
it('excludes the given schedule id from conflict check', async () => {
const qb = mockQueryBuilder<ClassSchedule>([]);
(scheduleRepo.createQueryBuilder as jest.Mock).mockReturnValue(qb);
await service.checkConflict(1, 3, '09:00', '11:00', '2026-03-01', '2026-06-30', 42);
expect(qb.andWhere).toHaveBeenCalledWith('cs.id != :excludeId', { excludeId: 42 });
});
});