fix(planner): a create expense click that saves nothing no longer opens the editor on the next save

In the desktop booking and transport dialogs, clicking "Create expense"
(or editing a linked expense) before the booking had a title saved
nothing, which is right, but the wish was kept. The next ordinary save
then opened the expense editor out of nowhere. The same happened after a
save that threw.

useBookingExpenseIntent stored the wish in a ref and only cleared it when
the form read it, which the desktop forms do after a successful save. The
hook now clears the wish once the save its click started has settled,
unless a newer click replaced it in the meantime. The phone sheets read
it at the start of the save and are unaffected.

Red tests:
- FE-PLANNER-RESMODAL-107 in ReservationModal.test.tsx: "expected
  "vi.fn()" to not be called at all, but actually been called 1 times".
- FE-PLANNER-BOOKINGEXPENSE-005 in useBookingExpenseIntent.test.ts:
  "expected { create: true } to be null".
- FE-PLANNER-BOOKINGEXPENSE-006: "expected { editItem: { id: 9, ... } }
  to be null".

No existing assertions changed.
This commit is contained in:
Maurice
2026-10-09 17:43:24 +02:00
parent 70f4f7cef3
commit 1e674f040a
3 changed files with 59 additions and 10 deletions
@@ -1,4 +1,4 @@
// FE-PLANNER-BOOKINGEXPENSE-001 to -004: the expense wish of the booking and
// FE-PLANNER-BOOKINGEXPENSE-001 to -006: the expense wish of the booking and
// transport forms, desktop and phone alike.
import { act, renderHook } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
@@ -51,4 +51,33 @@ describe('useBookingExpenseIntent', () => {
await expect(result.current.remove(buildBudgetItem())).resolves.toBeUndefined();
expect(submit).not.toHaveBeenCalled();
});
it('FE-PLANNER-BOOKINGEXPENSE-005: a save that ends without reading the wish does not leave it for the next save', async () => {
// The desktop reads the wish only after a successful save; an empty title
// returns before that point.
const submit = vi.fn(async () => undefined);
const { result } = renderHook(() => useBookingExpenseIntent(submit));
await act(async () => result.current.create());
expect(result.current.take()).toBeNull();
});
it('FE-PLANNER-BOOKINGEXPENSE-006: a save that throws does not leave the wish for the next save', async () => {
let fail: (e: Error) => void = () => undefined;
const submit = vi.fn(
() =>
new Promise<void>((_resolve, reject) => {
fail = reject;
})
);
const unhandled = vi.fn();
process.on('unhandledRejection', unhandled);
try {
const { result } = renderHook(() => useBookingExpenseIntent(submit));
act(() => result.current.edit(buildBudgetItem({ id: 9 })));
await act(async () => fail(new Error('save failed')));
expect(result.current.take()).toBeNull();
} finally {
process.off('unhandledRejection', unhandled);
}
});
});