rubis/e2e/tests/dashboard.spec.ts
ordinarthur e40f417caa
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 28s
test(e2e): PR 3 — billing states + quota + dashboard + settings (+ fix isDirty)
Couvre les surfaces transverses post auth/clients/factures :

- billing-states (3) : transitions webhook trial→active, past_due, cancel
- billing-quota (2) : Free limite à 2 factures actives, 3e bloquée + toast
  remonté avec message API (UX bug : onError du dialog masquait l'erreur)
- dashboard (2) : zéros au start, +rubis et activity feed après mark-paid
- settings (2) : sections visibles + persistence Prénom/Nom après reload

Bug isDirty détecté par TDD sur settings : AccountForm/OrganizationForm/
SignatureForm lisaient form.state.isDirty *hors* d'un form.Subscribe, donc
le bouton Save ne réagissait jamais aux changements (texte figé sur "Aucune
modification"). Fix : wrap le bouton dans form.Subscribe selector=isDirty,
même pattern que ManualInvoiceDialog.

36 tests Playwright vert, ~1m20.

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

86 lines
3.5 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { resetDb } from './helpers/api'
/**
* Scénarios dashboard : KPIs à zéro au start, bump après actions.
*
* Les calculs des KPIs sont testés par les tests japa functional
* (dashboard.spec.ts) — ici on valide la chaîne SPA → API → render
* sur la page d'accueil.
*/
async function signupAndOnboard(page: import('@playwright/test').Page) {
const email = `dash+${Date.now()}@rubis.test`
await page.goto('/signup')
await page.getByLabel(/Prénom \/ Nom/i).fill('Dashboard Test')
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 Dashboard')
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('Dashboard', () => {
test.beforeEach(async () => {
await resetDb()
})
test('zéros au start : 0 rubis, "Pas encore d\'activité"', async ({ page }) => {
await signupAndOnboard(page)
await page.goto('/')
// RubisHero : "0 rubis gagnés ce mois"
await expect(page.getByText(/0\s+rubis/i).first()).toBeVisible({ timeout: 10_000 })
// Activity feed vide
await expect(
page.getByText(/pas encore d'activité|importez votre première facture/i).first(),
).toBeVisible()
})
test('après mark-paid : rubis += 1 + activity contient l\'event', async ({
page,
}) => {
await signupAndOnboard(page)
// 1. Créer client + facture
await page.getByRole('button', { name: /^saisir$/i }).first().click()
const combobox = page.getByPlaceholder(/rechercher.*créer un client/i)
await combobox.fill('Dashboard Client')
await page.getByRole('button', { name: /créer le client.*dashboard client/i }).click()
await page.getByLabel(/email du client/i).fill('client@dashboard.test')
await page.getByLabel(/N° de facture/i).fill('F-DASH-001')
await page.getByLabel(/Montant TTC/i).fill('500')
await page.getByLabel(/Plan de relance/i).click()
await page.getByRole('option').first().click()
await page.getByRole('button', { name: /^créer la facture$/i }).click()
await expect(page.getByText(/facture créée/i)).toBeVisible({ timeout: 5_000 })
// 2. Aller sur la facture, mark-paid
await page.goto('/factures')
await page.getByText('F-DASH-001').first().click()
await page.getByRole('button', { name: /marquer encaissée/i }).click()
await expect(page.getByText(/encaissée.*rubis/i)).toBeVisible({ timeout: 5_000 })
// 3. Sur le dashboard, rubis count = 1 (création) + 1 (mark-paid) = 2 rubis
// Note : la création d'une facture saisie manuelle pose rubisEarned=1
// et le mark-paid bump encore +1
await page.goto('/')
// Le compteur RubisHero affiche "X rubis gagnés" et la sidebar aussi
await expect(page.getByText(/[1-2]\s+rubis/i).first()).toBeVisible({
timeout: 10_000,
})
// 4. Activity feed contient l'event "Facture F-DASH-001 marquée encaissée"
await expect(page.getByText(/F-DASH-001/).first()).toBeVisible({
timeout: 5_000,
})
})
})