# Fixtures AliExpress

Ce dossier contient des fichiers HTML réels capturés depuis AliExpress pour les tests.

## ⚠️ Note importante sur AliExpress

AliExpress utilise un **rendu client-side (SPA React/Vue)**:
- HTTP simple retourne **HTML minimal** (75KB sans contenu)
- **Playwright est OBLIGATOIRE** avec attente (~3s)
- Attendre le sélecteur `.product-title` pour obtenir les données
- Données chargées via **AJAX** après le render initial

## Spécificité AliExpress

AliExpress est un **marketplace chinois** avec des particularités:
- **Pas de JSON-LD** schema.org
- **Prix**: Extrait par **regex** (aucun sélecteur CSS stable)
- **Images**: Extraites depuis `window._d_c_.DCData.imagePathList` (JSON embarqué)
- **Classes CSS**: Générées aléatoirement (hachées) → **TRÈS instables**
- **SKU**: ID numérique long (13 chiffres) depuis l'URL

## Fichiers

### aliexpress_1005007187023722.html
- **Produit**: Samsung serveur DDR4 mémoire Ram ECC
- **SKU**: 1005007187023722
- **URL**: https://fr.aliexpress.com/item/1005007187023722.html
- **Taille**: 378 KB (rendu complet)
- **Date capture**: 2026-01-13
- **Méthode**: Playwright avec wait_for_selector='.product-title'
- **Prix capturé**: 136,69 EUR
- **Usage**: Test complet parsing produit électronique

## Structure HTML AliExpress

### JSON-LD Schema.org ✗
AliExpress **n'utilise PAS** JSON-LD (contrairement à Backmarket).

### Données embarquées ✓
AliExpress embarque les données dans des variables JavaScript:

```javascript
window._d_c_.DCData = {
  "imagePathList": ["https://ae01.alicdn.com/kf/..."],
  "summImagePathList": ["https://ae01.alicdn.com/kf/..."],
  "i18nMap": {...},
  "extParams": {...}
}
```

### Sélecteurs identifiés

#### Titre
```css
h1                         /* Apparaît après AJAX */
meta[property="og:title"]  /* Fallback dans meta tags */
```
Le h1 n'existe PAS dans le HTML initial, il est ajouté dynamiquement.

#### Prix
⚠️ **AUCUN SÉLECTEUR CSS STABLE** - Utiliser regex:
```regex
([0-9]+[.,][0-9]{2})\s*€    /* Prix avant € */
€\s*([0-9]+[.,][0-9]{2})    /* € avant prix */
```

#### Images
Priorité: **window._d_c_.DCData.imagePathList**
Fallback: `meta[property="og:image"]`

URLs CDN: `https://ae01.alicdn.com/kf/...`

#### SKU
Extraction depuis l'URL:
```regex
/item/(\d+)\.html
```
Exemple: `/item/1005007187023722.html` → SKU = "1005007187023722"

#### Stock
Chercher bouton "Add to cart" / "Ajouter au panier"
```css
button[class*='add-to-cart']
```

## Comparaison avec autres stores

| Aspect | Amazon | Cdiscount | Backmarket | **AliExpress** |
|--------|--------|-----------|------------|----------------|
| **Anti-bot** | Faible | Fort | Fort | Moyen |
| **Méthode** | HTTP OK | Playwright | Playwright | **Playwright** |
| **JSON-LD** | Partiel | ✗ Non | ✓ Oui | **✗ Non** |
| **Sélecteurs** | Stables (IDs) | Instables | Stables | **Très instables** |
| **SKU format** | `/dp/{ASIN}` | `/f-{cat}-{SKU}` | `/p/{slug}` | **/item/{ID}.html** |
| **Prix extraction** | CSS | CSS/Regex | JSON-LD | **Regex uniquement** |
| **Rendu** | Server-side | Server-side | Server-side | **Client-side (SPA)** |
| **Particularité** | - | Prix dynamiques | Reconditionné | **SPA React/Vue** |

## Utilisation dans les tests

```python
@pytest.fixture
def aliexpress_fixture_samsung():
    fixture_path = Path(__file__).parent.parent.parent / \
        "pricewatch/app/stores/aliexpress/fixtures/aliexpress_1005007187023722.html"
    with open(fixture_path, "r", encoding="utf-8") as f:
        return f.read()

def test_parse_real_fixture(store, aliexpress_fixture_samsung):
    url = "https://fr.aliexpress.com/item/1005007187023722.html"
    snapshot = store.parse(aliexpress_fixture_samsung, url)

    assert snapshot.title.startswith("Samsung serveur DDR4")
    assert snapshot.price == 136.69
    assert snapshot.reference == "1005007187023722"
    assert snapshot.currency == "EUR"
    assert len(snapshot.images) >= 6
```

## Points d'attention pour les tests

1. **HTML volumineux** - 378KB pour une page (SPA chargée)
2. **Prix instable** - Peut changer selon promo/devise
3. **Ne pas tester le prix exact** - Tester le format et la présence
4. **Images multiples** - Toujours 6+ images par produit
5. **Titre long** - Souvent 100-150 caractères
6. **Stock variable** - Peut changer rapidement

## Comment capturer une nouvelle fixture

```python
from pricewatch.app.scraping.pw_fetch import fetch_playwright

url = "https://fr.aliexpress.com/item/..."
result = fetch_playwright(
    url,
    headless=True,
    timeout_ms=15000,
    wait_for_selector=".product-title"  # IMPORTANT!
)

if result.success:
    with open("fixture.html", "w", encoding="utf-8") as f:
        f.write(result.html)
```

⚠️ **N'utilisez PAS** `fetch_http()` - il retourne un HTML minimal (75KB)!
⚠️ **Utilisez TOUJOURS** `wait_for_selector=".product-title"` avec Playwright!

## Avantages de AliExpress

✓ **HTTP fonctionne** → Pas d'anti-bot fort (mais HTML vide)
✓ **Données embarquées** → DCData JSON avec images
✓ **SKU simple** → ID numérique depuis URL

## Inconvénients

✗ **SPA client-side** → Playwright obligatoire avec wait (~3-5s)
✗ **Pas de JSON-LD** → Extraction moins fiable
✗ **Prix par regex** → Fragile, peut casser
✗ **Classes CSS instables** → Générées aléatoirement (hachées)
✗ **Temps de chargement** → 3-5s avec Playwright + wait
✗ **Specs mal structurées** → Souvent dans des onglets/modals
