Dinoer

The form reports success and never submits

The click succeeds, the scenario ends green, and the server received nothing. Two different causes produce this exact result — and the fix for one does not fix the other.

The symptom. You fill a form, click submit, get succes: true — and the target is unchanged. Reading the page afterwards shows the same page, or the home page, never the result page you expected.

Two unrelated causes produce this identical result. Tell them apart before reaching for a fix, or you will apply the wrong one.

Cause 1 — the browser blocked it, and said so quietly

HTML5 validation. A field marked required is empty, or a type="email" holds something that is not one. The browser refuses the submission and shows a small native bubble — Please fill out this field — anchored to the offending input.

Dinoer reports the click as successful, because it was: the click happened. The browser simply declined to act on it.

How to recognise it. The attendre_navigation right after the click returns in ~0 ms. Nothing navigated because nothing was sent. Read the resulting a11y_tree — the bubble’s text is present in it, easy to miss if you only check succes.

The fix. Fill the missing field. If the field must stay empty on purpose, submit the form directly and bypass native validation:

{"type": "evaluer",
 "script": "document.querySelector('#my-form').submit()"}

Cause 2 — a JavaScript click is not a submission

This one is more surprising. Calling .click() on a submit button from JavaScript fires the DOM click event but does not guarantee the HTTP submission of the parent form. Browsers treat a synthetic click differently from a user click, especially when validation handlers are attached.

Observed on a real WordPress theme update: the scenario ended succes: true, the resulting page showed the WordPress home page, and no theme had been updated.

{"type": "evaluer",
 "script": "document.querySelector('input[name=upgrade]').click()"}

The fix — always this form:

{"type": "evaluer",
 "script": "document.querySelector('input[value=\"theme-slug\"]').closest('form').submit()"}

.closest('form').submit() calls the browser’s native submission method directly. .click() on a submit button asks politely; .submit() does the thing.

The rule worth keeping

To submit a form from evaluer, always use .closest(‘form’).submit() — never .click() on the submit button.

And if you are not in evaluer at all, prefer a real cliquer on the button: Playwright’s native click behaves like a user’s, which is exactly what a synthetic one does not.

Before you conclude

A submission that appears to have failed may have succeeded. A slow POST — a clone, an import, anything taking tens of seconds — can hit the timeout while the server carries on and finishes the work. TimeoutError on a click means Playwright stopped waiting, not that nothing happened.

Check the target before retrying, or you will run the operation twice. The operation that takes a while →

In short

  • Two causes, one symptom: native validation blocked it, or a JS .click() never submitted.
  • ~0 ms on attendre_navigation after the click = nothing was sent.
  • From evaluer: .closest('form').submit(), always.
  • A timeout is not a failure — verify before you retry.