rubis/e2e/tests/plans.spec.ts
ordinarthur 0ecf8ad40f test(e2e): PR 2 — import OCR + plans + mailing Mailpit
Ajoute 6 scénarios Playwright qui couvrent les surfaces utilisateur
au-delà de l'auth/clients/factures : upload OCR via dropzone, listing
des plans pré-fournis, et la chaîne mailing complète end-to-end.

Import (2 tests) — import.spec.ts :
  - Upload PDF via setInputFiles : MockOcrProvider extrait depuis le
    filename → drafts créés → SPA redirige sur /factures/import/$batchId
    → on voit le filename listé dans les drafts
  - Empty state /factures/import : dropzone + bouton "Parcourir" visibles

Plans (3 tests) — plans.spec.ts :
  - Les 4 plans pré-fournis (Standard, Rapide, Patient, Ferme) sont
    visibles dès le signup (provisionnés par provisionDefaultPlans)
  - Clic "Créer un plan" → arrive sur le wizard /plans/nouveau
  - Clic "Modifier" sur une PlanCard → page détail /plans/{slug}

Mailing (1 test, le plus précieux) — mailing.spec.ts :
  - Helper helpers/mailpit.ts : clearMailpit, waitForMessageTo (poll
    200ms / 10s timeout), getMessage (HTML + texte)
  - Scénario : signup → onboarding → créer client avec email →
    créer facture saisie manuelle → mark-paid → BullMQ worker enqueue
    payment-thanks → email envoyé via SMTP → Mailpit catche →
    test inspecte subject + body (numero, montant)
  - Valide la chaîne complète : SPA → API → DB → BullMQ → Worker →
    Mailpit, en moins de 5 s

Total après cette PR : 26 scénarios Playwright verts en 55 s.

Pré-requis runtime :
  - `pnpm dev:up` (Postgres + Redis + Mailpit + MinIO)
  - `pnpm e2e:setup` (création DB rubis_test_e2e + migrations)
  - Mailpit accessible sur :8025 (clearMailpit l'utilise en beforeEach)

Note check-in flow : pas implémenté en E2E V1 — nécessite un endpoint
test_e2e pour générer un CheckinTask + clear token. Le flow checkin
est déjà couvert par les tests japa functional. À ajouter en PR 3 si
besoin de validation end-to-end UI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 16:45:39 +02:00

73 lines
3.0 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { resetDb } from './helpers/api'
/**
* Scénarios plans de relance.
*
* On valide la list view (4 plans pré-fournis après signup) + la
* navigation vers le wizard de création. Le wizard 4 étapes lui-même
* (avec génération IA des emails) est testé par les tests japa
* functional pour le détail métier, et reste hors scope E2E V1.
*/
async function signupAndOnboard(page: import('@playwright/test').Page, tag = 'pl') {
const email = `${tag}+${Date.now()}@rubis.test`
await page.goto('/signup')
await page.getByLabel(/Prénom \/ Nom/i).fill('Test User')
await page.getByLabel(/Email professionnel/i).fill(email)
await page.getByLabel(/Mot de passe/i).fill('motdepasse-fort-123')
await page.getByRole('button', { name: /créer mon compte/i }).click()
await page.waitForURL(/\/onboarding\/compte/, { timeout: 10_000 })
await page.getByRole('button', { name: /continuer/i }).click()
await page.waitForURL(/\/onboarding\/entreprise/)
await page.getByLabel(/nom de l'entreprise/i).fill('Atelier Test')
await page.getByRole('button', { name: /continuer/i }).click()
await page.waitForURL(/\/onboarding\/signature/)
await page.getByRole('button', { name: /terminer/i }).click()
await page.waitForURL('/', { timeout: 10_000 })
}
test.describe('Plans de relance', () => {
test.beforeEach(async () => {
await resetDb()
})
test('les 4 plans pré-fournis sont visibles après signup', async ({ page }) => {
await signupAndOnboard(page, 'pl-default')
await page.goto('/plans')
await expect(
page.getByRole('heading', { name: /plans de.*relance/i }),
).toBeVisible()
// Les 4 plans pré-fournis ont des slugs `standard-30j`, `rapide-15j`,
// `patient-60j`, `ferme-7j`. Leurs noms d'affichage utilisent les mots
// "Standard", "Rapide", "Patient", "Ferme".
await expect(page.getByText(/standard/i).first()).toBeVisible()
await expect(page.getByText(/rapide/i).first()).toBeVisible()
await expect(page.getByText(/patient/i).first()).toBeVisible()
await expect(page.getByText(/ferme/i).first()).toBeVisible()
// La carte "+ Créer un plan" est aussi visible
await expect(page.getByRole('link', { name: /créer un plan/i })).toBeVisible()
})
test('clic "Créer un plan" → arrive sur le wizard', async ({ page }) => {
await signupAndOnboard(page, 'pl-wizard')
await page.goto('/plans')
await page.getByRole('link', { name: /créer un plan/i }).click()
await expect(page).toHaveURL(/\/plans\/nouveau/, { timeout: 5_000 })
})
test('clic "Modifier" sur un plan → page détail du plan', async ({ page }) => {
await signupAndOnboard(page, 'pl-detail')
await page.goto('/plans')
// Chaque PlanCard a un lien "Modifier" → /plans/$slug. On clique sur
// le premier (qui correspondra à un des 4 plans pré-fournis).
await page.getByRole('link', { name: /^modifier/i }).first().click()
await expect(page).toHaveURL(/\/plans\/(standard|rapide|patient|ferme)/, {
timeout: 5_000,
})
})
})