220 lines
9.6 KiB
Python
Executable File
220 lines
9.6 KiB
Python
Executable File
"""
|
|
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_tuf608umrv004_price_value(self, store, fixture_tuf608umrv004):
|
|
"""Le prix doit correspondre à 1199,99 €."""
|
|
url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html"
|
|
snapshot = store.parse(fixture_tuf608umrv004, url)
|
|
assert snapshot.price == 1199.99
|
|
|
|
def test_parse_tuf608umrv004_category_and_msrp(
|
|
self, store, fixture_tuf608umrv004
|
|
):
|
|
"""La fixture ASUS doit fournir une catégorie et un prix conseillé."""
|
|
url = "https://www.cdiscount.com/informatique/.../f-10709-tuf608umrv004.html"
|
|
snapshot = store.parse(fixture_tuf608umrv004, url)
|
|
assert snapshot.category
|
|
assert "Ordinateur" in snapshot.category or "Portable" in snapshot.category
|
|
assert snapshot.msrp is not None
|
|
if snapshot.price:
|
|
assert snapshot.msrp >= snapshot.price
|
|
|
|
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
|