Frage

Wir haben Selen mit großem Erfolg mit High-Level-Website Tests zu behandeln (zusätzlich zu umfangreichem Python Doctests auf einer Modul-Ebene). Aber jetzt sind wir extjs für viele Seiten mit und seine erweist sich als schwierig Selenium-Tests für die komplexen Komponenten wie Gitter einzubauen.

Hat jemand hat schriftlich Erfolg automatisierte Tests für extjs-basierte Web-Seiten? Viele googeln finden Menschen mit ähnlichen Problemen, aber nur wenig Antworten. Dank!

War es hilfreich?

Lösung

Die größte Hürde mit Selen bei der Prüfung ExtJS ist, dass ExtJS macht keine Standard-HTML-Elemente und die Selenium IDE wird naiverweise (und zu Recht) erzeugt Befehle an Elementen gezielt, die nur als Dekor wirkt - überflüssige Elemente, die ExtJS Hilfe bei der gesamtes Desktop-Look-and-Feel. Hier sind ein paar Tipps und Tricks, die ich gesammelt habe, während automatisierten Selenium Test gegen eine ExtJS App zu schreiben.

Allgemeine Tipps

Führungselemente

Wenn Selenium Testfälle erzeugen, durch Benutzeraktionen mit Selenium IDE auf Firefox Aufnahme wird Selen die aufgezeichneten Aktionen auf die IDs der HTML-Elemente stützen. Doch für die meisten klickbare Elemente verwendet ExtJS-IDs wie „ext-gen-345“ erzeugt, die bei einem späteren Besuch auf der gleichen Seite sind wahrscheinlich zu ändern, auch wenn keine Änderungen am Code vorgenommen wurden. Nach der Aufzeichnung von Benutzeraktionen für einen Test, bedarf es ein manueller Aufwand wird durch alle solche Aktionen zu gehen, die IDs auf erzeugt abhängen und sie zu ersetzen. Es gibt zwei Arten von Ersetzungen, die gemacht werden können:

Ersetzen eines Id Locator mit einem CSS oder XPath Locator

CSS Locators beginnen mit "CSS =" und XPath beginnen mit "//" (die "xpath =" Präfix ist optional). CSS Locators sind weniger ausführlich und sind leichter zu lesen und sollte über XPath bevorzugt werden. Allerdings kann es Fälle geben, wo XPath verwendet werden müssen, weil ein CSS-Locator kann es einfach nicht schneiden.

Ausführen von JavaScript

Einige Elemente benötigen mehr als einfache Maus / Tastatur-Interaktionen aufgrund des komplexen Rendering von ExtJS durchgeführt. Zum Beispiel ist ein Ext.form.CombBox nicht wirklich ein <select> Element, sondern eine Texteingabe mit einer frei stehenden Dropdown-Liste, die irgendwo am unteren Rande des Dokumentbaums ist. Um eine ComboBox Auswahl richtig zu simulieren, ist es möglich, einen Klick auf dem Dropdown-Pfeil, um zuerst zu simulieren und dann auf der Liste zu klicken, das angezeigt wird. Jedoch können diese Elemente durch CSS oder XPath-Ortung umständlich. Eine Alternative ist die ComoBox Komponente selbst und rufen Methoden auf ihn zu suchen um die Auswahl zu simulieren:

var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components
combo.setValue('female'); // set the value
combo.fireEvent('select'); // because setValue() doesn't trigger the event

In Selenium der runScript Befehl verwendet werden kann, die über den Betrieb in einer prägnanten Form auszuführen:

with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

Der Umgang mit AJAX und Slow Rendering

Selen hat „* AndWait“ Aromen für alle Befehle zum Warten auf Seite geladen wird, wenn ein Benutzer Aktion Ergebnisse in Seitenübergängen oder neu geladen. Da jedoch AJAX holt aktuelle Seite geladen wird nicht verbunden, können diese Befehle nicht zur Synchronisation verwendet werden. Die Lösung ist die Verwendung von visuellen Hinweisen wie das Vorhandensein / Fehlen eines AJAX Fortschrittsanzeige oder dem Auftreten von Zeilen in einem Raster, zusätzliche Komponenten, Links etc. Zum Beispiel zu machen:

Command: waitForElementNotPresent
Target: css=div:contains('Loading...')

