# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: estimation-hubspot.spec.ts >> Formulaire Estimation (devis) -> HubSpot (live)
- Location: tests/estimation-hubspot.spec.ts:21:1

# Error details

```
StepExecutionError: 
Invalid error response format: Gateway request failed: The operation was aborted due to timeout
Step: Click the 'Recevoir mon budget indicatif' submit button
```

# Page snapshot

```yaml
- generic [ref=e1]:
  - region "Notifications (F8)":
    - list
  - region "Notifications alt+T"
  - navigation [ref=e2]:
    - generic [ref=e3]:
      - link "Covalba" [ref=e4] [cursor=pointer]:
        - /url: /
        - img "Covalba" [ref=e5]
      - generic [ref=e6]:
        - button "Solutions" [ref=e8] [cursor=pointer]:
          - text: Solutions
          - img [ref=e9]
        - button "Vous êtes" [ref=e12] [cursor=pointer]:
          - text: Vous êtes
          - img [ref=e13]
        - button "Covalba" [ref=e16] [cursor=pointer]:
          - text: Covalba
          - img [ref=e17]
      - generic [ref=e19]:
        - button "Language" [ref=e21] [cursor=pointer]:
          - img [ref=e22]
          - generic [ref=e25]: FR
          - img [ref=e26]
        - link "Demander un devis" [ref=e28] [cursor=pointer]:
          - /url: /diagnostic
          - generic [ref=e29]: Demander un devis
          - img [ref=e31]
  - generic [ref=e34]:
    - generic [ref=e35]:
      - heading "Estimez votre budget en 24h." [level=1] [ref=e36]
      - paragraph [ref=e37]: "Laissez vos coordonnées : un conseiller Covalba vous transmet un budget indicatif sous 24h, primes CEE incluses si votre bâtiment est éligible."
    - generic [ref=e38]:
      - generic [ref=e41]:
        - generic [ref=e42]:
          - generic [ref=e43]:
            - generic [ref=e45]: Prénom*
            - textbox "Jean" [ref=e46]: Claude
          - generic [ref=e47]:
            - generic [ref=e49]: Nom*
            - textbox "Dupont" [ref=e50]: TEST-Estimation
        - generic [ref=e51]:
          - generic [ref=e53]: E-mail professionnel*
          - textbox "jean.dupont@entreprise.fr" [ref=e54]: test-estimation@paf-studio.dev
        - generic [ref=e55]:
          - generic [ref=e57]: Nom de l'entreprise*
          - textbox "Nom de l'entreprise" [ref=e58]: Paf-Studio Code (TEST devis)
        - generic [ref=e59] [cursor=pointer]:
          - checkbox "J'accepte de recevoir d'autres communications de Covalba." [checked] [ref=e60]
          - generic [ref=e61]: J'accepte de recevoir d'autres communications de Covalba.
        - button "Recevoir mon budget indicatif" [ref=e387] [cursor=pointer]:
          - generic [ref=e63]: Recevoir mon budget indicatif
          - img [ref=e389]
      - generic [ref=e68]:
        - generic [ref=e69]:
          - img [ref=e71]
          - paragraph [ref=e73]: Budget travaux indicatif
        - generic [ref=e74]:
          - img [ref=e76]
          - paragraph [ref=e78]: Calcul des primes CEE si éligible
        - generic [ref=e79]:
          - img [ref=e81]
          - paragraph [ref=e83]: Sans engagement
  - contentinfo [ref=e84]:
    - generic [ref=e85]:
      - generic [ref=e86]:
        - generic [ref=e87]:
          - link "Covalba" [ref=e88] [cursor=pointer]:
            - /url: /
            - img "Covalba" [ref=e89]
          - paragraph [ref=e90]: Covalba, fabricant français de revêtements réfléchissants pour toitures professionnelles. Faites des économies d'énergie dès le premier été.
        - generic [ref=e91]:
          - heading "Gammes" [level=4] [ref=e92]
          - list [ref=e93]:
            - listitem [ref=e94]:
              - link "CovaTherm" [ref=e95] [cursor=pointer]:
                - /url: /peinture-reflective-covatherm
            - listitem [ref=e96]:
              - link "CovaSeal" [ref=e97] [cursor=pointer]:
                - /url: /covaseal
            - listitem [ref=e98]:
              - link "CovaMetal" [ref=e99] [cursor=pointer]:
                - /url: /covametal
            - listitem [ref=e100]:
              - link "Laque solaire" [ref=e101] [cursor=pointer]:
                - /url: /laque-solaire-covatherm-light
        - generic [ref=e102]:
          - heading "Secteurs" [level=4] [ref=e103]
          - list [ref=e104]:
            - listitem [ref=e105]:
              - link "Industrie" [ref=e106] [cursor=pointer]:
                - /url: /industrie
            - listitem [ref=e107]:
              - link "Distribution" [ref=e108] [cursor=pointer]:
                - /url: /distribution
            - listitem [ref=e109]:
              - link "Logistique" [ref=e110] [cursor=pointer]:
                - /url: /logistique
            - listitem [ref=e111]:
              - link "Tertiaire" [ref=e112] [cursor=pointer]:
                - /url: /tertiaire
            - listitem [ref=e113]:
              - link "Collectivités" [ref=e114] [cursor=pointer]:
                - /url: /collectivité
            - listitem [ref=e115]:
              - link "Agricole" [ref=e116] [cursor=pointer]:
                - /url: /industries/agricole
            - listitem [ref=e117]:
              - link "ERP" [ref=e118] [cursor=pointer]:
                - /url: /industries/erp
        - generic [ref=e119]:
          - heading "Covalba" [level=4] [ref=e120]
          - list [ref=e121]:
            - listitem [ref=e122]:
              - link "Qui sommes-nous" [ref=e123] [cursor=pointer]:
                - /url: /qui-sommes-nous
            - listitem [ref=e124]:
              - link "Réalisations" [ref=e125] [cursor=pointer]:
                - /url: /references
            - listitem [ref=e126]:
              - link "Devenir applicateur" [ref=e127] [cursor=pointer]:
                - /url: /devenir-applicateur
            - listitem [ref=e128]:
              - link "Contact" [ref=e129] [cursor=pointer]:
                - /url: /contact
        - generic [ref=e130]:
          - heading "Ressources" [level=4] [ref=e131]
          - list [ref=e132]:
            - listitem [ref=e133]:
              - link "Cool roof à Roissy-en-France" [ref=e134] [cursor=pointer]:
                - /url: /cool-roof-roissy
            - listitem [ref=e135]:
              - link "FAQ" [ref=e136] [cursor=pointer]:
                - /url: /faq
            - listitem [ref=e137]:
              - link "Guides" [ref=e138] [cursor=pointer]:
                - /url: /guides
            - listitem [ref=e139]:
              - link "Livre blanc" [ref=e140] [cursor=pointer]:
                - /url: /guide-cool-roof
            - listitem [ref=e141]:
              - link "Simulateur ROI" [ref=e142] [cursor=pointer]:
                - /url: /simulateur-economie-energie
            - listitem [ref=e143]:
              - link "Estimation budget travaux" [ref=e144] [cursor=pointer]:
                - /url: /estimation
            - listitem [ref=e145]:
              - link "Primes CEE" [ref=e146] [cursor=pointer]:
                - /url: /bat-en-112
      - generic [ref=e147]:
        - paragraph [ref=e148]: © 2026 Covalba. Tous droits réservés.
        - link "Mentions légales" [ref=e149] [cursor=pointer]:
          - /url: "#"
  - generic [active]:
    - generic [ref=e190]:
      - generic [ref=e191]:
        - generic [ref=e192]:
          - navigation [ref=e193]:
            - button "previous" [ref=e194] [cursor=pointer]:
              - img "previous" [ref=e195]
            - generic [ref=e197]:
              - generic [ref=e198]: 3/
              - text: "3"
            - button "next" [disabled] [ref=e199]:
              - img "next" [ref=e200]
          - img
        - generic [ref=e202]:
          - link "Next.js 16.2.6 (stale) Turbopack" [ref=e203] [cursor=pointer]:
            - /url: https://nextjs.org/docs/messages/version-staleness
            - img [ref=e204]
            - generic "There is a newer version (16.2.9) available, upgrade recommended!" [ref=e206]: Next.js 16.2.6 (stale)
            - generic [ref=e207]: Turbopack
          - img
      - dialog "Console Error" [ref=e209]:
        - generic [ref=e212]:
          - generic [ref=e213]:
            - generic [ref=e214]:
              - generic [ref=e216]: Console Error
              - generic [ref=e218]:
                - button "Copy Error Info" [ref=e219] [cursor=pointer]:
                  - img [ref=e220]
                - button "No related documentation found" [disabled] [ref=e222]:
                  - img [ref=e223]
                - button "Attach Node.js inspector" [ref=e225] [cursor=pointer]:
                  - img [ref=e226]
            - generic [ref=e235]: HubSpot 400 — The request is not valid
          - generic [ref=e237]:
            - generic [ref=e342]:
              - paragraph [ref=e344]:
                - img [ref=e346]
                - generic [ref=e350]: src/lib/hubspot.ts (122:11) @ postHubspotForm
                - button "Open in editor" [ref=e351] [cursor=pointer]:
                  - img [ref=e353]
              - generic [ref=e356]:
                - generic [ref=e357]: 120 | /* corps non-JSON */
                - generic [ref=e358]: "121 | }"
                - generic [ref=e359]: "> 122 | throw new Error(`HubSpot ${res.status}${detail ? ` — ${detail}` : ''}`);"
                - generic [ref=e360]: "| ^"
                - generic [ref=e361]: "123 | }"
                - generic [ref=e362]: "124 | }"
                - generic [ref=e363]: 125 |
            - generic [ref=e364]:
              - generic [ref=e365]:
                - paragraph [ref=e366]:
                  - text: Call Stack
                  - generic [ref=e367]: "4"
                - button "Show 1 ignore-listed frame(s)" [ref=e368] [cursor=pointer]:
                  - text: Show 1 ignore-listed frame(s)
                  - img [ref=e369]
              - generic [ref=e371]:
                - generic [ref=e372]:
                  - text: postHubspotForm
                  - button "Open postHubspotForm in editor" [ref=e373] [cursor=pointer]:
                    - img [ref=e374]
                - text: src/lib/hubspot.ts (122:11)
              - generic [ref=e376]:
                - generic [ref=e377]:
                  - text: async submitEstimationToHubspot
                  - button "Open async submitEstimationToHubspot in editor" [ref=e378] [cursor=pointer]:
                    - img [ref=e379]
                - text: src/lib/hubspot.ts (201:3)
              - generic [ref=e381]:
                - generic [ref=e382]:
                  - text: async onSubmit
                  - button "Open async onSubmit in editor" [ref=e383] [cursor=pointer]:
                    - img [ref=e384]
                - text: src/components/lead/LeadCaptureForm.tsx (55:7)
        - generic [ref=e289]: "1"
        - generic [ref=e290]: "2"
    - button "Open Next.js Dev Tools" [ref=e416] [cursor=pointer]:
      - img [ref=e156]
  - alert [ref=e169]
```

