# Tests E2E Playwright

> Version : 0.1 · Dernière maj : 2026-05-18
> Stack : Playwright + Chromium · DB séparée `rubis_test_e2e` · Stripe mocké

Tests end-to-end qui simulent un **vrai user** interagissant avec la SPA + landing dans un Chromium headless (ou headed). Validation complète de la chaîne navigation, formulaires, redirections, hydratation Tanstack, fetch API, persistence DB.

Complémentaires aux tests :
- **Unit** (`apps/api/tests/unit/`) : logique pure, fonctions isolées.
- **Functional HTTP** (`apps/api/tests/functional/`) : routes API via japa ApiClient.
- **Vitest SPA** (`apps/web/src/**/*.test.tsx`) : hooks + composants isolés.
- **E2E Playwright** (`e2e/tests/`) ← *vous êtes ici*. Navigateur réel, full stack.

---

## Pré-requis (une fois)

1. **PostgreSQL** local accessible (généralement via docker-compose dev) :
   ```bash
   pnpm dev:up   # spin up Postgres + Redis + Mailpit + MinIO
   ```
2. **Setup de la DB de test** :
   ```bash
   pnpm e2e:setup
   ```
   Crée `rubis_test_e2e` (si absente) et applique toutes les migrations Adonis.

3. **Chromium Playwright** (déjà fait si tu as `pnpm install` après ce commit) :
   ```bash
   pnpm exec playwright install chromium
   ```

---

## Lancement

```bash
# Headless (CI / dev rapide)
pnpm e2e

# Headed (regarder le navigateur en action — debug)
pnpm e2e:headed

# UI interactive (mode dev Playwright, idéal pour itérer)
pnpm e2e:ui
```

Playwright **spawn lui-même** l'API Adonis (port 3333) et la SPA Vite (port 5173) en mode `test_e2e` avant de lancer les tests. Pas besoin de `pnpm dev` à part. Si tu as déjà ton stack qui tourne, set `E2E_SKIP_WEBSERVER=1`.

### Variables d'env

| Variable | Default | Rôle |
|---|---|---|
| `E2E_PG_DB_NAME` | `rubis_test_e2e` | Nom de la DB de test |
| `E2E_WEB_URL` | `http://localhost:5173` | Base URL SPA |
| `E2E_API_URL` | `http://localhost:3333` | Base URL API (pour les helpers reset/mock) |
| `E2E_SKIP_WEBSERVER` | unset | Si défini, Playwright n'essaie pas de spawn API+SPA |
| `CI` | unset | Active retries + reporter github + traces |

---

## Architecture

### Stripe mocké côté API

Le SDK Stripe est remplacé par un mock déterministe via `__setStripeForTests` (cf. `apps/api/app/services/stripe.ts`). En `NODE_ENV=test_e2e`, les endpoints suivants sont exposés (gated, 404 sinon) :

| Endpoint | Rôle |
|---|---|
| `POST /__test__/reset` | TRUNCATE des tables applicatives + ré-install mock par défaut |
| `POST /__test__/stripe/mock` | Switch de scenario (`trial_happy`, `trial_decline`) |
| `POST /__test__/stripe/webhook` | Simule un event Stripe sans signer manuellement |
| `GET /__test__/state/org/:id` | Inspection directe DB d'une org |

Ces endpoints sont **invisibles** en prod : le contrôleur throw 404 si `NODE_ENV !== 'test_e2e'`. Aucun risque de fuite.

### DB de test isolée

`rubis_test_e2e` est physiquement séparée de `rubis` (dev). Chaque test commence par `await resetDb()` qui TRUNCATE les tables. Aucune pollution croisée.

Le TRUNCATE CASCADE prend ~50 ms ; bien plus rapide qu'un drop/recreate. Tests séquentiels (`workers: 1`) pour ne pas avoir 2 truncates en parallèle.

### Mocking Stripe au niveau navigateur ?

