169 lines
7.6 KiB
GDScript
169 lines
7.6 KiB
GDScript
extends SceneTree
|
|
|
|
const PageContext = preload("res://foundation/page_context.gd")
|
|
const GuildPageView = preload("res://entry/views/guild_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 := GuildPageView.new()
|
|
view.name = "GuildViewContractFixture"
|
|
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": "guild",
|
|
"caller_id": "entry",
|
|
"return_page_id": "title",
|
|
"return_focus_path": "GuildContractBoard",
|
|
"metadata": {"company_id": "company-001"},
|
|
}))
|
|
view.intent_emitted.connect(_record_intent)
|
|
root.add_child(view)
|
|
view.render(_fixture_view_data("empty"))
|
|
await process_frame
|
|
|
|
for node_name in [
|
|
"GuildMasterWorldExtension", "GuildMasterDesignCanvas", "GuildMasterLayeredWorld",
|
|
"GuildAnchorRoot", "GuildTopRail", "GuildTopRailLeft", "GuildTopRailCenter",
|
|
"GuildTopRailRight", "GuildBottomRail", "GuildBottomRailLeft",
|
|
"GuildBottomRailCenter", "GuildBottomRailRight", "GuildTitlePlate",
|
|
"GuildAnchorTitle", "GuildAnchorStatus", "GuildProgressStatus",
|
|
"GuildCoinStatus", "GuildAnchorCompanyStatus", "GuildSettings", "GuildTitle",
|
|
"GuildRoster", "GuildMemberPortraitTexture_0", "GuildMemberPortraitTexture_1",
|
|
"GuildMasterIdentityPlate0", "GuildMasterIdentityPlate1", "GuildMasterKioskTexture",
|
|
"GuildKioskCopyArea", "GuildKioskText", "GuildContractReason", "GuildMarketReason",
|
|
"GuildNotice", "GuildRosterButton", "GuildEquipment", "GuildParty", "GuildRisk",
|
|
"GuildContractBoard", "GuildMarketUnavailable", "GuildContractSticker", "GuildMarketSticker",
|
|
]:
|
|
expect(view.find_child(node_name, true, false) != null, "%s is rendered" % node_name)
|
|
|
|
var canvas := view.find_child("GuildMasterDesignCanvas", true, false) as Control
|
|
if canvas != null:
|
|
expect(is_equal_approx(canvas.size.x / canvas.size.y, 16.0 / 9.0), "Guild canvas preserves 16:9")
|
|
expect(canvas.get_global_rect().encloses(view.find_child("GuildMasterLayeredWorld", true, false).get_global_rect()), "layered world stays inside canvas")
|
|
var contract := view.find_child("GuildContractBoard", true, false) as Button
|
|
var market := view.find_child("GuildMarketUnavailable", true, false) as Button
|
|
var party := view.find_child("GuildParty", true, false) as Button
|
|
var risk := view.find_child("GuildRisk", true, false) as Button
|
|
expect(contract != null and not contract.disabled, "empty Guild enables Contract")
|
|
expect(market != null and market.disabled, "empty Guild disables Market")
|
|
expect(party != null and party.disabled, "empty Guild disables Party")
|
|
expect(risk != null and risk.disabled, "empty Guild disables Risk")
|
|
if contract != null:
|
|
contract.emit_signal("pressed")
|
|
await process_frame
|
|
expect(intents.size() == 1 and intents[0].get("intent_id") == "contract", "Contract emits explicit intent")
|
|
|
|
view.render(_fixture_view_data("active"))
|
|
await process_frame
|
|
for node_name in ["GuildContractActive", "GuildMarket", "GuildParty", "GuildRisk"]:
|
|
expect(view.find_child(node_name, true, false) != null, "%s is rendered for active state" % node_name)
|
|
for node_name in ["GuildMarket", "GuildParty", "GuildRisk"]:
|
|
var enabled := view.find_child(node_name, true, false) as Button
|
|
expect(enabled != null and not enabled.disabled, "%s is enabled for active state" % node_name)
|
|
for node_name in ["GuildSettings", "GuildTitle", "GuildRosterButton", "GuildEquipment", "GuildParty", "GuildRisk", "GuildMarket", "GuildContractActive"]:
|
|
var button := view.find_child(node_name, true, false) as Button
|
|
if button != null:
|
|
button.emit_signal("pressed")
|
|
await process_frame
|
|
expect(intents.size() == 9, "View emits one explicit intent per command")
|
|
if intents.size() == 9:
|
|
expect(intents[1].get("intent_id") == "settings", "Settings intent is named")
|
|
expect(intents[2].get("intent_id") == "title", "Title intent is named")
|
|
expect(intents[3].get("intent_id") == "roster", "Roster intent is named")
|
|
expect(intents[4].get("intent_id") == "equipment", "Equipment intent is named")
|
|
expect(intents[5].get("intent_id") == "party", "Party intent is named")
|
|
expect(intents[6].get("intent_id") == "risk", "Risk intent is named")
|
|
expect(intents[7].get("intent_id") == "market", "Market intent is named")
|
|
expect(intents[8].get("intent_id") == "contract", "Contract intent is named")
|
|
|
|
view.render(_fixture_view_data("returned"))
|
|
await process_frame
|
|
expect(view.find_child("GuildContractActive", true, false) != null and view.find_child("GuildContractActive", true, false).disabled, "returned state blocks later Contract")
|
|
expect(view.find_child("GuildMarketUnavailable", true, false) != null and view.find_child("GuildMarketUnavailable", true, false).disabled, "returned state blocks Market")
|
|
|
|
view.render({"ok": false, "locale": "en", "notice": "Guild unavailable"})
|
|
await process_frame
|
|
expect(view.find_child("GuildInvalidOverlay", true, false) != null, "invalid state renders safely")
|
|
expect(view.find_child("GuildContractBoard", true, false) == null, "invalid state is non-interactive")
|
|
|
|
var source := FileAccess.get_file_as_string("res://entry/views/guild_page_view.gd")
|
|
for forbidden in ["GuildContractService", "RuntimeContentRegistry", "current_screen", "entry_shell.gd", "res://compat/", "Save", "company_path"]:
|
|
expect(not source.contains(forbidden), "View does not own %s" % forbidden)
|
|
|
|
view.queue_free()
|
|
await process_frame
|
|
if failures.is_empty():
|
|
print("ABG_M43_GUILD_VIEW_CONTRACT_OK mount=true normalized_canvas=true layered_world=true rails=true actors=2 kiosk=true states=empty,active,returned commands=title,settings,roster,equipment,party,risk,contract,market intents=true 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(state: String) -> Dictionary:
|
|
var contract := {}
|
|
if state == "active" or state == "returned":
|
|
contract = {
|
|
"present": true,
|
|
"active": state == "active",
|
|
"returned": state == "returned",
|
|
"state": state,
|
|
"status": "market" if state == "active" else "returned",
|
|
"contract_id": "CTR-R1-01",
|
|
"run_id": "run-001",
|
|
"route_id": "windglass_verge",
|
|
"difficulty": "stormbound",
|
|
"coin": 38,
|
|
"line_capacity": 4,
|
|
}
|
|
return {
|
|
"ok": true,
|
|
"page_id": "guild",
|
|
"locale": "en",
|
|
"company": {
|
|
"company_id": "company-001",
|
|
"owned_count": 2,
|
|
"line_capacity": 4,
|
|
"display_recruits": [_recruit("owned-001", "Ari", "PF-B01"), _recruit("owned-002", "Bram", "PF-B02")],
|
|
},
|
|
"contract": contract,
|
|
"destinations": {
|
|
"contract": {"enabled": state == "empty"},
|
|
"market": {"enabled": state == "active"},
|
|
"equipment": {"enabled": state == "active"},
|
|
"party": {"enabled": state == "active"},
|
|
"risk": {"enabled": state == "active"},
|
|
},
|
|
}
|
|
|
|
|
|
func _recruit(recruit_id: String, name: String, profession_id: String) -> Dictionary:
|
|
return {
|
|
"recruit_id": recruit_id,
|
|
"profession_id": profession_id,
|
|
"rendered_name_snapshot": {"en": name, "zh_CN": name},
|
|
"profession_name": {"en": "Vanguard", "zh_CN": "先锋"},
|
|
}
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("M43 Guild View: %s" % message)
|