# Test source

```ts
  1  | import { test, expect } from "@playwright/test";
  2  | import { runSteps, configure } from "passmark";
  3  | 
  4  | configure({
  5  |   ai: {
  6  |     gateway: "vercel",
  7  |     models: {
  8  |       stepExecution: "google/gemini-3.5-flash",
  9  |       userFlowLow: "google/gemini-3-flash-preview",
  10 |       userFlowHigh: "google/gemini-3.5-flash",
  11 |       assertionPrimary: "anthropic/claude-sonnet-4.6",
  12 |       assertionSecondary: "google/gemini-3-flash",
  13 |       assertionArbiter: "anthropic/claude-sonnet-4.6",
  14 |     },
  15 |   },
  16 | });
  17 | 
  18 | const TARGET = "https://covalba-next-wp-tom-integration-hubspot-client.paf-studio.dev/estimation";
  19 | const TEST_EMAIL = "paf-studio-code+estimation@agentmail.to";
  20 | 
  21 | test("Formulaire Estimation (devis) -> HubSpot (live)", async ({ page }) => {
  22 |   test.setTimeout(600_000);
  23 |   const submitResponses: { url: string; status: number }[] = [];
  24 |   page.on("response", (res) => {
  25 |     if (res.url().includes("/submissions/v3/integration/submit/")) {
  26 |       submitResponses.push({ url: res.url(), status: res.status() });
  27 |     }
  28 |   });
> 29 |   await runSteps({
     |   ^ StepExecutionError: 
  30 |     page,
  31 |     userFlow: "Remplir et soumettre le formulaire d'estimation / budget Covalba",
  32 |     steps: [
  33 |       { description: `Navigate to ${TARGET}` },
  34 |       { description: "Scroll to the lead form whose submit button says 'Recevoir mon budget indicatif'" },
  35 |       { description: "Type the first name into the 'Prénom' input", data: { value: "Claude" } },
  36 |       { description: "Type the last name into the 'Nom' input", data: { value: "TEST-Estimation" } },
  37 |       { description: "Type the email into the 'E-mail professionnel' input", data: { value: TEST_EMAIL } },
  38 |       { description: "Type the company into the \"Nom de l'entreprise\" input", data: { value: "Paf-Studio Code (TEST devis)" } },
  39 |       { description: "Check the optional communications opt-in checkbox" },
  40 |       { description: "Click the 'Recevoir mon budget indicatif' submit button", waitUntil: "A success confirmation with the heading 'Demande envoyée !' is visible" },
  41 |     ],
  42 |     assertions: [
  43 |       { assertion: "The form shows a success confirmation with a green check icon and the heading 'Demande envoyée !'. The form fields are no longer visible." },
  44 |     ],
  45 |     test,
  46 |     expect,
  47 |   });
  48 |   console.log("[hubspot] submit responses:", JSON.stringify(submitResponses));
  49 |   expect(submitResponses.length, "au moins une requête HubSpot submit").toBeGreaterThan(0);
  50 |   expect(submitResponses.some((r) => r.status === 200), `HubSpot 200 attendu, recu ${JSON.stringify(submitResponses)}`).toBeTruthy();
  51 | });
  52 | 
```