**Non.** On mocke **côté API**, pas côté navigateur. Pourquoi : la SPA appelle de toute façon notre API, et notre API appelle Stripe. Mocker côté navigateur (via Playwright `route()`) ne couvrirait que les appels directs SPA → Stripe, ce qui n'existe pas dans notre archi (tout passe par l'API).

L'avantage : on teste l'intégralité de notre code applicatif comme en prod, seul Stripe est rempl.

### Limites — ce qui n'est PAS testé

- **L'UI Stripe Checkout** (3DS challenge, formulaire CB) — externe à notre app, mocké. Pour valider : utiliser le **playbook manuel** [stripe-trial-e2e-playbook.md](./stripe-trial-e2e-playbook.md) avec Stripe Test Clocks.
- **Le prélèvement réel à J+14** — nécessite Stripe Test Clocks + advance, hors scope automation.
- **Les emails sortants** — capturés par Mailpit en dev, mais les tests E2E ne vérifient pas le rendu HTML pixel-perfect (le visual regression viendrait en V2).

---

## Scénarios couverts (V1)

| Fichier | Scénarios |
|---|---|
| `tests/signup.spec.ts` | Signup + onboarding 3 étapes → dashboard |
| `tests/billing-trial.spec.ts` | Démarrer essai 14j (mock Stripe), fallback Free, retour `?trial=cancel`, inspection DB post-action |

Chaque scénario tourne en **~3 s** en headless. La suite complète : ~30 s.

---

## Étendre

Ajouter un nouveau test : créer `e2e/tests/<feature>.spec.ts` qui suit le pattern :

```ts
import { test, expect } from '@playwright/test'
import { resetDb } from './helpers/api'

test.describe('Ma feature', () => {
  test.beforeEach(async () => { await resetDb() })

  test('mon scénario', async ({ page }) => {
    await page.goto('/signup')
    // ...
  })
})
```

Pour simuler un webhook Stripe au milieu du scénario :

```ts
import { fireStripeWebhook } from './helpers/api'

await fireStripeWebhook({
  type: 'customer.subscription.trial_will_end',
  data: { object: { customer: 'cus_e2e_mock', id: 'sub_xxx' } },
})
```

Pour inspecter l'état DB sans naviguer dans le SPA :

```ts
import { getOrgState } from './helpers/api'

const state = await getOrgState(orgId)
expect(state?.plan).toBe('pro')
```

---

## CI

À ajouter dans le pipeline Gitea (suit le pattern de `apps/api` actuel) :

```yaml
# .gitea/workflows/e2e.yml (à créer)
e2e:
  steps:
    - run: pnpm install
    - run: pnpm dev:up   # Postgres + Redis + Mailpit
    - run: pnpm exec playwright install --with-deps chromium
    - run: pnpm e2e:setup
    - run: pnpm e2e
    - if: failure()
      uses: actions/upload-artifact@v4
      with:
        name: playwright-report
        path: playwright-report/
```

Tant que la CI E2E n'est pas montée, les tests se lancent **uniquement en local** avant les déploiements sensibles (changement signup, billing, onboarding).

---

## Troubleshooting

- **« could not connect to server: Connection refused »** → `pnpm dev:up` pour démarrer Postgres.
- **« Database "rubis_test_e2e" does not exist »** → `pnpm e2e:setup`.
- **« Timed out waiting for http://localhost:3333/api/v1/health »** → l'API ne boot pas. Vérifier `apps/api/.env` (APP_KEY notamment). Lancer manuellement `cd apps/api && NODE_ENV=test_e2e pnpm dev` pour voir les erreurs.
- **« Stripe SDK not initialized »** → l'endpoint `/__test__/stripe/mock` n'a pas été appelé. `resetDb()` le fait par défaut au début de chaque test.
- **Tests flaky** → augmenter `timeout` dans playwright.config.ts. La SPA peut être lente sur certaines machines.
