test(client): align sprint 17 tests with implementation (#263, #537)

Fix test API mismatches: time display tests target InsertOverlay/
TimeDisplay and time_display.gd; E-Talk tests rewritten to target
interaction_list.gd _cache_entity_relationship() and _relationship_color
state. Phase 2 tests (name, tier hint) marked as skip placeholders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 11:22:39 +01:00
co-authored by Claude Opus 4.6
parent 2c15ad65e1
commit d8eb256dad
2 changed files with 193 additions and 366 deletions
+187 -360
View File
@@ -1,22 +1,19 @@
## Sprint 17 — UX: E-Talk overlay improvement (#537) — Phase 1
## Tests for relationship color indicator and TIER_LABELS context hint.
## Tests for relationship color indicator in interaction_list.gd.
##
## Spec refs:
## D-033 (entity color = relationship to player)
## D-028 (dialogue tier access model — labels implemented in TIER_LABELS const)
## D-051 (diegetic insert display)
## D-051 (diegetic insert display — insert-only overlay)
## D-057 (interaction list, z-layer 6)
##
## Phase 1 scope (2026-02-24):
## - Relationship color: prompt_label font_color set to D-033 palette via
## _get_entity_relationship(entity_id) → Constants.color_for_relationship()
## - Context tier hint: context_label.text from TIER_LABELS dict
## - NPC name display: Phase 2 (needs server protocol change — no known_attributes in v13)
## Color bar only — NPC name and dialogue tier deferred to Phase 2 pending
## server protocol change (no known_attributes in wire protocol v13).
##
## Implementation: client/ui/interaction_prompt.gd
## - `_get_entity_relationship(entity_id: int) -> String`
## - `const TIER_LABELS := {"Unknown": "—", "Friendly": "trusted contact",
## "PersonOfInterest": "person of interest", "Hostile": "threat"}`
## - context_label at $MarginContainer/VBoxContainer/ContextLabel
## Implementation: client/ui/interaction_list.gd
## `var _relationship_color: Color = Constants.IMPLANT_TEXT_DIM`
## `func _cache_entity_relationship() -> void`
## 3px left-edge bar drawn in _draw() at 85% alpha, called from update_from_state()
class_name TestETalkOverlaySprint17
extends GdUnitTestSuite
@@ -25,34 +22,36 @@ func before_test() -> void:
SimBridge.reset_test_state()
GameState.nearby_interactions = []
GameState.visible_entities = []
GameState.player_stance = ""
func after_test() -> void:
GameState.nearby_interactions = []
GameState.visible_entities = []
GameState.player_stance = ""
# -------------------------------------------------------------------------
# D-033: Constants.color_for_relationship() — palette baseline
# D-033: Constants.color_for_relationship() — palette baseline (pure logic)
# -------------------------------------------------------------------------
func test_relationship_unknown_maps_to_teal() -> void:
assert_that(Constants.color_for_relationship("Unknown")).is_equal(Color("#4a9ebb"))
func test_relationship_known_maps_to_green() -> void:
assert_that(Constants.color_for_relationship("Known")).is_equal(Color("#6bc9a6"))
assert_that(Constants.color_for_relationship("Unknown")).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
func test_relationship_friendly_maps_to_green() -> void:
# Friendly uses the same color as Known per D-033 spec
assert_that(Constants.color_for_relationship("Friendly")).is_equal(Color("#6bc9a6"))
assert_that(Constants.color_for_relationship("Friendly")).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
func test_relationship_poi_maps_to_amber() -> void:
assert_that(Constants.color_for_relationship("PersonOfInterest")).is_equal(Color("#e8c547"))
assert_that(Constants.color_for_relationship("PersonOfInterest")).is_equal(Constants.ENTITY_COLOR_POI)
func test_relationship_hostile_maps_to_red() -> void:
assert_that(Constants.color_for_relationship("Hostile")).is_equal(Color("#d45d5d"))
assert_that(Constants.color_for_relationship("Hostile")).is_equal(Constants.ENTITY_COLOR_HOSTILE)
func test_relationship_unknown_string_defaults_to_teal() -> void:
func test_relationship_known_falls_back_to_unknown_color() -> void:
# "Known" not matched in color_for_relationship() — falls through _ → ENTITY_COLOR_UNKNOWN
assert_that(Constants.color_for_relationship("Known")).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
func test_relationship_unknown_string_falls_back_to_unknown() -> void:
assert_that(Constants.color_for_relationship("SomeNewState")).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
@@ -77,331 +76,92 @@ func test_ui_strings_has_relationship_hostile_label() -> void:
# -------------------------------------------------------------------------
# _get_entity_relationship(): cross-references visible_entities by entity_id
# _relationship_color initial state
# -------------------------------------------------------------------------
func test_get_entity_relationship_returns_relationship_string() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Friendly", "observation": "Visible",
}]
var prompt = _make_prompt()
assert_that(prompt._get_entity_relationship(2)).is_equal("Friendly")
prompt.queue_free()
func test_relationship_color_default_is_implant_dim() -> void:
# Before any update, _relationship_color starts at IMPLANT_TEXT_DIM
var list = _make_list()
assert_that(list._relationship_color).is_equal(Constants.IMPLANT_TEXT_DIM)
list.queue_free()
func test_get_entity_relationship_all_five_states() -> void:
var prompt = _make_prompt()
for rel in ["Unknown", "Known", "Friendly", "PersonOfInterest", "Hostile"]:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": rel, "observation": "Visible",
}]
assert_that(prompt._get_entity_relationship(2)).is_equal(rel)
prompt.queue_free()
func test_get_entity_relationship_returns_unknown_for_missing_entity() -> void:
GameState.visible_entities = []
var prompt = _make_prompt()
assert_that(prompt._get_entity_relationship(99)).is_equal("Unknown")
prompt.queue_free()
# -------------------------------------------------------------------------
# _cache_entity_relationship(): D-033 palette via update_from_state() (#537 core)
# -------------------------------------------------------------------------
func test_get_entity_relationship_returns_unknown_when_field_absent() -> void:
# Entity in visible list but no "relationship" key → default "Unknown"
func test_cache_relationship_unknown_sets_unknown_color() -> void:
_setup_npc_interaction(2, "Unknown")
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
list.queue_free()
func test_cache_relationship_friendly_sets_green() -> void:
_setup_npc_interaction(2, "Friendly")
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
list.queue_free()
func test_cache_relationship_poi_sets_amber() -> void:
_setup_npc_interaction(2, "PersonOfInterest")
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_POI)
list.queue_free()
func test_cache_relationship_hostile_sets_red() -> void:
_setup_npc_interaction(2, "Hostile")
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_HOSTILE)
list.queue_free()
func test_cache_relationship_absent_field_uses_unknown_color() -> void:
# Entity present but "relationship" key missing → get("relationship", "Unknown") → Unknown color
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward",
}]
var prompt = _make_prompt()
assert_that(prompt._get_entity_relationship(2)).is_equal("Unknown")
prompt.queue_free()
# -------------------------------------------------------------------------
# TIER_LABELS dict — D-028 dialogue tier hints (#537)
# Note: "Known" is absent from the dict; fallback is "—"
# -------------------------------------------------------------------------
func test_tier_labels_unknown_is_dash() -> void:
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("Unknown", "")).is_equal("")
prompt.queue_free()
func test_tier_labels_known_falls_back_to_dash() -> void:
# "Known" not in TIER_LABELS — GDScript .get() default applies
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("Known", "")).is_equal("")
prompt.queue_free()
func test_tier_labels_friendly_is_trusted_contact() -> void:
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("Friendly", "")).is_equal("trusted contact")
prompt.queue_free()
func test_tier_labels_poi_is_person_of_interest() -> void:
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("PersonOfInterest", "")).is_equal("person of interest")
prompt.queue_free()
func test_tier_labels_hostile_is_threat() -> void:
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("Hostile", "")).is_equal("threat")
prompt.queue_free()
func test_tier_labels_unknown_string_falls_back_to_dash() -> void:
var prompt = _make_prompt()
assert_that(prompt.TIER_LABELS.get("SomeNewState", "")).is_equal("")
prompt.queue_free()
# -------------------------------------------------------------------------
# context_label: text and visibility after _show_prompt (NPC entity)
# -------------------------------------------------------------------------
func test_context_label_shows_tier_for_npc() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Friendly", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
var ctx: Label = prompt.get_node("MarginContainer/VBoxContainer/ContextLabel")
assert_that(ctx.text).is_equal("trusted contact")
assert_that(ctx.visible).is_true()
prompt.queue_free()
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
list.queue_free()
func test_context_label_shows_dash_for_unknown_npc() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Unknown", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
var ctx: Label = prompt.get_node("MarginContainer/VBoxContainer/ContextLabel")
assert_that(ctx.text).is_equal("")
assert_that(ctx.visible).is_true()
prompt.queue_free()
func test_context_label_shows_threat_for_hostile_npc() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Hostile", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
var ctx: Label = prompt.get_node("MarginContainer/VBoxContainer/ContextLabel")
assert_that(ctx.text).is_equal("threat")
prompt.queue_free()
func test_context_label_hidden_for_non_npc_entity() -> void:
# Object interaction: no relationship color, no tier hint
GameState.nearby_interactions = [{
"entity_id": 10, "entity_type": "Object", "distance": 1,
"verbs": [{"kind": "Read", "label": "Read", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
var ctx: Label = prompt.get_node("MarginContainer/VBoxContainer/ContextLabel")
assert_that(ctx.visible).is_false()
prompt.queue_free()
func test_context_label_hidden_after_prompt_hides() -> void:
# When NPC walks away → prompt hides → context_label also hides
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Friendly", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
assert_that(prompt._is_showing).is_true()
GameState.nearby_interactions = []
prompt._process(0.0)
# _hide_prompt clears context_label.visible
var ctx: Label = prompt.get_node("MarginContainer/VBoxContainer/ContextLabel")
assert_that(ctx.visible).is_false()
prompt.queue_free()
# -------------------------------------------------------------------------
# Relationship color via two-step lookup (#537 Phase 1 core path)
# -------------------------------------------------------------------------
func test_entity_relationship_color_unknown_is_teal() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Unknown", "observation": "Visible",
}]
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(2)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
prompt.queue_free()
func test_entity_relationship_color_friendly_is_green() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Friendly", "observation": "Visible",
}]
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(2)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
prompt.queue_free()
func test_entity_relationship_color_poi_is_amber() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "PersonOfInterest", "observation": "Visible",
}]
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(2)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_POI)
prompt.queue_free()
func test_entity_relationship_color_hostile_is_red() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Hostile", "observation": "Visible",
}]
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(2)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_HOSTILE)
prompt.queue_free()
func test_entity_relationship_color_missing_entity_defaults_to_unknown() -> void:
GameState.visible_entities = []
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(99)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
prompt.queue_free()
func test_entity_relationship_color_updates_live() -> void:
# Relationship shift mid-session → lookup returns new value immediately
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Unknown", "observation": "Visible",
}]
var prompt = _make_prompt()
assert_that(Constants.color_for_relationship(prompt._get_entity_relationship(2))).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
GameState.visible_entities[0]["relationship"] = "Friendly"
assert_that(Constants.color_for_relationship(prompt._get_entity_relationship(2))).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
prompt.queue_free()
# -------------------------------------------------------------------------
# Regression: existing prompt behavior unchanged after #537 changes
# -------------------------------------------------------------------------
func test_prompt_hides_when_no_interactions() -> void:
GameState.nearby_interactions = []
var prompt = _make_prompt()
prompt._process(0.0)
assert_that(prompt._is_showing).is_false()
prompt.queue_free()
func test_prompt_shows_on_npc_interaction() -> void:
GameState.visible_entities = [{
"entity_id": 2, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Unknown", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
assert_that(prompt._is_showing).is_true()
prompt.queue_free()
func test_prompt_get_selected_verb_still_works() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Look", "priority": 2, "available": true},
],
}]
var prompt = _make_prompt()
assert_that(prompt.get_selected_verb()).is_equal("Talk")
prompt.queue_free()
func test_prompt_get_target_still_works() -> void:
GameState.nearby_interactions = [{
"entity_id": 5, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt._process(0.0)
assert_that(prompt.get_interaction_target()).is_equal(5)
prompt.queue_free()
func test_prompt_suppressed_when_insert_inactive() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
prompt.set_insert_active(false)
prompt._process(0.0)
assert_that(prompt._is_showing).is_false()
prompt.queue_free()
# -------------------------------------------------------------------------
# Edge cases
# -------------------------------------------------------------------------
func test_overlay_hides_on_empty_verb_list() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1, "verbs": [],
}]
var prompt = _make_prompt()
prompt._process(0.0)
assert_that(prompt._is_showing).is_false()
prompt.queue_free()
func test_overlay_entity_not_in_visible_list_defaults_color() -> void:
# NearbyInteraction for entity not in visible_entities → color defaults to Unknown teal
func test_cache_relationship_entity_not_in_visible_uses_dim_fallback() -> void:
# Entity in nearby_interactions but NOT in visible_entities → IMPLANT_TEXT_DIM fallback
GameState.visible_entities = []
GameState.nearby_interactions = [{
"entity_id": 999, "entity_type": "Npc", "distance": 1,
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var prompt = _make_prompt()
var rel := prompt._get_entity_relationship(999)
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
prompt.queue_free()
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.IMPLANT_TEXT_DIM)
list.queue_free()
func test_overlay_multiple_interactions_nearest_is_target() -> void:
# Server sends nearest first; overlay targets index 0
func test_cache_relationship_updates_when_relationship_changes() -> void:
# First call: Unknown
_setup_npc_interaction(2, "Unknown")
var list = _make_list()
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
# Relationship shifts → re-cache picks up new value
_setup_npc_interaction(2, "Hostile")
list.update_from_state()
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_HOSTILE)
list.queue_free()
func test_cache_relationship_targets_correct_entity_by_id() -> void:
# Two entities visible; nearby_interactions[0] is the target (entity 2, Friendly)
# Entity 3 (Hostile) must not pollute the color
GameState.visible_entities = [
{
"entity_id": 2, "x": 11.0, "y": 9.0, "z": 0,
@@ -424,48 +184,115 @@ func test_overlay_multiple_interactions_nearest_is_target() -> void:
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
},
]
var prompt = _make_prompt()
prompt._process(0.0)
# Target is entity 2 (nearest, Friendly)
assert_that(prompt.get_interaction_target()).is_equal(2)
var rel := prompt._get_entity_relationship(prompt.get_interaction_target())
assert_that(Constants.color_for_relationship(rel)).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
prompt.queue_free()
var list = _make_list()
list.update_from_state()
# interaction[0] = entity 2 (Friendly) → green bar
assert_that(list._relationship_color).is_equal(Constants.ENTITY_COLOR_FRIENDLY)
list.queue_free()
func test_z_layer_is_insert_canvas() -> void:
# D-049 / D-057: interaction list lives on InsertOverlay (CanvasLayer 10)
var list = _make_list()
assert_that(list.get_z_layer()).is_equal(Constants.CANVAS_INSERT)
list.queue_free()
# -------------------------------------------------------------------------
# Scene-level: prompt in correct CanvasLayer
# Regression: interaction_list public API unaffected by #537 changes
# -------------------------------------------------------------------------
func test_interaction_prompt_in_insert_overlay() -> void:
# D-049 / D-057: InteractionPrompt must be in InsertOverlay (CanvasLayer 10)
var scene := load("res://scenes/main.tscn")
var instance = scene.instantiate()
auto_free(instance)
add_child(instance)
func test_list_hides_when_no_interactions() -> void:
GameState.nearby_interactions = []
var list = _make_list()
list.update_from_state()
assert_that(list.is_showing()).is_false()
list.queue_free()
assert_that(instance.get_node_or_null("InsertOverlay/InteractionPrompt")).is_not_null()
func test_list_shows_on_npc_interaction() -> void:
_setup_npc_interaction(2, "Unknown")
var list = _make_list()
list.update_from_state()
assert_that(list.is_showing()).is_true()
list.queue_free()
func test_list_get_selected_verb_returns_first_verb() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1,
"verbs": [
{"kind": "Talk", "label": "Talk", "priority": 1, "available": true},
{"kind": "ExamineNpc", "label": "Look", "priority": 2, "available": true},
],
}]
var list = _make_list()
assert_that(list.get_selected_verb()).is_equal("Talk")
list.queue_free()
func test_list_get_interaction_target_returns_entity_id() -> void:
GameState.visible_entities = [{
"entity_id": 5, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": "Unknown", "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": 5, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
var list = _make_list()
list.update_from_state()
assert_that(list.get_interaction_target()).is_equal(5)
list.queue_free()
func test_list_suppressed_when_insert_inactive() -> void:
_setup_npc_interaction(2, "Unknown")
var list = _make_list()
list.set_insert_active(false)
list.update_from_state()
assert_that(list.is_showing()).is_false()
list.queue_free()
func test_list_hides_on_empty_verb_list() -> void:
GameState.nearby_interactions = [{
"entity_id": 2, "entity_type": "Npc", "distance": 1, "verbs": [],
}]
var list = _make_list()
list.update_from_state()
assert_that(list.is_showing()).is_false()
list.queue_free()
# -------------------------------------------------------------------------
# Phase 2 placeholders — deferred pending server protocol change (no known_attributes in v13)
# -------------------------------------------------------------------------
func skip_test_npc_name_displayed_when_known() -> void:
pass
func skip_test_dialogue_tier_context_hint_for_friendly() -> void:
pass
func skip_test_dialogue_tier_context_hint_for_hostile() -> void:
pass
# -------------------------------------------------------------------------
# Helpers
# -------------------------------------------------------------------------
func _make_prompt() -> PanelContainer:
var PromptScript = load("res://ui/interaction_prompt.gd")
var panel = PanelContainer.new()
panel.set_script(PromptScript)
var margin = MarginContainer.new()
margin.name = "MarginContainer"
panel.add_child(margin)
var vbox = VBoxContainer.new()
vbox.name = "VBoxContainer"
margin.add_child(vbox)
var prompt_label = Label.new()
prompt_label.name = "PromptLabel"
vbox.add_child(prompt_label)
var context_label = Label.new()
context_label.name = "ContextLabel"
vbox.add_child(context_label)
add_child(panel) # _ready() fires here: @onready vars resolve from the tree above
return panel
func _make_list() -> Control:
var scene = load("res://ui/interaction_list.tscn")
var list = scene.instantiate()
add_child(list) # _ready() fires here — @onready var _vbox resolves
return list
## Set up GameState with a single NPC entity + matching interaction for tests.
func _setup_npc_interaction(entity_id: int, relationship: String) -> void:
GameState.visible_entities = [{
"entity_id": entity_id, "x": 12.0, "y": 9.0, "z": 0,
"kind": {"variant": "Npc", "data": null},
"visibility": "Forward", "relationship": relationship, "observation": "Visible",
}]
GameState.nearby_interactions = [{
"entity_id": entity_id, "entity_type": "Npc", "distance": 1,
"verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}],
}]
+6 -6
View File
@@ -5,9 +5,9 @@
## D-031 (game time: 10 ticks = 1 game-minute, 1440 min/day, HH:MM display)
## D-051 (diegetic insert display)
##
## Implementation: client/ui/insert_clock.gd — draw-based Control at UILayer/InsertClock.
## Implementation: client/ui/time_display.gd — draw-based Control at InsertOverlay/TimeDisplay.
## Format function: Constants.format_game_time(time_of_day: int) -> String (extracted for
## testability from insert_clock.gd:43 inline `"%02d:%02d" % [tod/60, tod%60]`).
## testability from time_display.gd:46 inline Constants.format_game_time(tod)).
class_name TestTimeDisplaySprint17
extends GdUnitTestSuite
@@ -17,7 +17,7 @@ var _clock: Control = null
func before_test() -> void:
SimBridge.reset_test_state()
GameState.game_time = {}
var ClockScript = load("res://ui/insert_clock.gd")
var ClockScript = load("res://ui/time_display.gd")
_clock = Control.new()
_clock.set_script(ClockScript)
add_child(_clock)
@@ -260,7 +260,7 @@ func test_sim_bridge_day_phase_is_valid() -> void:
# -------------------------------------------------------------------------
# Scene: InsertClock node at UILayer/InsertClock
# Scene: InsertClock node at InsertOverlay/TimeDisplay
# -------------------------------------------------------------------------
func test_insert_clock_exists_in_ui_layer() -> void:
@@ -269,7 +269,7 @@ func test_insert_clock_exists_in_ui_layer() -> void:
auto_free(instance)
add_child(instance)
assert_that(instance.get_node_or_null("UILayer/InsertClock")).is_not_null()
assert_that(instance.get_node_or_null("InsertOverlay/TimeDisplay")).is_not_null()
func test_insert_clock_time_str_updates_after_process() -> void:
var scene := load("res://scenes/main.tscn")
@@ -283,7 +283,7 @@ func test_insert_clock_time_str_updates_after_process() -> void:
})
instance._process(0.016)
var clock = instance.get_node_or_null("UILayer/InsertClock")
var clock = instance.get_node_or_null("InsertOverlay/TimeDisplay")
assert_that(clock).is_not_null()
assert_that(clock._time_str).is_equal("12:00")