ammocpr/test/ammoprices/scraping/runner_test.exs
Graham McIntire 16a28ac01c
Add Target Sports USA scraper, product filtering, and subsonic detection
- Add subsonic boolean field to products with composite filter indexes
- Add TextDetector utility for detecting subsonic/casing from product titles
- Wire TextDetector into SgAmmo (casing + subsonic) and LuckyGunner (subsonic + fallback casing)
- Extend latest_prices_for_caliber with casing, grain_weight, and subsonic filter options
- Add distinct_grain_weights_for_caliber and distinct_casings_for_caliber queries
- Add filter UI with toggleable casing, grain weight, and subsonic buttons
- Add grain weight column and subsonic badge to product table
- Refresh filter options on PubSub price updates for real-time UI
- Implement Target Sports USA scraper with 18 caliber mappings
- Display all prices in dollar format ($0.38 instead of 38¢)
2026-03-11 16:28:04 -05:00

52 lines
1.6 KiB
Elixir

defmodule Ammoprices.Scraping.RunnerTest do
use Ammoprices.DataCase, async: true
import Ammoprices.Fixtures
alias Ammoprices.Catalog
alias Ammoprices.Scraping.Retailers.LuckyGunner
alias Ammoprices.Scraping.Runner
@fixture_html File.read!("test/fixtures/lucky_gunner/9mm.html")
setup do
retailer = retailer_fixture(%{name: "Lucky Gunner", slug: "lucky-gunner", base_url: "https://www.luckygunner.com"})
caliber = caliber_fixture(%{name: "9mm Luger", slug: "9mm-luger", category: "handgun", aliases: ["9mm", "9x19"]})
Req.Test.stub(Ammoprices.Scraping.HttpClient, fn conn ->
Req.Test.html(conn, @fixture_html)
end)
%{retailer: retailer, caliber: caliber}
end
describe "run/2" do
test "creates products and snapshots from scrape", %{caliber: caliber} do
scraper = LuckyGunner
assert {:ok, stats} = Runner.run(scraper, caliber)
assert stats.products_count == 4
assert stats.snapshots_count == 4
products = Catalog.list_products_for_caliber(caliber.id)
assert length(products) == 4
end
test "updates retailer last_scraped_at", %{caliber: caliber} do
scraper = LuckyGunner
{:ok, _stats} = Runner.run(scraper, caliber)
retailer = Catalog.get_retailer_by_slug!("lucky-gunner")
assert retailer.last_scraped_at
end
test "handles scraper returning nil category_url", %{caliber: _caliber} do
caliber = caliber_fixture(%{name: "Unknown", slug: "unknown", category: "handgun"})
scraper = LuckyGunner
assert {:ok, stats} = Runner.run(scraper, caliber)
assert stats.products_count == 0
end
end
end