1c64dd4967
Two things, found together while investigating a stuck blocker task:
1. URGENT: main_menu.gd currently fails to parse at all on main
("Identifier '_dob_edit' not declared in the current scope"). PR #44
(hide-all-fields-on-auth-success) and PR #45 (DOBEdit -> Over18Check
checkbox) each merged cleanly on their own -- Gitea's merge reported
mergeable:true for both -- but together they left a reference to the
old _dob_edit var on a line neither PR's diff touched, so no conflict
was ever flagged. Same failure mode in smoke_test_main_menu_full_flow.gd
(dob_edit, would have failed to even parse in the checkpoint suite).
Fixed both to reference _over_18_check / over_18_check.
2. Lands the Play -> Back session-persistence fix (PR #43, task
28357bca192d) that was stuck behind review the whole time main didn't
have it yet: signal auth_state_ready, _show_authenticated() /
_reset_to_logged_out() helpers, and _ready() restoring the
authenticated UI (not resetting it) when ApiClient already holds a
valid token. Plus the real fix a review round caught on top of that
(task 9186405a6373): _show_authenticated() was hiding AuthPanel while
claiming the welcome label inside it was visible -- a no-op UI-wise,
since WelcomeLabel.visible=true does nothing once its parent is
hidden. AuthPanel now stays visible; the regression test
(smoke_test_main_menu_back.gd, new) asserts is_visible_in_tree(), not
just .visible, so this class of bug can't pass silently again.
Verified against a live backend: 61/61 pytest, 7/7 Godot smoke tests
(including the new smoke_test_main_menu_back.gd, 12/12).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M6rUEynmv2QmweocAQYARN
87 lines
4.2 KiB
GDScript
87 lines
4.2 KiB
GDScript
extends SceneTree
|
|
## Full click-through simulation of the real user flow: press Register,
|
|
## fill the form exactly as a human would, submit, confirm Play actually
|
|
## becomes clickable. Also verifies that after successful auth the auth
|
|
## form fields are hidden, leaving only the welcome message visible.
|
|
|
|
var passed := 0
|
|
var failed := 0
|
|
|
|
|
|
func _initialize() -> void:
|
|
_run()
|
|
|
|
|
|
func _run() -> void:
|
|
await process_frame
|
|
|
|
var packed: PackedScene = load("res://scenes/main_menu.tscn")
|
|
var instance: Control = packed.instantiate()
|
|
root.add_child(instance)
|
|
await process_frame
|
|
|
|
var register_button: Button = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton")
|
|
var auth_buttons_row: HBoxContainer = instance.get_node("CenterContainer/VBoxContainer/AuthButtonsRow")
|
|
var username_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/UsernameEdit")
|
|
var password_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit")
|
|
var email_edit: LineEdit = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/EmailEdit")
|
|
var over_18_check: CheckBox = instance.get_node("CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/Over18Check")
|
|
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 play_button: Button = instance.get_node("CenterContainer/VBoxContainer/PlayButton")
|
|
|
|
_check("Play starts disabled", play_button.disabled)
|
|
|
|
# Click Register -- a real signal emission is fine here since
|
|
# _on_register_button_pressed() is synchronous (no await), same as a
|
|
# real click's GUI event dispatch would drive it.
|
|
register_button.pressed.emit()
|
|
await process_frame
|
|
|
|
_check("auth panel opened in register mode", instance.get_node("CenterContainer/VBoxContainer/AuthPanel").visible)
|
|
|
|
# Fill the form exactly as a user would type into it.
|
|
var unique_id := int(Time.get_unix_time_from_system() * 1000)
|
|
username_edit.text = "mainmenu_e2e_%d" % unique_id
|
|
password_edit.text = "TestPass123!"
|
|
email_edit.text = "mainmenu_e2e_%d@test.example.com" % unique_id
|
|
over_18_check.button_pressed = true
|
|
|
|
# Call the submit handler directly (awaited) rather than via
|
|
# auth_button.pressed.emit() -- a synthetic .emit() in --script/
|
|
# SceneTree headless mode doesn't drive an await-using handler's
|
|
# coroutine forward the same way real GUI input event dispatch does
|
|
# (confirmed via a direct-call vs emit() comparison: the direct call
|
|
# always resolves, the synthetic emit sometimes doesn't advance past
|
|
# its own await point even after 50 real process_frame waits). This
|
|
# is a headless-mode test-harness limitation, not a bug in the actual
|
|
# click-driven flow.
|
|
await instance._on_auth_button_pressed()
|
|
|
|
_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("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("Over18 checkbox hidden after auth", not over_18_check.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])
|
|
quit(0 if failed == 0 else 1)
|
|
|
|
|
|
func _check(description: String, condition: bool) -> void:
|
|
if condition:
|
|
print(" PASS: ", description)
|
|
passed += 1
|
|
else:
|
|
printerr(" FAIL: ", description)
|
|
failed += 1
|