stepstead-client/tests/e2e_test.gd
jts 6a1706051d İlk commit: Stepstead Godot istemci (4.6 Mobile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:31:35 +03:00

147 lines
6.6 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
## Headless E2E — gerçek backend'e karşı istemci akışlarını doğrular.
## Çalıştırma (RP5): tests/run_e2e.sh (token üretir + tea_mint seed eder + bunu çağırır)
## godot --headless --path . res://tests/e2e_test.tscn
## Env: SS_TOKEN_A (ana karakter), SS_TOKEN_B (wstestchar), SS_API_BASE (ops. override)
var _fails := 0
var _ws_connected := false
var _got_online_list := false
var _got_chat_history := false
var _got_local_history := false
var _moved_payload: Dictionary = {}
var _chat_payload: Dictionary = {}
func _ready() -> void:
await _run()
print("== SONUÇ: %s (%d hata) ==" % ["BAŞARILI" if _fails == 0 else "BAŞARISIZ", _fails])
get_tree().quit(0 if _fails == 0 else 1)
func _run() -> void:
print("== Stepstead headless E2E ==")
var base := OS.get_environment("SS_API_BASE")
if base != "":
Config.override_base = base
print(" API base: ", base)
var token_a := OS.get_environment("SS_TOKEN_A")
var token_b := OS.get_environment("SS_TOKEN_B")
if token_a == "" or token_b == "":
_check(false, "SS_TOKEN_A / SS_TOKEN_B env değişkenleri gerekli")
return
Auth.token = token_a
# 1) Karakter yükle
var res: Dictionary = await GameState.load_character()
_check(res.ok and str(GameState.character.get("name", "")) != "", "load_character")
print(" karakter: %s, adım: %d" % [str(GameState.character.get("name", "")), int(GameState.character.get("step_balance", 0))])
# 2) Envanter yükle
res = await GameState.load_inventory()
_check(res.ok, "load_inventory (%d item)" % GameState.inventory.size())
# 3) Consumable kullan (wrapper tea_mint seed etti)
var bal_before: int = int(GameState.character.get("step_balance", 0))
res = await GameState.use_item("tea_mint", 1)
_check(res.ok, "use_item HTTP")
var bal_after: int = int(GameState.character.get("step_balance", 0))
_check(bal_after == bal_before + 50, "use_item +50 adım (önce %d, sonra %d)" % [bal_before, bal_after])
# 4) WebSocket bağlan
WsClient.connection_changed.connect(func(c: bool) -> void: _ws_connected = c)
WsClient.online_list.connect(func(_players: Array) -> void: _got_online_list = true)
WsClient.chat_history.connect(func(_messages: Array) -> void: _got_chat_history = true)
WsClient.player_moved.connect(func(p: Dictionary) -> void: _moved_payload = p)
WsClient.chat_received.connect(func(m: Dictionary) -> void: _chat_payload = m)
WsClient.start()
_check(await _wait_for(func() -> bool: return _ws_connected, 10.0), "WS bağlantısııldı")
_check(await _wait_for(func() -> bool: return _got_online_list, 5.0), "online_list alındı")
_check(await _wait_for(func() -> bool: return _got_chat_history, 5.0), "chat_history alındı")
# 4b) Chat: gönder → echo geri gelmeli
var chat_msg := "e2e test %d" % (Time.get_ticks_msec())
WsClient.send_chat(chat_msg)
_check(await _wait_for(func() -> bool: return str(_chat_payload.get("text", "")) == chat_msg, 10.0),
"chat gönderildi ve echo alındı")
# 4c) Yerel chat: kanal local echo + yerel geçmiş
await get_tree().create_timer(1.2).timeout # flood koruması
var local_msg := "e2e yerel %d" % (Time.get_ticks_msec())
WsClient.send_chat(local_msg, "local")
_check(await _wait_for(func() -> bool:
return str(_chat_payload.get("text", "")) == local_msg \
and str(_chat_payload.get("channel", "")) == "local", 10.0),
"yerel chat echo alındı (channel=local)")
WsClient.local_chat_history.connect(func(_m: Array) -> void: _got_local_history = true)
WsClient.request_local_history()
_check(await _wait_for(func() -> bool: return _got_local_history, 5.0), "yerel chat geçmişi alındı")
# 4d) Günlük hedef + market vitrini
res = await GameState.daily_status()
_check(res.ok and res.body is Dictionary and res.body.has("goal"),
"daily_status (hedef %d, bugün %d)" % [int(res.body.get("goal", 0)), int(res.body.get("today_steps", 0))] if res.ok else "daily_status")
var market_rows: Array = await GameState.market_listings()
_check(market_rows is Array, "market_listings (%d ilan)" % market_rows.size())
var vendor_rows: Array = await GameState.vendor_prices()
_check(not vendor_rows.is_empty(), "vendor_prices (%d çeşit item)" % vendor_rows.size())
var stock_rows: Array = await GameState.vendor_stock()
_check(not stock_rows.is_empty(), "vendor_stock (%d mal)" % stock_rows.size())
res = await GameState.leaderboard("steps")
_check(res.ok and res.body is Dictionary and not (res.body.get("rows", []) as Array).is_empty(),
"leaderboard (sıram #%d)" % int(res.body.get("my_rank", 0)) if res.ok else "leaderboard")
# 5) Harita + seyahat (lokasyon-graf dünya)
res = await GameState.load_map()
var locs: Array = GameState.map_data.get("locations", [])
var my_loc := str(GameState.map_data.get("my_location", ""))
_check(res.ok and locs.size() >= 10 and my_loc != "", "load_map (%d lokasyon, buradayım: %s)" % [locs.size(), my_loc])
# Bulunduğum yerden giden ilk yolu seç, oraya git
var dest := ""
for r in GameState.map_data.get("roads", []):
if str(r["a"]) == my_loc:
dest = str(r["b"])
break
if str(r["b"]) == my_loc:
dest = str(r["a"])
break
_check(dest != "", "gidilecek komşu lokasyon bulundu (%s)" % dest)
res = await GameState.travel(dest)
_check(res.ok and str(GameState.character.get("location_code", "")) == dest, "travel → %s" % dest)
# Yolda olay çıktıysa çöz (0. seçim)
if res.ok and res.body is Dictionary and res.body.get("event") is Dictionary:
var ev_res: Dictionary = await GameState.resolve_event(0)
_check(ev_res.ok, "yol olayı çözüldü (%s)" % str(res.body["event"].get("name", "")))
# 6) Lokasyon detayı
res = await GameState.load_location()
_check(res.ok and res.body is Dictionary and res.body.has("resources"),
"load_location (%d kaynak)" % (res.body.get("resources", []) as Array).size() if res.ok else "load_location")
# 7) B karakteri REST ile seyahat etsin → bize location_code'lu player_moved düşmeli
Auth.token = token_b
var mv: Dictionary = await Api.request("POST", "/world/travel", {"to_code": "fisilti_ormani"}, true)
if not mv.ok:
mv = await Api.request("POST", "/world/travel", {"to_code": "koy"}, true)
Auth.token = token_a
_check(mv.ok, "B /world/travel")
_check(await _wait_for(func() -> bool: return str(_moved_payload.get("name", "")) == "wstestchar", 10.0),
"player_moved eventi WS'ten alındı (lokasyon: %s)" % str(_moved_payload.get("location_code", "")))
WsClient.stop()
func _wait_for(cond: Callable, timeout: float) -> bool:
var elapsed := 0.0
while elapsed < timeout:
if cond.call():
return true
await get_tree().process_frame
elapsed += get_process_delta_time()
return bool(cond.call())
func _check(ok: bool, what: String) -> void:
if ok:
print("", what)
else:
_fails += 1
printerr("", what)