From 438f71bbc62818a5cf9a2b88d60664ae64b7dded Mon Sep 17 00:00:00 2001 From: Maurice Date: Wed, 17 Jun 2026 22:27:53 +0200 Subject: [PATCH] test(reservations): align syncBudgetOnUpdate unit tests with no-wipe + type-sync The service now leaves a linked expense alone when no budget entry is on the payload (only an explicit total_price 0 deletes it) and syncs the category on a booking type change. Update the unit tests accordingly - the old "price cleared" case passed entry: undefined, which is now a no-op and left a mocked return queued that leaked into the next test. --- .../unit/nest/reservations.service.test.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/server/tests/unit/nest/reservations.service.test.ts b/server/tests/unit/nest/reservations.service.test.ts index c838b106..b4caa283 100644 --- a/server/tests/unit/nest/reservations.service.test.ts +++ b/server/tests/unit/nest/reservations.service.test.ts @@ -75,13 +75,28 @@ describe('ReservationsService', () => { }); describe('syncBudgetOnUpdate', () => { - it('deletes the linked item when the price is cleared', () => { + it('deletes the linked item when the price is explicitly cleared (total_price 0)', () => { dbMock._stmt.get.mockReturnValueOnce({ id: 7 }); - svc().syncBudgetOnUpdate('5', '9', 'Hotel', 'lodging', 'Hotel', 'lodging', undefined, 'sock'); + svc().syncBudgetOnUpdate('5', '9', 'Hotel', 'lodging', 'Hotel', 'lodging', { total_price: 0 }, 'sock'); expect(budget.deleteBudgetItem).toHaveBeenCalledWith(7, '5'); expect(broadcast).toHaveBeenCalledWith('5', 'budget:deleted', { itemId: 7 }, 'sock'); }); + it('leaves the linked item alone when no budget entry is on the payload (no wipe)', () => { + svc().syncBudgetOnUpdate('5', '9', 'Hotel', 'lodging', 'Hotel', 'lodging', undefined, 'sock'); + expect(budget.deleteBudgetItem).not.toHaveBeenCalled(); + expect(budget.updateBudgetItem).not.toHaveBeenCalled(); + expect(budget.createBudgetItem).not.toHaveBeenCalled(); + }); + + it('syncs the linked expense category when the booking type changes', () => { + dbMock._stmt.get.mockReturnValueOnce({ id: 7, category: 'other' }); + budget.updateBudgetItem.mockReturnValue({ id: 7, category: 'flights' }); + svc().syncBudgetOnUpdate('5', '9', 'X', 'flight', 'X', 'other', undefined, 'sock'); + expect(budget.updateBudgetItem).toHaveBeenCalledWith(7, '5', { category: 'flights' }); + expect(broadcast).toHaveBeenCalledWith('5', 'budget:updated', { item: { id: 7, category: 'flights' } }, 'sock'); + }); + it('updates an existing linked item when a price is provided', () => { dbMock._stmt.get.mockReturnValueOnce({ id: 7 }); // existing lookup budget.updateBudgetItem.mockReturnValue({ id: 7 });