Manchmal wird ein Element erst nach einer gewissen Zeit erscheinen, je nachdem wie schnell ExtJS Komponenten nach einer Benutzeraktion führt zu einer Änderung anzeigen macht. Anstelle von willkürlichen Verzögerungen bei dem pause Befehl verwendet, ist die ideale Methode, zu warten, bis das Element von Interesse in greifbarer Nähe gerückt kommt. Zum Beispiel auf einem Element klicken, um nach einer Wartezeit für sie angezeigt werden:

Command: waitForElementPresent
Target: css=span:contains('Do the funky thing')
Command: click
Target: css=span:contains('Do the funky thing')

auf beliebige Pausen Unter Berufung ist keine gute Idee, da Unterschiede Timing, die aus dem Ausführen der Tests in verschiedenen Browsern oder auf verschiedenen Maschinen führt die Testfälle flockig machen.

Non-klickbare Elemente

Einige Elemente können nicht vom click Befehl ausgelöst werden. Es ist, weil der Ereignis-Listener tatsächlich auf dem Behälter ist, gerade für Mausereignisse auf seine untergeordneten Elemente, die schließlich an die Mutter sprudeln. Die Registersteuer ist ein Beispiel. Zum Klicken auf die eine Registerkarte, haben Sie eine mouseDown Ereignis auf der Registerkarte Etikett zu simulieren:

Command: mouseDownAt
Target: css=.x-tab-strip-text:contains('Options')
Value: 0,0

Feldprüfung

Formularfelder (Ext.form. * Komponenten), die reguläre Ausdrücke oder vtypes für die Validierung in Verbindung gebracht wird tVorbereiter Validierung mit einer gewissen Verzögerung (die validationDelay Eigenschaft sehen, die auf 250ms voreingestellt ist), nachdem der Benutzer Text eingibt oder unmittelbar, wenn das Feld den Fokus verliert - oder Unschärfen (siehe validateOnDelay Eigenschaft). Um Feldvalidierung auszulösen, nachdem die Art Selenium Befehl ausgibt, etwas Text in einem Feld einzugeben, müssen Sie eine der folgenden Aufgaben:

  • Triggerung Verzögerte Validation

    ExtJS feuert die Validierung Verzögerungs-Timer ab, wenn das Feld Ereignis empfängt keyup. Um diesen Timer auslösen, geben Sie einfach ein Dummy-keyup Ereignis (es spielt keine Rolle, welche Tasten Sie verwenden als ExtJS ignoriert), gefolgt von einer kurzen Pause, die länger ist als die validationDelay:

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
  • Triggerung Sofortige Validierung

    Sie können eine Unschärfe Ereignis in das Feld injizieren sofortige Validierung auslösen:

    Command: runScript
    Target: someComponent.nameTextField.fireEvent("blur")
    

Überprüfung auf Validation Ergebnisse

Validierung Nach können Sie auf die Anwesenheit oder Abwesenheit eines Fehlers Feld überprüfen:

Command: verifyElementNotPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Command: verifyElementPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]
Hinweis

, dass die „display: none“. Prüfung ist notwendig, weil einmal eine Fehler-Feld angezeigt wird, und dann muss es ausgeblendet werden, ExtJS einfach Fehlerfeld verstecken, anstatt vollständig aus dem DOM-Baum zu entfernen

Element-spezifische Tipps

Durch Klicken auf ein Ext.form.Button

  • Option 1

    Befehl: klicken    Ziel: css = Taste: enthält ( 'Speicher')

    Wählt die Schaltfläche durch seine Beschriftung

  • Option 2

    Befehl: klicken    Ziel: css = # save-Optionen Taste

    Wählt die Schaltfläche durch seine id

Auswählen eines Werts aus einer Ext.form.ComboBox

Command: runScript
Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

Zuerst wird der Wert und dann feuert ausdrücklich das select-Ereignis in Fall gibt es Beobachter.

Andere Tipps

Das Blog viel hat mir geholfen. Er geschrieben ziemlich viel über das Thema und es scheint, wie es ist immer noch aktiv. Der Mann scheint auch ein gutes Design zu schätzen wissen.

Er spricht im Grunde über das Senden mit Hilfe von Javascript-Abfragen zu tun und mit der Ext.ComponentQuery.query Methode Sachen in der gleichen Art und Weise abrufen Sie intern in Ihrem ext App tun. Auf diese Weise Sie verwenden können xtypes und ItemIDs und müssen nicht befürchten versuchen, eine der verrückten automatisch generierten Dateien zu analysieren.

