mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
1e674f040a
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.
84 lines
3.5 KiB
TypeScript
84 lines
3.5 KiB
TypeScript
// 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';
|
|
|
|
import { buildBudgetItem } from '../../../tests/helpers/factories';
|
|
import { useBookingExpenseIntent } from './useBookingExpenseIntent';
|
|
|
|
describe('useBookingExpenseIntent', () => {
|
|
it('FE-PLANNER-BOOKINGEXPENSE-001: create notes the wish before the save it starts reads it', () => {
|
|
const seen: unknown[] = [];
|
|
const { result } = renderHook(() =>
|
|
useBookingExpenseIntent(async () => {
|
|
seen.push(result.current.take());
|
|
})
|
|
);
|
|
act(() => result.current.create());
|
|
expect(seen).toEqual([{ create: true }]);
|
|
expect(result.current.take()).toBeNull();
|
|
});
|
|
|
|
it('FE-PLANNER-BOOKINGEXPENSE-002: edit saves first with the linked item, and reset forgets an old wish', () => {
|
|
const submit = vi.fn(async () => undefined);
|
|
const item = buildBudgetItem({ id: 7 });
|
|
const { result } = renderHook(() => useBookingExpenseIntent(submit));
|
|
act(() => result.current.edit(item));
|
|
expect(submit).toHaveBeenCalledTimes(1);
|
|
expect(result.current.take()).toEqual({ editItem: item });
|
|
expect(result.current.take()).toBeNull();
|
|
|
|
act(() => result.current.create());
|
|
result.current.reset();
|
|
expect(result.current.take()).toBeNull();
|
|
});
|
|
|
|
it('FE-PLANNER-BOOKINGEXPENSE-003: remove deletes the linked expense and reports a failure', async () => {
|
|
const remove = vi.fn().mockResolvedValueOnce(undefined).mockRejectedValueOnce(new Error('nope'));
|
|
const onError = vi.fn();
|
|
const item = buildBudgetItem({ id: 3 });
|
|
const { result } = renderHook(() => useBookingExpenseIntent(async () => undefined, { remove, onError }));
|
|
await result.current.remove(item);
|
|
expect(remove).toHaveBeenCalledWith(item);
|
|
expect(onError).not.toHaveBeenCalled();
|
|
await result.current.remove(item);
|
|
expect(onError).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('FE-PLANNER-BOOKINGEXPENSE-004: without a removal, as on the phone, remove does nothing', async () => {
|
|
const submit = vi.fn(async () => undefined);
|
|
const { result } = renderHook(() => useBookingExpenseIntent(submit));
|
|
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);
|
|
}
|
|
});
|
|
});
|