Domanda

Stiamo usando il selenio, con grande successo, per gestire ad alto livello di test del sito (oltre alla vasta python doctests a livello di modulo).Tuttavia, ora stiamo usando extjs per un sacco di pagine e difficili da incorporare Selenio test per i componenti complessi come le griglie.

Qualcuno ha avuto successo la scrittura di test automatizzati per extjs a base di pagine web?Un sacco di ricerche su google, trova persone con problemi simili, ma poche risposte.Grazie!

È stato utile?

Soluzione

Il più grande ostacolo in fase di test ExtJS con il Selenio è che ExtJS non eseguire il rendering di elementi standard del HTML e Selenium IDE ingenuamente (e giustamente) generare i comandi mirati a elementi che proprio agire come arredamento-elementi superflui che aiutano ExtJS con l'intero desktop-look-and-feel.Qui ci sono alcuni suggerimenti e trucchi che ho raccolto durante la scrittura automatizzata Selenio test contro un ExtJS app.

Consigli Generali

Individuazione Di Elementi Di

Quando la generazione di Selenio casi di test da registrazione azioni utente con Selenium IDE su Firefox, Selenio base azioni registrate su gli id degli elementi HTML.Tuttavia, per la maggior parte cliccabile elementi, ExtJS utilizza generato id come "ext-gen-345", che sono suscettibili di cambiamento in una visita successiva alla stessa pagina, anche se nessun codice sono state apportate modifiche.Dopo la registrazione azioni utente per un test, c'è bisogno di essere un manuale sforzo per passare attraverso tutte le azioni che dipendono generato id e sostituirli.Ci sono due tipi di sostituzioni che possono essere fatte:

La sostituzione di un Id Locator con un CSS o XPath Locator

CSS localizzatori iniziano con "css=" e XPath localizzatori iniziano con "//" (il "xpath=" prefisso è opzionale).CSS indicatori sono meno prolisso e più facile da leggere e dovrebbe essere preferito a XPath localizzatori.Tuttavia, ci possono essere casi in cui XPath indicatori devono essere utilizzati a causa di un CSS localizzatore semplicemente non si può tagliare.

L'Esecuzione Di JavaScript

Alcuni elementi richiedono di più di un semplice mouse/tastiera interazioni a causa della complessa di rendering effettuato da ExtJS.Per esempio, un Ext.forma.CombBox non è davvero un <select> elemento, ma un testo di input con distaccata di riepilogo a discesa che da qualche parte in fondo all'albero del documento.Per simulare correttamente un ComboBox di selezione, è possibile prima di simulare un clic sulla freccia a discesa e quindi fare clic su elenco che appare.Tuttavia, l'individuazione di questi elementi attraverso i CSS o XPath indicatori può essere ingombrante.Un'alternativa è quella di individuare il ComoBox componente stesso e chiamare i metodi per simulare la selezione:

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 Selenio l' runScript il comando può essere utilizzato per eseguire l'operazione in modo più conciso:

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

Affrontare con AJAX e Rallentare il Rendering

Il selenio, "*AndWait" sapori di tutti i comandi per i tempi di attesa per il caricamento della pagina quando un utente azione risultati in transizioni di pagina o ricarica.Tuttavia, poiché AJAX recupera non comportano l'effettivo caricamento della pagina, questi comandi non può essere utilizzato per la sincronizzazione.La soluzione è di fare uso di indizi visivi, come la presenza/assenza di un AJAX indicatore di progresso o la comparsa di righe della griglia, componenti aggiuntivi, link, etc.Per esempio:

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

A volte un elemento apparirà solo dopo un certo periodo di tempo, a seconda di quanto velocemente ExtJS rende i componenti dopo un azione da parte dell'utente dei risultati in un'ottica di cambiamento.Invece di utilizzare arbitrario ritardi con la pause comando, il metodo ideale è quello di aspettare fino a quando l'elemento di interesse è a nostra portata.Per esempio, per fare clic su un elemento, dopo aver aspettato per farlo apparire:

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

Basandosi su arbitrario pause non è una buona idea, dato che le differenze temporanee risultanti dall'esecuzione del test in browser diversi o su macchine diverse renderà i casi di test a falde.