Ich fand insbesondere href="http://developertips.blogspot.co.uk/2013/09/locate-extjs-component-selenium-web.html"> sehr hilfreich.

Könnte etwas ein bisschen mehr detailliert hier bald veröffentlichen - immer noch meinen Kopf zu bekommen versuchen, um, wie diese richtig zu machen

Ich habe die Prüfung meiner ExtJs Web-Anwendung mit Selen. Eines der größten Probleme war ein Element in dem Gitter, um damit zu tun, etwas auswählen.

Dazu schrieb ich Helfer-Methode (in SeleniumExtJsUtils Klasse, die für eine einfachere Interaktion mit ExtJs eine Sammlung von nützlichen Methoden ist):

/**
 * Javascript needed to execute in order to select row in the grid
 * 
 * @param gridId Grid id
 * @param rowIndex Index of the row to select
 * @return Javascript to select row
 */
public static String selectGridRow(String gridId, int rowIndex) {
    return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)";
}

und wenn ich eine Zeile auszuwählen benötigen, würde ich rufen Sie einfach an:

selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) );

Damit dies funktioniert, muss ich meine ID auf dem Gitter setzen und nicht zulassen, ExtJs erzeugen seine eigene.

, dieses Element zu erkennen ist sichtbar Sie die Klausel verwenden: not(contains(@style, "display: none")

Es ist besser zu nutzen:

visible_clause = "not(ancestor::*[contains(@style,'display: none')" +
    " or contains(@style, 'visibility: hidden') " + 
    " or contains(@class,'x-hide-display')])"

hidden_clause = "parent::*[contains(@style,'display: none')" + 
    " or contains(@style, 'visibility: hidden')" + 
    " or contains(@class,'x-hide-display')]"

Können Sie mehr Einblick in die Art von Problemen die Sie haben mit extjs Tests?

Eine Selen-Erweiterung I nützlich ist WAITFORCONDITION . Wenn Ihr Problem Probleme mit dem Ajax Ereignissen zu sein scheint, können Sie WAITFORCONDITION verwenden, um für Veranstaltungen zu warten geschehen.

Ext JS Web-Seiten können schwierig sein wegen des komplizierten HTML zu testen, sie zu erzeugen am Ende wie mit Ext JS Gittern.

HTML5 Robot mit dieser befasst sich durch eine Reihe von Best Practices für die Verwendung, wie zuverlässig zum Nachschlagen und mit Komponenten basierend auf Attributen in Wechselwirkung treten und Bedingungen, die sind nicht dynamisch. Es bietet dann Verknüpfungen, dies zu tun mit all den HTML, Ext JS und Sencha Touch-Komponenten, die Sie benötigen, zu interagieren. Es kommt in zwei Geschmacksrichtungen:

  1. Java -. Vertrauen Selen und JUnit-basierte API, die für alle modernen Browser in Web-Treiber-Unterstützung gebaut
  2. Gwen - Eine menschliche Stil Sprache schnell und einfach erstellen und Browser-Tests beibehalten, die mit einer eigenen integrierten Entwicklungsumgebung kommt. All das basiert auf der Java-API.

Wenn Sie zum Beispiel fehlten die Ext JS Startreihe zu finden, den Text „Foo“ enthalten, können Sie den folgenden in Java tun:

findExtJsGridRow("Foo");

... und man konnte die folgende in Gwen tun:

extjsgridrow by text "Foo"

Es gibt eine Menge an Dokumentation für beide Java und Gwen, wie zu arbeiten mit Ext JS spezifischen Komponenten. Die Dokumentation beschreibt auch den resultierenden HTML-Code für alle diese Ext JS-Komponenten, die Sie auch von Nutzen sein können.

Nützliche Tipps für holen Raster über Id des Gitters auf der Seite: Ich glaube, Sie können mehr nützliche Funktion von dieser API erweitern.

   sub get_grid_row {
        my ($browser, $grid, $row)  = @_;


        my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" .
            "var grid = doc.getElementById('$grid');\n" .
            "var table = grid.getElementsByTagName('table');\n" .
            "var result = '';\n" .
            "var row = 0;\n" . 
            "for (var i = 0; i < table.length; i++) {\n" .
            "   if (table[i].className == 'x-grid3-row-table') {\n".
            "       row++;\n" . 
            "       if (row == $row) {\n" .
            "           var cols_len = table[i].rows[0].cells.length;\n" .
            "           for (var j = 0; j < cols_len; j++) {\n" .
            "               var cell = table[i].rows[0].cells[j];\n" .
            "               if (result.length == 0) {\n" .
            "                   result = getText(cell);\n" .
            "               } else { \n" .
            "                   result += '|' + getText(cell);\n" .
            "               }\n" .
            "           }\n" .
            "       }\n" .
            "   }\n" .
            "}\n" .
            "result;\n";

        my $result = $browser->get_eval($script);
        my @res = split('\|', $result);
        return @res;
    }

Einfachere Tests durch benutzerdefinierte HTML-Data- Attribute

Von der Sencha Dokumentation :

  

Ein itemId kann als Alternative Art und Weise verwendet werden, um einen Verweis auf eine Komponente zu erhalten, wenn keine Objektreferenz verfügbar ist. Statt eine ID mit Ext.getCmp arbeiten, verwendet itemId mit Ext.container.Container.getComponent den itemId oder die ids abruft. Da itemId der ein Index den internen MixedCollection des Behälters ist, wird der itemId lokal an den Behälter scoped -. Potentielle Konflikte mit Ext.ComponentManager vermieden werden, die eine eindeutige ID erfordert

Aufschalten der Ext.AbstractComponent Methode des onBoxReady, habe ich ein Attribut benutzerdefinierte Daten (deren Name kommt von meiner benutzerdefinierten testIdAttr Eigenschaft jeder Komponente) auf die itemId Wert der Komponente, wenn es vorhanden ist. Fügen Sie die Testing.overrides.AbstractComponent Klasse zu Ihrer application.js Datei requires Array.

/**
 * Overrides the Ext.AbstracComponent's onBoxReady
 * method to add custom data attributes to the
 * component's dom structure.
 *
 * @author Brian Wendt
 */
Ext.define('Testing.overrides.AbstractComponent', {
  override: 'Ext.AbstractComponent',


  onBoxReady: function () {
    var me = this,
      el = me.getEl();


    if (el && el.dom && me.itemId) {
      el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId);
    }


    me.callOverridden(arguments);
  }
});

