test(import): remove stale frontend pytest
- delete the source-text guard for the old album lookup cache pattern\n- keep the import-page source-routing contract covered by Vitest route tests\n- avoid duplicating frontend behavior checks across pytest and the webui test suite
This commit is contained in:
parent
0721a859a9
commit
56f642aadd
1 changed files with 0 additions and 132 deletions
|
|
@ -1,132 +0,0 @@
|
||||||
"""Pin the import-page album-lookup cache pattern in
|
|
||||||
``webui/static/stats-automations.js`` — github issue #524 regression
|
|
||||||
guard at the source-text level.
|
|
||||||
|
|
||||||
Why a structural test instead of a behavioral JS test:
|
|
||||||
|
|
||||||
``stats-automations.js`` is a ~7k-line file with a lot of global state
|
|
||||||
+ inline DOM rendering. Loading it into a sandboxed Node `vm` context
|
|
||||||
(the pattern used in `tests/static/test_discover_section_controller.mjs`)
|
|
||||||
would require stubbing dozens of unrelated dependencies. The file
|
|
||||||
needs to be modularized before behavioral tests are practical for
|
|
||||||
arbitrary functions in it.
|
|
||||||
|
|
||||||
Until then, this test fails the suite if the critical pattern from
|
|
||||||
the #524 fix gets removed:
|
|
||||||
|
|
||||||
1. The album cache (``_albumLookup`` field on ``importPageState``)
|
|
||||||
2. Card renderers populating the cache before emitting the onclick
|
|
||||||
3. The match-POST builder reading source/name/artist from the cache
|
|
||||||
|
|
||||||
If anyone deletes the cache, the click handler, or the cache writes,
|
|
||||||
this test catches it before the regression ships.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
_REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
||||||
_SOURCE = _REPO_ROOT / "webui" / "static" / "stats-automations.js"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def js_source() -> str:
|
|
||||||
return _SOURCE.read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def test_album_lookup_cache_field_exists_on_state(js_source: str):
|
|
||||||
"""importPageState must have an `_albumLookup` field. Without it,
|
|
||||||
card renderers have nowhere to stash source/name/artist for the
|
|
||||||
click handler to read."""
|
|
||||||
assert "_albumLookup:" in js_source, (
|
|
||||||
"importPageState._albumLookup field missing — the album cache "
|
|
||||||
"that backs the source-routing fix for issue #524 has been "
|
|
||||||
"removed. The click handler will fall back to passing only "
|
|
||||||
"album_id and the backend will silently misroute lookups again."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_select_album_handler_reads_cache(js_source: str):
|
|
||||||
"""importPageSelectAlbum must read source / name / artist from
|
|
||||||
the cache and include them in the match POST body. The whole
|
|
||||||
point of the fix."""
|
|
||||||
# Find the function body
|
|
||||||
match = re.search(
|
|
||||||
r"async function importPageSelectAlbum\([^)]*\) \{(.*?)^\}",
|
|
||||||
js_source, re.DOTALL | re.MULTILINE,
|
|
||||||
)
|
|
||||||
assert match, "importPageSelectAlbum function not found"
|
|
||||||
body = match.group(1)
|
|
||||||
|
|
||||||
# Must read from the lookup cache
|
|
||||||
assert "_albumLookup[" in body, (
|
|
||||||
"importPageSelectAlbum no longer reads from "
|
|
||||||
"importPageState._albumLookup — match POST will drop source "
|
|
||||||
"again, see issue #524."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Must build a matchBody that includes source + album_name + album_artist
|
|
||||||
for required_field in ("source:", "album_name:", "album_artist:"):
|
|
||||||
assert required_field in body, (
|
|
||||||
f"matchBody missing required field {required_field!r}. "
|
|
||||||
"Backend's get_artist_album_tracks needs source to route "
|
|
||||||
"the lookup to the correct metadata client. Without it, "
|
|
||||||
"cross-source album_ids fall through to the failure-fallback "
|
|
||||||
"dict (Unknown Artist / album_id-as-title / 0 tracks). "
|
|
||||||
"See issue #524 for the original symptom."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_card_renderer_populates_cache_before_onclick(js_source: str):
|
|
||||||
"""The shared card-renderer ``_renderSuggestionCard`` must write to
|
|
||||||
``_albumLookup`` before emitting the onclick — otherwise the click
|
|
||||||
handler reads an empty cache for newly-displayed albums.
|
|
||||||
|
|
||||||
Originally this test required >=2 cache writes (one per inline
|
|
||||||
renderer), but the search-results inline render was consolidated
|
|
||||||
into a single ``_renderSuggestionCard`` call as part of the #681
|
|
||||||
fix. The invariant now is: the shared renderer populates the cache,
|
|
||||||
and every render call site goes through it (no inline duplicates)."""
|
|
||||||
# 1. The shared renderer must contain the cache write.
|
|
||||||
match = re.search(
|
|
||||||
r"function _renderSuggestionCard\([^)]*\) \{(.*?)^\}",
|
|
||||||
js_source, re.DOTALL | re.MULTILINE,
|
|
||||||
)
|
|
||||||
assert match, "_renderSuggestionCard function not found"
|
|
||||||
body = match.group(1)
|
|
||||||
assert re.search(r"_albumLookup\[a\.id\]\s*=\s*\{", body), (
|
|
||||||
"_renderSuggestionCard no longer writes to _albumLookup before "
|
|
||||||
"emitting the onclick — every card rendered through this helper "
|
|
||||||
"would have an empty cache on click, regressing issue #524."
|
|
||||||
)
|
|
||||||
|
|
||||||
# 2. No inline card render allowed outside the shared helper.
|
|
||||||
# A second `_albumLookup[a.id] = {` write means a caller is
|
|
||||||
# re-implementing the renderer instead of calling the helper —
|
|
||||||
# that's exactly the duplication the #524 fix consolidated away.
|
|
||||||
cache_writes = re.findall(r"_albumLookup\[a\.id\]\s*=\s*\{", js_source)
|
|
||||||
assert len(cache_writes) == 1, (
|
|
||||||
f"Expected exactly 1 _albumLookup write (inside _renderSuggestionCard), "
|
|
||||||
f"found {len(cache_writes)}. A new inline card-render site has "
|
|
||||||
"duplicated the cache-write logic — route the new caller through "
|
|
||||||
"_renderSuggestionCard(a, primarySource) instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_cache_entry_carries_source_field(js_source: str):
|
|
||||||
"""The cache must store `source:` per entry — not just id/name/artist."""
|
|
||||||
write_blocks = re.findall(
|
|
||||||
r"_albumLookup\[a\.id\]\s*=\s*\{[^}]*\}",
|
|
||||||
js_source,
|
|
||||||
)
|
|
||||||
assert write_blocks, "no _albumLookup writes found"
|
|
||||||
assert any("source:" in block for block in write_blocks), (
|
|
||||||
"_albumLookup cache entries must include `source` — that's the "
|
|
||||||
"field the click handler forwards to /api/import/album/match "
|
|
||||||
"to route the lookup to the correct provider."
|
|
||||||
)
|
|
||||||
Loading…
Reference in a new issue