Files
gongxue-base/apps/server/src/attendance/attendance.service.spec.ts
wangziqi 7b298a615c feat: complete PRD verification fixes and deployment readiness
- Add CommonModule to provide/export CampusScope across business modules
- Replace DepartmentsModule imports with CommonModule in 11 modules
- Add missing Class/Tenant repository imports to StudentsModule and SchedulesModule
- Fix service specs with CampusScope, ClassRepository, StudentRepository mocks
- Move better-sqlite3 to optionalDependencies for production Docker builds
- Rewrite Dockerfiles for monorepo root build context
- Update docker-compose.yml service build contexts
2026-07-06 01:55:35 +08:00

95 lines
3.8 KiB
TypeScript

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 { Class } from '../entities/class.entity';
import { Student } from '../entities/student.entity';
import { CampusScope } from '../common/campus-scope';
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 mockClassRepo = { find: jest.fn().mockResolvedValue([]) };
const mockStudentRepo = { find: jest.fn().mockResolvedValue([]) };
const mockCampusScope = { getScopeDepartmentIds: jest.fn().mockResolvedValue(null), filter: jest.fn((w: any) => w) };
const module: TestingModule = await Test.createTestingModule({
providers: [
AttendanceService,
{ provide: getRepositoryToken(AttendanceRecord), useValue: mockRepo },
{ provide: getRepositoryToken(DingAttendanceRaw), useValue: mockDingRepo },
{ provide: getRepositoryToken(Class), useValue: mockClassRepo },
{ provide: getRepositoryToken(Student), useValue: mockStudentRepo },
{ provide: CampusScope, useValue: mockCampusScope },
],
}).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);
});
});