import { request, type APIRequestContext } from '@playwright/test' /** * Helpers HTTP pour les tests E2E. Tape directement l'API Adonis pour : * - reset la DB entre tests * - installer / configurer le mock Stripe * - simuler la livraison de webhooks Stripe * - inspecter l'état d'une org en DB * * Tous les endpoints touchés ici sont gated par `NODE_ENV=test_e2e` côté * API (cf. apps/api/app/controllers/test_e2e_controller.ts). */ const API_URL = process.env.E2E_API_URL ?? 'http://localhost:3333' let _ctx: APIRequestContext | null = null async function ctx(): Promise { if (_ctx) return _ctx _ctx = await request.newContext({ baseURL: API_URL }) return _ctx } /** * Vide les tables applicatives + ré-installe un Stripe mock par défaut. * À appeler en `test.beforeEach`. */ export async function resetDb(): Promise { const c = await ctx() const r = await c.post('/__test__/reset') if (!r.ok()) throw new Error(`reset failed: ${r.status()}`) } /** * Override le scenario du mock Stripe — `'trial_decline'` simule un user * qui ferme Stripe Checkout sans valider (redirige vers /onboarding/billing * avec ?trial=cancel). Default = happy path. */ export async function installStripeMock(scenario?: string): Promise { const c = await ctx() await c.post('/__test__/stripe/mock', { data: { scenario } }) } /** * Simule la livraison d'un webhook Stripe — déclenche le dispatcher * applicatif comme si Stripe avait POST. Évite à Playwright de devoir * signer manuellement les payloads. * * Exemple : await fireStripeWebhook({ type: 'customer.subscription.trial_will_end', * data: { object: { customer: 'cus_e2e_mock', ... } } }) */ export async function fireStripeWebhook(event: { type: string data: { object: Record } }): Promise { const c = await ctx() const r = await c.post('/__test__/stripe/webhook', { data: event }) if (!r.ok()) throw new Error(`fire webhook failed: ${r.status()} ${await r.text()}`) } /** * Lit l'état d'une org directement en DB. Utile pour asserter post-action * sans naviguer dans le SPA. */ export async function getOrgState(orgId: string): Promise { const c = await ctx() const r = await c.get(`/__test__/state/org/${orgId}`) if (!r.ok()) throw new Error(`getOrgState failed: ${r.status()}`) const json = (await r.json()) as { data: OrgState | null } return json.data } /** * Retourne la dernière org créée (toutes confondues). Comme `resetDb` * est appelé en `beforeEach`, la dernière est forcément celle du * scénario en cours — pratique pour récupérer l'orgId après signup * sans avoir à plonger dans le SPA pour le Bearer token. */ export async function getLastOrg(): Promise { const c = await ctx() const r = await c.get('/__test__/state/last-org') if (!r.ok()) throw new Error(`getLastOrg failed: ${r.status()}`) const json = (await r.json()) as { data: OrgState | null } return json.data } export type OrgState = { id: string name: string plan: 'free' | 'pro' | 'business' subscription_status: string | null stripe_customer_id: string | null stripe_subscription_id: string | null trial_ends_at: string | null grace_period_ends_at: string | null }