1+ from urllib .parse import parse_qs , urlparse
2+
13import pytest
24
35import serpapi
46
57
8+ def _query_param (url , param ):
9+ values = parse_qs (urlparse (url ).query ).get (param )
10+ if values :
11+ return values [0 ]
12+
13+
614def test_basic_import ():
715 """Test that basic import works as intended."""
816 import serpapi
@@ -18,6 +26,43 @@ def test_entrypoints(client):
1826 assert api .locations
1927
2028
29+ def test_locations_query_limit_and_shape (client ):
30+ locations = client .locations (q = "Austin" , limit = 5 )
31+
32+ assert isinstance (locations , list )
33+ assert 0 < len (locations ) <= 5
34+
35+ expected_fields = {
36+ "id" ,
37+ "name" ,
38+ "canonical_name" ,
39+ "country_code" ,
40+ "target_type" ,
41+ "reach" ,
42+ }
43+
44+ for location in locations :
45+ assert expected_fields .issubset (location .keys ())
46+ assert isinstance (location ["canonical_name" ], str )
47+
48+ assert any (
49+ "Austin" in location ["name" ] or "Austin" in location ["canonical_name" ]
50+ for location in locations
51+ )
52+
53+
54+ def test_search_accepts_location_from_locations_api (client ):
55+ locations = client .locations (q = "Austin" , limit = 1 )
56+ location_name = locations [0 ]["canonical_name" ]
57+
58+ search = client .search (q = "coffee" , location = location_name )
59+
60+ assert search .get ("error" ) is None
61+ assert search ["organic_results" ]
62+ assert "Austin" in search ["search_parameters" ]["location_requested" ]
63+ assert "United States" in search ["search_parameters" ]["location_used" ]
64+
65+
2166def test_account_without_credentials ():
2267 """Ensure that an HTTPError is raised when account is accessed without API Credentials."""
2368 with pytest .raises (serpapi .HTTPError ):
@@ -58,29 +103,53 @@ def test_coffee_search_as_dict(coffee_search):
58103 assert isinstance (d , dict )
59104
60105
61- def test_coffee_search_html (coffee_search_html ):
106+ def test_search_output_html_contains_raw_html_document (coffee_search_html ):
62107 assert isinstance (coffee_search_html , str )
108+ assert "<html" in coffee_search_html .lower ()
109+ assert "</html>" in coffee_search_html .lower ()
110+ assert "coffee" in coffee_search_html .lower ()
63111 assert not hasattr (coffee_search_html , "next_page_url" )
64112
65113
66- def test_coffee_search_n_pages (coffee_search ):
67- page_count = 0
68- max_pages = 3
114+ def test_next_page_url_uses_serpapi_pagination_next (coffee_search ):
115+ next_page_url = coffee_search .next_page_url
69116
70- for page in coffee_search .yield_pages (max_pages = max_pages ):
71- if page_count == 0 :
72- assert 'start' not in page ['search_parameters' ], "The 'start' parameter should not be in the first page"
73-
74- page_count += 1
117+ assert next_page_url == coffee_search ["serpapi_pagination" ]["next" ]
118+ assert _query_param (next_page_url , "start" ) == "10"
119+ assert _query_param (next_page_url , "api_key" ) is None
120+
121+
122+ def test_yield_pages_returns_unique_search_pages (coffee_search ):
123+ max_pages = 3
124+ pages = list (coffee_search .yield_pages (max_pages = max_pages ))
75125
76- assert page_count == max_pages
126+ assert len (pages ) == max_pages
127+ assert len ({page ["search_metadata" ]["id" ] for page in pages }) == max_pages
128+ assert "start" not in pages [0 ]["search_parameters" ]
129+ assert int (pages [1 ]["search_parameters" ]["start" ]) == 10
130+ assert int (pages [2 ]["search_parameters" ]["start" ]) == 20
77131
78132
79- def test_coffee_search_next_page (coffee_search ):
133+ def test_next_page_advances_start_and_returns_new_results (coffee_search ):
80134 next_page = coffee_search .next_page ()
81135
82136 assert isinstance (next_page , serpapi .SerpResults )
83137 assert coffee_search ["search_metadata" ]["id" ] != next_page ["search_metadata" ]["id" ]
138+ assert int (next_page ["search_parameters" ]["start" ]) == 10
139+ assert next_page ["organic_results" ]
140+
141+ page_number = next_page ["search_information" ].get ("page_number" )
142+ if page_number is not None :
143+ assert int (page_number ) == 2
144+
145+
146+ def test_search_archive_round_trips_search_id (client , coffee_search ):
147+ search_id = coffee_search ["search_metadata" ]["id" ]
148+
149+ archived_search = client .search_archive (search_id = search_id )
150+
151+ assert isinstance (archived_search , serpapi .SerpResults )
152+ assert archived_search ["search_metadata" ]["id" ] == search_id
84153
85154
86155def test_search_function_signature (coffee_params , client ):
0 commit comments