131 lines
5.5 KiB
GDScript
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)
|