有没有办法优化/加速使用Protractor将数据发送到UI?

时间:2014-09-05 15:17:39

标签: angularjs selenium-webdriver webdriver protractor chrome-web-driver

我的代码类似于:

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

这是page.sendKeys功能。请注意,目前这并没有做任何承诺或类似的回报。如果函数编码不好,那么欢迎评论:

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

我看着它慢慢填满我屏幕上的每个字段,然后在接下来的更多测试中一次又一次地重复它。

有没有什么方法可以优化它,或者我必须等待一个字段接一个填充并且必须忍受需要很长时间才能运行的测试?

我认为sendKeys是基于承诺的。我可以使用 AngularJS $ q 同时发出所有sendKeys,然后使用$ q等待它们完成吗?

5 个答案:

答案 0 :(得分:10)

潜在的解决方案我认为无论你如何优化它,至少需要一点hackery - 量角器不会为你提供开箱即用的功能。然而,像这样的小帮手功能是否适合您的需求?你还需要什么来加速text input的{​​{1}} ng-model次?

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

解决方案示例:

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

为什么解决方案有效?

您需要使用$eval来包装作业,而不仅仅是作业evaluate不评估副作用(嵌套评估,但是......嘿)。假设角度表达式中的真实性,则从$digest()调用&&;这会导致摘要发生,您需要更新所有内容,因为您在摘要周期之外设置了一个值。

关于解决方案的想法:

E2E测试背后的整个想法是使用您的应用“模仿”最终用户。这可以说不是那么做,而是一个一个地发送密钥,或者复制粘贴(因为粘贴到元素中是输入输入的有效方式;由于闪存等原因很难设置) ,见下文)。

其他潜在解决方案:

  • 复制并粘贴:创建元素,输入文本,复制文本,将发送Ctrl + V的文本粘贴到目标元素。这可能需要做一些花哨的步法,比如使用Flash(暴露系统剪贴板是一种安全风险)并且“复制它”点击一个看不见的flash播放器。请参阅executeScript以评估目标上的功能,以便在需要时可以访问window等变量。

  • 并行测试。阅读官方文档here并搜索“shard”然后搜索“multiple”。如果您主要担心整个测试集合的持续时间而不是单独的测试,那么扩展浏览器数量可能就好了。然而,你很有可能是TDD-ing或其他东西,因此需要每个测试运行得更快。

答案 1 :(得分:3)

您可以执行以下操作 -

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默认返回promise。见这里 - 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);
} 

答案 2 :(得分:2)

如果你真的想加快以任何方式操纵DOM的过程(包括填写数据表格),可以考虑使用:browser.executeScriptbrowser.executeAsyncScript。在这种情况下,webdriver让浏览器自己执行脚本 - 唯一的开销是将脚本体发送到浏览器,所以我认为没有更快的事情。

从我看到的,你通过id识别DOM元素,所以它应该顺利地与我提出的方法一起工作。

这是它的支架 - 测试它并且它工作正常:

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

小评论:如果您将webdriver.WebElement作为参数之一传递,则会将其转换为相应的DOM element

答案 3 :(得分:0)

我还使用了browser.executeScript。但我并不需要使用$ apply waitForAngular

我在运行E2E测试时添加一个脚本,并在全局范围内添加一个函数,不要只在E2E测试期间担心它,如果你愿意,你可以命名。

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

然后在你的量角器测试中(在页面对象中):

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

答案 4 :(得分:0)

以下在测试 angular 2 应用程序时对我有用

await browser.executeScript("arguments[0].value='" + inputText + "';", await element.by.css("#cssID"))

灵感来自https://stackoverflow.com/a/43404924/6018757