2015-03-23 8 views
5

Selen hat einen bequemen Mechanismus für Dutzende oder Hunderte von Elementen aus dem DOM ziemlich effizient und in einer einzigen schnellen Hin- und Rückfahrt ziehen:Wie kann Selen viele Aufrufe von isElementDisplay verarbeiten?

buttons = driver.find_elements_by_css_selector('button') 

Das Ergebnis buttons sein kann eine Liste von Dutzenden oder Hunderten von Elementen ohne Problem.

Aber Dinge langsam zu einem Crawl, wenn Sie die Elemente mit is_displayed() filtern möchten (oder wie Java es nennt, isElementDisplayed), weil jeder Aufruf der Methode einen Hin-und zurück zum Browser beinhaltet. Auch auf meiner schnellsten Entwicklungsmaschine jeden solcher Anruf dauert etwa 0,1 Sekunden, was bedeutet, dass die folgenden Filter über 100 Elemente dauern 10 Sekunden (!):

[b.is_displayed() for b in buttons] 

Das gleiche Problem tritt auf, wenn Sie für eine Schaltfläche aussehen wollen mit insbesondere Text, weil jeder Nachschlag des .text Attributs in der Tat ruft eine Unterkunft mit einem eigenen Round-Trip an den Browser zurück:

[('Subscribe' in b.text) for b in buttons] 

Dies macht es schwierig, robust Selenium-Tests zu schreiben, die die Aufmerksamkeit auf die zwei Dinge achten, dass sind in Bezug auf das DOM wirklich benutzerorientiert: ob ein Element sichtbar ist und welchen Text es enthält. Wenn wir uns vollständig von der Sichtbarkeit und dem Textinhalt wegbewegen, z. B. zu eindeutigen IDs oder Kombinationen von Klassen oder Dokumentenstandorten, würden unsere Tests schneller laufen, würde es stattdessen eine unsichtbare Verbindung zwischen unseren Selenium-Tests und der gesuchten Schaltfläche schaffen Die Testergebnisse behalten die Nutzererfahrung im Auge und sehen, was Nutzer auf dem Bildschirm sehen und lesen können.

Meine Frage:

  • Gibt es eine Möglichkeit is_displayed() oder ein text Test-Elemente über auf dem Browser während der anfänglichen entweder gelten holen von Elementen?

  • Oder gibt es noch eine Möglichkeit, einen Stapel is_displayed() Anruf, der über viele Elemente statt nur eine fragt fragt?

  • Oder ist eine 0.1s Round-Trip-Zeit von einem Python-Test zu Selenium unter Firefox einfach völlig unvernünftig und es läuft schneller für alle anderen und deshalb gibt es offensichtlich Batch-Versionen dieser gemeinsamen Operationen nicht existieren?

ich gedacht hatte, dass ich konnte nur schwenken execute_script() von Python zu laufen (Java Namen: executeScript()) und aus meinem JavaScript-Code irgendwie Selenium Logik ausführen, die hinter der komplizierten Idee liegt der „bin dieses Element sichtbar“. Leider scheint executeScript() Scripts keinen Zugang zu den util-Funktionen zu geben, die Selenium selbst als wesentlich erachtet. Um Zugriff auf eine is-visible-Funktion zu erhalten, müssten wir entweder jQuery oder ein zufälliges Selenium-Codefragment in Seiten ziehen, die ihnen sonst fehlen Das stört das gesamte Konzept eines Tests: Er testet die Seite wie sie ist, ohne ihr JS-Profil zu ändern, nur um unseren Test zu starten.

Danke für jede Idee! Ich bin ziemlich überrascht, dass Selenium erwartet, dass Anrufer wie is_displayed() wie ein Blick auf den Code schlägt, ein Hauptmerkmal von Selenium ist, das aussieht, als ob es viel Arbeit gekostet hat, um richtig zu werden, und das würde man wollen Zugriff von allem Code, der möglicherweise könnte, um zu vermeiden, ein so wichtiges Rad neu zu erfinden.

Antwort

3

Von was ich verstehe nach selenium Python Bindings Quellcode, gibt es keine Option zum Senden von Befehlen, wie isElementDisplayed, in Batches. Die Methode execute(), die für die Übertragung des Befehls über das JSON-Drahtprotokoll verantwortlich ist, verarbeitet jeweils nur einen Befehl.

FYI, hier ist die underlying isDisplayed() algorithm von der W3C Webdriver-Spezifikation. Und ich denke, this is what chrome webdriver itself has implemented.

Als Abhilfe kann und unter Berufung auf this solution, können wir Javascript (nicht getestet) ausführen:

script = """ 
function isHidden(el) { 
    var style = window.getComputedStyle(el); 
    return (style.display === 'none') 
} 

var result = []; 
for (var i = 0; i < arguments.length; i++) { 
    result.push(isHidden(arguments[i])); 
} 
return result; 
""" 

driver.execute_script(script, *buttons) 

Beachten Sie, dass es nicht mehr als eine Abhilfe ist da, streng genommen, nicht einmal in der Nähe ist, was Webdriver wirklich tut, um die Sichtbarkeit zu bestimmen.

Sprechen über den text Wert der Tastenelemente überprüft, eine mögliche Abhilfe, abgesehen von einem ähnlichen execute_script() Ansatz wäre einen XPath-Ausdruck zu verwenden und den Text überprüfen:

buttons = driver.find_elements_by_xpath('//button[contains(., "some text")]') 
+0

Ihr Test für die Sichtbarkeit tut nur ein winziger Bruchteil dessen, was die [WebDriver-Spezifikation] angibt (https://w3c.github.io/webdriver/webdriver-spec.html#dfn-element-displayed). Es wird Ergebnisse liefern, die nicht mit "is_displayed" und mit der Spezifikation übereinstimmen. – Louis

+1

@Louis 100% stimmen zu, deshalb wurde es als Workaround bezeichnet. Vielen Dank. – alecxe

Verwandte Themen