174 lines
8.2 KiB
GDScript
174 lines
8.2 KiB
GDScript
extends SceneTree
|
|
|
|
const PageContext = preload("res://foundation/page_context.gd")
|
|
const RiskCommitmentPageView = preload("res://entry/views/risk_commitment_page_view.gd")
|
|
|
|
var failures: Array[String] = []
|
|
var intents: Array[Dictionary] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
root.size = Vector2(844, 390)
|
|
var view := RiskCommitmentPageView.new()
|
|
view.name = "RiskCommitmentViewContractFixture"
|
|
view.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
view.configure_presentation({"safe_area": 24, "text_scale": 1.0, "locale": "en"})
|
|
view.mount(PageContext.new({
|
|
"page_id": "risk_commitment",
|
|
"caller_id": "risk_board",
|
|
"return_page_id": "risk_board",
|
|
"return_focus_path": "RiskCommitmentCancel",
|
|
}))
|
|
view.intent_emitted.connect(_record_intent)
|
|
root.add_child(view)
|
|
view.render(_fixture_view_data(false))
|
|
await process_frame
|
|
|
|
var context = view.get("context")
|
|
expect(context != null and String(context.get("page_id")) == "risk_commitment", "mount stores a copied PageContext")
|
|
expect(view.find_child("RiskCommitmentMatte", true, false) != null, "View owns the commitment matte")
|
|
expect(view.find_child("RiskCommitmentMasterCanvas", true, false) != null, "View owns the normalized 16:9 canvas")
|
|
expect(view.find_child("RiskCommitmentStaticMaster", true, false) != null, "View owns the static master")
|
|
expect(view.find_child("RiskFrozenMembers", true, false) != null and view.find_child("RiskFrozenMembers", true, false).get_child_count() == 4, "View renders four frozen Party members")
|
|
expect(view.find_child("RiskConsequenceFact0", true, false) != null and view.find_child("RiskConsequenceFact5", true, false) != null, "View renders six consequence facts")
|
|
|
|
var settings := view.find_child("RiskCommitmentSettings", true, false) as Button
|
|
var details := view.find_child("RiskSelectedRiskDetails", true, false) as Button
|
|
var consequences := view.find_child("RiskConsequenceBand", true, false) as Button
|
|
var acknowledge := view.find_child("RiskCommitmentAcknowledge", true, false) as Button
|
|
var begin := view.find_child("RiskBeginBattle", true, false) as Button
|
|
var back := view.find_child("RiskCommitmentCancel", true, false) as Button
|
|
expect(settings != null and not settings.disabled, "Settings intent is enabled")
|
|
expect(details != null and not details.disabled, "risk-details intent is enabled")
|
|
expect(consequences != null and not consequences.disabled, "consequence intent is enabled")
|
|
expect(acknowledge != null and not acknowledge.disabled and begin != null and begin.disabled, "blocked command state is reflected")
|
|
expect(back != null and not back.disabled and back.focus_mode != Control.FOCUS_NONE, "Back intent is focusable")
|
|
|
|
for button in [settings, details, consequences, acknowledge]:
|
|
if button != null:
|
|
button.emit_signal("pressed")
|
|
await process_frame
|
|
expect(intents.size() == 4, "first four intents are emitted exactly once")
|
|
expect(intents[0].get("intent_id") == "settings", "Settings intent is named")
|
|
expect(intents[1].get("intent_id") == "review_risk_details", "risk-details intent is named")
|
|
expect(intents[2].get("intent_id") == "review_consequences", "consequence intent is named")
|
|
expect(intents[3].get("intent_id") == "acknowledge", "acknowledge intent is named")
|
|
|
|
view.render(_fixture_view_data(true))
|
|
await process_frame
|
|
var ready_begin := view.find_child("RiskBeginBattle", true, false) as Button
|
|
var ready_acknowledge := view.find_child("RiskCommitmentAcknowledge", true, false) as Button
|
|
expect(ready_begin != null and not ready_begin.disabled and ready_acknowledge != null and ready_acknowledge.disabled, "ready command state is reflected")
|
|
if ready_begin != null:
|
|
ready_begin.emit_signal("pressed")
|
|
await process_frame
|
|
expect(intents.size() == 5 and intents[4].get("intent_id") == "begin_battle", "Begin Battle intent is named")
|
|
var ready_back := view.find_child("RiskCommitmentCancel", true, false) as Button
|
|
if ready_back != null:
|
|
ready_back.emit_signal("pressed")
|
|
await process_frame
|
|
expect(intents.size() == 6 and intents[5].get("intent_id") == "back", "Back intent is named")
|
|
|
|
view.render({"ok": false, "locale": "en", "notice": "Risk unavailable"})
|
|
await process_frame
|
|
expect(view.find_child("RiskCommitmentInvalidOverlay", true, false) != null, "View renders invalid state from supplied data")
|
|
expect(view.find_child("RiskCommitmentMasterOverlay", true, false) == null, "invalid render removes the interactive overlay")
|
|
|
|
var source := FileAccess.get_file_as_string("res://entry/views/risk_commitment_page_view.gd")
|
|
expect(not source.contains("FormationRiskService"), "View does not import FormationRiskService")
|
|
expect(not source.contains("BattleService"), "View does not import BattleService")
|
|
expect(not source.contains("RuntimeContentRegistry"), "View does not resolve RuntimeContentRegistry")
|
|
expect(not source.contains("current_screen"), "View does not own route state")
|
|
expect(not source.contains("res://compat/"), "View does not import compatibility facade")
|
|
|
|
view.queue_free()
|
|
await process_frame
|
|
if failures.is_empty():
|
|
print("ABG_M36_RISK_COMMITMENT_VIEW_CONTRACT_OK mount=true normalized_canvas=true static_master=true party=4 facts=6 intents=settings,review_risk_details,review_consequences,acknowledge,begin_battle,back invalid=true forbidden_imports=true")
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func _record_intent(intent_id: String, payload: Dictionary) -> void:
|
|
intents.append({"intent_id": intent_id, "payload": payload})
|
|
|
|
|
|
func _fixture_view_data(acknowledged: bool) -> Dictionary:
|
|
var facts: Array = []
|
|
for item in [
|
|
["THREAT", "3 · 2 WAVES", "!", Color("#a74337")],
|
|
["UNCERTAINTY", "ONE INTENT OPEN", "?", Color("#5d3f91")],
|
|
["ENTRY COIN", "4 · 34 LEFT", "¢", Color("#a07816")],
|
|
["REWARD", "27 · ENHANCED", "◆", Color("#3d7449")],
|
|
["RECOVERY", "MODERATE", "!", Color("#a44a2e")],
|
|
["RETREAT", "NEXT STAGE", "↩", Color("#2c67a3")],
|
|
]:
|
|
facts.append({"label": item[0], "value": item[1], "text": item[1], "glyph": item[2], "color": item[3]})
|
|
return {
|
|
"ok": true,
|
|
"page_id": "risk_commitment",
|
|
"locale": "en",
|
|
"contract": {"contract_id": "CTR-R1-01", "coin": 38},
|
|
"risk": {
|
|
"risk_option_id": "risk-2",
|
|
"option": {
|
|
"risk_option_id": "risk-2",
|
|
"tier_id": "pressured",
|
|
"risk": 1,
|
|
"option_hash": "option-hash-001",
|
|
"known_threat": {"enemy_count": 3, "wave_count": 2},
|
|
"uncertainty_id": "one_intent_unresolved",
|
|
"entry_cost": 4,
|
|
"reward_coin": 27,
|
|
"reward_class_id": "enhanced_choice",
|
|
"recovery_exposure_id": "moderate",
|
|
},
|
|
},
|
|
"consequences": {"facts": facts, "count": facts.size()},
|
|
"party": {
|
|
"snapshot_id": "snapshot-001",
|
|
"snapshot_hash": "snapshot-hash-001",
|
|
"front_to_rear_ids": ["r-1", "r-2", "r-3", "r-4"],
|
|
"ordered_recruits": [
|
|
{"position": 0, "recruit": _recruit("r-1", "PF-B01", "Ari", "Hearthguard"), "relation": {"exposure_id": "highest", "reach_id": "front_two"}},
|
|
{"position": 1, "recruit": _recruit("r-2", "PF-B05", "Bram", "Farstring"), "relation": {"exposure_id": "high", "reach_id": "front_three"}},
|
|
{"position": 2, "recruit": _recruit("r-3", "PF-B07", "Cera", "Kindhand"), "relation": {"exposure_id": "guarded", "reach_id": "full_line"}},
|
|
{"position": 3, "recruit": _recruit("r-4", "PF-B03", "Dain", "Spear"), "relation": {"exposure_id": "rear", "reach_id": "limited"}},
|
|
],
|
|
"coverage": {"protection": 2, "long_reach": 2, "sustain": 1, "control": 1},
|
|
},
|
|
"dependency": {"ok": true, "code": "READY", "facts": {"ok": true, "code": "READY", "coin": 38, "cost": 4}},
|
|
"confirmation": {"acknowledged": acknowledged, "state": "acknowledged" if acknowledged else "required"},
|
|
"commands": {
|
|
"settings_enabled": true,
|
|
"selected_details_enabled": true,
|
|
"consequences_review_enabled": true,
|
|
"cancel_enabled": true,
|
|
"acknowledge_enabled": not acknowledged,
|
|
"begin_enabled": acknowledged,
|
|
},
|
|
"notice": "",
|
|
}
|
|
|
|
|
|
func _recruit(recruit_id: String, profession_id: String, name: String, profession: String) -> Dictionary:
|
|
return {
|
|
"recruit_id": recruit_id,
|
|
"profession_id": profession_id,
|
|
"rendered_name_snapshot": {"en": name},
|
|
"profession_name": {"en": profession},
|
|
}
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("M36 Risk Commitment View: %s" % message)
|
|
|