Skip to content

Commit 883a1e7

Browse files
committed
fix(component editor): allow users to correct errors before proceeding
1 parent dc6ed20 commit 883a1e7

2 files changed

Lines changed: 61 additions & 4 deletions

File tree

ardupilot_methodic_configurator/frontend_tkinter_component_editor_base.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,9 @@ def on_save_pressed(self) -> None:
532532
if (not ConfirmationPopupWindow.should_display("component_editor_validation")) or confirm_component_properties(
533533
cast("tk.Tk", self.root)
534534
):
535-
self.save_component_json()
536-
self.root.destroy()
535+
save_error = self.save_component_json()
536+
if save_error is False:
537+
self.root.destroy()
537538

538539
def save_component_json(self) -> bool:
539540
"""Save component JSON data to file."""
@@ -569,6 +570,8 @@ def on_closing(self) -> None:
569570
ret = False
570571
if answer:
571572
ret = self.save_component_json()
573+
if ret:
574+
return
572575
else:
573576
# If it just created the files from a new template and the user chooses not to save,
574577
# delete the created files

tests/test_frontend_tkinter_component_editor_base.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,32 @@ def test_user_must_confirm_before_saving_component_data(self, editor_for_save_te
637637
validation_mock.assert_called_once()
638638
mock_save.assert_called_once()
639639

640+
def test_user_stays_in_component_editor_when_save_fails(self, editor_for_save_tests: ComponentEditorWindowBase) -> None:
641+
"""
642+
The editor window remains open when the save operation fails.
643+
644+
GIVEN: A user attempts to save component configuration
645+
WHEN: The save operation fails due to invalid JSON or filesystem error
646+
THEN: The component editor window should stay open
647+
"""
648+
# Arrange: Simulate failed save operation
649+
editor_for_save_tests.validate_data_and_highlight_errors_in_red = MagicMock(return_value="")
650+
with (
651+
patch(
652+
"ardupilot_methodic_configurator.frontend_tkinter_component_editor_base."
653+
"ConfirmationPopupWindow.should_display",
654+
return_value=False,
655+
),
656+
patch.object(editor_for_save_tests, "save_component_json", return_value=True) as mock_save,
657+
patch.object(editor_for_save_tests.root, "destroy"),
658+
):
659+
# Act: Trigger on-save handler
660+
editor_for_save_tests.on_save_pressed()
661+
662+
# Assert: Failed save does not close the window
663+
mock_save.assert_called_once()
664+
editor_for_save_tests.root.destroy.assert_not_called()
665+
640666

641667
class TestWindowClosingWorkflows:
642668
"""Test user workflows for closing the editor window."""
@@ -672,6 +698,34 @@ def test_user_can_save_before_closing_when_prompted(self, editor_for_closing_tes
672698
editor_for_closing_tests.save_component_json.assert_called_once()
673699
mock_exit.assert_called_once_with(0)
674700

701+
def test_user_stays_in_component_editor_when_closing_save_fails(
702+
self,
703+
editor_for_closing_tests: ComponentEditorWindowBase,
704+
) -> None:
705+
"""
706+
The editor window remains open when closing fails due to a save error.
707+
708+
GIVEN: A user attempts to close the component editor and chooses to save
709+
WHEN: The save operation fails
710+
THEN: The component editor window should remain open and no exit should occur
711+
"""
712+
editor_for_closing_tests.save_component_json = MagicMock(return_value=True)
713+
with (
714+
patch(
715+
"ardupilot_methodic_configurator.frontend_tkinter_component_editor_base.messagebox.askyesnocancel",
716+
return_value=True,
717+
),
718+
patch.object(editor_for_closing_tests.root, "destroy"),
719+
patch("ardupilot_methodic_configurator.frontend_tkinter_component_editor_base.sys_exit") as mock_exit,
720+
):
721+
# Act: Trigger window closing
722+
editor_for_closing_tests.on_closing()
723+
724+
# Assert: Failed save does not close or exit the application
725+
editor_for_closing_tests.save_component_json.assert_called_once()
726+
editor_for_closing_tests.root.destroy.assert_not_called()
727+
mock_exit.assert_not_called()
728+
675729
def test_user_can_close_without_saving_when_prompted(self, editor_for_closing_tests: ComponentEditorWindowBase) -> None:
676730
"""
677731
User can choose to close without saving when prompted.
@@ -1505,7 +1559,7 @@ def test_user_must_confirm_component_properties_before_save(
15051559
WHEN: The confirmation popup is enabled
15061560
THEN: They should be asked to confirm all properties are correct before saving
15071561
"""
1508-
editor_for_validation_tests.save_component_json = MagicMock()
1562+
editor_for_validation_tests.save_component_json = MagicMock(return_value=False)
15091563

15101564
with (
15111565
patch.object(editor_for_validation_tests.root, "destroy") as mock_destroy,
@@ -1530,7 +1584,7 @@ def test_user_can_save_without_confirmation_when_popup_disabled(
15301584
self, editor_for_validation_tests: ComponentEditorWindowBase
15311585
) -> None:
15321586
"""If the confirmation popup is disabled, saving should proceed immediately."""
1533-
editor_for_validation_tests.save_component_json = MagicMock()
1587+
editor_for_validation_tests.save_component_json = MagicMock(return_value=False)
15341588

15351589
with (
15361590
patch.object(editor_for_validation_tests.root, "destroy") as mock_destroy,

0 commit comments

Comments
 (0)