"""Tests de la préférence de contenus par utilisateur (animés / séries / les deux).""" from app.scrapers.base import SearchResult class MixedSource: """Source factice renvoyant animés, séries et films.""" name = "mixed" label = "Mixed" base_url = "https://mixed.example" media_types = ("anime", "serie") async def search(self, query: str) -> list[SearchResult]: return [ SearchResult(source="mixed", source_id="a1", title="Animé X", url="https://mixed.example/a1"), SearchResult(source="mixed", source_id="s1", title="Série Y", url="https://mixed.example/s1", media_type="serie"), SearchResult(source="mixed", source_id="f1", title="Film Z", url="https://mixed.example/f1", media_type="film"), ] async def latest(self) -> list[SearchResult]: return await self.search("") class AnimeOnlySource: name = "animeonly" label = "AnimeOnly" base_url = "https://animeonly.example" media_types = ("anime",) async def search(self, query: str) -> list[SearchResult]: return [ SearchResult(source="animeonly", source_id="a2", title="Animé W", url="https://animeonly.example/a2") ] async def latest(self) -> list[SearchResult]: return await self.search("") async def _patch_sources(monkeypatch, *sources): import app.routers.search as search_module monkeypatch.setattr(search_module, "all_sources", lambda: list(sources)) import app.services.discover as discover_module async def enabled(name): return True monkeypatch.setattr(discover_module, "is_source_enabled", enabled) discover_module.discover._cache.clear() monkeypatch.setattr(discover_module, "all_sources", lambda: list(sources)) # ---------------------------------------------------------------- endpoints async def test_me_exposes_default_preference(client, admin_cookies): r = await client.get("/auth/me", cookies=admin_cookies) assert r.status_code == 200 assert r.json()["content_preference"] == "both" async def test_preference_roundtrip(client, admin_cookies): r = await client.put( "/auth/preferences", json={"content_preference": "serie"}, cookies=admin_cookies ) assert r.status_code == 200 assert (await client.get("/auth/me", cookies=admin_cookies)).json()["content_preference"] == "serie" async def test_preference_rejects_invalid_value(client, admin_cookies): r = await client.put( "/auth/preferences", json={"content_preference": "documentaire"}, cookies=admin_cookies ) assert r.status_code == 422 # ---------------------------------------------------------------- filtrage recherche async def test_search_both_keeps_everything(client, admin_cookies, monkeypatch): await _patch_sources(monkeypatch, MixedSource(), AnimeOnlySource()) r = await client.get("/api/search", params={"q": "test"}, cookies=admin_cookies) assert r.status_code == 200 assert r.json()["count"] == 4 # animés + série + film async def test_search_anime_filters_serie(client, admin_cookies, monkeypatch): await _patch_sources(monkeypatch, MixedSource(), AnimeOnlySource()) await client.put("/auth/preferences", json={"content_preference": "anime"}, cookies=admin_cookies) r = await client.get("/api/search", params={"q": "test"}, cookies=admin_cookies) types = {x["media_type"] for x in r.json()["results"]} assert types == {"anime"} # le mode animés reste sur l'animation (films réels → côté séries) async def test_search_serie_skips_anime_sources(client, admin_cookies, monkeypatch): """Préférence séries : les sources anime-only ne sont même pas interrogées.""" await _patch_sources(monkeypatch, MixedSource(), AnimeOnlySource()) await client.put("/auth/preferences", json={"content_preference": "serie"}, cookies=admin_cookies) queried = [] class SpySource(AnimeOnlySource): async def search(self, query: str) -> list[SearchResult]: queried.append(self.name) return await super().search(query) import app.routers.search as search_module monkeypatch.setattr(search_module, "all_sources", lambda: [MixedSource(), SpySource()]) r = await client.get("/api/search", params={"q": "test"}, cookies=admin_cookies) assert r.status_code == 200 assert queried == [] # source anime-only ignorée assert {x["media_type"] for x in r.json()["results"]} == {"serie", "film"} # ---------------------------------------------------------------- filtrage découverte async def test_discover_latest_filtered_by_preference(client, admin_cookies, monkeypatch): """Rails par type : chaque mode n'expose que ses rails (les films suivent les séries).""" await _patch_sources(monkeypatch, MixedSource()) r = await client.get("/api/discover", cookies=admin_cookies) data = r.json() assert {i["media_type"] for i in data["latest_anime"]} == {"anime"} assert {i["media_type"] for i in data["latest_serie"]} == {"serie", "film"} await client.put("/auth/preferences", json={"content_preference": "serie"}, cookies=admin_cookies) data = (await client.get("/api/discover", cookies=admin_cookies)).json() assert data["latest_anime"] == [] assert {i["media_type"] for i in data["latest_serie"]} == {"serie", "film"} await client.put("/auth/preferences", json={"content_preference": "anime"}, cookies=admin_cookies) data = (await client.get("/api/discover", cookies=admin_cookies)).json() assert {i["media_type"] for i in data["latest_anime"]} == {"anime"} assert data["latest_serie"] == [] async def test_discover_hides_kitsu_sections_in_serie_mode(client, admin_cookies, monkeypatch): """Incontournables et Pour toi (Kitsu = animés) disparaissent en mode séries.""" import app.services.discover as discover_module await _patch_sources(monkeypatch, MixedSource()) async def fake_must_watch(limit=20): return [{"kitsu_id": 1, "title": "Animé top"}] async def fake_for_you(user_id=0, limit=20): return {"based_on": ["Action"], "items": [{"kitsu_id": 2}]} monkeypatch.setattr(discover_module.discover, "must_watch", fake_must_watch) monkeypatch.setattr(discover_module.discover, "for_you", fake_for_you) r = await client.get("/api/discover", cookies=admin_cookies) assert len(r.json()["must_watch"]) == 1 assert len(r.json()["for_you"]["items"]) == 1 await client.put("/auth/preferences", json={"content_preference": "serie"}, cookies=admin_cookies) data = (await client.get("/api/discover", cookies=admin_cookies)).json() assert data["must_watch"] == [] assert data["for_you"] == {"based_on": [], "items": []}