rubis/e2e/tests/settings.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

75 lines
2.9 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { resetDb } from './helpers/api'
/**
* Scénarios /parametres : forms account + organization + signature.
*
* Chaque form est isolé (son propre Save button). On valide la
* persistence après reload page — pas juste l'UI optimiste.
*/
async function signupAndOnboard(page: import('@playwright/test').Page) {
const email = `set+${Date.now()}@rubis.test`
await page.goto('/signup')
await page.getByLabel(/Prénom \/ Nom/i).fill('Settings 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 Settings')
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('Settings', () => {
test.beforeEach(async () => {
await resetDb()
})
test('page /parametres affiche les sections principales', async ({ page }) => {
await signupAndOnboard(page)
await page.goto('/parametres')
await expect(page.getByRole('heading', { name: /paramètres/i })).toBeVisible()
// Les sections AccountForm, OrganizationForm, SignatureForm sont
// toutes visibles (rendues par /parametres). Le scroll est long mais
// tous les labels sont dans le DOM dès le mount.
await expect(page.getByText(/^compte$/i).first()).toBeVisible()
await expect(page.getByText(/^entreprise$/i).first()).toBeVisible()
await expect(page.getByText(/signature email/i).first()).toBeVisible()
})
test('modifier "Prénom et nom" → toast + persistence après reload', async ({
page,
}) => {
await signupAndOnboard(page)
await page.goto('/parametres')
const fullNameInput = page.getByLabel(/^Prénom et nom$/i)
await expect(fullNameInput).toBeVisible({ timeout: 5_000 })
// L'initial du onboarding était "Settings Test"
await expect(fullNameInput).toHaveValue('Settings Test')
await fullNameInput.fill('Pierre Modifié')
// Le bouton passe de "Aucune modification" à "Enregistrer"
const saveButton = page.getByRole('button', { name: /^enregistrer$/i }).first()
await saveButton.click()
// Confirmation : le bouton revient à "Aucune modification" après save
await expect(
page.getByRole('button', { name: /aucune modification/i }).first(),
).toBeVisible({ timeout: 5_000 })
// Reload : la valeur persiste
await page.reload()
await expect(page.getByLabel(/^Prénom et nom$/i)).toHaveValue('Pierre Modifié')
})
})