From ad958feabd2053a141015717af3112809350ef42 Mon Sep 17 00:00:00 2001 From: Pouzor Date: Sun, 3 May 2026 17:16:05 +0200 Subject: [PATCH] fix(node-modal): keep modal open when delete confirm is cancelled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bare if without braces meant onClose() ran unconditionally after the window.confirm — clicking Cancel still closed the modal and dropped unsaved edits. Wrap the confirm body so onClose only fires on accept. --- frontend/src/components/modals/NodeModal.tsx | 7 +++++- .../modals/__tests__/NodeModal.test.tsx | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/modals/NodeModal.tsx b/frontend/src/components/modals/NodeModal.tsx index 31626b5..69b83c0 100644 --- a/frontend/src/components/modals/NodeModal.tsx +++ b/frontend/src/components/modals/NodeModal.tsx @@ -404,7 +404,12 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node' variant="ghost" size="sm" className="text-[#f85149] hover:text-[#f85149] hover:bg-[#f85149]/10 cursor-pointer" - onClick={() => { if (window.confirm('Delete this node?')) onSubmit({ ...form, _delete: true }); onClose(); }} + onClick={() => { + if (window.confirm('Delete this node?')) { + onSubmit({ ...form, _delete: true }) + onClose() + } + }} style={{ minWidth: 64 }} > Delete diff --git a/frontend/src/components/modals/__tests__/NodeModal.test.tsx b/frontend/src/components/modals/__tests__/NodeModal.test.tsx index 828a8e8..c561495 100644 --- a/frontend/src/components/modals/__tests__/NodeModal.test.tsx +++ b/frontend/src/components/modals/__tests__/NodeModal.test.tsx @@ -83,6 +83,28 @@ describe('NodeModal', () => { expect(onClose).toHaveBeenCalledOnce() }) + // ── Delete confirm ──────────────────────────────────────────────────── + + it('deletes and closes when Delete confirm is accepted', () => { + const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true) + const { onClose, onSubmit } = renderModal({ title: 'Edit Node', initial: BASE }) + fireEvent.click(screen.getByRole('button', { name: 'Delete' })) + expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({ _delete: true })) + expect(onClose).toHaveBeenCalledOnce() + confirmSpy.mockRestore() + }) + + // Regression: bare-if without braces used to call onClose() unconditionally, + // closing the modal even when the user cancelled the confirm dialog. + it('does not delete or close when Delete confirm is cancelled', () => { + const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false) + const { onClose, onSubmit } = renderModal({ title: 'Edit Node', initial: BASE }) + fireEvent.click(screen.getByRole('button', { name: 'Delete' })) + expect(onSubmit).not.toHaveBeenCalled() + expect(onClose).not.toHaveBeenCalled() + confirmSpy.mockRestore() + }) + // ── Label validation ────────────────────────────────────────────────── it('blocks submit and shows error when label is empty', () => {