Guard destructive settings and radio actions
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped

- Route reset campaign and tutorial replay through one reusable confirmation dialog; repeated presses cannot stack or emit twice.
- Keep emergency hold-to-send single-shot and cover the post-submit release.
- Add destructive-action regression checks, strings and documentation.
This commit is contained in:
Gig Line Dev committed 2026-11-02 16:29:26 +01:00
1 parent f6aa26e6ca
commit 7315166361
10 files changed
+121 -14

No files matched your search

+4 -1
View File
@@ -35,5 +35,8 @@ func test_emergency_requires_hold() -> bool:
panel.action_button.button_down.emit()
panel._process(RadioPanel.HOLD_NEEDED + 0.1)
var c := TestUtils.check_eq(int(calls["count"]), 1, "full hold sends exactly once")
# Releasing after the hold has already submitted must not send again.
panel.action_button.button_up.emit()
var d := TestUtils.check_eq(int(calls["count"]), 1, "release after a completed hold does not double-send")
panel.free()
return a and b and c
return a and b and c and d
+43
View File
@@ -96,6 +96,49 @@ func test_settings_panel_cancel_discards() -> bool:
panel.free()
return a and b
func test_destructive_settings_require_confirmation() -> bool:
var panel: Node = SettingsPanel.new()
var tree := Engine.get_main_loop() as SceneTree
if tree:
tree.root.add_child(panel)
panel._build()
var resets := {"count": 0}
var replays := {"count": 0}
panel.reset_campaign_requested.connect(func(): resets["count"] += 1)
panel.replay_tutorial_requested.connect(func(): replays["count"] += 1)
var reset_button: Button = panel.find_child("ResetCampaignButton", true, false) as Button
if reset_button:
reset_button.pressed.emit()
var first: ConfirmationDialog = panel._destructive_dialog
panel._confirm_reset_campaign()
var a := TestUtils.check(first != null and panel._destructive_dialog == first,
"a second reset press reuses the open confirmation")
if first:
first.confirmed.emit()
var b := TestUtils.check_eq(resets["count"], 1, "reset emits once after confirmation")
var c := TestUtils.check(panel._destructive_dialog == null,
"the reset confirmation is dismissed after use")
var replay_button: Button = panel.find_child("ReplayTutorialButton", true, false) as Button
if replay_button:
replay_button.pressed.emit()
var replay_dialog: ConfirmationDialog = panel._destructive_dialog
var d := TestUtils.check_eq(replays["count"], 0,
"tutorial replay waits for confirmation")
if replay_dialog:
replay_dialog.confirmed.emit()
var e := TestUtils.check_eq(replays["count"], 1,
"tutorial replay emits once from its confirmation")
panel._confirm_replay_tutorial()
var cancel_dialog: ConfirmationDialog = panel._destructive_dialog
if cancel_dialog:
cancel_dialog.canceled.emit()
var f := TestUtils.check_eq(replays["count"], 1,
"canceling tutorial replay does not emit")
if tree:
tree.root.remove_child(panel)
panel.free()
return a and b and c and d and e and f
func test_routine_traffic_is_ephemeral() -> bool:
var avatar: Node = NpcAvatar.new()
var a := TestUtils.check(avatar.ephemeral, "avatars default to ephemeral")