Two areas of behaviour that weren't covered in the §3 test push (#264 → #269) because each has its own setup cost and was considered lower-priority than landing the core regression net first. Capturing here so they don't get forgotten.
Drag-and-drop
src/hooks/useDragNDrop.tsx wires native HTML5 drag events on collection rows and value rows. Currently zero test coverage. The reason it wasn't tackled in #269: jsdom doesn't fire real drag events, RTL's userEvent has no DnD API, and react-dnd-style abstractions aren't in play here — we'd have to drive dragStart / dragOver / drop via fireEvent manually and assert on the resulting setData shape.
Scenarios worth covering
- Rearrange keys within an object —
setData reflects the new order, values intact
- Rearrange elements within an array — same
- Drag from a collection into a sibling collection — restructures both source and destination
- Drag onto a leaf (should be rejected or no-op, depending on current behaviour — lock it in)
restrictDrag (boolean) hides drag affordance / blocks the drop
restrictDrag (function) selectively allows/blocks per node, same shape as the §5 functional-restriction tests
- Drag interaction during edit — should cancel or be blocked
Approach
fireEvent.dragStart(source, { dataTransfer }) + fireEvent.dragOver(target) + fireEvent.drop(target, { dataTransfer }). The dataTransfer object needs to be supplied (jsdom doesn't construct one automatically). Worth wrapping in a helper, e.g. dragAndDrop(source, target), so each test is one line.
Undo-on-cancel
ValueNodeWrapper.tsx:245-246 (and the matching code in CollectionNode.tsx:272-273) restores previousValue when a cancel happens after a type change. The contract here is subtle: changing a value's type (e.g. string → object) immediately fires setData with the converted default; if the user then cancels, the editor reverts both the type and the value. This was the bug behind the now-closed #122 — easy to regress if anyone refactors the cancel path.
Scenarios worth covering
- Type-change-then-cancel reverts to the original type and value (in one PR with the test, asserting on both
setData calls)
- Cancel after just opening edit mode (no change made) — no
setData revert call needed
- Cancel after type change AND value change — verify which value is restored (likely the pre-type-change one)
- Cancel after multiple consecutive type changes — does it revert all the way, or just the last?
Approach
Plain RTL — the cancel path goes through the keyboard handler and the Cancel icon, both already exercised in #269. The complication is asserting on a sequence of setData calls. Use setData.mock.calls directly and inspect each entry, not just toHaveBeenCalledWith.
Acceptance
- Both areas covered with tests in test/JsonEditor.test.tsx (or a sibling file if the file grows past comfort)
- The DnD helper, if introduced, lives in
test/ and is reused across tests
pnpm test green; new tests follow the contract-not-implementation discipline noted in CLAUDE.md
Priority
Low. The §4 / §16 refactors don't deeply touch DnD or undo-on-cancel paths, so the absence of these tests isn't a blocker. Pick up when there's a natural moment — e.g. before any refactor that does touch them.
Two areas of behaviour that weren't covered in the §3 test push (#264 → #269) because each has its own setup cost and was considered lower-priority than landing the core regression net first. Capturing here so they don't get forgotten.
Drag-and-drop
src/hooks/useDragNDrop.tsx wires native HTML5 drag events on collection rows and value rows. Currently zero test coverage. The reason it wasn't tackled in #269: jsdom doesn't fire real drag events, RTL's
userEventhas no DnD API, andreact-dnd-style abstractions aren't in play here — we'd have to drivedragStart/dragOver/dropviafireEventmanually and assert on the resultingsetDatashape.Scenarios worth covering
setDatareflects the new order, values intactrestrictDrag(boolean) hides drag affordance / blocks the droprestrictDrag(function) selectively allows/blocks per node, same shape as the §5 functional-restriction testsApproach
fireEvent.dragStart(source, { dataTransfer })+fireEvent.dragOver(target)+fireEvent.drop(target, { dataTransfer }). ThedataTransferobject needs to be supplied (jsdom doesn't construct one automatically). Worth wrapping in a helper, e.g.dragAndDrop(source, target), so each test is one line.Undo-on-cancel
ValueNodeWrapper.tsx:245-246 (and the matching code in CollectionNode.tsx:272-273) restores
previousValuewhen a cancel happens after a type change. The contract here is subtle: changing a value's type (e.g. string → object) immediately firessetDatawith the converted default; if the user then cancels, the editor reverts both the type and the value. This was the bug behind the now-closed #122 — easy to regress if anyone refactors the cancel path.Scenarios worth covering
setDatacalls)setDatarevert call neededApproach
Plain RTL — the cancel path goes through the keyboard handler and the Cancel icon, both already exercised in #269. The complication is asserting on a sequence of
setDatacalls. UsesetData.mock.callsdirectly and inspect each entry, not justtoHaveBeenCalledWith.Acceptance
test/and is reused across testspnpm testgreen; new tests follow the contract-not-implementation discipline noted in CLAUDE.mdPriority
Low. The §4 / §16 refactors don't deeply touch DnD or undo-on-cancel paths, so the absence of these tests isn't a blocker. Pick up when there's a natural moment — e.g. before any refactor that does touch them.