test: add unit tests for Schedules, Bills, and Attendance services
This commit is contained in:
85
apps/server/src/attendance/attendance.service.spec.ts
Normal file
85
apps/server/src/attendance/attendance.service.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { BadRequestException, ValidationPipe } from '@nestjs/common';
|
||||
import { Repository } from 'typeorm';
|
||||
import { AttendanceService } from './attendance.service';
|
||||
import { AttendanceRecord } from '../entities/attendance-record.entity';
|
||||
import { DingAttendanceRaw } from '../entities/ding-attendance-raw.entity';
|
||||
import { BatchCreateAttendanceDto } from './dto/attendance.dto';
|
||||
|
||||
describe('AttendanceService — batchCreate', () => {
|
||||
let service: AttendanceService;
|
||||
let attendanceRepo: jest.Mocked<Pick<Repository<AttendanceRecord>, 'create' | 'save'>>;
|
||||
|
||||
const savedRecords: AttendanceRecord[] = [];
|
||||
|
||||
beforeEach(async () => {
|
||||
savedRecords.length = 0;
|
||||
const mockRepo = {
|
||||
create: jest
|
||||
.fn()
|
||||
.mockImplementation((data: Partial<AttendanceRecord>) => ({ id: 1, ...data } as AttendanceRecord)),
|
||||
save: jest
|
||||
.fn()
|
||||
.mockImplementation((entities: AttendanceRecord[]) => {
|
||||
const result = entities.map((e, i) => ({ ...e, id: i + 1 } as AttendanceRecord));
|
||||
savedRecords.push(...result);
|
||||
return Promise.resolve(result);
|
||||
}),
|
||||
};
|
||||
|
||||
const mockDingRepo = {};
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
AttendanceService,
|
||||
{ provide: getRepositoryToken(AttendanceRecord), useValue: mockRepo },
|
||||
{ provide: getRepositoryToken(DingAttendanceRaw), useValue: mockDingRepo },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AttendanceService>(AttendanceService);
|
||||
attendanceRepo = module.get(getRepositoryToken(AttendanceRecord));
|
||||
});
|
||||
|
||||
it('valid batch with morning_reading, evening_study, and night_check sessions → succeeds', async () => {
|
||||
const dto: BatchCreateAttendanceDto = {
|
||||
records: [
|
||||
{ studentId: 1, classId: 10, attendanceDate: '2026-07-05', session: 'morning_reading', status: 'present' },
|
||||
{ studentId: 2, classId: 10, attendanceDate: '2026-07-05', session: 'evening_study', status: 'present' },
|
||||
{ studentId: 3, classId: 10, attendanceDate: '2026-07-05', session: 'night_check', status: 'present' },
|
||||
],
|
||||
};
|
||||
|
||||
const result = await service.batchCreate(dto);
|
||||
|
||||
expect(result.count).toBe(3);
|
||||
expect(result.records).toHaveLength(3);
|
||||
expect(result.records[0].session).toBe('morning_reading');
|
||||
expect(result.records[1].session).toBe('evening_study');
|
||||
expect(result.records[2].session).toBe('night_check');
|
||||
});
|
||||
|
||||
it('invalid session → validation error (DTO-level)', async () => {
|
||||
const pipe = new ValidationPipe({ whitelist: true });
|
||||
|
||||
const invalidPayload = {
|
||||
records: [
|
||||
{ studentId: 1, attendanceDate: '2026-07-05', session: 'invalid_session', status: 'present' },
|
||||
],
|
||||
};
|
||||
|
||||
await expect(
|
||||
pipe.transform(invalidPayload, {
|
||||
type: 'body',
|
||||
metatype: BatchCreateAttendanceDto,
|
||||
}),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('empty batch → BadRequestException', async () => {
|
||||
const dto: BatchCreateAttendanceDto = { records: [] };
|
||||
|
||||
await expect(service.batchCreate(dto)).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user