""" Tests pour pricewatch.app.stores.cdiscount.store avec fixtures HTML réels. Teste le parsing de vraies pages HTML capturées depuis Cdiscount.com. """ import pytest from pathlib import Path from pricewatch.app.stores.cdiscount.store import CdiscountStore from pricewatch.app.core.schema import DebugStatus, StockStatus class TestCdiscountRealFixtures: """Tests avec fixtures HTML réels capturés depuis Cdiscount.""" @pytest.fixture def store(self) -> CdiscountStore: """Fixture: CdiscountStore instance.""" return CdiscountStore() @pytest.fixture def fixture_tuf608umrv004(self) -> str: """Fixture: HTML Cdiscount tuf608umrv004 (PC Portable Gamer ASUS).""" fixture_path = Path(__file__).parent.parent.parent / \ "pricewatch/app/stores/cdiscount/fixtures/cdiscount_tuf608umrv004_pw.html" with open(fixture_path, "r", encoding="utf-8") as f: return f.read() @pytest.fixture def fixture_a128902(self) -> str: """Fixture: HTML Cdiscount a128902 (Canapé d'angle NIRVANA).""" fixture_path = Path(__file__).parent.parent.parent / \ "pricewatch/app/stores/cdiscount/fixtures/cdiscount_a128902_pw.html" with open(fixture_path, "r", encoding="utf-8") as f: return f.read() def test_parse_tuf608umrv004_complete(self, store, fixture_tuf608umrv004): """Parse fixture tuf608umrv004 - doit extraire toutes les données essentielles.""" url = "https://www.cdiscount.com/informatique/ordinateurs-pc-portables/pc-portable-gamer-asus-tuf-gaming-a16-sans-windo/f-10709-tuf608umrv004.html" snapshot = store.parse(fixture_tuf608umrv004, url) # Métadonnées assert snapshot.source == "cdiscount" assert snapshot.url == url assert snapshot.reference == "10709-tuf608umrv004" assert snapshot.fetched_at is not None # Titre (doit contenir "ASUS" ou "TUF") assert snapshot.title is not None assert len(snapshot.title) > 0 assert "ASUS" in snapshot.title or "TUF" in snapshot.title # Prix assert snapshot.price is not None assert snapshot.price > 0 assert snapshot.currency == "EUR" # Status assert snapshot.debug.status in [DebugStatus.SUCCESS, DebugStatus.PARTIAL] def test_parse_a128902_complete(self, store, fixture_a128902): """Parse fixture a128902 - doit extraire toutes les données essentielles.""" url = "https://www.cdiscount.com/maison/canape-canapes/canape-d-angle-convertible-reversible-nirvana-4-5/f-11701-a128902.html" snapshot = store.parse(fixture_a128902, url) # Métadonnées assert snapshot.source == "cdiscount" assert snapshot.url == url assert snapshot.reference == "11701-a128902" # Titre assert snapshot.title is not None assert "Canapé" in snapshot.title or "NIRVANA" in snapshot.title.upper() # Prix assert snapshot.price is not None assert snapshot.price > 0 assert snapshot.currency == "EUR" # Status assert snapshot.debug.status in [DebugStatus.SUCCESS, DebugStatus.PARTIAL] def test_parse_tuf608umrv004_images(self, store, fixture_tuf608umrv004): """Parse fixture tuf608umrv004 - doit extraire au moins une image.""" url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot = store.parse(fixture_tuf608umrv004, url) # Doit avoir au moins une image assert len(snapshot.images) > 0 # Les images doivent être des URLs valides for img_url in snapshot.images: assert img_url.startswith("http") assert "cdiscount.com" in img_url.lower() or "cdscdn.com" in img_url.lower() def test_parse_a128902_images(self, store, fixture_a128902): """Parse fixture a128902 - doit extraire au moins une image.""" url = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot = store.parse(fixture_a128902, url) # Doit avoir au moins une image assert len(snapshot.images) > 0 # Les images doivent être des URLs valides for img_url in snapshot.images: assert img_url.startswith("http") def test_parse_tuf608umrv004_completeness(self, store, fixture_tuf608umrv004): """Parse fixture tuf608umrv004 - vérifier is_complete().""" url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot = store.parse(fixture_tuf608umrv004, url) # Si titre ET prix sont présents, is_complete() doit être True if snapshot.title and snapshot.price: assert snapshot.is_complete() is True else: assert snapshot.is_complete() is False def test_parse_a128902_completeness(self, store, fixture_a128902): """Parse fixture a128902 - vérifier is_complete().""" url = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot = store.parse(fixture_a128902, url) # Si titre ET prix sont présents, is_complete() doit être True if snapshot.title and snapshot.price: assert snapshot.is_complete() is True else: assert snapshot.is_complete() is False def test_parse_tuf608umrv004_json_serialization(self, store, fixture_tuf608umrv004): """Parse fixture tuf608umrv004 - vérifier sérialisation JSON.""" url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot = store.parse(fixture_tuf608umrv004, url) # Doit pouvoir sérialiser en JSON sans erreur json_str = snapshot.to_json() assert json_str is not None assert len(json_str) > 0 assert 'cdiscount' in json_str assert 'tuf608umrv004' in json_str.lower() def test_parse_a128902_json_serialization(self, store, fixture_a128902): """Parse fixture a128902 - vérifier sérialisation JSON.""" url = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot = store.parse(fixture_a128902, url) # Doit pouvoir sérialiser en JSON sans erreur json_str = snapshot.to_json() assert json_str is not None assert len(json_str) > 0 assert 'cdiscount' in json_str assert 'a128902' in json_str def test_parse_fixtures_preserve_sku(self, store, fixture_tuf608umrv004, fixture_a128902): """Parse fixtures - le SKU dans l'URL doit être préservé dans reference.""" # Test tuf608umrv004 url1 = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot1 = store.parse(fixture_tuf608umrv004, url1) assert snapshot1.reference == "10709-tuf608umrv004" # Test a128902 url2 = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot2 = store.parse(fixture_a128902, url2) assert snapshot2.reference == "11701-a128902" def test_parse_tuf608umrv004_price_format(self, store, fixture_tuf608umrv004): """Parse fixture tuf608umrv004 - le prix doit être un float valide.""" url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot = store.parse(fixture_tuf608umrv004, url) if snapshot.price: assert isinstance(snapshot.price, float) assert snapshot.price > 0 # Le prix doit avoir maximum 2 décimales assert snapshot.price == round(snapshot.price, 2) def test_parse_a128902_price_format(self, store, fixture_a128902): """Parse fixture a128902 - le prix doit être un float valide.""" url = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot = store.parse(fixture_a128902, url) if snapshot.price: assert isinstance(snapshot.price, float) assert snapshot.price > 0 # Le prix doit avoir maximum 2 décimales assert snapshot.price == round(snapshot.price, 2) def test_parse_different_categories(self, store, fixture_tuf608umrv004, fixture_a128902): """Parse fixtures de catégories différentes - les deux doivent fonctionner.""" # PC Portable (informatique) url1 = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html" snapshot1 = store.parse(fixture_tuf608umrv004, url1) assert snapshot1.is_complete() # Canapé (maison) url2 = "https://www.cdiscount.com/maison/.../f-11701-a128902.html" snapshot2 = store.parse(fixture_a128902, url2) assert snapshot2.is_complete() # Les deux doivent être valides assert snapshot1.price != snapshot2.price # Produits différents assert snapshot1.title != snapshot2.title # Produits différents