forked from wangziqi/gongxue-base
108 lines
4.1 KiB
TypeScript
108 lines
4.1 KiB
TypeScript
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
|
import { ExpensesService } from './expenses.service';
|
|
import { PersonalExpense } from '../entities/personal-expense.entity';
|
|
|
|
const qb = (affected = 1) => ({
|
|
delete: jest.fn().mockReturnThis(),
|
|
where: jest.fn().mockReturnThis(),
|
|
execute: jest.fn().mockResolvedValue({ affected }),
|
|
});
|
|
|
|
function createService(options?: {
|
|
roomFind?: any[];
|
|
personalFind?: any[];
|
|
roomExpense?: any;
|
|
personalExpense?: any;
|
|
}) {
|
|
const roomExpRepo = {
|
|
create: jest.fn((value) => value),
|
|
save: jest.fn(async (value) => value),
|
|
find: jest.fn().mockResolvedValue(options?.roomFind ?? []),
|
|
findOne: jest.fn().mockResolvedValue(options?.roomExpense ?? null),
|
|
createQueryBuilder: jest.fn(() => qb()),
|
|
};
|
|
const personalExpRepo = {
|
|
create: jest.fn((value) => value),
|
|
save: jest.fn(async (value) => value),
|
|
find: jest.fn().mockResolvedValue(options?.personalFind ?? []),
|
|
findOne: jest.fn().mockResolvedValue(options?.personalExpense ?? null),
|
|
createQueryBuilder: jest.fn(() => qb()),
|
|
delete: jest.fn(),
|
|
};
|
|
const roomRepo = {
|
|
find: jest.fn().mockImplementation(async () => options?.roomFind ?? []),
|
|
findOne: jest.fn().mockResolvedValue({ id: 1 }),
|
|
};
|
|
const studentRepo = { findOne: jest.fn().mockResolvedValue({ id: 1 }) };
|
|
return {
|
|
service: new ExpensesService(roomExpRepo as any, personalExpRepo as any, roomRepo as any, studentRepo as any, {} as any),
|
|
roomExpRepo,
|
|
personalExpRepo,
|
|
roomRepo,
|
|
};
|
|
}
|
|
|
|
describe('ExpensesService boundaries', () => {
|
|
it('rejects an empty room-expense batch', async () => {
|
|
const { service, roomExpRepo } = createService();
|
|
await expect(service.batchCreateRoomExpenses({
|
|
periodStart: '2026-07-01',
|
|
periodEnd: '2026-07-31',
|
|
expenses: [],
|
|
})).rejects.toBeInstanceOf(BadRequestException);
|
|
expect(roomExpRepo.save).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('rejects a batch when any room does not exist', async () => {
|
|
const { service, roomExpRepo } = createService({ roomFind: [{ id: 1 }] });
|
|
await expect(service.batchCreateRoomExpenses({
|
|
periodStart: '2026-07-01',
|
|
periodEnd: '2026-07-31',
|
|
expenses: [
|
|
{ roomId: 1, expenseType: 'water', amount: 10 },
|
|
{ roomId: 2, expenseType: 'water', amount: 20 },
|
|
],
|
|
})).rejects.toBeInstanceOf(NotFoundException);
|
|
expect(roomExpRepo.save).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('rejects a reversed room-expense period', async () => {
|
|
const { service } = createService();
|
|
await expect(service.createRoomExpense({
|
|
roomId: 1,
|
|
expenseType: 'water',
|
|
amount: 10,
|
|
periodStart: '2026-08-01',
|
|
periodEnd: '2026-07-31',
|
|
})).rejects.toBeInstanceOf(BadRequestException);
|
|
});
|
|
|
|
it('rejects a batch delete when only part of the ids exist', async () => {
|
|
const { service, roomExpRepo } = createService({ roomFind: [{ id: 1 }] });
|
|
await expect(service.batchDeleteRoomExpenses([1, 2])).rejects.toBeInstanceOf(NotFoundException);
|
|
expect(roomExpRepo.createQueryBuilder).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not edit or delete a personal expense already linked to a bill', async () => {
|
|
const linked = { id: 1, studentId: 1, amount: 20, billId: 9 } as PersonalExpense;
|
|
const { service, personalExpRepo } = createService({ personalExpense: linked });
|
|
|
|
await expect(service.updatePersonalExpense(1, { amount: 30 })).rejects.toBeInstanceOf(BadRequestException);
|
|
await expect(service.deletePersonalExpense(1)).rejects.toBeInstanceOf(BadRequestException);
|
|
expect(personalExpRepo.save).not.toHaveBeenCalled();
|
|
expect(personalExpRepo.delete).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('rejects a personal-expense batch delete containing billed records', async () => {
|
|
const { service, personalExpRepo } = createService({
|
|
personalFind: [
|
|
{ id: 1, billId: null },
|
|
{ id: 2, billId: 9 },
|
|
],
|
|
});
|
|
|
|
await expect(service.batchDeletePersonalExpenses([1, 2])).rejects.toBeInstanceOf(BadRequestException);
|
|
expect(personalExpRepo.createQueryBuilder).not.toHaveBeenCalled();
|
|
});
|
|
});
|