Files
scrap/tests/stores/test_backmarket.py
2026-01-13 19:49:04 +01:00

260 lines
8.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Tests pour le store Backmarket."""
import pytest
from pathlib import Path
from pricewatch.app.stores.backmarket.store import BackmarketStore
class TestBackmarketStore:
"""Tests pour BackmarketStore."""
@pytest.fixture
def store(self):
"""Fixture du store Backmarket."""
return BackmarketStore()
# ========== Tests de match() ==========
def test_match_backmarket_fr(self, store):
"""URL backmarket.fr reconnue."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
score = store.match(url)
assert score == 0.9
def test_match_backmarket_com(self, store):
"""URL backmarket.com reconnue (autres pays)."""
url = "https://www.backmarket.com/en-us/p/iphone-15-pro"
score = store.match(url)
assert score == 0.8
def test_match_other_site(self, store):
"""Autres sites non reconnus."""
urls = [
"https://www.amazon.fr/dp/ASIN",
"https://www.cdiscount.com/f-123-abc.html",
"https://www.fnac.com/produit",
"",
None,
]
for url in urls:
if url is not None:
score = store.match(url)
assert score == 0.0
def test_match_case_insensitive(self, store):
"""Match insensible à la casse."""
url = "https://WWW.BACKMARKET.FR/FR-FR/P/IPHONE"
score = store.match(url)
assert score == 0.9
# ========== Tests de canonicalize() ==========
def test_canonicalize_remove_query_params(self, store):
"""Canonicalize retire les paramètres de query."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro?color=black"
canonical = store.canonicalize(url)
assert canonical == "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
def test_canonicalize_remove_fragment(self, store):
"""Canonicalize retire le fragment (#)."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro#specs"
canonical = store.canonicalize(url)
assert canonical == "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
def test_canonicalize_keep_path(self, store):
"""Canonicalize garde le chemin complet."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
canonical = store.canonicalize(url)
assert canonical == "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
def test_canonicalize_empty_url(self, store):
"""Canonicalize avec URL vide retourne la même."""
assert store.canonicalize("") == ""
assert store.canonicalize(None) is None
# ========== Tests de extract_reference() ==========
def test_extract_reference_standard_format(self, store):
"""Extraction du SKU depuis format standard /p/{slug}."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
ref = store.extract_reference(url)
assert ref == "iphone-15-pro"
def test_extract_reference_with_query_params(self, store):
"""Extraction du SKU ignore les paramètres de query."""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro?color=black"
ref = store.extract_reference(url)
assert ref == "iphone-15-pro"
def test_extract_reference_different_locale(self, store):
"""Extraction du SKU fonctionne avec d'autres locales."""
url = "https://www.backmarket.com/en-us/p/macbook-air-m2"
ref = store.extract_reference(url)
assert ref == "macbook-air-m2"
def test_extract_reference_with_numbers(self, store):
"""Extraction du SKU avec chiffres dans le slug."""
url = "https://www.backmarket.fr/fr-fr/p/samsung-galaxy-s23"
ref = store.extract_reference(url)
assert ref == "samsung-galaxy-s23"
def test_extract_reference_invalid_url(self, store):
"""Extraction du SKU depuis URL invalide retourne None."""
urls = [
"https://www.backmarket.fr/fr-fr/collections/smartphones",
"https://www.backmarket.fr/",
"",
None,
]
for url in urls:
ref = store.extract_reference(url)
assert ref is None
# ========== Tests de parse() ==========
def test_parse_basic_html(self, store):
"""Parse HTML basique avec JSON-LD."""
html = """
<html>
<head>
<script type="application/ld+json">
{
"@type": "Product",
"name": "iPhone 15 Pro",
"offers": {
"@type": "Offer",
"price": "571.00",
"priceCurrency": "EUR"
},
"image": "https://example.com/image.jpg"
}
</script>
</head>
<body>
<h1 class="heading-1">iPhone 15 Pro</h1>
</body>
</html>
"""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
snapshot = store.parse(html, url)
assert snapshot.source == "backmarket"
assert snapshot.url == "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
assert snapshot.title == "iPhone 15 Pro"
assert snapshot.price == 571.0
assert snapshot.currency == "EUR"
assert snapshot.reference == "iphone-15-pro"
assert len(snapshot.images) == 1
assert snapshot.is_complete()
def test_parse_without_json_ld(self, store):
"""Parse HTML sans JSON-LD utilise les sélecteurs CSS."""
html = """
<html>
<body>
<h1 class="heading-1">MacBook Air M2</h1>
<div data-test="price">799,99 €</div>
</body>
</html>
"""
url = "https://www.backmarket.fr/fr-fr/p/macbook-air-m2"
snapshot = store.parse(html, url)
assert snapshot.title == "MacBook Air M2"
assert snapshot.price == 799.99
assert snapshot.currency == "EUR"
assert snapshot.reference == "macbook-air-m2"
def test_parse_with_condition(self, store):
"""Parse extrait la condition du reconditionné."""
html = """
<html>
<head>
<script type="application/ld+json">
{
"@type": "Product",
"name": "iPhone 15",
"offers": {"price": "500", "priceCurrency": "EUR"}
}
</script>
</head>
<body>
<h1>iPhone 15</h1>
<button data-test="condition-button">Excellent</button>
</body>
</html>
"""
url = "https://www.backmarket.fr/fr-fr/p/iphone-15"
snapshot = store.parse(html, url)
assert "Condition" in snapshot.specs
assert snapshot.specs["Condition"] == "Excellent"
assert any("reconditionné" in note.lower() for note in snapshot.debug.notes)
def test_parse_missing_title_and_price(self, store):
"""Parse avec titre et prix manquants → status PARTIAL."""
html = "<html><body><p>Contenu vide</p></body></html>"
url = "https://www.backmarket.fr/fr-fr/p/test"
snapshot = store.parse(html, url)
assert snapshot.title is None
assert snapshot.price is None
assert not snapshot.is_complete()
assert snapshot.debug.status == "partial"
def test_parse_stock_status_detection(self, store):
"""Parse détecte le statut de stock depuis le bouton add-to-cart."""
html = """
<html>
<head>
<script type="application/ld+json">
{
"@type": "Product",
"name": "Test Product",
"offers": {"price": "100", "priceCurrency": "EUR"}
}
</script>
</head>
<body>
<button data-test="add-to-cart">Ajouter au panier</button>
</body>
</html>
"""
url = "https://www.backmarket.fr/fr-fr/p/test-product"
snapshot = store.parse(html, url)
assert snapshot.stock_status == "in_stock"
def test_parse_specs_from_definition_list(self, store):
"""Parse extrait les specs depuis les <dl>."""
html = """
<html>
<head>
<script type="application/ld+json">
{
"@type": "Product",
"name": "Test",
"offers": {"price": "100", "priceCurrency": "EUR"}
}
</script>
</head>
<body>
<dl>
<dt>Mémoire</dt>
<dd>256 Go</dd>
<dt>Couleur</dt>
<dd>Noir</dd>
</dl>
</body>
</html>
"""
url = "https://www.backmarket.fr/fr-fr/p/test"
snapshot = store.parse(html, url)
assert "Mémoire" in snapshot.specs
assert snapshot.specs["Mémoire"] == "256 Go"
assert "Couleur" in snapshot.specs
assert snapshot.specs["Couleur"] == "Noir"