Non cliccabile Elementi

Alcuni elementi non possono essere attivati dalle click comando.Perché il listener di eventi è in realtà il contenitore, guardando gli eventi del mouse sul suo bambino elementi, che alla fine bolle al genitore.La scheda di controllo è un esempio.Per fare clic su una scheda, è necessario simulare un mouseDown evento presso l'etichetta della scheda:

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

La Convalida Del Campo

I campi modulo (Ext.forma.* componenti) a cui sono associate le espressioni regolari o vtypes per la convalida del trigger di convalida con un certo ritardo (vedere il validationDelay la struttura, che è impostato a 250ms per impostazione predefinita), dopo che l'utente immette il testo, o immediatamente quando il campo perde la messa a fuoco-o sfocature (vedere il validateOnDelay la struttura).Per attivare la convalida del campo dopo l'emanazione del tipo di Selenio comando per inserire del testo all'interno di un campo, è necessario effettuare una delle seguenti operazioni:

  • Attivazione Ritardata Convalida

    ExtJS spara la convalida del timer di ritardo quando il campo riceve keyup eventi.Per attivare il timer, è sufficiente eseguire un manichino evento keyup (non importa quale tasto si usa come ExtJS ignora), seguiti da una breve pausa più lunga dell'validationDelay:

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
  • Attivazione Immediata Convalida

    Si può iniettare una sfocatura evento nel campo di attivazione immediata di convalida:

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

Verifica per la Validazione dei Risultati

A seguito di convalida, è possibile verificare la presenza o l'assenza di un campo di errore:

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"))]

Si noti che il "display:nessuno di controllo" è necessario perché una volta un campo di errore viene visualizzato e quindi ha bisogno di essere nascosto, ExtJS semplicemente nascondere il campo di errore invece di rimuoverlo dall'albero DOM.

Elemento-Suggerimenti

Fare clic su un Ext.forma.Pulsante

  • Opzione 1

    Comando:fare clic su Destinazione:css=pulsante:contiene ("Salva")

    Seleziona il pulsante per la didascalia

  • Opzione 2

    Comando:fare clic su Destinazione:css=#salva-pulsante opzioni

    Seleziona il pulsante per id

La selezione di un Valore da un Ext.forma.ComboBox

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

Per prima cosa imposta il valore e quindi in modo esplicito incendi evento select nel caso in cui ci sono gli osservatori.

Altri suggerimenti

Questo blog mi ha aiutato molto. Ha scritto parecchio sull'argomento e sembra che sia ancora attivo. Il ragazzo sembra anche apprezzare il buon design.

Parla fondamentalmente dell'uso dell'invio di javascript per eseguire query e dell'utilizzo del metodo Ext.ComponentQuery.query per recuperare le cose nello stesso modo in cui si fa all'interno dell'app ext internamente. In questo modo puoi usare xtypes e itemIds e non devi preoccuparti di provare ad analizzare qualsiasi roba folle generata automaticamente.

Ho trovato questo articolo in particolare molto utile.

Potrei pubblicare presto qualcosa di più dettagliato qui - ancora cercando di capire come fare correttamente

Ho testato la mia applicazione Web ExtJs con selenio. Uno dei maggiori problemi era selezionare un elemento nella griglia per farci qualcosa.

Per questo, ho scritto il metodo helper (nella classe SeleniumExtJsUtils che è una raccolta di metodi utili per una più facile interazione con ExtJs):

