""" Tests pour pricewatch.app.stores.cdiscount.store Vérifie match(), canonicalize(), extract_reference() et parse() pour le store Cdiscount. """ import pytest from pricewatch.app.stores.cdiscount.store import CdiscountStore from pricewatch.app.core.schema import DebugStatus, StockStatus class TestCdiscountMatch: """Tests de la méthode match() pour Cdiscount.""" @pytest.fixture def store(self) -> CdiscountStore: """Fixture: CdiscountStore instance.""" return CdiscountStore() def test_match_cdiscount_com(self, store): """cdiscount.com doit retourner 0.9.""" score = store.match("https://www.cdiscount.com/informatique/example/f-123-sku.html") assert score == 0.9 def test_match_non_cdiscount(self, store): """URL non-Cdiscount doit retourner 0.0.""" score = store.match("https://www.amazon.fr/dp/B08N5WRWNW") assert score == 0.0 def test_match_empty_url(self, store): """URL vide doit retourner 0.0.""" score = store.match("") assert score == 0.0 def test_match_case_insensitive(self, store): """Match doit être insensible à la casse.""" score = store.match("https://www.CDISCOUNT.COM/product/f-123-sku.html") assert score == 0.9 class TestCdiscountCanonicalize: """Tests de la méthode canonicalize() pour Cdiscount.""" @pytest.fixture def store(self) -> CdiscountStore: """Fixture: CdiscountStore instance.""" return CdiscountStore() def test_canonicalize_with_query_params(self, store): """URL avec query params doit être normalisée.""" url = "https://www.cdiscount.com/informatique/pc/product/f-10709-sku.html?idOffre=123&sw=abc" canonical = store.canonicalize(url) assert canonical == "https://www.cdiscount.com/informatique/pc/product/f-10709-sku.html" assert "?" not in canonical def test_canonicalize_already_canonical(self, store): """URL déjà canonique ne change pas.""" url = "https://www.cdiscount.com/informatique/pc/f-10709-sku.html" canonical = store.canonicalize(url) assert canonical == url def test_canonicalize_with_fragment(self, store): """URL avec fragment doit être normalisée.""" url = "https://www.cdiscount.com/informatique/pc/f-10709-sku.html#mpos=2" canonical = store.canonicalize(url) assert canonical == "https://www.cdiscount.com/informatique/pc/f-10709-sku.html" assert "#" not in canonical def test_canonicalize_empty_url(self, store): """URL vide retourne URL vide.""" canonical = store.canonicalize("") assert canonical == "" class TestCdiscountExtractReference: """Tests de la méthode extract_reference() pour Cdiscount.""" @pytest.fixture def store(self) -> CdiscountStore: """Fixture: CdiscountStore instance.""" return CdiscountStore() def test_extract_reference_standard_format(self, store): """Extraction du SKU depuis format standard /f-{ID}-{SKU}.html.""" url = "https://www.cdiscount.com/informatique/pc/f-10709-tuf608umrv004.html" ref = store.extract_reference(url) assert ref == "10709-tuf608umrv004" def test_extract_reference_long_url(self, store): """Extraction du SKU depuis URL longue avec chemin complet.""" url = "https://www.cdiscount.com/informatique/ordinateurs-pc-portables/pc-portable-gamer-asus/f-10709-tuf608umrv004.html" ref = store.extract_reference(url) assert ref == "10709-tuf608umrv004" def test_extract_reference_with_query_params(self, store): """Extraction du SKU depuis URL avec query params.""" url = "https://www.cdiscount.com/informatique/pc/f-10709-sku123.html?idOffre=456" ref = store.extract_reference(url) assert ref == "10709-sku123" def test_extract_reference_invalid_url(self, store): """URL sans SKU retourne None.""" url = "https://www.cdiscount.com/informatique/" ref = store.extract_reference(url) assert ref is None def test_extract_reference_empty_url(self, store): """URL vide retourne None.""" ref = store.extract_reference("") assert ref is None class TestCdiscountParse: """Tests de la méthode parse() pour Cdiscount.""" @pytest.fixture def store(self) -> CdiscountStore: """Fixture: CdiscountStore instance.""" return CdiscountStore() @pytest.fixture def minimal_html(self) -> str: """Fixture: HTML Cdiscount minimal avec titre et prix.""" return """
"""
@pytest.fixture
def empty_html(self) -> str:
"""Fixture: HTML vide."""
return ""
def test_parse_minimal_html(self, store, minimal_html):
"""Parse un HTML minimal avec titre et prix."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-sku123.html"
snapshot = store.parse(minimal_html, url)
assert snapshot.source == "cdiscount"
assert snapshot.url == "https://www.cdiscount.com/informatique/pc/f-10709-sku123.html"
assert snapshot.title == "PC Portable Test"
assert snapshot.price == 899.99
assert snapshot.currency == "EUR"
assert snapshot.is_complete() is True
def test_parse_complete_html(self, store, complete_html):
"""Parse un HTML plus complet avec images."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-asus123.html"
snapshot = store.parse(complete_html, url)
assert snapshot.title == "PC Portable Gamer ASUS"
assert snapshot.price == 1299.99
assert snapshot.reference == "10709-asus123"
assert len(snapshot.images) >= 2
assert snapshot.is_complete() is True
assert snapshot.debug.status == DebugStatus.SUCCESS
def test_parse_empty_html(self, store, empty_html):
"""Parse un HTML vide doit retourner un snapshot partiel."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-sku.html"
snapshot = store.parse(empty_html, url)
assert snapshot.source == "cdiscount"
assert snapshot.title is None
assert snapshot.price is None
assert snapshot.is_complete() is False
assert snapshot.debug.status == DebugStatus.PARTIAL
def test_parse_canonicalizes_url(self, store, minimal_html):
"""Parse doit canonicaliser l'URL."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-sku.html?idOffre=123#mpos=2"
snapshot = store.parse(minimal_html, url)
assert snapshot.url == "https://www.cdiscount.com/informatique/pc/f-10709-sku.html"
assert "?" not in snapshot.url
assert "#" not in snapshot.url
def test_parse_extracts_reference_from_url(self, store, minimal_html):
"""Parse doit extraire le SKU depuis l'URL."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-tuf608umrv004.html"
snapshot = store.parse(minimal_html, url)
assert snapshot.reference == "10709-tuf608umrv004"
def test_parse_sets_fetched_at(self, store, minimal_html):
"""Parse doit définir fetched_at."""
url = "https://www.cdiscount.com/informatique/pc/f-10709-sku.html"
snapshot = store.parse(minimal_html, url)
assert snapshot.fetched_at is not None
def test_parse_partial_status_without_title(self, store):
"""Parse sans titre doit avoir status PARTIAL."""
html = """