fix(ci): the drag hook lists its dependencies, closeOnDone stays module-private, and the weight test waits for its save

This commit is contained in:
Maurice
2026-11-12 07:10:18 +00:00
parent 855bf8610a
commit c515f95d17
3 changed files with 15 additions and 10 deletions
@@ -5,7 +5,7 @@ import { fireEvent, render, screen, waitFor } from '../../../tests/helpers/rende
import { WeightInput } from './PackingListPanelWeightInput';
/** A row whose stored weight changes only once a save answers, as the store does. */
function SlowRow({ onSave }: { onSave: (grams: number | null) => void }) {
function SlowRow({ onSave, onStored }: { onSave: (grams: number | null) => void; onStored: () => void }) {
const [stored, setStored] = useState<number | null>(null);
return (
<WeightInput
@@ -13,7 +13,10 @@ function SlowRow({ onSave }: { onSave: (grams: number | null) => void }) {
width={36}
onSave={(grams) => {
onSave(grams);
setTimeout(() => setStored(grams), 300);
setTimeout(() => {
setStored(grams);
onStored();
}, 300);
}}
/>
);
@@ -22,7 +25,8 @@ function SlowRow({ onSave }: { onSave: (grams: number | null) => void }) {
describe('WeightInput', () => {
it('FE-COMP-PACKING-095: #3005 keeps every typed digit and saves the whole weight once', async () => {
const onSave = vi.fn();
render(<SlowRow onSave={onSave} />);
const onStored = vi.fn();
render(<SlowRow onSave={onSave} onStored={onStored} />);
const input = screen.getByRole('textbox') as HTMLInputElement;
fireEvent.focus(input);
@@ -35,7 +39,9 @@ describe('WeightInput', () => {
fireEvent.blur(input);
expect(onSave).toHaveBeenCalledTimes(1);
expect(onSave).toHaveBeenCalledWith(250);
await waitFor(() => expect(input.value).toBe('250'));
// Wait for the save to answer, so its update lands while the test still runs.
await waitFor(() => expect(onStored).toHaveBeenCalled());
expect(input.value).toBe('250');
});
it('FE-COMP-PACKING-096: saves on Enter and stores an empty field as no weight', () => {
@@ -40,8 +40,9 @@ export function useDayPlanDragState(dragDataRef: MutableRefObject<unknown>) {
if (!draggingId && !dropTargetKey && !dragOverDayId) return;
const settle = (e: MouseEvent | PointerEvent) => {
if (e.type === 'mousemove' && e.buttons !== 0) return;
setDraggingId(null);
setDropTargetKey(null);
setDraggingIdState(null);
dropTargetRef.current = null;
setDropTargetKeyState(null);
setDragOverDayId(null);
dragDataRef.current = null;
window.__dragData = null;
@@ -52,9 +53,7 @@ export function useDayPlanDragState(dragDataRef: MutableRefObject<unknown>) {
document.removeEventListener('mousemove', settle);
document.removeEventListener('pointerdown', settle, true);
};
// The setters close over nothing that changes; the effect follows the drag state only.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [draggingId, dropTargetKey, dragOverDayId]);
}, [draggingId, dropTargetKey, dragOverDayId, dragDataRef]);
return {
draggingId,
+1 -1
View File
@@ -115,7 +115,7 @@ export function prepareField(target: EventTarget | null): void {
* the capture phase, so the field's text is read before any handler of the field
* runs; whether one took the Enter is read off the event once it has gone round.
*/
export function closeOnDone(e: KeyboardEvent): void {
function closeOnDone(e: KeyboardEvent): void {
const el = e.target;
if (e.key !== 'Enter' || e.isComposing) return;
if (!(el instanceof HTMLInputElement) || el.getAttribute('enterkeyhint') !== 'done') return;