Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33b0c3f1fb | |||
| dc0c133af8 | |||
| 8f1a1110e2 | |||
| 12fef51020 | |||
| af50819a16 | |||
| 16bb87c6b0 |
@@ -89,10 +89,6 @@ visible = false
|
|||||||
placeholder_text = "Date of Birth (YYYY-MM-DD)"
|
placeholder_text = "Date of Birth (YYYY-MM-DD)"
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
[node name="ModeToggle" type="CheckButton" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
||||||
layout_mode = 1
|
|
||||||
text = "Register"
|
|
||||||
|
|
||||||
[node name="AuthButton" type="Button" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
[node name="AuthButton" type="Button" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
text = "Login"
|
text = "Login"
|
||||||
@@ -125,7 +121,6 @@ size_flags_horizontal = 4
|
|||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton" to="." method="_on_register_button_pressed"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton" to="." method="_on_register_button_pressed"]
|
||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/PlayButton" to="." method="_on_play_button_pressed"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/PlayButton" to="." method="_on_play_button_pressed"]
|
||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/QuitButton" to="." method="_on_quit_button_pressed"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/QuitButton" to="." method="_on_quit_button_pressed"]
|
||||||
[connection signal="toggled" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/ModeToggle" to="." method="_on_mode_toggle_toggled"]
|
|
||||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton" to="." method="_on_auth_button_pressed"]
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton" to="." method="_on_auth_button_pressed"]
|
||||||
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/UsernameEdit" to="." method="_on_auth_button_pressed"]
|
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/UsernameEdit" to="." method="_on_auth_button_pressed"]
|
||||||
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit" to="." method="_on_auth_button_pressed"]
|
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit" to="." method="_on_auth_button_pressed"]
|
||||||
|
|||||||
+22
-77
@@ -3,25 +3,13 @@ extends Control
|
|||||||
##
|
##
|
||||||
## The AuthPanel is hidden by default. When the user clicks the LoginButton or
|
## The AuthPanel is hidden by default. When the user clicks the LoginButton or
|
||||||
## RegisterButton (AuthButtonsRow, above the panel), the auth panel slides in.
|
## RegisterButton (AuthButtonsRow, above the panel), the auth panel slides in.
|
||||||
## The ModeToggle switches between Login and Register modes, showing/hiding
|
## The Login and Register buttons on the AuthButtonsRow directly set the panel's
|
||||||
## the email and DOB fields accordingly.
|
## mode, so the user can switch between Login and Register at any time while
|
||||||
|
## the panel is open.
|
||||||
##
|
##
|
||||||
## On successful auth the token is stored via ApiClient, AuthButtonsRow hides,
|
## On successful auth the token is stored via ApiClient, AuthButtonsRow hides,
|
||||||
## the welcome label shows the username, and the Play button becomes enabled.
|
## the welcome label shows the username, and the Play button becomes enabled.
|
||||||
##
|
## The auth form fields are hidden, leaving only the welcome message visible.
|
||||||
## When returning from another scene (e.g. world_list), _ready() checks whether
|
|
||||||
## ApiClient already holds a valid token. If so, it restores the authenticated
|
|
||||||
## UI state (Play enabled, welcome label visible) instead of forcing the user
|
|
||||||
## back to the login form.
|
|
||||||
|
|
||||||
|
|
||||||
## Emitted once _ready()'s session check (has_token() + the awaited
|
|
||||||
## get_me() call) has actually resolved, whichever way -- lets a test (or
|
|
||||||
## anything else) know the UI state is trustworthy now, rather than
|
|
||||||
## guessing from a frame count or from UI properties that are ambiguous
|
|
||||||
## mid-await (e.g. AuthButtonsRow.visible is true both before the check
|
|
||||||
## resolves AND in a genuine logged-out end state).
|
|
||||||
signal auth_state_ready
|
|
||||||
|
|
||||||
# ─── UI references ────────────────────────────────────────────────────────────
|
# ─── UI references ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -34,7 +22,6 @@ var _username_edit: LineEdit
|
|||||||
var _password_edit: LineEdit
|
var _password_edit: LineEdit
|
||||||
var _email_edit: LineEdit
|
var _email_edit: LineEdit
|
||||||
var _dob_edit: LineEdit
|
var _dob_edit: LineEdit
|
||||||
var _mode_toggle: CheckButton
|
|
||||||
var _auth_button: Button
|
var _auth_button: Button
|
||||||
var _status_label: Label
|
var _status_label: Label
|
||||||
var _welcome_label: Label
|
var _welcome_label: Label
|
||||||
@@ -58,53 +45,13 @@ func _ready() -> void:
|
|||||||
_password_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit
|
_password_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit
|
||||||
_email_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit
|
_email_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit
|
||||||
_dob_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/DOBEdit
|
_dob_edit = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/DOBEdit
|
||||||
_mode_toggle = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/ModeToggle
|
|
||||||
_auth_button = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton
|
_auth_button = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton
|
||||||
_status_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthStatusLabel
|
_status_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthStatusLabel
|
||||||
_welcome_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel
|
_welcome_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel
|
||||||
_play_button = $CenterContainer/VBoxContainer/PlayButton
|
_play_button = $CenterContainer/VBoxContainer/PlayButton
|
||||||
_quit_button = $CenterContainer/VBoxContainer/QuitButton
|
_quit_button = $CenterContainer/VBoxContainer/QuitButton
|
||||||
|
|
||||||
# Default to Play being gated. When a token exists, the async session
|
# Initial state.
|
||||||
# check below may take several frames (a real get_me() round-trip);
|
|
||||||
# keeping the button disabled until validation succeeds prevents a fast
|
|
||||||
# click from navigating to world_list with an expired/invalid token.
|
|
||||||
_play_button.disabled = true
|
|
||||||
|
|
||||||
# Check whether a valid session already exists (e.g. user logged in,
|
|
||||||
# navigated to world_list, then clicked Back). If so, restore the
|
|
||||||
# authenticated UI state instead of forcing the login form again.
|
|
||||||
if ApiClient.has_token():
|
|
||||||
var me_result: Dictionary = await ApiClient.get_me()
|
|
||||||
if me_result.ok and me_result.data is Dictionary:
|
|
||||||
var username: String = str((me_result.data as Dictionary).get("username", ""))
|
|
||||||
if username != "":
|
|
||||||
_show_authenticated(username)
|
|
||||||
auth_state_ready.emit()
|
|
||||||
return
|
|
||||||
|
|
||||||
# Token missing or invalid — fall through to logged-out state.
|
|
||||||
_reset_to_logged_out()
|
|
||||||
auth_state_ready.emit()
|
|
||||||
|
|
||||||
|
|
||||||
## Restore the UI to the authenticated state (Play enabled, welcome label,
|
|
||||||
## auth buttons hidden).
|
|
||||||
func _show_authenticated(username: String) -> void:
|
|
||||||
_auth_panel.visible = true
|
|
||||||
_status_label.visible = false
|
|
||||||
_welcome_label.text = "Welcome, %s!" % username
|
|
||||||
_welcome_label.visible = true
|
|
||||||
_email_edit.visible = false
|
|
||||||
_dob_edit.visible = false
|
|
||||||
_play_button.disabled = false
|
|
||||||
_auth_buttons_row.visible = false
|
|
||||||
print("Restored authenticated session for: ", username)
|
|
||||||
|
|
||||||
|
|
||||||
## Reset the UI to the logged-out state (Play disabled, auth panel hidden,
|
|
||||||
## login/register buttons visible).
|
|
||||||
func _reset_to_logged_out() -> void:
|
|
||||||
_auth_panel.visible = false
|
_auth_panel.visible = false
|
||||||
_status_label.visible = false
|
_status_label.visible = false
|
||||||
_welcome_label.visible = false
|
_welcome_label.visible = false
|
||||||
@@ -114,7 +61,7 @@ func _reset_to_logged_out() -> void:
|
|||||||
_update_auth_mode_ui()
|
_update_auth_mode_ui()
|
||||||
|
|
||||||
|
|
||||||
# ─── Play / Quit ─────────────────────────────────────────────────────────────
|
# ─── Play / Quit ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func _on_play_button_pressed() -> void:
|
func _on_play_button_pressed() -> void:
|
||||||
if _play_button.disabled:
|
if _play_button.disabled:
|
||||||
@@ -128,11 +75,14 @@ func _on_quit_button_pressed() -> void:
|
|||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
|
|
||||||
|
|
||||||
# ─── Auth panel toggle ───────────────────────────────────────────────────────
|
# ─── Auth panel toggle ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func _on_login_button_pressed() -> void:
|
func _on_login_button_pressed() -> void:
|
||||||
"""Show the auth panel, called from AuthButtonsRow/LoginButton."""
|
"""Show the auth panel in login mode, called from AuthButtonsRow/LoginButton."""
|
||||||
_auth_panel.visible = true
|
_auth_panel.visible = true
|
||||||
|
_is_register_mode = false
|
||||||
|
_update_auth_mode_ui()
|
||||||
|
_clear_status()
|
||||||
_username_edit.grab_focus()
|
_username_edit.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
@@ -140,20 +90,11 @@ func _on_register_button_pressed() -> void:
|
|||||||
"""Show the auth panel in register mode, called from AuthButtonsRow/RegisterButton."""
|
"""Show the auth panel in register mode, called from AuthButtonsRow/RegisterButton."""
|
||||||
_auth_panel.visible = true
|
_auth_panel.visible = true
|
||||||
_is_register_mode = true
|
_is_register_mode = true
|
||||||
_mode_toggle.button_pressed = true
|
|
||||||
_update_auth_mode_ui()
|
_update_auth_mode_ui()
|
||||||
_clear_status()
|
_clear_status()
|
||||||
_username_edit.grab_focus()
|
_username_edit.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
# ─── Mode toggle (Login / Register) ──────────────────────────────────────────
|
|
||||||
|
|
||||||
func _on_mode_toggle_toggled(button_pressed: bool) -> void:
|
|
||||||
_is_register_mode = button_pressed
|
|
||||||
_update_auth_mode_ui()
|
|
||||||
_clear_status()
|
|
||||||
|
|
||||||
|
|
||||||
func _update_auth_mode_ui() -> void:
|
func _update_auth_mode_ui() -> void:
|
||||||
"""Update labels and field visibility based on login vs register mode."""
|
"""Update labels and field visibility based on login vs register mode."""
|
||||||
if _is_register_mode:
|
if _is_register_mode:
|
||||||
@@ -168,7 +109,7 @@ func _update_auth_mode_ui() -> void:
|
|||||||
_dob_edit.visible = false
|
_dob_edit.visible = false
|
||||||
|
|
||||||
|
|
||||||
# ─── Auth submission ─────────────────────────────────────────────────────────
|
# ─── Auth submission ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func _on_auth_button_pressed() -> void:
|
func _on_auth_button_pressed() -> void:
|
||||||
"""Handle login or register button press."""
|
"""Handle login or register button press."""
|
||||||
@@ -225,12 +166,16 @@ func _on_auth_complete(result: Dictionary) -> void:
|
|||||||
_is_authenticating = false
|
_is_authenticating = false
|
||||||
|
|
||||||
if result.ok:
|
if result.ok:
|
||||||
# Success — show welcome, enable Play, hide the now-redundant
|
# Success — hide the auth form fields, show only the welcome label.
|
||||||
# Login/Register entry points (the auth panel itself stays open,
|
_username_edit.visible = false
|
||||||
# showing the welcome message in place of the form).
|
_password_edit.visible = false
|
||||||
|
_email_edit.visible = false
|
||||||
|
_dob_edit.visible = false
|
||||||
|
_auth_button.visible = false
|
||||||
|
_auth_mode_label.visible = false
|
||||||
|
_status_label.visible = false
|
||||||
_welcome_label.text = "Welcome, %s!" % _username_edit.text.strip_edges()
|
_welcome_label.text = "Welcome, %s!" % _username_edit.text.strip_edges()
|
||||||
_welcome_label.visible = true
|
_welcome_label.visible = true
|
||||||
_status_label.visible = false
|
|
||||||
_play_button.disabled = false
|
_play_button.disabled = false
|
||||||
_auth_buttons_row.visible = false
|
_auth_buttons_row.visible = false
|
||||||
print("Auth successful. Token stored.")
|
print("Auth successful. Token stored.")
|
||||||
@@ -239,7 +184,7 @@ func _on_auth_complete(result: Dictionary) -> void:
|
|||||||
_show_status(result.detail)
|
_show_status(result.detail)
|
||||||
|
|
||||||
|
|
||||||
# ─── Status helpers ──────────────────────────────────────────────────────────
|
# ─── Status helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func _show_status(message: String) -> void:
|
func _show_status(message: String) -> void:
|
||||||
_status_label.text = message
|
_status_label.text = message
|
||||||
@@ -251,7 +196,7 @@ func _clear_status() -> void:
|
|||||||
_status_label.visible = false
|
_status_label.visible = false
|
||||||
|
|
||||||
|
|
||||||
# ─── Validation ──────────────────────────────────────────────────────────────
|
# ─── Validation ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func _is_valid_date(date_str: String) -> bool:
|
func _is_valid_date(date_str: String) -> bool:
|
||||||
"""Check if a string looks like a valid YYYY-MM-DD date."""
|
"""Check if a string looks like a valid YYYY-MM-DD date."""
|
||||||
|
|||||||
@@ -1,154 +0,0 @@
|
|||||||
extends SceneTree
|
|
||||||
## Regression test for the Play -> Back navigation bug.
|
|
||||||
##
|
|
||||||
## The reported bug: after logging in and clicking Play, the user lands on
|
|
||||||
## world_list.tscn; clicking Back returns to main_menu.tscn, but the menu
|
|
||||||
## reset to a fully logged-out state (Play disabled, login form showing)
|
|
||||||
## even though ApiClient still held a valid token. main_menu.gd's _ready()
|
|
||||||
## used to unconditionally reset the UI on every scene load.
|
|
||||||
##
|
|
||||||
## This test drives the real navigation flow (change_scene_to_file) against
|
|
||||||
## a live backend:
|
|
||||||
## 1. Register a unique user so ApiClient holds a valid token.
|
|
||||||
## 2. Load main_menu.tscn and assert it restores the authenticated state.
|
|
||||||
## 3. Click Play -> world_list.tscn.
|
|
||||||
## 4. Click Back -> main_menu.tscn.
|
|
||||||
## 5. Assert the menu is STILL authenticated (Play enabled, welcome label
|
|
||||||
## actually visible in the tree, login/register buttons hidden).
|
|
||||||
##
|
|
||||||
## Run with:
|
|
||||||
## godot --headless --path . --script res://scripts/smoke_test_main_menu_back.gd
|
|
||||||
##
|
|
||||||
## Requires the backend to be running (default base URL
|
|
||||||
## `application/agp/api_base_url` -> http://127.0.0.1:8000).
|
|
||||||
|
|
||||||
const USERNAME := "backnav_%d"
|
|
||||||
const EMAIL := "backnav_%d@test.example.com"
|
|
||||||
const PASSWORD := "BackNav123!"
|
|
||||||
const DOB := "2000-01-01"
|
|
||||||
|
|
||||||
var passed := 0
|
|
||||||
var failed := 0
|
|
||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
|
||||||
_run()
|
|
||||||
|
|
||||||
|
|
||||||
func _run() -> void:
|
|
||||||
await process_frame
|
|
||||||
|
|
||||||
var api := root.get_node("ApiClient")
|
|
||||||
if api == null:
|
|
||||||
printerr("FAIL: ApiClient autoload not found")
|
|
||||||
quit(1)
|
|
||||||
return
|
|
||||||
|
|
||||||
# 1. Establish a real, valid session exactly the way a user would.
|
|
||||||
randomize()
|
|
||||||
var unique_id: int = int(Time.get_unix_time_from_system() * 1000) + randi() % 100000
|
|
||||||
var username := USERNAME % unique_id
|
|
||||||
var email := EMAIL % unique_id
|
|
||||||
print("\n=== Setup: register ", username, " ===")
|
|
||||||
var register_result: Dictionary = await api.register(username, email, PASSWORD, DOB)
|
|
||||||
if not _check("register succeeds", register_result.ok):
|
|
||||||
print(" detail: ", register_result.detail)
|
|
||||||
_finish()
|
|
||||||
return
|
|
||||||
_check("ApiClient stores token after register", api.has_token())
|
|
||||||
|
|
||||||
# 2. First visit to the main menu: should already show the authenticated
|
|
||||||
# state (no login form, Play enabled).
|
|
||||||
change_scene_to_file("res://scenes/main_menu.tscn")
|
|
||||||
# change_scene_to_file defers the actual swap -- a couple frames is
|
|
||||||
# plenty for the scene object itself to exist (unlike the real
|
|
||||||
# get_me() network round-trip afterward, which is what auth_state_ready
|
|
||||||
# actually waits for below).
|
|
||||||
for i in 5:
|
|
||||||
await process_frame
|
|
||||||
if current_scene is Control:
|
|
||||||
break
|
|
||||||
|
|
||||||
var menu: Control = current_scene
|
|
||||||
if menu == null or not menu is Control:
|
|
||||||
printerr("FAIL: main_menu.tscn did not become current_scene")
|
|
||||||
_finish()
|
|
||||||
return
|
|
||||||
await menu.auth_state_ready
|
|
||||||
_check("first main menu visit restores authenticated state", _is_authenticated(menu))
|
|
||||||
|
|
||||||
# 3. Play -> world_list.tscn (real button press).
|
|
||||||
var play_button: Button = menu.get_node("CenterContainer/VBoxContainer/PlayButton")
|
|
||||||
play_button.pressed.emit()
|
|
||||||
await _wait_for_scene_change(menu)
|
|
||||||
|
|
||||||
var world_list_scene := current_scene
|
|
||||||
if world_list_scene == null or world_list_scene == menu:
|
|
||||||
printerr("FAIL: world_list.tscn did not become current_scene after Play")
|
|
||||||
_finish()
|
|
||||||
return
|
|
||||||
|
|
||||||
# 4. Back -> main_menu.tscn (real button press).
|
|
||||||
var back_button: Button = world_list_scene.get_node("VBoxContainer/HeaderHBox/BackButton")
|
|
||||||
back_button.pressed.emit()
|
|
||||||
await _wait_for_scene_change(world_list_scene)
|
|
||||||
|
|
||||||
menu = current_scene
|
|
||||||
if menu == null or not menu is Control:
|
|
||||||
printerr("FAIL: main_menu.tscn did not become current_scene after Back")
|
|
||||||
_finish()
|
|
||||||
return
|
|
||||||
|
|
||||||
# The new main_menu instance's own _ready() is *also* awaiting a real
|
|
||||||
# get_me() call -- _wait_for_scene_change only confirms the scene
|
|
||||||
# object exists, not that its authenticated-state fields have been
|
|
||||||
# set yet. Wait for the real signal, not a guess.
|
|
||||||
await menu.auth_state_ready
|
|
||||||
|
|
||||||
# 5. THE regression assertion: still logged in after returning.
|
|
||||||
_check("main menu stays authenticated after Play -> Back", _is_authenticated(menu))
|
|
||||||
|
|
||||||
_finish()
|
|
||||||
|
|
||||||
|
|
||||||
func _is_authenticated(menu: Control) -> bool:
|
|
||||||
var play_button: Button = menu.get_node("CenterContainer/VBoxContainer/PlayButton")
|
|
||||||
var welcome_label: Label = menu.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel")
|
|
||||||
var auth_buttons_row: HBoxContainer = menu.get_node("CenterContainer/VBoxContainer/AuthButtonsRow")
|
|
||||||
var auth_panel: PanelContainer = menu.get_node("CenterContainer/VBoxContainer/AuthPanel")
|
|
||||||
|
|
||||||
_check("Play enabled", not play_button.disabled)
|
|
||||||
# WelcomeLabel lives inside AuthPanel, so `.visible` alone is a
|
|
||||||
# false-positive: the label can have visible=true while its parent is
|
|
||||||
# hidden and it renders as nothing. `is_visible_in_tree()` is the
|
|
||||||
# check that proves the user can actually see the welcome message.
|
|
||||||
_check("Welcome label visible in tree", welcome_label.is_visible_in_tree())
|
|
||||||
_check("Auth buttons row hidden", not auth_buttons_row.visible)
|
|
||||||
_check("Auth panel visible (it contains the welcome label)", auth_panel.visible)
|
|
||||||
|
|
||||||
return (not play_button.disabled) \
|
|
||||||
and welcome_label.is_visible_in_tree() \
|
|
||||||
and not auth_buttons_row.visible \
|
|
||||||
and auth_panel.visible
|
|
||||||
|
|
||||||
|
|
||||||
func _wait_for_scene_change(previous_scene: Node) -> void:
|
|
||||||
for i in 20:
|
|
||||||
await process_frame
|
|
||||||
if current_scene != previous_scene and current_scene != null:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
func _check(description: String, condition: bool) -> bool:
|
|
||||||
if condition:
|
|
||||||
print(" PASS: ", description)
|
|
||||||
passed += 1
|
|
||||||
else:
|
|
||||||
printerr(" FAIL: ", description)
|
|
||||||
failed += 1
|
|
||||||
return condition
|
|
||||||
|
|
||||||
|
|
||||||
func _finish() -> void:
|
|
||||||
print("\n=== SMOKE RESULT: %d/%d passed ===" % [passed, passed + failed])
|
|
||||||
quit(0 if failed == 0 else 1)
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
extends SceneTree
|
extends SceneTree
|
||||||
## Full click-through simulation of the real user flow: press Register,
|
## Full click-through simulation of the real user flow: press Register,
|
||||||
## fill the form exactly as a human would, submit, confirm Play actually
|
## fill the form exactly as a human would, submit, confirm Play actually
|
||||||
## becomes clickable. This is the check that would have caught the
|
## becomes clickable. Also verifies that after successful auth the auth
|
||||||
## original bug (no way to even open the form) and would catch a repeat
|
## form fields are hidden, leaving only the welcome message visible.
|
||||||
## of it.
|
|
||||||
|
|
||||||
var passed := 0
|
var passed := 0
|
||||||
var failed := 0
|
var failed := 0
|
||||||
@@ -28,6 +27,7 @@ func _run() -> void:
|
|||||||
var email_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit")
|
var email_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit")
|
||||||
var dob_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/DOBEdit")
|
var dob_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/DOBEdit")
|
||||||
var auth_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton")
|
var auth_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton")
|
||||||
|
var auth_mode_label: Label = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthModeLabel")
|
||||||
var welcome_label: Label = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel")
|
var welcome_label: Label = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel")
|
||||||
var play_button: Button = instance.get_node("CenterContainer/VBoxContainer/PlayButton")
|
var play_button: Button = instance.get_node("CenterContainer/VBoxContainer/PlayButton")
|
||||||
|
|
||||||
@@ -60,9 +60,19 @@ func _run() -> void:
|
|||||||
await instance._on_auth_button_pressed()
|
await instance._on_auth_button_pressed()
|
||||||
|
|
||||||
_check("Play became enabled after real register submission", not play_button.disabled)
|
_check("Play became enabled after real register submission", not play_button.disabled)
|
||||||
_check("Welcome label visible in tree", welcome_label.is_visible_in_tree())
|
_check("Welcome label visible", welcome_label.visible)
|
||||||
_check("Auth buttons row hid itself after success", not auth_buttons_row.visible)
|
_check("Auth buttons row hid itself after success", not auth_buttons_row.visible)
|
||||||
|
|
||||||
|
# Verify the auth form fields are hidden after successful auth,
|
||||||
|
# leaving only the welcome message visible within the panel.
|
||||||
|
_check("Username edit hidden after auth", not username_edit.visible)
|
||||||
|
_check("Password edit hidden after auth", not password_edit.visible)
|
||||||
|
_check("Email edit hidden after auth", not email_edit.visible)
|
||||||
|
_check("DOB edit hidden after auth", not dob_edit.visible)
|
||||||
|
_check("Auth button hidden after auth", not auth_button.visible)
|
||||||
|
_check("Auth mode label hidden after auth", not auth_mode_label.visible)
|
||||||
|
_check("Welcome label contains username", welcome_label.text.begins_with("Welcome, mainmenu_e2e_"))
|
||||||
|
|
||||||
print("\n=== SMOKE RESULT: %d/%d passed ===" % [passed, passed + failed])
|
print("\n=== SMOKE RESULT: %d/%d passed ===" % [passed, passed + failed])
|
||||||
quit(0 if failed == 0 else 1)
|
quit(0 if failed == 0 else 1)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
extends SceneTree
|
extends SceneTree
|
||||||
## Verifies the main menu's Login/Register buttons actually open the auth
|
## Verifies the main menu's Login/Register buttons correctly open the auth
|
||||||
## panel via a real signal emission (not calling the handler method
|
## panel and toggle between Login and Register modes via signal emission.
|
||||||
## directly) -- that's the exact gap that shipped without ever being
|
##
|
||||||
## caught: the AuthPanel and its logic were all correct, but nothing in
|
## Key tests:
|
||||||
## the scene was ever wired to open it.
|
## - AuthPanel starts hidden.
|
||||||
|
## - LoginButton press opens the panel in Login mode.
|
||||||
|
## - RegisterButton press opens the panel in Register mode.
|
||||||
|
## - Clicking Login while in Register mode switches back to Login mode.
|
||||||
|
## - Clicking Register while in Login mode switches to Register mode.
|
||||||
|
## - The ModeToggle CheckButton no longer exists in the scene.
|
||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
@@ -24,26 +29,87 @@ func _run() -> void:
|
|||||||
var login_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow/LoginButton")
|
var login_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow/LoginButton")
|
||||||
var register_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton")
|
var register_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton")
|
||||||
var auth_panel: PanelContainer = instance.get_node("CenterContainer/VBoxContainer/AuthPanel")
|
var auth_panel: PanelContainer = instance.get_node("CenterContainer/VBoxContainer/AuthPanel")
|
||||||
|
var auth_mode_label: Label = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthModeLabel")
|
||||||
|
var email_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit")
|
||||||
|
var dob_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/DOBEdit")
|
||||||
|
|
||||||
|
# --- Test 1: auth panel starts hidden ---
|
||||||
if _check("auth panel starts hidden", not auth_panel.visible):
|
if _check("auth panel starts hidden", not auth_panel.visible):
|
||||||
passed += 1
|
passed += 1
|
||||||
else:
|
else:
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
|
# --- Test 2: LoginButton press opens panel in Login mode ---
|
||||||
login_button.pressed.emit()
|
login_button.pressed.emit()
|
||||||
await process_frame
|
await process_frame
|
||||||
|
|
||||||
if _check("auth panel visible after a real LoginButton press signal", auth_panel.visible):
|
if _check("auth panel visible after LoginButton press", auth_panel.visible):
|
||||||
passed += 1
|
passed += 1
|
||||||
else:
|
else:
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
# Reset and check RegisterButton independently too.
|
if _check("Login mode label after LoginButton press", auth_mode_label.text == "Login"):
|
||||||
auth_panel.visible = false
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("Email field hidden in Login mode", not email_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("DOB field hidden in Login mode", not dob_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
# --- Test 3: RegisterButton press switches to Register mode ---
|
||||||
register_button.pressed.emit()
|
register_button.pressed.emit()
|
||||||
await process_frame
|
await process_frame
|
||||||
|
|
||||||
if _check("auth panel visible after a real RegisterButton press signal", auth_panel.visible):
|
if _check("auth panel still visible after RegisterButton press", auth_panel.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("Register mode label after RegisterButton press", auth_mode_label.text == "Register"):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("Email field visible in Register mode", email_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("DOB field visible in Register mode", dob_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
# --- Test 4: LoginButton press switches back to Login mode ---
|
||||||
|
login_button.pressed.emit()
|
||||||
|
await process_frame
|
||||||
|
|
||||||
|
if _check("Login mode label after second LoginButton press", auth_mode_label.text == "Login"):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("Email field hidden after switching back to Login", not email_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
if _check("DOB field hidden after switching back to Login", not dob_edit.visible):
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
# --- Test 5: ModeToggle CheckButton no longer exists ---
|
||||||
|
var mode_toggle_path = "CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/ModeToggle"
|
||||||
|
var has_mode_toggle = instance.has_node(mode_toggle_path)
|
||||||
|
if _check("ModeToggle CheckButton removed from scene", not has_mode_toggle):
|
||||||
passed += 1
|
passed += 1
|
||||||
else:
|
else:
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|||||||
Reference in New Issue
Block a user