Skip to content

Commit ea19ffb

Browse files
fix(app-business-reviews): fix integration tests per skill guidelines
1 parent c7f4d5a commit ea19ffb

1 file changed

Lines changed: 139 additions & 10 deletions

File tree

app-business-reviews/tests/test_app_business_reviews_integration.py

Lines changed: 139 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
"""
2-
Integration tests for the App Business Reviews integration (SerpApi).
2+
End-to-end integration tests for the App Business Reviews integration.
33
4-
Requires APP_BUSINESS_REVIEWS_API_KEY set in environment or .env file.
4+
These tests call the real SerpApi API and require a valid API key
5+
set in the APP_BUSINESS_REVIEWS_API_KEY environment variable (via .env or export).
56
67
Run with:
78
pytest app-business-reviews/tests/test_app_business_reviews_integration.py -m integration
9+
10+
Never runs in CI -- the default pytest marker filter (-m unit) excludes these,
11+
and the file naming (test_*_integration.py) is not matched by python_files.
812
"""
913

10-
import importlib.util
1114
import os
1215
import sys
16+
import importlib
17+
import importlib.util
1318

1419
_parent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
1520
_deps = os.path.abspath(os.path.join(os.path.dirname(__file__), "../dependencies"))
16-
os.chdir(_parent)
1721
sys.path.insert(0, _parent)
1822
sys.path.insert(0, _deps)
1923

2024
import pytest # noqa: E402
21-
from unittest.mock import AsyncMock, MagicMock # noqa: E402
22-
25+
from unittest.mock import MagicMock, AsyncMock # noqa: E402
2326
from autohive_integrations_sdk import FetchResponse # noqa: E402
2427

2528
_spec = importlib.util.spec_from_file_location("abr_mod", os.path.join(_parent, "app_business_reviews.py"))
@@ -43,7 +46,7 @@ def live_context():
4346
async def real_fetch(url, *, method="GET", json=None, headers=None, params=None, **kwargs):
4447
async with aiohttp.ClientSession() as session:
4548
async with session.request(method, url, json=json, headers=headers or {}, params=params) as resp:
46-
data = await resp.json()
49+
data = await resp.json(content_type=None)
4750
return FetchResponse(status=resp.status, headers=dict(resp.headers), data=data)
4851

