Files
aetherbound-guild/runtime/tests/foundation/contract_choice_page_view_test.gd
T

131 lines
5.5 KiB
GDScript

extends SceneTree
const PageContext = preload("res://foundation/page_context.gd")
const ContractChoicePageView = preload("res://entry/views/contract_choice_page_view.gd")
var failures: Array[String] = []
var intents: Array[Dictionary] = []
func _initialize() -> void:
call_deferred("run_test")
func run_test() -> void:
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
# Single target size (owner policy): every screen is authored at 1280x720.
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
root.content_scale_size = Vector2i(1280, 720)
root.size = Vector2i(1280, 720)
var view := ContractChoicePageView.new()
view.name = "ContractChoiceViewContractFixture"
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": "contract_choice",
"caller_id": "guild",
"return_page_id": "guild_handoff",
"return_focus_path": "GuildContractBoard",
}))
view.intent_emitted.connect(_record_intent)
root.add_child(view)
view.render(_fixture_view_data())
await process_frame
var context = view.get("context")
expect(context != null and String(context.get("page_id")) == "contract_choice", "mount stores a copied PageContext")
for node_name in [
"WorldBackground", "ContractChoiceFrame", "ContractChoiceLayout",
"ContractChoiceBody", "ContractBoardScene", "ContractCompanyScene",
"ContractCompanyMember_0", "ContractCompanyMember_1", "ContractReview",
"ContractDifficultySegments", "ContractDifficultyWayfinder",
"ContractDifficultyStandard", "ContractDifficultyStormbound",
"ContractDifficultyIronOath", "ContractDifficultyCopy",
"ContractCreationFacts", "ContractNotice", "ContractChoiceFooter",
"ContractCancel", "ContractConfirm",
]:
expect(view.find_child(node_name, true, false) != null, "%s is rendered" % node_name)
var standard := view.find_child("ContractDifficultyStandard", true, false) as Button
var wayfinder := view.find_child("ContractDifficultyWayfinder", true, false) as Button
var cancel := view.find_child("ContractCancel", true, false) as Button
var confirm := view.find_child("ContractConfirm", true, false) as Button
expect(standard != null and bool(standard.get_meta("selected", false)), "selected difficulty is local View state")
expect(confirm != null and not confirm.disabled, "Confirm follows supplied eligibility")
if wayfinder != null:
wayfinder.emit_signal("pressed")
await process_frame
if confirm != null:
confirm.emit_signal("pressed")
await process_frame
if cancel != null:
cancel.emit_signal("pressed")
await process_frame
expect(intents.size() == 3, "View emits exactly three explicit intents")
if intents.size() == 3:
expect(intents[0].get("intent_id") == "select_difficulty", "difficulty intent is named")
expect(intents[0].get("payload", {}).get("difficulty") == "wayfinder", "difficulty intent carries the selected value")
expect(intents[1].get("intent_id") == "confirm", "Confirm intent is named")
expect(intents[2].get("intent_id") == "back", "Back intent is named")
view.render({"ok": false, "locale": "en", "code": "COMPANY_REQUIRED", "notice": "Company unavailable"})
await process_frame
expect(view.find_child("ContractChoiceInvalidOverlay", true, false) != null, "View renders invalid state")
expect(view.find_child("ContractConfirm", true, false) == null, "invalid state is non-interactive")
var source := FileAccess.get_file_as_string("res://entry/views/contract_choice_page_view.gd")
for forbidden in ["GuildContractService", "RuntimeContentRegistry", "current_screen", "entry_shell.gd", "res://compat/", "Save"]:
expect(not source.contains(forbidden), "View does not own %s" % forbidden)
view.queue_free()
await process_frame
if failures.is_empty():
print("ABG_M42_CONTRACT_CHOICE_VIEW_CONTRACT_OK mount=true frame=true company=2 difficulties=4 facts=true commands=select_difficulty,confirm,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() -> Dictionary:
return {
"ok": true,
"page_id": "contract_choice",
"locale": "en",
"company": {
"company_id": "company-001",
"owned_count": 2,
"recruits": [
{"recruit_id": "owned-001", "profession_id": "PF-B01"},
{"recruit_id": "owned-002", "profession_id": "PF-B02"},
],
},
"contract": {
"contract_id": "CTR-R1-01",
"route_id": "windglass_verge",
"route_title": "FIRST WINDGLASS CROSSING",
"route_copy": "Cross the suspended windglass and establish the Guild's first safe route.",
"starting_coin": 52,
"line_capacity": 4,
"market_counts": {"recruit": 3, "equipment": 4, "battle": 3},
},
"difficulties": [
{"id": "wayfinder", "name": "Wayfinder", "copy": "More forgiving enemy parameters.", "selected": false},
{"id": "standard", "name": "Standard", "copy": "The complete standard balance.", "selected": true},
{"id": "stormbound", "name": "Stormbound", "copy": "Higher pressure and rewards.", "selected": false},
{"id": "iron_oath", "name": "Iron Oath", "copy": "Highest pressure.", "selected": false},
],
"selected_difficulty": "standard",
"confirm": {"eligible": true, "reason": "ready"},
"notice": "",
}
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("M42 Contract Choice View: %s" % message)