NEO-85: Fix flaky GdUnit signal assertions in full suite runs.

Await async assert_signal calls and match emitted payload args with any()
where tests only care that the signal fired, preventing orphaned 2s timeouts
that surfaced as false failures in later suites (e.g. hotbar_loadout_client_test).
pull/120/head
VinPropane 2026-05-25 13:32:51 -04:00
parent bf9fd84b1c
commit b90fedf7a8
11 changed files with 29 additions and 27 deletions

View File

@ -91,7 +91,7 @@ func test_successful_cast_triggers_combat_target_sync() -> void:
# Act
harness.request_cast()
# Assert
assert_signal(harness._cast).is_emitted("cast_result_received")
await assert_signal(harness._cast).is_emitted("cast_result_received", true, "", any())
assert_that(harness.combat_sync_calls).is_equal(1)
assert_that(harness._combat.sync_calls).is_equal(1)

View File

@ -72,7 +72,7 @@ func test_successful_craft_triggers_both_refreshes() -> void:
# Act
harness.post_craft("refine_scrap_standard")
# Assert
assert_signal(harness._craft).is_emitted("craft_result_received")
await assert_signal(harness._craft).is_emitted("craft_result_received", "refine_scrap_standard", any())
assert_that(harness._inventory.sync_calls).is_equal(1)
assert_that(harness._skill.sync_calls).is_equal(1)

View File

@ -109,7 +109,9 @@ func test_allowed_resource_interact_triggers_both_refreshes() -> void:
# Act
harness.post_resource_alpha()
# Assert
assert_signal(harness._ix).is_emitted("interaction_result_received")
await assert_signal(harness._ix).is_emitted(
"interaction_result_received", "prototype_resource_node_alpha", true, ""
)
assert_that(harness._inventory.sync_calls).is_equal(1)
assert_that(harness._skill.sync_calls).is_equal(1)

View File

@ -156,7 +156,7 @@ func test_denied_update_emits_reason_signal() -> void:
# Act
c.call("request_bind_slot", 1, "not_real")
# Assert
assert_signal(c).is_emitted("loadout_update_denied")
await assert_signal(c).is_emitted("loadout_update_denied", "unknown_ability", any())
func test_bind_slot_while_busy_is_ignored() -> void:

View File

