defmodule Ammoprices.Scraping.Retailers.TargetSportsUsaTest do use ExUnit.Case, async: true alias Ammoprices.Scraping.Retailers.TargetSportsUsa @fixture_path "test/fixtures/target_sports_usa/9mm.html" describe "retailer_slug/0" do test "returns target-sports-usa" do assert TargetSportsUsa.retailer_slug() == "target-sports-usa" end end describe "category_url/1" do test "maps 9mm-luger caliber to correct URL" do caliber = %{slug: "9mm-luger", category: "handgun"} assert TargetSportsUsa.category_url(caliber) == "/9mm-luger-ammo-c-51.aspx" end test "maps 300-blackout caliber to correct URL" do caliber = %{slug: "300-blackout", category: "rifle"} assert TargetSportsUsa.category_url(caliber) == "/300-aac-blackout-ammo-c-969.aspx" end test "returns nil for unmapped caliber" do caliber = %{slug: "unknown", category: "handgun"} assert TargetSportsUsa.category_url(caliber) == nil end end describe "parse_products/1" do setup do html = File.read!(@fixture_path) %{html: html} end test "extracts all products from HTML", %{html: html} do products = TargetSportsUsa.parse_products(html) assert length(products) == 4 end test "extracts product title", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.title =~ "Federal Champion 9mm Ammo 115 Grain Full Metal Jacket" end test "extracts product URL", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.url == "/federal-champion-9mm-ammo-115-grain-fmj-wm5199-p-58432.aspx" end test "extracts price in cents", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.price_cents == 1275 end test "extracts price per round in cents", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.price_per_round_cents == 26 end test "extracts brand from h2 strong", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.brand == "Federal" end test "strips trailing Ammunition/Ammo from brand", %{html: html} do products = TargetSportsUsa.parse_products(html) # "Winchester Ammo" -> "Winchester" assert Enum.at(products, 1).brand == "Winchester" # "Tula Ammo" -> "Tula" assert Enum.at(products, 3).brand == "Tula" end test "extracts grain weight from title", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.grain_weight == 115 end test "extracts round count from title", %{html: html} do products = TargetSportsUsa.parse_products(html) # Second product: "50 Round Box" assert Enum.at(products, 1).round_count == 50 end test "marks in-stock products", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.in_stock == true end test "marks out-of-stock products", %{html: html} do products = TargetSportsUsa.parse_products(html) assert Enum.at(products, 3).in_stock == false end test "detects subsonic from title", %{html: html} do products = TargetSportsUsa.parse_products(html) # 3rd product has "Subsonic" in title assert Enum.at(products, 2).subsonic == true end test "non-subsonic products return false", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.subsonic == false end test "detects casing from title", %{html: html} do products = TargetSportsUsa.parse_products(html) # 4th product has "Steel Case" in title assert Enum.at(products, 3).casing == "steel" end test "returns nil casing when not detected", %{html: html} do [first | _] = TargetSportsUsa.parse_products(html) assert first.casing == nil end end end