test: harden business boundary conditions
This commit is contained in:
@@ -117,8 +117,9 @@ describe('OccupanciesService — manual check-in deposit', () => {
|
||||
expect(depositRepo.save).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not create another paid deposit when one already exists', async () => {
|
||||
const { service, depositRepo } = createService({ id: 99 } as Deposit);
|
||||
it('adds the collected amount to the existing student deposit', async () => {
|
||||
const existing = { id: 99, amount: 200, status: 'refunded' } as Deposit;
|
||||
const { service, depositRepo } = createService(existing);
|
||||
|
||||
await service.checkIn({
|
||||
studentId: 3,
|
||||
@@ -130,7 +131,15 @@ describe('OccupanciesService — manual check-in deposit', () => {
|
||||
});
|
||||
|
||||
expect(depositRepo.create).not.toHaveBeenCalled();
|
||||
expect(depositRepo.save).not.toHaveBeenCalled();
|
||||
expect(depositRepo.save).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: 99,
|
||||
amount: 1000,
|
||||
status: 'paid',
|
||||
paidDate: '2026-07-14',
|
||||
notes: '入住登记自动收取',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -274,3 +283,66 @@ describe('OccupanciesService — import student matching', () => {
|
||||
expect(result).toEqual(expect.objectContaining({ imported: 1, skipped: 0 }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('OccupanciesService — stay lifecycle boundaries', () => {
|
||||
it('rejects check-out before check-in without releasing resources', async () => {
|
||||
const occupancy = {
|
||||
id: 1,
|
||||
roomId: 2,
|
||||
bedId: 3,
|
||||
lockerId: 4,
|
||||
checkInDate: '2026-07-10',
|
||||
billingStartDate: '2026-07-10',
|
||||
checkOutDate: null,
|
||||
} as Occupancy;
|
||||
const occupancyRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(occupancy),
|
||||
save: jest.fn(),
|
||||
} as any as Repository<Occupancy>;
|
||||
const roomRepo = { update: jest.fn() } as any as Repository<Room>;
|
||||
const bedRepo = { update: jest.fn() } as any as Repository<Bed>;
|
||||
const lockerRepo = { update: jest.fn() } as any as Repository<Locker>;
|
||||
const service = new OccupanciesService(
|
||||
occupancyRepo,
|
||||
roomRepo,
|
||||
{} as Repository<Student>,
|
||||
{} as Repository<Deposit>,
|
||||
bedRepo,
|
||||
lockerRepo,
|
||||
{} as Repository<any>,
|
||||
{} as DataSource,
|
||||
);
|
||||
|
||||
await expect(service.checkOut(1, { checkOutDate: '2026-07-09' })).rejects.toThrow(
|
||||
'退宿日期不能早于入住日期',
|
||||
);
|
||||
expect(occupancyRepo.save).not.toHaveBeenCalled();
|
||||
expect(bedRepo.update).not.toHaveBeenCalled();
|
||||
expect(lockerRepo.update).not.toHaveBeenCalled();
|
||||
expect(roomRepo.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects check-in to a maintenance room', async () => {
|
||||
const occupancyRepo = {
|
||||
findOne: jest.fn().mockResolvedValue(null),
|
||||
count: jest.fn(),
|
||||
} as any as Repository<Occupancy>;
|
||||
const service = new OccupanciesService(
|
||||
occupancyRepo,
|
||||
{
|
||||
findOne: jest.fn().mockResolvedValue({ id: 2, capacity: 4, status: 'maintenance' }),
|
||||
} as any,
|
||||
{} as Repository<Student>,
|
||||
{} as Repository<Deposit>,
|
||||
{} as Repository<Bed>,
|
||||
{} as Repository<Locker>,
|
||||
{} as Repository<any>,
|
||||
{} as DataSource,
|
||||
);
|
||||
|
||||
await expect(
|
||||
service.checkIn({ studentId: 1, roomId: 2, checkInDate: '2026-07-10', bedId: 3 }),
|
||||
).rejects.toThrow('该宿舍当前不可入住');
|
||||
expect(occupancyRepo.count).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user