Dinoer

Es hat geklickt, aber nicht auf dem Element, das Sie gemeint haben

Drei identische Schaltflächen, eine Liste, die um vier Zeilen länger wurde, ein Auswahlfeld, das gestern noch funktionierte. Jedes Ziel hier ist ein CSS-Selektor – was bedeutet, dass jeder Fehler hier ein Fehler im Selektor ist.

Das Symptom: Der Klick funktioniert. Etwas passiert. Es ist nicht das, was Sie wollten – die falsche Domain wurde geklont, die falsche Zeile wurde gelöscht, der falsche Dialog wurde geöffnet.

Es gibt keine Fehler, weil mechanisch nichts schiefgelaufen ist. Dinoer hat das angeklickt, was Sie angegeben haben. Sie haben etwas Falsches angegeben – und da jedes Ziel hier ein CSS-Selektor ist, ohne eine nummerierte Alternative als Ausweichmöglichkeit, handelt es sich immer um ein Problem des Selektors, nicht um ein Wahrnehmungsproblem.

Ursache 1 – mehrere Elemente stimmen mit Ihrem Selektor überein

Eine Seite mit drei “Klonieren”-Buttons, jeweils für eine Domain. Dieser Selektor wählt den ersten Button aus, der in der DOM-Reihenfolge steht:

{"type": "cliquer", "selecteur": "button:has-text('Clone')"}

Beobachtet in der Realität: Der Klon wurde auf einer anderen Domain gestartet als der vorgesehenen, und nur das Serverprotokoll hat dies angezeigt. Eine stille Umkehrung.

Die Lösung – benennen, nicht beschreiben. Qualifizieren Sie den Selektor mit etwas, das für diese Zeile einzigartig ist:

{"type": "cliquer", "selecteur": "button[title='Clone example-two']"}

Wenn nichts im Markup eindeutig ist, kann evaluer das richtige Element anhand seines Inhalts finden und Ihnen vor der Aktion ein selektortaugliches Attribut zurückgeben:

{"type": "evaluer",
 "script": "Array.from(document.querySelectorAll('tr')).findIndex(tr => tr.textContent.includes('example-two'))"}

Ursache 2 – Ein positionsbasierter Selektor, und die Position wurde verschoben

:nth-child() und :nth-of-type() benennen eine Zeile anhand ihrer Position in der Liste, nicht nach ihrem Inhalt. Fügen Sie vier Zeilen oberhalb Ihrer Zielzeile zwischen dem Schreiben des Szenarios und seiner Ausführung hinzu, und Ihre Zielzeile verschiebt sich um vier Positionen. Eine Prozedur, die auf einer Seite mit einer Zeile funktioniert, schlägt auf derselben Seite mit fünf Zeilen fehl – derselbe Selektor, unterschiedliches Ergebnis, keine Fehlermeldung irgendwo.

Die Lösung. Vermeiden Sie es, Positionen zu codieren, an denen Inhalte platziert werden sollen:

{"type": "cliquer", "selecteur": "tr:nth-child(3) button.delete"}
{"type": "cliquer", "selecteur": "tr:has-text('example-two') button.delete"}

Die zweite Version funktioniert weiterhin, auch wenn sich die Form der Liste ändert, weil sie die Zeile anhand ihres Inhalts benennt und nicht danach, wo sie zufällig platziert ist.

Identifizieren anhand des Inhalts, nicht anhand der Position

„Die dritte Zeile ist die neueste“, das stimmt, bis jemand eine vierte hinzufügt.

Wenn Ihr Ziel etwas Identifizierendes trägt – einen Zeitstempel, einen Slug, eine Kennung –, erstellen Sie den Selektor daraus oder lesen Sie es zuerst mit evaluer und entscheiden Sie dann programmgesteuert:

{"type": "evaluer",
 "script": "Array.from(document.querySelectorAll('input.chk-item')).map(i => i.value)"}

Kein zu befolgendes Nummerierungsschema, keine Heuristik, die nächste Woche ungültig wird – nur der bereits vorhandene Inhalt der Seite, direkt lesbar.

Kurz gesagt

  • Ein Selektor, der mehrere Elemente auswählt, wählt standardmäßig das erste Element aus.
  • :nth-child()/:nth-of-type() funktionieren nicht mehr, wenn sich die Struktur der Liste ändert – bevorzugen Sie einen inhaltsbasierten Selektor, wo immer dies möglich ist.
  • evaluer kann ein Element anhand seines Inhalts finden, bevor Sie sich für einen Selektor entscheiden, was günstiger ist als zu raten.
  • Identifizieren Sie Ziele anhand ihres Inhalts, niemals anhand ihrer Position in einer Liste.