Diese Methode bietet Entwicklern eine Möglichkeit, einen beschreibenden Bezeichner in ihrem Code wiederverwenden und die Identifier zur Verfügung, jedes Mal haben die Seite gerendert wird. Kein lästiges Suchen durch nicht-deskriptiven, dynamisch generierte IDs.

Wir entwickeln einen Test-Framework, das Selen und auftretenden Probleme mit extjs verwendet (da es Client-Seite-Rendering). Ich finde es nützlich für ein Element zu suchen, sobald das DOM bereit ist.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
    def maxSeconds = DEFAULT_WAIT_SECONDS * 10
    for (count in 1..maxSeconds) {
        Thread.sleep(100)
        def ready = isDOMReady(driver);
        if (ready) {
            break;
        }
    }
}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

Für komplex Benutzeroberfläche, die nicht formale HTML ist, ist xPath immer etwas, das Sie sich verlassen können, aber ein wenig komplexe, wenn es darum geht, verschiedene UI-Implementierung unter Verwendung von ExtJS.

Sie können Firebug und Firexpath als Firefox-Erweiterungen verwenden, um ein bestimmtes Element des XPath zu testen und einfachen Pass voll XPath als Parameter an Selen.

Zum Beispiel in Java-Code:

String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button"

selenium.click(fullXpath);

Als ich ExtJS Anwendung Tests mit WebDriver ich nächsten Ansatz verwendet: suchte ich nach Feld von Text des Labels und bekam @for Attribut von Label. Zum Beispiel haben wir ein Label

<label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for">
Name Of Needed Label
<label/>

Und wir müssen zeigen WebDriver eine Eingabe. //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)]

So wird es die ID von @for Attribute holen und weiter verwenden. Dies ist wahrscheinlich der einfachste Fall, aber es gibt Ihnen die Möglichkeit, Element zu lokalisieren. Es ist viel schwieriger, wenn Sie kein Label haben, aber dann müssen Sie ein Element finden und Ihre XPath schreiben für Geschwister suchen, steigen / ascend Elemente.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top