169 lines
5.4 KiB
GDScript
169 lines
5.4 KiB
GDScript
extends GdUnitTestSuite
|
|
|
|
## NEO-110: `EncounterProgressClient` GET parse + failure signals.
|
|
|
|
const EncounterProgressClient := preload("res://scripts/encounter_progress_client.gd")
|
|
|
|
const PROTOTYPE_ENCOUNTER_ID := "prototype_combat_pocket"
|
|
|
|
var _progress_capture: Dictionary = {}
|
|
|
|
|
|
func _capture_progress(snapshot: Dictionary) -> void:
|
|
_progress_capture = snapshot
|
|
|
|
|
|
class MockHttpTransport:
|
|
extends Node
|
|
signal request_completed(
|
|
result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray
|
|
)
|
|
var last_url: String = ""
|
|
var response_code: int = 200
|
|
var body_json: String = ""
|
|
|
|
func request(
|
|
url: String,
|
|
_custom_headers: PackedStringArray = PackedStringArray(),
|
|
_method: HTTPClient.Method = HTTPClient.METHOD_GET,
|
|
_request_data: String = ""
|
|
) -> Error:
|
|
last_url = url
|
|
request_completed.emit(
|
|
HTTPRequest.RESULT_SUCCESS,
|
|
response_code,
|
|
PackedStringArray(),
|
|
body_json.to_utf8_buffer()
|
|
)
|
|
return OK
|
|
|
|
|
|
static func _inactive_progression_json() -> String:
|
|
return (
|
|
'{"schemaVersion":1,"playerId":"dev-local-1","encounters":'
|
|
+ '[{"encounterId":"prototype_combat_pocket","state":"inactive","defeatedTargetIds":[]}]}'
|
|
)
|
|
|
|
|
|
static func _active_two_defeats_json() -> String:
|
|
return (
|
|
'{"schemaVersion":1,"playerId":"dev-local-1","encounters":'
|
|
+ '[{"encounterId":"prototype_combat_pocket","state":"active",'
|
|
+ '"defeatedTargetIds":["prototype_npc_melee","prototype_npc_ranged"]}]}'
|
|
)
|
|
|
|
|
|
static func _completed_with_grants_json() -> String:
|
|
return (
|
|
'{"schemaVersion":1,"playerId":"dev-local-1","encounters":'
|
|
+ '[{"encounterId":"prototype_combat_pocket","state":"completed",'
|
|
+ '"defeatedTargetIds":["prototype_npc_elite","prototype_npc_melee","prototype_npc_ranged"],'
|
|
+ '"completedAt":"2026-05-31T12:00:00Z",'
|
|
+ '"rewardGrantSummary":[{"itemId":"scrap_metal_bulk","quantity":10},'
|
|
+ '{"itemId":"contract_handoff_token","quantity":1}]}]}'
|
|
)
|
|
|
|
|
|
func _make_client(transport: Node) -> Node:
|
|
var c: Node = EncounterProgressClient.new()
|
|
c.set("injected_http", transport)
|
|
auto_free(transport)
|
|
auto_free(c)
|
|
add_child(c)
|
|
return c
|
|
|
|
|
|
func test_parse_inactive_encounter_row() -> void:
|
|
# Arrange
|
|
var json := _inactive_progression_json()
|
|
# Act
|
|
var snapshot: Variant = EncounterProgressClient.parse_encounter_progress_json(json)
|
|
# Assert
|
|
assert_that(snapshot is Dictionary).is_true()
|
|
var c: Node = EncounterProgressClient.new()
|
|
auto_free(c)
|
|
var row: Dictionary = c.call("encounter_row", PROTOTYPE_ENCOUNTER_ID, snapshot as Dictionary)
|
|
assert_that(str(row.get("state", ""))).is_equal("inactive")
|
|
assert_that((row.get("defeatedTargetIds", []) as Array).size()).is_equal(0)
|
|
|
|
|
|
func test_parse_active_row_has_two_defeats() -> void:
|
|
# Arrange
|
|
var json := _active_two_defeats_json()
|
|
# Act
|
|
var snapshot: Variant = EncounterProgressClient.parse_encounter_progress_json(json)
|
|
# Assert
|
|
assert_that(snapshot is Dictionary).is_true()
|
|
var c: Node = EncounterProgressClient.new()
|
|
auto_free(c)
|
|
var row: Dictionary = c.call("encounter_row", PROTOTYPE_ENCOUNTER_ID, snapshot as Dictionary)
|
|
assert_that(str(row.get("state", ""))).is_equal("active")
|
|
assert_that((row.get("defeatedTargetIds", []) as Array).size()).is_equal(2)
|
|
|
|
|
|
func test_parse_completed_row_has_reward_grant_summary() -> void:
|
|
# Arrange
|
|
var json := _completed_with_grants_json()
|
|
# Act
|
|
var snapshot: Variant = EncounterProgressClient.parse_encounter_progress_json(json)
|
|
# Assert
|
|
assert_that(snapshot is Dictionary).is_true()
|
|
var c: Node = EncounterProgressClient.new()
|
|
auto_free(c)
|
|
var row: Dictionary = c.call("encounter_row", PROTOTYPE_ENCOUNTER_ID, snapshot as Dictionary)
|
|
assert_that(str(row.get("state", ""))).is_equal("completed")
|
|
var grants: Variant = row.get("rewardGrantSummary", null)
|
|
assert_that(grants is Array).is_true()
|
|
assert_that((grants as Array).size()).is_equal(2)
|
|
|
|
|
|
func test_request_sync_emits_encounter_progress_received() -> void:
|
|
# Arrange
|
|
_progress_capture = {}
|
|
var transport := MockHttpTransport.new()
|
|
transport.body_json = _inactive_progression_json()
|
|
var c := _make_client(transport)
|
|
c.connect("encounter_progress_received", Callable(self, "_capture_progress"))
|
|
monitor_signals(c)
|
|
# Act
|
|
c.call("request_sync_from_server")
|
|
# Assert
|
|
await assert_signal(c).is_emitted("encounter_progress_received", any())
|
|
assert_that(_progress_capture.get("playerId", "")).is_equal("dev-local-1")
|
|
assert_that(transport.last_url).contains("/encounter-progress")
|
|
|
|
|
|
func test_http_404_emits_encounter_sync_failed() -> void:
|
|
# Arrange
|
|
var transport := MockHttpTransport.new()
|
|
transport.response_code = 404
|
|
var c := _make_client(transport)
|
|
monitor_signals(c)
|
|
# Act
|
|
c.call("request_sync_from_server")
|
|
# Assert
|
|
await assert_signal(c).is_emitted("encounter_sync_failed", "HTTP 404 (player unknown)")
|
|
|
|
|
|
func test_parse_encounter_progress_json_returns_null_for_schema_mismatch() -> void:
|
|
# Arrange
|
|
var json := '{"schemaVersion":2,"playerId":"dev-local-1","encounters":[]}'
|
|
# Act
|
|
var snapshot: Variant = EncounterProgressClient.parse_encounter_progress_json(json)
|
|
# Assert
|
|
assert_that(snapshot).is_null()
|
|
|
|
|
|
func test_invalid_schema_emits_encounter_sync_failed() -> void:
|
|
# Arrange
|
|
var transport := MockHttpTransport.new()
|
|
transport.body_json = '{"schemaVersion":2,"playerId":"dev-local-1","encounters":[]}'
|
|
var c := _make_client(transport)
|
|
monitor_signals(c)
|
|
# Act
|
|
c.call("request_sync_from_server")
|
|
# Assert
|
|
await assert_signal(c).is_emitted(
|
|
"encounter_sync_failed", "non-JSON body or schemaVersion mismatch"
|
|
)
|