@@ -222,3 +222,97 @@ async def test_list_pull_requests_success(github_client, mock_aiohttp_session):
222222 prs = await github_client .list_pull_requests ("owner/repo" , installation_id = 123 )
223223
224224 assert prs == [{"number" : 1 }]
225+
226+
227+ @pytest .mark .asyncio
228+ async def test_get_pull_request_files_paginates (github_client , mock_aiohttp_session ):
229+ """Files endpoint should fetch all pages when results fill a page."""
230+ mock_token_response = mock_aiohttp_session .create_mock_response (201 , json_data = {"token" : "access_token" })
231+ mock_aiohttp_session .post .return_value = mock_token_response
232+
233+ # Page 1: full page (100 items) triggers fetching page 2
234+ page1 = [{"filename" : f"file_{ i } .py" } for i in range (100 )]
235+ page2 = [{"filename" : f"file_{ i } .py" } for i in range (100 , 135 )]
236+
237+ mock_resp_page1 = mock_aiohttp_session .create_mock_response (200 , json_data = page1 )
238+ mock_resp_page2 = mock_aiohttp_session .create_mock_response (200 , json_data = page2 )
239+
240+ mock_aiohttp_session .get .side_effect = [mock_resp_page1 , mock_resp_page2 ]
241+
242+ files = await github_client .get_pull_request_files ("owner/repo" , 1 , installation_id = 123 )
243+
244+ assert len (files ) == 135
245+ assert files [0 ]["filename" ] == "file_0.py"
246+ assert files [- 1 ]["filename" ] == "file_134.py"
247+ assert mock_aiohttp_session .get .call_count == 2
248+
249+
250+ @pytest .mark .asyncio
251+ async def test_get_pull_request_files_single_page (github_client , mock_aiohttp_session ):
252+ """Files endpoint should not paginate when results don't fill a page."""
253+ mock_token_response = mock_aiohttp_session .create_mock_response (201 , json_data = {"token" : "access_token" })
254+ mock_aiohttp_session .post .return_value = mock_token_response
255+
256+ page1 = [{"filename" : f"file_{ i } .py" } for i in range (30 )]
257+ mock_resp = mock_aiohttp_session .create_mock_response (200 , json_data = page1 )
258+ mock_aiohttp_session .get .return_value = mock_resp
259+
260+ files = await github_client .get_pull_request_files ("owner/repo" , 1 , installation_id = 123 )
261+
262+ assert len (files ) == 30
263+ assert mock_aiohttp_session .get .call_count == 1
264+
265+
266+ @pytest .mark .asyncio
267+ async def test_get_pull_request_files_uses_per_page_100 (github_client , mock_aiohttp_session ):
268+ """Files endpoint should request per_page=100."""
269+ mock_token_response = mock_aiohttp_session .create_mock_response (201 , json_data = {"token" : "access_token" })
270+ mock_aiohttp_session .post .return_value = mock_token_response
271+
272+ mock_resp = mock_aiohttp_session .create_mock_response (200 , json_data = [])
273+ mock_aiohttp_session .get .return_value = mock_resp
274+
275+ await github_client .get_pull_request_files ("owner/repo" , 1 , installation_id = 123 )
276+
277+ call_args = mock_aiohttp_session .get .call_args
278+ url = call_args [0 ][0 ]
279+ assert "per_page=100" in url
280+ assert "page=1" in url
281+
282+
283+ @pytest .mark .asyncio
284+ async def test_get_pull_request_reviews_paginates (github_client , mock_aiohttp_session ):
285+ """Reviews endpoint should fetch all pages when results fill a page."""
286+ mock_token_response = mock_aiohttp_session .create_mock_response (201 , json_data = {"token" : "access_token" })
287+ mock_aiohttp_session .post .return_value = mock_token_response
288+
289+ page1 = [{"id" : i , "state" : "APPROVED" } for i in range (100 )]
290+ page2 = [{"id" : i , "state" : "CHANGES_REQUESTED" } for i in range (100 , 110 )]
291+
292+ mock_resp_page1 = mock_aiohttp_session .create_mock_response (200 , json_data = page1 )
293+ mock_resp_page2 = mock_aiohttp_session .create_mock_response (200 , json_data = page2 )
294+
295+ mock_aiohttp_session .get .side_effect = [mock_resp_page1 , mock_resp_page2 ]
296+
297+ reviews = await github_client .get_pull_request_reviews ("owner/repo" , 1 , installation_id = 123 )
298+
299+ assert len (reviews ) == 110
300+ assert mock_aiohttp_session .get .call_count == 2
301+
302+
303+ @pytest .mark .asyncio
304+ async def test_get_pull_request_files_error_on_page2 (github_client , mock_aiohttp_session ):
305+ """Files endpoint should return partial results if a later page errors."""
306+ mock_token_response = mock_aiohttp_session .create_mock_response (201 , json_data = {"token" : "access_token" })
307+ mock_aiohttp_session .post .return_value = mock_token_response
308+
309+ page1 = [{"filename" : f"file_{ i } .py" } for i in range (100 )]
310+ mock_resp_page1 = mock_aiohttp_session .create_mock_response (200 , json_data = page1 )
311+ mock_resp_page2 = mock_aiohttp_session .create_mock_response (500 , text_data = "Internal Server Error" )
312+
313+ mock_aiohttp_session .get .side_effect = [mock_resp_page1 , mock_resp_page2 ]
314+
315+ files = await github_client .get_pull_request_files ("owner/repo" , 1 , installation_id = 123 )
316+
317+ # Should return the first page's results even if page 2 fails
318+ assert len (files ) == 100
0 commit comments