12

Ich habe Code ähnlich wie diese:Gibt es eine Möglichkeit, das Senden von Daten an eine Benutzeroberfläche mit Protractor zu optimieren/beschleunigen?

ExamPage.prototype.enterDetailsInputData = function (modifier) { 
    page.sendKeys(this.modalExamName, 'Test Exam ' + modifier); 
    page.sendKeys(this.modalExamVersionId, 'Test exam version ' + modifier); 
    page.sendKeys(this.modalExamProductVersionId, 'Test exam product version ' + modifier); 
    page.sendKeys(this.modalExamAudienceId, 'Test exam audience ' + modifier); 
    page.sendKeys(this.modalExamPublishedId, '2014-06-1' + modifier); 
    page.sendKeys(this.modalExamPriceId, '100' + modifier); 
    page.sendKeys(this.modalExamDurationId, '6' + modifier); 
}; 

Hier ist die page.sendKeys Funktion. Beachten Sie, dass dies derzeit keine Versprechen oder ähnliches zurückgibt. Ist die Funktion nicht gut, dann codiert Ich begrüße Kommentare:

// page.sendkeys function 
sendKeys(id: string, text: string) { 
    element(by.id(id)).sendKeys(text); 
} 

Ich beobachte, wie es füllt sich langsam jedes Feld auf meinem Bildschirm und dann wiederholt er immer wieder in mehr Tests, die folgen.

Gibt es irgendeine Möglichkeit, dass dies optimiert werden könnte oder muss ich warten, bis ein Feld nach dem anderen gefüllt ist und mit Tests leben muss, die lange dauern?

Ich nehme an, sendKeys ist Versprechen basiert. Könnte ich zum Beispiel AngularJS $ q verwenden, um alle sendKeys gleichzeitig auszugeben und dann $ q zu verwenden, um auf sie zu warten?

+0

Welchen Browser verwenden Sie Sie? Oder hängt es tatsächlich vom Browser ab? – alecxe

+0

Ich verwende momentan den Chrome-Browser, aber ich nehme an, dass es bei allen Browsern gleich ist. Die Tests werden langsam ausgeführt, da jedes Feld einzeln ausgefüllt wird. Das Problem ist, ich habe viele Felder ausgefüllt und meine Testsuite dauert länger und länger. –

+0

Eine Option könnte sein, die Mock-Modul-Funktionalität des Winkelmessers zu verwenden, so dass Ihr Controller bereits die Werte an den Bereich gebunden hat. Dadurch wird das Ausfüllen des Formulars jedes Mal vermieden, wenn – scarlz

Antwort

10

mögliche Lösung Ich denke, zumindest ein wenig hackery egal erforderlich ist, wie Sie es optimieren - Winkelmesser geben Sie nicht diese aus dem Kasten heraus. Aber würde eine kleine Helferfunktion wie diese Ihren Bedürfnissen entsprechen? Was brauchen Sie noch, um Seiten zu beschleunigen textinput s mit ng-model s?

function setNgModelToString(element, value) { 
    return element.getAttribute('ng-model').then(function (ngModel) { 
     element.evaluate('$eval("' + ngModel + ' = \'' + value + '\'") && $digest()'); 
    }); 
} 

Lösung Beispiel:

describe('angularjs homepage', function() { 
    it('should have a title', function() { 
    browser.get('http://juliemr.github.io/protractor-demo/'); 

    var inputString1 = ''; 
    var inputString2 = ''; 
    for (var i = 0; i < 1000; i++) { 
     inputString1 += '1'; 
     inputString2 += '2'; 
    } 

    /* Uncomment this to see it runs much much slower when you enter each key. */ 
    //element(by.model('second')).sendKeys(inputString1); 

    setNgModelToString(element(by.model('second')), inputString2); 

    expect(element(by.model('second')).getAttribute('value')).toEqual(inputString2); 
    }); 
}); 

Warum funktioniert die Lösung?

Sie müssen $eval verwenden, um die Zuweisung und nicht nur Zuweisung zu wickeln, da evaluate keine Nebenwirkungen bewertet (eine geschachtelte Auswertung, obwohl ... heh). Angenommen, das ist in Winkelausdrücken truthy, dann wird $digest() von der && aufgerufen; Dies führt zu einem Digest, bei dem Sie alles aktualisieren müssen, da Sie einen Wert außerhalb des Digest-Zyklus festlegen.

Gedanken über die Lösung:

Die ganze Idee hinter einem E2E-Test ist ein End-Benutzer mit Ihrer App zu "emulieren". Das geht wohl auch nicht so, wie wenn man die Tasten einzeln oder nach dem Kopieren-und-Einfügen-Befehl sendet (seit dem Einfügen in Elemente ist das ein gültiger Eingang), es ist nur schwer, es durch Flash usw. einzurichten. , siehe unten).

Andere Potential Lösungen:

  • Kopieren und Einfügen: ein Element erstellen, geben Sie den Text, kopieren Sie sie, fügen Sie den Text zu senden Strg + V an das Zielelement.Dies kann erfordern eine Reihe von ausgefallenen Fußarbeit, wie die Verwendung von Flash (Aussetzen der Systemzwischenablage ist ein Sicherheitsrisiko) und "Kopieren" klicken Sie auf einen unsichtbaren Flash-Player. Siehe executeScript, um Funktionen auf dem Ziel auszuwerten, so dass Sie Zugriff auf Variablen wie window haben, wenn Sie das benötigen.

  • Parallelisieren Sie Ihre Tests. Lesen Sie das offizielle Dokument here und suchen Sie nach "shard" und dann "multiple". Wenn Sie hauptsächlich über die Dauer Ihrer gesamten Testsammlung und nicht über einzelne Tests besorgt sind, ist es wahrscheinlich die beste Lösung, die Anzahl Ihrer Browser zu verringern. Allerdings gibt es eine gute Chance, dass Sie TDD-ing oder etwas sind, daher muss jeder Test schneller ausgeführt werden. browser.executeScript oder browser.executeAsyncScript: verwenden

