""" A track with no artist tag is still music, and the grid has to say so. The album grid drew `albums` and nothing else, so a track with no artist at all — which belongs to no album — appeared nowhere in it. `empty` counted those tracks, so it stayed false and no message was drawn either: a library nothing has tagged rendered a toolbar over a blank page, with every one of its tracks a mode-switch away and nothing on screen saying so. Found after a node restart, where the index is briefly served before its tags have been re-read, and true of a genuinely untagged library with no restart involved. Measured rather than read: both halves of `music-app.js` are correct on their own, and the fault is that they disagree about what "nothing" means. """ import json import shutil import subprocess from pathlib import Path import pytest HARNESS = Path(__file__).parent / "harness" / "music_untagged_probe.py" STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" pytestmark = pytest.mark.skipif( shutil.which("google-chrome") is None or not (STATIC / "music-app.js").exists(), reason="Chrome or the SPA sources are not available") @pytest.fixture(scope="module") def cases(): run = subprocess.run(["python3", str(HARNESS)], capture_output=True, timeout=240) assert run.returncode == 0, run.stderr.decode()[-2000:] return {c["name"]: c for c in json.loads(run.stdout.decode())} def test_no_case_draws_a_blank_panel(cases): """The bug, stated once: a toolbar with nothing under it and nothing said.""" for name, case in cases.items(): assert "error" not in case, f"{name}: {case.get('error')}" assert case["cards"] or case["messages"], ( f"{name}: the panel drew neither a card nor a message") def test_untagged_tracks_reach_the_grid(cases): case = cases["nothing tagged"] assert len(case["cards"]) == 1, "seven untagged tracks are one card, not seven" assert case["messages"] == [], "there is music here — saying otherwise is the old lie" def test_the_card_names_what_it_is(cases): """Not a real release, and it must not read like one.""" card = cases["nothing tagged"]["cards"][0] assert card["title"] and card["sub"] assert card["title"] != card["sub"] def test_the_pile_does_not_displace_real_albums(cases): case = cases["some tagged"] assert len(case["cards"]) == 4, "three tagged albums and one pile" # Last, not sorted in among the artists: it is not a name anybody chose. assert case["cards"][-1]["sub"] == cases["nothing tagged"]["cards"][0]["sub"] assert [c["title"] for c in case["cards"][:3]] == ["disque 1", "disque 2", "disque 3"] def test_an_empty_library_still_says_so(cases): """The one case that really is empty. Widening `empty` would have broken this.""" case = cases["no audio"] assert case["cards"] == [] assert len(case["messages"]) == 1 def test_the_flat_list_still_lists_every_untagged_track(cases): """The grid reaching them must not cost the list what it always drew.""" assert cases["nothing tagged"]["flatTracks"] == 7 assert cases["some tagged"]["flatTracks"] == 4 assert cases["some tagged"]["flatRows"] == 3, "the three tagged artists, as folders" def test_no_cover_is_looked_up_for_an_album_this_page_invented(cases): """ A third-party request, on the operator's connection, that cannot match anything: the release name is one the browser wrote. Seen in a live node's log, going out with a placeholder as both artist and release. """ # The discriminating one: this card is drawn with or without the fix, so it # is the only case where the count says anything about the gate itself. assert cases["singletons only"]["cards"], "the folded card must still be drawn" assert cases["singletons only"]["musicMetaCalls"] == 0 assert cases["nothing tagged"]["musicMetaCalls"] == 0 assert cases["some tagged"]["musicMetaCalls"] == 3, ( "the three real albums are still looked up — only the invented ones are not")