@ -118,7 +118,7 @@ func test_interaction_result_emits_allow_signal() -> void:
# Act
ix.call("post_interact_id", "prototype_resource_node_alpha")
# Assert
assert_signal(ix).is_emitted(
await assert_signal(ix).is_emitted(
"interaction_result_received", "prototype_resource_node_alpha", true, ""
)
@ -132,7 +132,7 @@ func test_interaction_result_emits_deny_signal() -> void:
# Act
ix.call("post_interact_id", "prototype_urban_bulk_delta")
# Assert
assert_signal(ix).is_emitted(
await assert_signal(ix).is_emitted(
"interaction_result_received", "prototype_urban_bulk_delta", false, "node_depleted"
)
@ -146,7 +146,7 @@ func test_interaction_request_failed_emits_on_http_error() -> void:
# Act
ix.call("post_interact_id", "prototype_resource_node_alpha")
# Assert
assert_signal(ix).is_emitted(
await assert_signal(ix).is_emitted(
"interaction_request_failed", "prototype_resource_node_alpha", "HTTP 500"
)

View File

@ -82,7 +82,7 @@ func test_request_sync_emits_inventory_received() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("inventory_received")
await assert_signal(c).is_emitted("inventory_received", any())
assert_that(_inventory_capture.has("bagSlots")).is_true()
assert_that((_inventory_capture["bagSlots"] as Array).size()).is_equal(24)
assert_that((_inventory_capture["equipmentSlots"] as Array).size()).is_equal(1)
@ -98,7 +98,7 @@ func test_http_404_emits_inventory_sync_failed() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("inventory_sync_failed", "HTTP 404 (player unknown)")
await assert_signal(c).is_emitted("inventory_sync_failed", "HTTP 404 (player unknown)")
func test_malformed_json_emits_inventory_sync_failed() -> void:
@ -110,4 +110,4 @@ func test_malformed_json_emits_inventory_sync_failed() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("inventory_sync_failed")
await assert_signal(c).is_emitted("inventory_sync_failed", any())

View File

@ -84,7 +84,7 @@ func test_request_sync_hits_definitions_endpoint_and_emits() -> void:
c.call("request_sync_from_server")
# Assert
assert_that(transport.last_url).contains("/game/world/item-definitions")
assert_signal(c).is_emitted("definitions_ready")
await assert_signal(c).is_emitted("definitions_ready", any())
func test_display_name_for_after_request_sync() -> void:
@ -107,4 +107,4 @@ func test_http_error_does_not_emit_definitions_ready() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).wait_until(400).is_not_emitted("definitions_ready")
await assert_signal(c).wait_until(400).is_not_emitted("definitions_ready")

View File

@ -65,7 +65,7 @@ func test_sync_boot_get_200_emits_snap() -> void:
# Act
c.sync_from_server()
# Assert
assert_signal(c).is_emitted("authoritative_position_received", Vector3(1.0, 0.9, -5.0), true)
await assert_signal(c).is_emitted("authoritative_position_received", Vector3(1.0, 0.9, -5.0), true)
# NEO-24: boot sync also emits the cooldown-throttled heartbeat.
@ -78,7 +78,7 @@ func test_sync_boot_get_200_emits_authoritative_ack() -> void:
# Act
c.sync_from_server()
# Assert
assert_signal(c).is_emitted("authoritative_ack", Vector3(1.0, 0.9, -5.0))
await assert_signal(c).is_emitted("authoritative_ack", Vector3(1.0, 0.9, -5.0))
func test_sync_boot_get_200_malformed_position_does_not_emit() -> void:
@ -90,7 +90,7 @@ func test_sync_boot_get_200_malformed_position_does_not_emit() -> void:
# Act
c.sync_from_server()
# Assert
assert_signal(c).wait_until(400).is_not_emitted("authoritative_position_received")
await assert_signal(c).wait_until(400).is_not_emitted("authoritative_position_received")
func test_move_stream_post_400_emits_move_rejected_then_boot_get() -> void:
@ -103,8 +103,8 @@ func test_move_stream_post_400_emits_move_rejected_then_boot_get() -> void:
# Act
c.submit_stream_targets([Vector3(1.0, 2.0, 3.0)])
# Assert
assert_signal(c).is_emitted("move_rejected", "vertical_step_exceeded")
assert_signal(c).is_emitted("authoritative_position_received", Vector3(0.0, 0.9, 0.0), true)
await assert_signal(c).is_emitted("move_rejected", "vertical_step_exceeded")
await assert_signal(c).is_emitted("authoritative_position_received", Vector3(0.0, 0.9, 0.0), true)
func test_move_stream_post_400_without_reason_emits_unknown() -> void:
@ -117,8 +117,8 @@ func test_move_stream_post_400_without_reason_emits_unknown() -> void:
# Act
c.submit_stream_targets([Vector3.ZERO])
# Assert
assert_signal(c).is_emitted("move_rejected", "unknown")
assert_signal(c).is_emitted("authoritative_position_received", Vector3(1.0, 0.9, 1.0), true)
await assert_signal(c).is_emitted("move_rejected", "unknown")
await assert_signal(c).is_emitted("authoritative_position_received", Vector3(1.0, 0.9, 1.0), true)
func test_second_sync_while_busy_is_ignored() -> void:
@ -148,7 +148,7 @@ func test_move_stream_post_200_does_not_emit_position() -> void:
# Act
c.submit_stream_targets([Vector3(-4.9, 0.9, -5.0)])
# Assert
assert_signal(c).wait_until(400).is_not_emitted("authoritative_position_received")
await assert_signal(c).wait_until(400).is_not_emitted("authoritative_position_received")
# NEO-24: move-stream 200 must emit `authoritative_ack` so a held target lock can re-validate
@ -169,4 +169,4 @@ func test_move_stream_post_200_emits_authoritative_ack() -> void:
# Act
c.submit_stream_targets([Vector3(-4.9, 0.9, -5.0)])
# Assert
assert_signal(c).is_emitted("authoritative_ack", Vector3(-4.9, 0.9, -5.0))
await assert_signal(c).is_emitted("authoritative_ack", Vector3(-4.9, 0.9, -5.0))

View File

@ -80,7 +80,7 @@ func test_request_sync_emits_recipes_ready_in_order() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("recipes_ready")
await assert_signal(c).is_emitted("recipes_ready", any())
assert_that(_recipes_capture.size()).is_equal(2)
assert_that(str(_recipes_capture[0].get("id", ""))).is_equal("make_armor_quick")
assert_that(transport.last_url).contains("/recipe-definitions")
@ -95,7 +95,7 @@ func test_schema_mismatch_emits_recipes_sync_failed() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("recipes_sync_failed")
await assert_signal(c).is_emitted("recipes_sync_failed", any())
func test_http_error_emits_recipes_sync_failed_with_status() -> void:

View File

@ -80,7 +80,7 @@ func test_request_sync_emits_progression_received() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("progression_received")
await assert_signal(c).is_emitted("progression_received", any())
assert_that(_progression_capture.has("skills")).is_true()
assert_that(transport.last_url).contains("/skill-progression")
@ -94,4 +94,4 @@ func test_http_404_emits_progression_sync_failed() -> void:
# Act
c.call("request_sync_from_server")
# Assert
assert_signal(c).is_emitted("progression_sync_failed", "HTTP 404 (player unknown)")
await assert_signal(c).is_emitted("progression_sync_failed", "HTTP 404 (player unknown)")

View File

@ -91,7 +91,7 @@ func test_sync_get_200_emits_state() -> void:
# Act
c.request_sync_from_server()
# Assert
assert_signal(c).is_emitted("target_state_changed")
await assert_signal(c).is_emitted("target_state_changed", any())
var state: Dictionary = c.cached_state()
assert_that(state.get("validity", "")).is_equal("none")
assert_that(state.get("lockedTargetId", "non-null-sentinel")).is_null()
@ -111,7 +111,7 @@ func test_tab_from_no_lock_selects_first_id() -> void:
assert_that(transport.last_url).contains("/target/select")
assert_that(transport.last_method).is_equal(HTTPClient.METHOD_POST)
assert_that(transport.last_body).contains('"targetId":"%s"' % ALPHA_ID)
assert_signal(c).is_emitted("target_state_changed")
await assert_signal(c).is_emitted("target_state_changed", any())
assert_that(c.cached_state().get("lockedTargetId")).is_equal(ALPHA_ID)