test(walmart): cover capability registry, schemas, and executors for both verbs

This commit is contained in:
CREDO23 2026-07-19 08:49:10 +02:00
parent b5cddcfb2b
commit 07721bda40
8 changed files with 197 additions and 0 deletions

View file

@ -0,0 +1,38 @@
from __future__ import annotations
from app.capabilities.walmart.reviews.executor import build_reviews_executor
from app.capabilities.walmart.reviews.schemas import ReviewsInput
from app.proprietary.platforms.walmart import WalmartReviewsInput
class _FakeScraper:
def __init__(self) -> None:
self.calls: list[tuple[WalmartReviewsInput, int | None]] = []
async def __call__(
self, input_model: WalmartReviewsInput, *, limit: int | None = None
) -> list[dict]:
self.calls.append((input_model, limit))
return [{"reviewId": "r1", "rating": 5}]
async def test_executor_maps_agent_input_to_scraper_input():
scraper = _FakeScraper()
execute = build_reviews_executor(scraper)
output = await execute(
ReviewsInput(
urls=["https://www.walmart.com/ip/123456"],
item_ids=["222"],
max_reviews=50,
sort_by="most-helpful",
)
)
assert output.items[0].reviewId == "r1"
input_model, limit = scraper.calls[0]
assert input_model.itemIds == ["https://www.walmart.com/ip/123456", "222"]
assert input_model.maxReviews == 50
assert input_model.sort == "most-helpful"
# limit is the pre-flight worst case: 2 sources * 50 reviews
assert limit == 100

View file

@ -0,0 +1,37 @@
from __future__ import annotations
import pytest
from pydantic import ValidationError
from app.capabilities.walmart.reviews.schemas import ReviewsInput, ReviewsOutput
def test_estimated_units_scale_with_sources_and_max_reviews():
payload = ReviewsInput(
urls=["https://www.walmart.com/ip/1"], item_ids=["222"], max_reviews=150
)
# 2 sources * 150 reviews each
assert payload.estimated_units == 300
def test_at_least_one_source_is_required():
with pytest.raises(ValidationError):
ReviewsInput()
def test_sources_merge_urls_then_item_ids():
payload = ReviewsInput(urls=["https://www.walmart.com/ip/1"], item_ids=["222"])
assert payload.sources() == ["https://www.walmart.com/ip/1", "222"]
def test_error_items_are_not_billable():
output = ReviewsOutput(
items=[
{"reviewId": "r1", "rating": 5},
{"error": "reviews_not_found"},
]
)
assert output.billable_units == 1

View file

@ -0,0 +1,42 @@
from __future__ import annotations
from app.capabilities.walmart.scrape.executor import build_scrape_executor
from app.capabilities.walmart.scrape.schemas import MAX_WALMART_RESULTS, ScrapeInput
from app.proprietary.platforms.walmart import WalmartScrapeInput
class _FakeScraper:
def __init__(self) -> None:
self.calls: list[tuple[WalmartScrapeInput, int | None]] = []
async def __call__(
self, input_model: WalmartScrapeInput, *, limit: int | None = None
) -> list[dict]:
self.calls.append((input_model, limit))
return [{"usItemId": "123", "name": "Product"}]
async def test_executor_maps_agent_input_to_scraper_input():
scraper = _FakeScraper()
execute = build_scrape_executor(scraper)
output = await execute(
ScrapeInput(
search_terms=["air fryer"],
urls=["https://www.walmart.com/ip/123456"],
max_items=5,
include_details=False,
include_reviews_sample=False,
)
)
assert output.items[0].usItemId == "123"
input_model, limit = scraper.calls[0]
assert input_model.startUrls == [
"https://www.walmart.com/ip/123456",
"https://www.walmart.com/search?q=air+fryer",
]
assert input_model.maxItemsPerStartUrl == 5
assert input_model.includeDetails is False
assert input_model.includeReviewsSample is False
assert limit == MAX_WALMART_RESULTS

View file

@ -0,0 +1,58 @@
from __future__ import annotations
import pytest
from pydantic import ValidationError
from app.capabilities.walmart.scrape.schemas import (
MAX_WALMART_RESULTS,
ScrapeInput,
ScrapeOutput,
)
def test_estimated_units_cover_search_and_direct_sources():
payload = ScrapeInput(
search_terms=["air fryer", "blender"],
urls=["https://www.walmart.com/ip/123456"],
max_items=20,
)
# (2 search + 1 direct source) * 20 items each
assert payload.estimated_units == 60
def test_estimated_units_respect_hard_run_ceiling():
payload = ScrapeInput(search_terms=["x"] * 20, max_items=100)
assert payload.estimated_units == MAX_WALMART_RESULTS
def test_at_least_one_source_is_required():
with pytest.raises(ValidationError):
ScrapeInput()
def test_combined_sources_are_capped():
with pytest.raises(ValidationError):
ScrapeInput(urls=["u"] * 11, search_terms=["t"] * 10)
def test_start_urls_synthesize_a_search_url_per_term():
payload = ScrapeInput(
urls=["https://www.walmart.com/ip/1"], search_terms=["air fryer"]
)
assert payload.start_urls() == [
"https://www.walmart.com/ip/1",
"https://www.walmart.com/search?q=air+fryer",
]
def test_error_items_are_not_billable():
output = ScrapeOutput(
items=[
{"usItemId": "123", "name": "Product"},
{"error": "product_not_found", "errorDescription": "Missing"},
]
)
assert output.billable_units == 1

View file

@ -0,0 +1,22 @@
from __future__ import annotations
from app.capabilities.core import BillingUnit
from app.capabilities.core.store import get_capability
from app.capabilities.walmart.reviews.schemas import ReviewsInput, ReviewsOutput
from app.capabilities.walmart.scrape.schemas import ScrapeInput, ScrapeOutput
def test_walmart_scrape_is_registered_and_metered():
capability = get_capability("walmart.scrape")
assert capability.input_schema is ScrapeInput
assert capability.output_schema is ScrapeOutput
assert capability.billing_unit is BillingUnit.WALMART_PRODUCT
def test_walmart_reviews_is_registered_and_metered():
capability = get_capability("walmart.reviews")
assert capability.input_schema is ReviewsInput
assert capability.output_schema is ReviewsOutput
assert capability.billing_unit is BillingUnit.WALMART_REVIEW