4952
ctx = MagicMock(name="ExecutionContext")
@@ -52,8 +55,10 @@ async def real_fetch(url, *, method="GET", json=None, headers=None, params=None,
5255
return ctx
5356

5457

58+
# ---- Read-Only Tests ----
59+
60+
5561
class TestSearchAppsIos:
56-
@pytest.mark.asyncio
5762
async def test_returns_apps(self, live_context):
5863
result = await abr.execute_action(
5964
"search_apps_ios",
@@ -65,9 +70,18 @@ async def test_returns_apps(self, live_context):
6570
assert "apps" in data
6671
assert isinstance(data["apps"], list)
6772

73+
async def test_num_limit_respected(self, live_context):
74+
result = await abr.execute_action(
75+
"search_apps_ios",
76+
{"term": "Instagram", "num": 2},
77+
live_context,
78+
)
79+
80+
data = result.result.data
81+
assert data["total_results"] <= 2
82+
6883

6984
class TestSearchAppsAndroid:
70-
@pytest.mark.asyncio
7185
async def test_returns_apps(self, live_context):
7286
result = await abr.execute_action(
7387
"search_apps_android",
@@ -79,9 +93,18 @@ async def test_returns_apps(self, live_context):
7993
assert "apps" in data
8094
assert isinstance(data["apps"], list)
8195

96+
async def test_limit_respected(self, live_context):
97+
result = await abr.execute_action(
98+
"search_apps_android",
99+
{"query": "Spotify", "limit": 2},
100+
live_context,
101+
)
102+
103+
data = result.result.data
104+
assert data["total_results"] <= 2
105+
82106

83107
class TestSearchPlacesGoogleMaps:
84-
@pytest.mark.asyncio
85108
async def test_returns_places(self, live_context):
86109
result = await abr.execute_action(
87110
"search_places_google_maps",
@@ -92,3 +115,109 @@ async def test_returns_places(self, live_context):
92115
data = result.result.data
93116
assert "places" in data
94117
assert isinstance(data["places"], list)
118+
119+
async def test_location_filters_results(self, live_context):
120+
result = await abr.execute_action(
121+
"search_places_google_maps",
122+
{"query": "pizza", "location": "New York, NY", "num_results": 3},
123+
live_context,
124+
)
125+
126+
data = result.result.data
127+
assert "places" in data
128+
assert data["total_results"] <= 3
129+
130+
131+
class TestGetReviewsAppStore:
132+
async def test_returns_reviews_for_whatsapp(self, live_context):
133+
# First get a real product ID from search
134+
search_result = await abr.execute_action(
135+
"search_apps_ios", {"term": "WhatsApp", "num": 1}, live_context
136+
)
137+
apps = search_result.result.data["apps"]
138+
if not apps:
139+
pytest.skip("No iOS apps returned from search")
140+
141+
product_id = str(apps[0]["id"])
142+
143+
result = await abr.execute_action(
144+
"get_reviews_app_store", {"product_id": product_id, "max_pages": 1}, live_context
145+
)
146+
147+
data = result.result.data
148+
assert "reviews" in data
149+
assert "total_reviews" in data
150+
assert "product_id" in data
151+
152+
async def test_auto_resolve_by_app_name(self, live_context):
153+
result = await abr.execute_action(
154+
"get_reviews_app_store", {"app_name": "WhatsApp", "max_pages": 1}, live_context
155+
)
156+
157+
data = result.result.data
158+
assert "reviews" in data
159+
assert "app_name" in data
160+
161+
162+
class TestGetReviewsGooglePlay:
163+
async def test_returns_reviews_for_whatsapp(self, live_context):
164+
result = await abr.execute_action(
165+
"get_reviews_google_play", {"product_id": "com.whatsapp", "max_pages": 1}, live_context
166+
)
167+
168+
data = result.result.data
169+
assert "reviews" in data
170+
assert "total_reviews" in data
171+
assert data["product_id"] == "com.whatsapp"
172+
173+
async def test_auto_resolve_by_app_name(self, live_context):
174+
result = await abr.execute_action(
175+
"get_reviews_google_play", {"app_name": "WhatsApp", "max_pages": 1}, live_context
176+
)
177+
178+
data = result.result.data
179+
assert "reviews" in data
180+
assert "product_id" in data
181+
182+
183+
class TestGetReviewsGoogleMaps:
184+
async def test_returns_reviews_chained_from_search(self, live_context):
185+
# Get a real place_id from search
186+
search_result = await abr.execute_action(
187+
"search_places_google_maps", {"query": "Starbucks Sydney", "num_results": 1}, live_context
188+
)
189+
places = search_result.result.data["places"]
190+
if not places:
191+
pytest.skip("No places returned from search")
192+
193+
place = places[0]
194+
identifier = {"place_id": place["place_id"]} if place.get("place_id") else {"data_id": place["data_id"]}
195+
196+
result = await abr.execute_action(
197+
"get_reviews_google_maps", {**identifier, "max_pages": 1}, live_context
198+
)
199+
200+
data = result.result.data
201+
assert "reviews" in data
202+
assert "total_reviews" in data
203+
assert "business_name" in data
204+
205+
async def test_response_structure(self, live_context):
206+
search_result = await abr.execute_action(
207+
"search_places_google_maps", {"query": "McDonald's Melbourne", "num_results": 1}, live_context
208+
)
209+
places = search_result.result.data["places"]
210+
if not places:
211+
pytest.skip("No places returned from search")
212+
213+
place = places[0]
214+
identifier = {"place_id": place["place_id"]} if place.get("place_id") else {"data_id": place["data_id"]}
215+
216+
result = await abr.execute_action(
217+
"get_reviews_google_maps", {**identifier, "max_pages": 1}, live_context
218+
)
219+
220+
data = result.result.data
221+
assert "reviews" in data
222+
assert "average_rating" in data
223+
assert "place_id" in data

0 commit comments

Comments
 (0)