From e6fae2907d3686ac1de79ed1d73a41b665f578d5 Mon Sep 17 00:00:00 2001 From: Toutsu Date: Tue, 16 Jun 2026 16:14:40 +0300 Subject: [PATCH] fix(web): use oninput binding in EditSession for reliable E2E interaction Blazor Server's default change-event binding races with Playwright fills, causing input values to revert before the form submits. Switch Title, JoinLink and MaxPlayers to @bind-Value:event=oninput so the model stays in sync while the test types. Co-Authored-By: Claude Opus 4.8 --- .../Components/Pages/EditSession.razor | 6 ++-- .../test_dashboard_auth_and_sessions.py | 32 ++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/GmRelay.Web/Components/Pages/EditSession.razor b/src/GmRelay.Web/Components/Pages/EditSession.razor index e290acc..fbc2344 100644 --- a/src/GmRelay.Web/Components/Pages/EditSession.razor +++ b/src/GmRelay.Web/Components/Pages/EditSession.razor @@ -36,7 +36,7 @@
- +
Изменение этого поля обновит все сессии в одной группе.
@@ -48,12 +48,12 @@
- +
- +
Пустое значение означает запись без лимита. Если лимит заполнен, новые игроки попадут в лист ожидания.
diff --git a/tests/e2e/dashboard/test_dashboard_auth_and_sessions.py b/tests/e2e/dashboard/test_dashboard_auth_and_sessions.py index 2d2e9ab..2b69e6b 100644 --- a/tests/e2e/dashboard/test_dashboard_auth_and_sessions.py +++ b/tests/e2e/dashboard/test_dashboard_auth_and_sessions.py @@ -334,20 +334,44 @@ def test_dashboard_session_edit_flow() -> None: page.goto(f"{base_url}/session/edit/{session_id}") page.wait_for_selector("text=Редактирование сессии", timeout=15000) + def _fill_blazor_input(locator, value: str) -> None: + """Fill a Blazor-bound input, move focus out, and wait for the value to stick.""" + locator.fill(value) + locator.press("Tab") + # Blazor Server round-trips on change; give it time to update the model + # and re-render before the next field is touched. + page.wait_for_timeout(500) + expect(locator).to_have_value(value) + title_input = page.locator(".gm-form-group").filter(has_text="Название игры").locator("input").first - title_input.fill(updated_title) + _fill_blazor_input(title_input, updated_title) join_input = page.locator(".gm-form-group").filter(has_text="Ссылка для подключения").locator("input").first - join_input.fill(updated_join_link) + _fill_blazor_input(join_input, updated_join_link) max_players_input = page.locator(".gm-form-group").filter(has_text="Лимит мест").locator("input").first - max_players_input.fill("3") + _fill_blazor_input(max_players_input, "3") + + # Verify the form actually received the new values before Blazor submits. + filled_title = title_input.input_value() + filled_join = join_input.input_value() + filled_max = max_players_input.input_value() + print(f"Edit form values before save: title={filled_title!r}, join={filled_join!r}, max={filled_max!r}") save_button = page.locator("button:has-text('Сохранить изменения')").first save_button.click() page.wait_for_url(f"{base_url}/group/{group_id}", timeout=15000) - page.wait_for_selector(f"text={updated_title}", timeout=15000) + try: + page.wait_for_selector(f"text={updated_title}", timeout=15000) + except Exception: + dump_path = "e2e_edit_group_debug.html" + with open(dump_path, "w", encoding="utf-8") as f: + f.write(page.content()) + print("URL after edit save:", page.url) + print(f"Group page HTML dumped to {dump_path}") + page.screenshot(path="e2e_edit_group_debug.png") + raise expect(page.locator(f"text={updated_title}").first).to_be_visible() db_session = _get_session_from_db(session_id)