NEO-131: Split reward HUD tests to satisfy gdlint limit.
parent
7e3507088b
commit
dc39250e96
|
|
@ -5,9 +5,6 @@ extends GdUnitTestSuite
|
|||
const QuestHudController := preload("res://scripts/quest_hud_controller.gd")
|
||||
const QuestProgressClient := preload("res://scripts/quest_progress_client.gd")
|
||||
const QuestDefinitionsClient := preload("res://scripts/quest_definitions_client.gd")
|
||||
const ItemDefsClient := preload("res://scripts/item_definitions_client.gd")
|
||||
|
||||
const OPERATOR_CHAIN_QUEST_ID := "prototype_quest_operator_chain"
|
||||
|
||||
|
||||
class MockHttpTransport:
|
||||
|
|
@ -78,15 +75,6 @@ class FailStartAcceptHttpTransport:
|
|||
return ERR_UNAVAILABLE
|
||||
|
||||
|
||||
class StubItemDefsClient:
|
||||
extends Node
|
||||
|
||||
func display_name_for(item_id: String) -> String:
|
||||
if item_id == "survey_drone_kit":
|
||||
return "Survey Drone Kit"
|
||||
return item_id
|
||||
|
||||
|
||||
func _make_progress_client(sync_transport: Node, accept_transport: Node = null) -> Node:
|
||||
var c: Node = QuestProgressClient.new()
|
||||
c.set("injected_sync_http", sync_transport)
|
||||
|
|
@ -487,226 +475,3 @@ func test_definitions_ready_repaints_with_display_names_when_progress_error() ->
|
|||
# Assert
|
||||
assert_str(progress_label.text).contains("Intro: Salvage Run")
|
||||
assert_str(progress_label.text).not_contains("prototype_quest_gather_intro")
|
||||
|
||||
|
||||
func _active_gather_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": QuestHudController.GATHER_QUEST_ID,
|
||||
"status": "active",
|
||||
"currentStepIndex": 0,
|
||||
"objectiveCounters": {"gather_intro_obj_scrap": 2},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _completed_gather_with_summary_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": QuestHudController.GATHER_QUEST_ID,
|
||||
"status": "completed",
|
||||
"currentStepIndex": 0,
|
||||
"objectiveCounters": {},
|
||||
"completedAt": "2026-06-07T12:00:00Z",
|
||||
"completionRewardSummary":
|
||||
{
|
||||
"itemGrants": [],
|
||||
"skillXpGrants": [{"skillId": "salvage", "amount": 25}],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func test_completion_transition_paints_reward_label_with_skill_xp() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var progress_label := Label.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(progress_label)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_progress_label", progress_label)
|
||||
controller.set("_reward_label", reward_label)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Quest rewards:")
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
|
||||
|
||||
func test_first_success_paints_reward_when_quest_was_active_in_session() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.call("_mark_quest_active_in_session", QuestHudController.GATHER_QUEST_ID)
|
||||
# Act — first successful GET already completed (missed intermediate snapshots)
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
|
||||
|
||||
func test_boot_completed_snapshot_does_not_paint_reward_label() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).is_equal("Quest rewards:\n—")
|
||||
|
||||
|
||||
func _active_operator_chain_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": OPERATOR_CHAIN_QUEST_ID,
|
||||
"status": "active",
|
||||
"currentStepIndex": 3,
|
||||
"objectiveCounters": {},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _completed_operator_chain_with_summary_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": OPERATOR_CHAIN_QUEST_ID,
|
||||
"status": "completed",
|
||||
"currentStepIndex": 3,
|
||||
"objectiveCounters": {},
|
||||
"completedAt": "2026-06-07T14:00:00Z",
|
||||
"completionRewardSummary":
|
||||
{
|
||||
"itemGrants": [{"itemId": "survey_drone_kit", "quantity": 1}],
|
||||
"skillXpGrants": [{"skillId": "salvage", "amount": 50}],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func test_completion_transition_paints_item_grant_with_display_name() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
var item_defs := StubItemDefsClient.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
auto_free(item_defs)
|
||||
add_child(controller)
|
||||
add_child(item_defs)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_item_defs_client", item_defs)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _active_operator_chain_snapshot())
|
||||
controller.call("_on_progress_received", _completed_operator_chain_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Survey Drone Kit ×1")
|
||||
assert_str(reward_label.text).contains("Salvage +50 XP")
|
||||
|
||||
|
||||
func test_definitions_ready_repaints_reward_label_with_display_name() -> void:
|
||||
# Arrange
|
||||
var defs_transport := MockHttpTransport.new()
|
||||
defs_transport.body_json = _gather_defs_json()
|
||||
var defs_client: Node = _make_defs_client(defs_transport)
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_defs_client", defs_client)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.call("_on_progress_received", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
assert_str(reward_label.text).contains(QuestHudController.GATHER_QUEST_ID)
|
||||
# Act
|
||||
defs_client.call("request_sync_from_server")
|
||||
controller.call("_on_definitions_ready", [])
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Intro: Salvage Run")
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
assert_str(reward_label.text).not_contains("prototype_quest_gather_intro")
|
||||
|
||||
|
||||
func _survey_drone_item_defs_json() -> String:
|
||||
return (
|
||||
'{"schemaVersion":1,"items":[{"id":"survey_drone_kit",'
|
||||
+ '"displayName":"Survey Drone Kit","inventorySlotKind":"bag"}]}'
|
||||
)
|
||||
|
||||
|
||||
func test_item_definitions_ready_repaints_reward_item_display_name() -> void:
|
||||
# Arrange
|
||||
var item_transport := MockHttpTransport.new()
|
||||
item_transport.body_json = _survey_drone_item_defs_json()
|
||||
var item_defs: Node = ItemDefsClient.new()
|
||||
item_defs.set("injected_http", item_transport)
|
||||
auto_free(item_transport)
|
||||
auto_free(item_defs)
|
||||
add_child(item_defs)
|
||||
await get_tree().process_frame
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_item_defs_client", item_defs)
|
||||
controller.call("_on_progress_received", _active_operator_chain_snapshot())
|
||||
controller.call("_on_progress_received", _completed_operator_chain_with_summary_snapshot())
|
||||
assert_str(reward_label.text).contains("survey_drone_kit")
|
||||
# Act
|
||||
item_defs.call("request_sync_from_server")
|
||||
controller.call("_on_item_definitions_ready", {})
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Survey Drone Kit ×1")
|
||||
assert_str(reward_label.text).not_contains("survey_drone_kit ×1")
|
||||
|
||||
|
||||
func test_sync_failure_shows_progress_error_and_idle_reward_label() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var progress_label := Label.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(progress_label)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_progress_label", progress_label)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_last_snapshot", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Act
|
||||
controller.call("_on_sync_failed", "HTTP 503")
|
||||
# Assert
|
||||
assert_str(progress_label.text).contains("error — HTTP 503")
|
||||
assert_str(reward_label.text).is_equal("Quest rewards:\n—")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,277 @@
|
|||
extends GdUnitTestSuite
|
||||
|
||||
## NEO-131: quest completion reward label HUD tests.
|
||||
|
||||
const QuestHudController := preload("res://scripts/quest_hud_controller.gd")
|
||||
const QuestDefinitionsClient := preload("res://scripts/quest_definitions_client.gd")
|
||||
const ItemDefsClient := preload("res://scripts/item_definitions_client.gd")
|
||||
|
||||
const OPERATOR_CHAIN_QUEST_ID := "prototype_quest_operator_chain"
|
||||
|
||||
|
||||
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 StubItemDefsClient:
|
||||
extends Node
|
||||
|
||||
func display_name_for(item_id: String) -> String:
|
||||
if item_id == "survey_drone_kit":
|
||||
return "Survey Drone Kit"
|
||||
return item_id
|
||||
|
||||
|
||||
func _make_defs_client(transport: Node) -> Node:
|
||||
var c: Node = QuestDefinitionsClient.new()
|
||||
c.set("injected_http", transport)
|
||||
auto_free(transport)
|
||||
auto_free(c)
|
||||
add_child(c)
|
||||
return c
|
||||
|
||||
|
||||
func _gather_defs_json() -> String:
|
||||
return (
|
||||
'{"schemaVersion":1,"quests":['
|
||||
+ '{"id":"prototype_quest_gather_intro","displayName":"Intro: Salvage Run",'
|
||||
+ '"prerequisiteQuestIds":[],"steps":[]}]}'
|
||||
)
|
||||
|
||||
|
||||
func _active_gather_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": QuestHudController.GATHER_QUEST_ID,
|
||||
"status": "active",
|
||||
"currentStepIndex": 0,
|
||||
"objectiveCounters": {"gather_intro_obj_scrap": 2},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _completed_gather_with_summary_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": QuestHudController.GATHER_QUEST_ID,
|
||||
"status": "completed",
|
||||
"currentStepIndex": 0,
|
||||
"objectiveCounters": {},
|
||||
"completedAt": "2026-06-07T12:00:00Z",
|
||||
"completionRewardSummary":
|
||||
{
|
||||
"itemGrants": [],
|
||||
"skillXpGrants": [{"skillId": "salvage", "amount": 25}],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _active_operator_chain_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": OPERATOR_CHAIN_QUEST_ID,
|
||||
"status": "active",
|
||||
"currentStepIndex": 3,
|
||||
"objectiveCounters": {},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _completed_operator_chain_with_summary_snapshot() -> Dictionary:
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"playerId": "dev-local-1",
|
||||
"quests":
|
||||
[
|
||||
{
|
||||
"questId": OPERATOR_CHAIN_QUEST_ID,
|
||||
"status": "completed",
|
||||
"currentStepIndex": 3,
|
||||
"objectiveCounters": {},
|
||||
"completedAt": "2026-06-07T14:00:00Z",
|
||||
"completionRewardSummary":
|
||||
{
|
||||
"itemGrants": [{"itemId": "survey_drone_kit", "quantity": 1}],
|
||||
"skillXpGrants": [{"skillId": "salvage", "amount": 50}],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
func _survey_drone_item_defs_json() -> String:
|
||||
return (
|
||||
'{"schemaVersion":1,"items":[{"id":"survey_drone_kit",'
|
||||
+ '"displayName":"Survey Drone Kit","inventorySlotKind":"bag"}]}'
|
||||
)
|
||||
|
||||
|
||||
func test_completion_transition_paints_reward_label_with_skill_xp() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Quest rewards:")
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
|
||||
|
||||
func test_first_success_paints_reward_when_quest_was_active_in_session() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.call("_mark_quest_active_in_session", QuestHudController.GATHER_QUEST_ID)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
|
||||
|
||||
func test_boot_completed_snapshot_does_not_paint_reward_label() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).is_equal("Quest rewards:\n—")
|
||||
|
||||
|
||||
func test_completion_transition_paints_item_grant_with_display_name() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
var item_defs := StubItemDefsClient.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
auto_free(item_defs)
|
||||
add_child(controller)
|
||||
add_child(item_defs)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_item_defs_client", item_defs)
|
||||
# Act
|
||||
controller.call("_on_progress_received", _active_operator_chain_snapshot())
|
||||
controller.call("_on_progress_received", _completed_operator_chain_with_summary_snapshot())
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Survey Drone Kit ×1")
|
||||
assert_str(reward_label.text).contains("Salvage +50 XP")
|
||||
|
||||
|
||||
func test_definitions_ready_repaints_reward_label_with_display_name() -> void:
|
||||
# Arrange
|
||||
var defs_transport := MockHttpTransport.new()
|
||||
defs_transport.body_json = _gather_defs_json()
|
||||
var defs_client: Node = _make_defs_client(defs_transport)
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_defs_client", defs_client)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.call("_on_progress_received", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
assert_str(reward_label.text).contains(QuestHudController.GATHER_QUEST_ID)
|
||||
# Act
|
||||
defs_client.call("request_sync_from_server")
|
||||
controller.call("_on_definitions_ready", [])
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Intro: Salvage Run")
|
||||
assert_str(reward_label.text).contains("Salvage +25 XP")
|
||||
assert_str(reward_label.text).not_contains("prototype_quest_gather_intro")
|
||||
|
||||
|
||||
func test_item_definitions_ready_repaints_reward_item_display_name() -> void:
|
||||
# Arrange
|
||||
var item_transport := MockHttpTransport.new()
|
||||
item_transport.body_json = _survey_drone_item_defs_json()
|
||||
var item_defs: Node = ItemDefsClient.new()
|
||||
item_defs.set("injected_http", item_transport)
|
||||
auto_free(item_transport)
|
||||
auto_free(item_defs)
|
||||
add_child(item_defs)
|
||||
await get_tree().process_frame
|
||||
var controller: Node = QuestHudController.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_item_defs_client", item_defs)
|
||||
controller.call("_on_progress_received", _active_operator_chain_snapshot())
|
||||
controller.call("_on_progress_received", _completed_operator_chain_with_summary_snapshot())
|
||||
assert_str(reward_label.text).contains("survey_drone_kit")
|
||||
# Act
|
||||
item_defs.call("request_sync_from_server")
|
||||
controller.call("_on_item_definitions_ready", {})
|
||||
# Assert
|
||||
assert_str(reward_label.text).contains("Survey Drone Kit ×1")
|
||||
assert_str(reward_label.text).not_contains("survey_drone_kit ×1")
|
||||
|
||||
|
||||
func test_sync_failure_shows_progress_error_and_idle_reward_label() -> void:
|
||||
# Arrange
|
||||
var controller: Node = QuestHudController.new()
|
||||
var progress_label := Label.new()
|
||||
var reward_label := Label.new()
|
||||
auto_free(controller)
|
||||
auto_free(progress_label)
|
||||
auto_free(reward_label)
|
||||
add_child(controller)
|
||||
controller.set("_progress_label", progress_label)
|
||||
controller.set("_reward_label", reward_label)
|
||||
controller.set("_last_snapshot", _active_gather_snapshot())
|
||||
controller.call("_on_progress_received", _completed_gather_with_summary_snapshot())
|
||||
# Act
|
||||
controller.call("_on_sync_failed", "HTTP 503")
|
||||
# Assert
|
||||
assert_str(progress_label.text).contains("error — HTTP 503")
|
||||
assert_str(reward_label.text).is_equal("Quest rewards:\n—")
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d4n7q1rewardhudtest01
|
||||
|
|
@ -165,7 +165,7 @@ Combat intro completion is **skill XP only** in quest bundle — encounter token
|
|||
| Test file | What it covers |
|
||||
|-----------|----------------|
|
||||
| `client/test/quest_progress_client_test.gd` | **Add:** parse completed row with **`completionRewardSummary`** (empty **`itemGrants`**, skill XP row); helper returns summary dict. |
|
||||
| `client/test/quest_hud_controller_test.gd` | **Add:** transition **`active` → `completed`** paints reward label with skill XP line; boot with already-**`completed`** does not paint; sync failure leaves progress error + reward **`—`**; operator-chain item grant + display name; **`definitions_ready`** reward label repaint. |
|
||||
| `client/test/quest_reward_hud_test.gd` | **Add:** transition **`active` → `completed`** paints reward label with skill XP line; boot with already-**`completed`** does not paint; first-success-after-active; sync failure idle reward; operator-chain item grant + display name; quest/item **`definitions_ready`** reward repaint. |
|
||||
|
||||
**Regression:** existing NEO-122 GdUnit suites unchanged; `dotnet test` N/A (client-only).
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue