""" Unit tests for WikiJSClient page listing and pagination (offline). Wiki.js 2.x `pages.list` supports only a `limit` argument (no offset), so exhaustive listing works by growing the limit until the API returns fewer pages than requested. These tests mock the GraphQL layer. """ import pytest from src.clients.wikijs_client import WikiJSClient def make_pages(count_other: int, count_user: int): """Build a fake TITLE-ordered page listing: 'other/' pages sort before 'users/jp/' pages.""" pages = [ {"id": i, "path": f"other/p{i:03d}", "title": f"A{i:03d}", "tags": []} for i in range(count_other) ] pages += [ {"id": count_other + i, "path": f"users/jp/p{i:03d}", "title": f"Z{i:03d}", "tags": ["projects"]} for i in range(count_user) ] return pages @pytest.fixture def client(): """WikiJSClient with a mocked GraphQL layer serving 138 pages (100 other + 38 user).""" client = WikiJSClient("http://wiki.test", "") client._all_pages = make_pages(100, 38) client._requested_limits = [] async def fake_execute(query, variables=None): limit = variables["limit"] client._requested_limits.append(limit) return {"pages": {"list": client._all_pages[:limit]}} client._execute_query = fake_execute return client @pytest.mark.unit class TestListAllPagesPagination: """list_all_pages must exhaust the listing via a limit-growth loop.""" async def test_grows_limit_until_exhausted(self, client): pages = await client.list_all_pages(batch_size=50) # 50 -> full batch, 100 -> full batch, 200 -> 138 < 200 done assert client._requested_limits == [50, 100, 200] assert len(pages) == 138 async def test_single_call_when_first_batch_not_full(self, client): pages = await client.list_all_pages(batch_size=500) assert client._requested_limits == [500] assert len(pages) == 138 async def test_path_prefix_filter_after_exhaustion(self, client): """All 38 user pages are returned even though they sort last (beyond batch_size).""" pages = await client.list_all_pages(path_prefix="users/jp", batch_size=50) assert len(pages) == 38 assert all(p["path"].startswith("users/jp") for p in pages) async def test_empty_wiki(self, client): client._all_pages = [] pages = await client.list_all_pages(batch_size=100) assert pages == [] @pytest.mark.unit class TestListPagesLimitAfterFilter: """list_pages must apply `limit` AFTER client-side filters, not before.""" async def test_prefix_filter_with_small_limit(self, client): """Old defect: API limit=5 returned 5 'other/' pages, filter dropped all -> 0 results.""" pages = await client.list_pages(path_prefix="users/jp", limit=5) assert len(pages) == 5 assert all(p["path"].startswith("users/jp") for p in pages) async def test_tag_filter_with_small_limit(self, client): pages = await client.list_pages(tags=["projects"], limit=10) assert len(pages) == 10 assert all("projects" in p["tags"] for p in pages) async def test_unfiltered_passes_limit_to_api(self, client): pages = await client.list_pages(limit=7) assert client._requested_limits == [7] assert len(pages) == 7 async def test_tags_normalized_to_list(self, client): client._all_pages = [{"id": 1, "path": "home", "title": "Home", "tags": None}] pages = await client.list_pages(limit=10) assert pages[0]["tags"] == []