+1

sehr gut durchdacht –

+1

Einfach genial, mein einfacher Login-Test ging von 29.27 Sekunden auf 4.467 runter. – vonwolf

+0

Funktioniert das immer noch in Angular> = 2? Ich versuchte es und scheint in https://stackoverflow.com/questions/36201691/protractor-angular-2-failed-unknown-error-angular-is-not-defined zu laufen –

3

Sie können folgendes tun -

ExamPage.prototype.enterDetailsInputData = function (modifier) { 
var arr=[ 
{id:this.modalExamName, text:'Test Exam ' + modifier}, 
{id:this.modalExamVersionId, text:'Test exam version ' + modifier }, 
{id:this.modalExamProductVersionId, text:'Test exam product version ' + modifier}, 
{id:this.modalExamAudienceId,text:'Test exam audience ' + modifier}, 
{id:this.modalExamPublishedId, text:'2014-06-1' + modifier}, 
{id:this.modalExamPriceId, text:'100' + modifier}, 
{this.modalExamDurationId, text:'6' + modifier} 
]; 
var Q = require('q'), 
    promises = []; 
for (var i = 0; i < arr.length; i++) { 
    promises.push(page.sendKeys(arr[i].id, arr[i].text)); 
} 

Q.all(promises).done(function() { 
    //do here whatever you want 
}); 

}; 

Sendkeys Renditen versprechen standardmäßig. Sehen Sie hier - https://github.com/angular/protractor/blob/master/docs/api.md#api-webdriver-webelement-prototype-sendkeys

sendKeys(id: string, text: string) { 
    return element(by.id(id)).sendKeys(text); 
} 
+0

Müsste ich page.sendKeys ändern, da es momentan kein Versprechen gibt? Wenn ich es ändern muss, wie könnte ich das tun? –

+0

SendKey gibt das Versprechen standardmäßig zurück. Ich denke, es sollte funktionieren. Ich habe auch die Antwort aktualisiert. – pankaj

+0

Ich verstehe, dass sendkey ein Versprechen zurückgibt, aber in meiner Anwendung geschieht das innerhalb der Funktion sendKeys (id: string, text: string) { element (by.id (id)) sendKeys (text); } Wird das Versprechen immer noch von page.sendKeys zurückgegeben? –

2

Wenn Sie wirklich beschleunigen wollen, ist der Prozess der Manipulation DOM in irgendeiner Weise (einschließlich Auffüllen Datenformulare) eine Option zu prüfen. In solch einem Fall kann der Browser mit dem webdriver das Skript eigenständig ausführen - der einzige Overhead ist, den Skriptkörper an den Browser zu senden, also glaube ich nicht, dass es etwas schneller geben könnte.

Von was ich sehe, identifizieren Sie DOM-Elemente von id s so sollte es reibungslos mit dem Ansatz, den ich vorschlagen, arbeiten.

ist hier ein Gerüst ihn - es getestet und es funktioniert gut:

browser.get('someUrlToBeTested'); 
browser.waitForAngular(); 
browser.executeScript(function(param1, param2, param3){ 

     // form doc: arguments may be a boolean, number, string, or webdriver.WebElement 
     // here all are strings: param1 = "someClass", param2 = "someId", param3 = "someModifier" 
     var el1 = document.getElementsByClassName(param1)[0]; 
     var el2 = document.getElementById(param2); 

     el1.setAttribute('value', 'yoohoo ' + param3); 
     el2.setAttribute('value', 'hooyoo ' + param3); 

     // depending on your context it will probably 
     // be needed to manually digest the changes 
     window.angular.element(el1).scope().$apply(); 


},'someClass', 'someId', 'someModifier') 

kleine Bemerkung: Wenn Sie webdriver.WebElement als eine Ihres Arguments übergeben wird es bis auf die entsprechenden DOM element gegossen werden.

0

Ich habe auch browser.executeScript verwendet. Aber ich brauchte nicht $ anwenden waitForAngular

Ich füge ein Skript, wenn E2E-Tests ausgeführt werden, und setzen Sie eine Funktion auf globalen Bereich, keine Sorge, es ist nur während E2E-Tests, und Sie können Namespace, wenn Sie wollen zu.

'use strict'; 
function fastSendKeys(testId, value) { 
    //test id is just an attribute we add in our elements 
    //you can use whatever selector you want, test-id is just easy and repeatable 
    var element = jQuery('[test-id=' + '"' + testId + '"' + ']'); 
    element.val(value); 
    element.trigger('input'); 
} 

Dann in Ihrem Winkelmesser Test so etwas wie diese (in einem Seitenobjekt):

this.enterText = function (testId, value) { 
     var call = 'fastSendKeys(' + '"' + testId + '"' + ',' + '"' + value + '"' + ')'; 
     console.log('call is ', call); 
     browser.executeScript(call); 
    }; 
Verwandte Themen