Fix add-form JS: name→sort-name sync and related-game disable

Two bugs in the add forms, both root-caused via the e2e harness:

1. add_game Name → Sort name never synced. syncSelectInputUntilChanged was
   scoped to "form", but the first <form> on every page is the navbar logout
   form — the add-form fields live in a later form, so the delegated listener
   never heard their events. Scope to "#add-form" (the add-form wrapper). Also
   switch the sync from the "change" event to "input" so Sort name mirrors Name
   live as you type, not only on blur.

2. add_purchase Related game not disabled when Type == Game.
   disableElementsWhenTrue set `.disabled` on #id_related_game, which is the
   SearchSelect wrapper <div> (a <div> ignores `disabled`). Target the inner
   [data-search-select-search] input instead, so the widget is actually disabled.

Adds two e2e regression tests (live sync; type-game disables the related-game
search input and re-enables it for other types).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 18:11:49 +02:00
parent 2e2dcdc3e7
commit 5bb8b92c05
4 changed files with 38 additions and 5 deletions
+25
View File
@@ -147,3 +147,28 @@ def test_add_purchase_related_game_is_flat_game_search(
related = page.locator('[data-search-select][data-name="related_game"]')
expect(related).to_have_count(1)
expect(related).to_have_attribute("data-search-url", "/api/games/search")
def test_add_game_syncs_sort_name_from_name(authenticated_page: Page, live_server):
"""Typing into Name live-fills Sort name (sync bound to the add form, not
the navbar logout form which is the first <form> on the page)."""
page = authenticated_page
page.goto(f"{live_server.url}{reverse('games:add_game')}")
page.locator("#id_name").click()
page.locator("#id_name").type("Halo")
expect(page.locator("#id_sort_name")).to_have_value("Halo")
def test_add_purchase_type_game_disables_related_game_search(
authenticated_page: Page, live_server
):
"""When Type is 'game', the related-game SearchSelect is disabled — the
real disable target is the inner search input, not the wrapper <div>
(a <div> ignores the disabled property)."""
page = authenticated_page
page.goto(f"{live_server.url}{reverse('games:add_purchase')}")
search = page.locator('#id_related_game [data-search-select-search]')
page.select_option("#id_type", "game")
expect(search).to_be_disabled()
page.select_option("#id_type", "dlc")
expect(search).to_be_enabled()