2010-11-05 3 views
14

Utilizziamo Selenium con l'API Java e alcune estensioni utente JavaScript. Utilizziamo molte chiamate AJAX nella nostra app. Molti dei nostri test falliscono casualmente perché a volte le chiamate AJAX terminano più lentamente delle altre volte, quindi la pagina non è completamente caricata. Lo aggiustiamo attendendo elementi specifici o Thread.sleep. Stavo cercando di trovare un modo per invece aspettare il completamento del traffico di rete. In modo da poter fare questo:Selenio - Attendi il traffico di rete

selenium.click("some JS button"); 
selenium.waitForNetwork(); 
assertTrue(something); 

In questo modo siamo in grado di sbarazzarsi del sonno filo e hanno test passano più velocemente quando il server risponde più velocemente e non avere così tanti test falliscono a causa di problemi di temporizzazione.

Non sono stato in grado di trovare un modo per farlo cercando su Google. Qualcuno ha qualche idea su come possiamo riuscirci? (Preferibilmente tramite Javascript o l'API Java ma tutti i suggerimenti sono benvenuti).

Nota: le altre varianti di "waitFor" non sono quello che sto cercando. Stiamo già utilizzando quelli in clic e altre cose. Sto cercando qualcosa che aspetti il ​​TRAFFICO DI RETE. Grazie per tutto il feedback, proverò un paio di suggerimenti, ma sono ancora aperto ad altre idee.

Grazie.

risposta

2

Update: io uso lo stesso metodo (wrapRequest) allo stesso modo con Selenium2 e funziona ancora. L'unica differenza è che non uso un'estensione utente. Eseguo semplicemente javascript per interrogare il codice che viene caricato da JSP.

Ecco cosa abbiamo finito per fare. (Nota, ci sono modi più semplici per ottenere se una chiamata Ajax è in esecuzione se si utilizza sempre un solo framework come JQuery. Abbiamo dovuto jimmy-rig un po 'di più perché abbiamo alcune pagine che usano JQuery e un gruppo che usano GWT)

Ho creato un file Javascript che ogni pagina carica solo se stai provando. (L'ho fatto includendo uno snippet nel modello JSP: se il parametro querystring di test viene passato come true, imposta un cookie.Se il cookie è impostato, includi il file javascript) Questo file javascript avvolge essenzialmente l'oggetto XMLHttpRequest per mantenere contare di tutte le richieste di invio:

function wrapRequest(xmlRequest) { 
    var oldSend = xmlRequest.prototype.send; 
    xmlRequest.prototype.send = function() { 
     var oldOnReady = this.onreadystatechange; 
     oldOnReady = function() { 
      oldOnReady.apply(this, arguments); 
      // if call is complete, decrement counter. 
     } 
     // increment counter 
     if(oldSend.apply) 
      oldSend.apply(this, arguments); 
     else if (oldOnReady.handleEvent) { //Firefox sometimes will need this 
      oldOnReady.handleEvent.apply(this, arguments); 
     } 
    } 
} 

C'è un po 'di più ad esso che quello, se async == false, ma che dovrebbe essere abbastanza facile da capire.

poi ho aggiunto una funzione per gli utenti di selenio-extensions.js che semplicemente si presenta così:

Selenium.prototype.getIsNetworkReady = function() { 
    if(this.browserbot.topWindow.isNetworkReady) { //sometimes this method is called before the page has loaded the isNetworkReady function 
     return this.browserbot.topWindow.isNetworkReady(); 
    } 
    return false; 
} 

Inoltre, notare il controllo sul topWindow: questo è dovuto al fatto che si ottiene problemi quando si seleziona un iframe.

Inoltre, sarà necessario chiamare il metodo wrapRequest sull'oggetto XMLHttpRequest di ogni iFrame che viene caricato. Lo faccio adesso usando: document.addEventListener("DOMNodeInserted", onElementAdded, true); e poi in onElementAdded, ho appena afferrato l'iframe quando è caricato e ho passato l'oggetto XMLHttpRequest. ma quello non funziona in IE quindi sto cercando un'alternativa. Se qualcuno conosce un modo migliore per farlo in modo che funzioni sia in IE che in FF mi piacerebbe ascoltarlo.

In ogni caso, questo è il succo dell'implementazione. Spero che questo aiuti chiunque in futuro.

0

Sì, fare qualcosa di simile (Pseudocodice):

int i = 0; 
while (element is not yet present) { 
    i++; 
    if (i>TRESHOLD) { 
    throw an exception 
    } 
    Thread.sleep(200); 
} 
//go on 

È propably vogliono roba in una funzione.

4

Ci sono pochi tipi di waitFor disponibili in Selenium. Nel tuo caso di test, se sei consapevole del fatto che un particolare testo dovrebbe apparire al caricamento della pagina, puoi usare waitForText. Se ci sono diversi elementi DOM che vengono popolati (tramite Ajax/pageload) è possibile aggiungere in sequenza waitForText.

1

Abbiamo già il codice lato client per modificare il cursore del mouse durante una richiesta AJAX (utilizzando a4j:status con attributi onstart e onstop). Quindi possiamo semplicemente waitFor il valore dell'espressione JavaScript

window.document.body.style.cursor 

Tuttavia, ho trovato che questo non funziona in modo affidabile, vale a dire a volte il test procede troppo presto. Non sono sicuro della causa, ma sospetto che l'aggiornamento del DOM non sia necessariamente completo quando viene invocato lo onstop.

Per quanto riguarda la riduzione del ritardo inutile, è possibile implementare il polling autonomamente e eseguire il polling più frequentemente rispetto al selenio.

4

Dopo aver provato tutte le variazioni descritte in questa pagina, abbiamo finito con questa strategia:

iniettare una speciale javascript che sostituisce in pratica tutti i vostri metodi quadro rilevanti e mantenere un contatore del numero di richieste incomplete, che viene incrementato all'avvio e decrementato al completamento. A causa della natura asincrona di javascript è non sufficiente per mantenere una variabile booleana, è probabile che tu finisca con le condizioni di gara all'interno della tua logica.

Se si utilizzano effetti visivi, è probabile che lo si desideri anche per gli effetti visivi; morphing/fading e altri elementi visivi avranno lo stesso problema.

Quindi fondamentalmente facciamo un "clic" regolare e quindi aspettiamo sempre che questo contatore raggiunga nuovamente 0, usando javascript come gli altri suggeriscono qui. Dopo aver ottenuto questo risultato, abbiamo ridotto i problemi transitori a nessuno.

Ricordare che il selenio non ritorna da "clic" finché non vengono elaborati tutti gli eventi onclick sincroni, pertanto è necessario assicurarsi che tali contatori vengano incrementati come conseguenza diretta di onclick.

Per istruzioni su come sovrascrivere i metodi framework è necessario consultare la documentazione del framework; usiamo addMethods in prototipo. È possibile mantenere questo override in un javascript speciale che viene aggiunto alla pagina solo quando si eseguono i test.

+0

Facciamo la stessa cosa per il nostro framework AJAX costruito in casa, chiamando la funzione IsTheCountZeroYet() in WaitForCondition(). Capisco che puoi farlo facilmente con jQuery. Altri quadri, forse anche. –

+0

La cosa interessante è che i contatori ajax in prototype.js sono bacati, non sempre ritornano a 0.E gli effetti visivi non hanno ancora questo tipo di contatore. Quindi abbiamo dovuto rollare il nostro. – krosenvold

1

Questo potrebbe non essere accettabile per voi, ma a causa dei problemi simili ci siamo spostati a Selenium 2 (aka WebDriver). Usiamo PageFactory con AjaxElementLocatorFactory

Per rendere più facile la migrazione, c'è un Selenium Emulation e il piano è di fondere completamente Selenio 1 e WebDriver, che è l'obiettivo principale di selenio 2.