extends GdUnitTestSuite ## NEO-142: faction standing label + faction_gate_blocked accept deny HUD tests. const QuestHudController := preload("res://scripts/quest_hud_controller.gd") const QuestDefinitionsClient := preload("res://scripts/quest_definitions_client.gd") const FactionStandingClient := preload("res://scripts/faction_standing_client.gd") const GRID_CONTRACT_QUEST_ID := "prototype_quest_grid_contract" class MockHttpTransport: extends Node signal request_completed( result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray ) var body_json: String = "" func request( _url: String, _custom_headers: PackedStringArray = PackedStringArray(), _method: HTTPClient.Method = HTTPClient.METHOD_GET, _request_data: String = "" ) -> Error: request_completed.emit( HTTPRequest.RESULT_SUCCESS, 200, PackedStringArray(), body_json.to_utf8_buffer() ) return OK class MockFactionSyncClient: extends Node var sync_count: int = 0 func request_sync_from_server() -> void: sync_count += 1 func display_name_for(faction_id: String) -> String: return FactionStandingClient.display_name_for(faction_id) static func _post_operator_chain_standing_snapshot() -> Dictionary: return { "schemaVersion": 1, "playerId": "dev-local-1", "factions": [ {"id": FactionStandingClient.GRID_OPERATORS_ID, "standing": 15}, {"id": FactionStandingClient.RUST_COLLECTIVE_ID, "standing": 0}, ], } static func _grid_contract_defs_json() -> String: return ( '{"schemaVersion":1,"quests":[' + '{"id":"prototype_quest_grid_contract","displayName":"Grid Contract",' + '"prerequisiteQuestIds":["prototype_quest_operator_chain"],' + '"factionGateRules":[{"factionId":"prototype_faction_grid_operators","minStanding":15}],' + '"steps":[]}]}' ) func test_faction_standing_label_paints_grid_operators_standing() -> void: # Arrange var controller: Node = QuestHudController.new() var standing_label := Label.new() auto_free(controller) auto_free(standing_label) add_child(controller) controller.set("_faction_standing_label", standing_label) # Act controller.call("_on_faction_standing_received", _post_operator_chain_standing_snapshot()) # Assert assert_str(standing_label.text).contains("Faction standing:") assert_str(standing_label.text).contains("Grid Operators: 15") assert_str(standing_label.text).contains("Rust Collective: 0") func test_faction_standing_sync_error_shows_error_line() -> void: # Arrange var controller: Node = QuestHudController.new() var standing_label := Label.new() auto_free(controller) auto_free(standing_label) add_child(controller) controller.set("_faction_standing_label", standing_label) # Act controller.call("_on_faction_standing_sync_failed", "HTTP 503") # Assert assert_str(standing_label.text).contains("error — HTTP 503") assert_str(standing_label.text).contains("Grid Operators: 0") func test_faction_gate_blocked_deny_uses_readable_gate_copy() -> void: # Arrange var defs_transport := MockHttpTransport.new() defs_transport.body_json = _grid_contract_defs_json() var defs_client: Node = QuestDefinitionsClient.new() defs_client.set("injected_http", defs_transport) auto_free(defs_transport) auto_free(defs_client) add_child(defs_client) defs_client.call("request_sync_from_server") var controller: Node = QuestHudController.new() var accept_label := Label.new() auto_free(controller) auto_free(accept_label) add_child(controller) controller.set("_defs_client", defs_client) controller.set("_accept_label", accept_label) controller.call( "_on_faction_standing_received", {"schemaVersion": 1, "playerId": "dev-local-1", "factions": []} ) # Act var deny_text: String = str( controller.call("_format_faction_gate_blocked_deny", GRID_CONTRACT_QUEST_ID) ) # Assert assert_str(deny_text).contains("Grid Operators standing 15 required (have 0)") func test_faction_gate_blocked_deny_falls_back_without_gate_rules() -> void: # Arrange var controller: Node = QuestHudController.new() auto_free(controller) add_child(controller) # Act var deny_text: String = str( controller.call("_format_faction_gate_blocked_deny", GRID_CONTRACT_QUEST_ID) ) # Assert assert_str(deny_text).contains("faction standing too low") assert_str(deny_text).contains("faction_gate_blocked") func test_accept_result_received_paints_readable_faction_gate_blocked() -> void: # Arrange var defs_transport := MockHttpTransport.new() defs_transport.body_json = _grid_contract_defs_json() var defs_client: Node = QuestDefinitionsClient.new() defs_client.set("injected_http", defs_transport) auto_free(defs_transport) auto_free(defs_client) add_child(defs_client) defs_client.call("request_sync_from_server") var controller: Node = QuestHudController.new() var accept_label := Label.new() var progress_client := Node.new() auto_free(controller) auto_free(accept_label) auto_free(progress_client) add_child(controller) controller.set("_defs_client", defs_client) controller.set("_accept_label", accept_label) controller.set("_progress_client", progress_client) controller.call( "_on_faction_standing_received", {"schemaVersion": 1, "playerId": "dev-local-1", "factions": []} ) # Act controller.call( "_on_accept_result_received", GRID_CONTRACT_QUEST_ID, {"schemaVersion": 1, "accepted": false, "reasonCode": "faction_gate_blocked"} ) # Assert assert_str(accept_label.text).contains("Grid Operators standing 15 required (have 0)") func test_completion_transition_requests_faction_standing_refresh() -> void: # Arrange var controller: Node = QuestHudController.new() var faction_client := MockFactionSyncClient.new() auto_free(controller) auto_free(faction_client) add_child(controller) add_child(faction_client) controller.set("_faction_standing_client", faction_client) var active_snapshot := { "schemaVersion": 1, "playerId": "dev-local-1", "quests": [ { "questId": "prototype_quest_operator_chain", "status": "active", "currentStepIndex": 3, "objectiveCounters": {}, } ], } var completed_snapshot := { "schemaVersion": 1, "playerId": "dev-local-1", "quests": [ { "questId": "prototype_quest_operator_chain", "status": "completed", "currentStepIndex": 3, "objectiveCounters": {}, "completedAt": "2026-06-07T14:00:00Z", "completionRewardSummary": { "itemGrants": [], "skillXpGrants": [], "reputationGrants": [{"factionId": FactionStandingClient.GRID_OPERATORS_ID, "amount": 15}], }, } ], } # Act controller.call("_on_progress_received", active_snapshot) controller.call("_on_progress_received", completed_snapshot) # Assert assert_int(faction_client.sync_count).is_equal(1) func test_setup_wires_faction_standing_hud_dictionary() -> void: # Arrange var controller: Node = QuestHudController.new() var progress_label := Label.new() var accept_label := Label.new() var standing_label := Label.new() var progress := Node.new() var defs := Node.new() var faction_client := MockFactionSyncClient.new() auto_free(controller) auto_free(progress_label) auto_free(accept_label) auto_free(standing_label) auto_free(progress) auto_free(defs) auto_free(faction_client) add_child(controller) # Act controller.call( "setup", progress, defs, progress_label, accept_label, Callable(self, "_noop_http_config"), null, null, null, null, {"client": faction_client, "label": standing_label} ) # Assert assert_object(controller.get("_faction_standing_client")).is_same(faction_client) assert_object(controller.get("_faction_standing_label")).is_same(standing_label) func _noop_http_config(_client: Node) -> void: pass