/**
 * 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)";
}

e quando avevo bisogno di selezionare una riga, chiamavo semplicemente:

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

Perché questo funzioni, devo impostare il mio ID sulla griglia e non lasciare che ExtJs generi il proprio.

Per rilevare quell'elemento è visibile si usa la clausola: not(contains(@style, "display: none")

È meglio usare questo:

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')]"

Puoi fornire maggiori informazioni sui tipi di problemi che stai riscontrando con i test extjs?

Un'estensione di selenio che trovo utile è waitForCondition . Se il tuo problema sembra essere un problema con gli eventi Ajax, puoi utilizzare waitForCondition per attendere che si verifichino eventi.

Le pagine web di Ext JS possono essere difficili da testare, a causa del complicato HTML che finiscono per generare come con le griglie Ext JS.

Robot HTML5 si occupa di questo utilizzando una serie di best practice per la ricerca e l'interazione affidabili con i componenti in base agli attributi e condizioni che non sono dinamiche. Fornisce quindi scorciatoie per farlo con tutti i componenti HTML, Ext JS e Sencha Touch con i quali avresti bisogno di interagire. È disponibile in 2 gusti:

  1. Java - Familiare API basata su Selenium e JUnit che ha integrato il supporto del driver Web per tutti i browser moderni.
  2. Gwen : un linguaggio di stile umano per creare e mantenere in modo semplice e rapido test del browser, fornito con un proprio ambiente di sviluppo integrato. Tutto ciò si basa sull'API Java.

Ad esempio, se si desidera trovare la riga della griglia Ext JS contenente il testo " Foo " ;, è possibile effettuare le seguenti operazioni in Java:

findExtJsGridRow("Foo");

... e potresti fare quanto segue in Gwen:

extjsgridrow by text "Foo"

C'è molta documentazione sia per Java sia per Gwen con componenti specifici Ext JS. La documentazione descrive anche in dettaglio il codice HTML risultante per tutti questi componenti Ext JS, che potresti trovare utile.

Suggerimenti utili per recuperare la griglia tramite ID della griglia nella pagina: Penso che puoi estendere le funzioni più utili da questa API.

   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;
    }

Test più semplici tramite attributi di dati HTML personalizzati

Dalla Documentazione Sencha :

  

Un itemId può essere usato come un modo alternativo per ottenere un riferimento a un componente quando non è disponibile alcun riferimento all'oggetto. Invece di usare un id con Ext.getCmp, usa itemId con Ext.container.Container.getComponent che recupererà itemId o id. Poiché itemId's è un indice del MixedCollection interno del contenitore, itemId è localizzato localmente nel contenitore, evitando potenziali conflitti con Ext.ComponentManager che richiede un ID univoco.

Sovrascrivendo il metodo Ext.AbstractComponent del onBoxReady, ho impostato un attributo di dati personalizzati (il cui nome deriva dalla mia proprietà testIdAttr personalizzata di ciascun componente) sul valore itemId del componente, se esiste. Aggiungi la classe Testing.overrides.AbstractComponent all'array application.js del tuo file requires.

/**
 * 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);
  }
});

Questo metodo fornisce agli sviluppatori un modo per riutilizzare un identificatore descrittivo all'interno del loro codice e per rendere disponibili tali identificatori ogni volta che viene eseguito il rendering della pagina. Non dovrai più cercare tra ID non descrittivi e generati dinamicamente.

Stiamo sviluppando un framework di test che utilizza il selenio e ha riscontrato problemi con extjs (dal momento che è il rendering lato client). Trovo utile cercare un elemento quando il DOM è pronto.

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");
}

Per l'interfaccia utente complessa che non è un HTML formale, xPath è sempre qualcosa su cui puoi contare, ma un po 'complesso quando si tratta di un'implementazione dell'interfaccia utente diversa utilizzando ExtJs.

Puoi usare Firebug e Firexpath come estensioni di firefox per testare un certo xpath di un elemento, e passare semplicemente xpath completo come parametro al selenio.

Ad esempio nel codice Java:

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

selenium.click(fullXpath);

Quando stavo testando l'applicazione ExtJS usando WebDriver ho usato l'approccio successivo: ho cercato il campo dal testo dell'etichetta e ho ottenuto l'attributo @for dall'etichetta. Ad esempio, abbiamo un'etichetta

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

E dobbiamo indicare a WebDriver alcuni input: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)].

Quindi, sceglierà l'id dall'attributo <=> e lo userà ulteriormente. Questo è probabilmente il caso più semplice, ma ti dà il modo di individuare l'elemento. È molto più difficile quando non hai un'etichetta ma devi trovare qualche elemento e scrivere il tuo xpath in cerca di fratelli, elementi discendenti / ascendenti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top