It clicked, but not on the element you meant
Three identical buttons, a list that grew by four rows, a selector that worked yesterday. Every target is a CSS selector, so every mistake here is a selector mistake.
The symptom. The click works and something happens, but not what you wanted: the wrong row deleted, the wrong dialog opened, the action applied to the wrong item.
Nothing reports an error, because nothing failed mechanically: Dinoer clicked what you designated. Every target is a CSS selector, so the mistake is in the selector.
Cause 1: several elements match your selector
A page with three “Clone” buttons, one per row. This selector takes the first one in document order:
{"type": "cliquer", "selecteur": "button:has-text('Clone')"}
The action then runs on another row than the one you meant, and nothing in the answer says so.
The fix: designate, do not describe. Qualify the selector with something unique to that row:
{"type": "cliquer", "selecteur": "button[title='Clone example-two']"}
If nothing in the markup is unique, evaluer can find the right element by
its content before you act:
{"type": "evaluer",
"script": "Array.from(document.querySelectorAll('tr')).findIndex(tr => tr.textContent.includes('example-two'))"}
Cause 2: a selector based on position, and the position moved
:nth-child() and :nth-of-type() name a row by its place in the list, not by
what it is. Add four rows above your target between writing the scenario and
running it, and the target moves by four. A scenario tested on a page with one
row fails on the same page with five: same selector, different result, no
error.
The fix. Never encode a position where content will do:
{"type": "cliquer", "selecteur": "tr:nth-child(3) button.delete"}
{"type": "cliquer", "selecteur": "tr:has-text('example-two') button.delete"}
The second version keeps working after the list changes, because it names the row by what it contains, not by where it sits.
Identify by content, not by position
“The third row is the most recent one” is true until someone adds a fourth.
When the target carries something that identifies it (a timestamp, a slug, an
identifier), build the selector from it, or read it first with evaluer and
decide from what comes back:
{"type": "evaluer",
"script": "Array.from(document.querySelectorAll('input.chk-item')).map(i => i.value)"}
In short
- A selector that matches several elements takes the first one, silently.
:nth-child()and:nth-of-type()break when the list changes; use a selector based on content whenever one exists.evaluercan locate an element by its content before you choose a selector.- Identify targets by what they contain, never by their place in a list.