"""get_playlist_tracks must parse BOTH /items response shapes: entries keyed "track" (grandfathered / extended-quota apps) and "item" (apps on Spotify's February 2026 renamed shape), and must fail loudly, not return [], when Spotify withholds a playlist's contents (no items field at all).""" import pytest from app.services import spotify_client URL = "https://open.spotify.com/playlist/XYZ123" class _Resp: def __init__(self, data): self._data = data def raise_for_status(self): pass def json(self): return self._data def _fake_api(monkeypatch, pages): it = iter(pages) monkeypatch.setattr(spotify_client, "_get_token", lambda db: "tok") monkeypatch.setattr( spotify_client.httpx, "get", lambda url, params=None, headers=None, timeout=None: _Resp(next(it)), ) def _track(name, artist, isrc=None): return { "name": name, "artists": [{"name": artist}], "external_ids": {"isrc": isrc} if isrc else {}, } def test_parses_legacy_track_shape(monkeypatch): _fake_api(monkeypatch, [{"items": [{"track": _track("Sandstorm", "Darude", "FIDAR9900011")}], "next": None}]) tracks = spotify_client.get_playlist_tracks(None, URL) assert tracks == [{"artist": "Darude", "title": "Sandstorm", "isrc": "FIDAR9900011"}] def test_parses_renamed_item_shape(monkeypatch): # February 2026 shape: payload under "item", not "track" _fake_api(monkeypatch, [{"items": [{"item": _track("Sandstorm", "Darude")}], "next": None}]) tracks = spotify_client.get_playlist_tracks(None, URL) assert tracks == [{"artist": "Darude", "title": "Sandstorm", "isrc": None}] def test_missing_items_field_raises_not_empty(monkeypatch): # metadata-only response (playlist not owned by the connected account on a # new app) must be an error the UI can show, never a silent empty list _fake_api(monkeypatch, [{"name": "DJ-USB", "public": True}]) with pytest.raises(RuntimeError, match="without its contents"): spotify_client.get_playlist_tracks(None, URL) def test_skips_null_entries_and_paginates(monkeypatch): _fake_api( monkeypatch, [ {"items": [{"track": None}, {"track": _track("A", "X")}], "next": "page2"}, {"items": [{"item": _track("B", "Y")}], "next": None}, ], ) tracks = spotify_client.get_playlist_tracks(None, URL) assert [t["title"] for t in tracks] == ["A", "B"]