有没有办法使用量角器优化/加快向 UI 发送数据的速度?

Is there any way to optimize / speed up the sending of data to a UI with Protractor?

提问人:Samantha J T Star 提问时间:9/5/2014 最后编辑:Samantha J T Star 更新时间:1/18/2021 访问量:2400

问:

我有类似这样的代码:

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 是基于 promise 的。例如,我可以使用 AngularJS $q 同时发出所有 sendKey,然后使用 $q 等待它们完成吗?

angularjs selenium-webdriver webdriver 量角器 chrome-web-driver

评论

0赞 alecxe 9/5/2014
您使用哪种浏览器?或者,它实际上取决于浏览器吗?
0赞 Samantha J T Star 9/6/2014
我目前正在使用 Chrome 浏览器,但我认为所有浏览器都是一样的。测试运行缓慢,因为我看到每个字段都被一个接一个地填写。问题是我填写了很多字段,我的测试套件需要的时间越来越长。
0赞 scarlz 9/6/2014
一种选择是使用量角器的模拟模块功能,以便控制器已经将值绑定到作用域,从而绕过每次填写表单的需要
1赞 Thomas Roch 9/12/2014
Q 无济于事。量角器基于WebdriverJS,具有控制流。当您使用 sendKeys 时,它会将它们全部调度,然后一个接一个地执行它们。您可以查看 code.google.com/p/selenium/wiki/WebDriverJs(“定义多个控制流”)。

答:

3赞 pankaj 9/8/2014 #1

您可以执行以下操作 -

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

评论

0赞 Samantha J T Star 9/8/2014
我是否需要更改page.sendKeys,因为目前它不返回承诺?如果我需要更改它,那么我该怎么做呢?
0赞 pankaj 9/9/2014
默认情况下,Sendkey 返回 promise。我想它应该有效。我也更新了答案。
0赞 Samantha J T Star 9/9/2014
我知道 sendkey 返回一个承诺,但在我的应用程序中,这发生在函数 sendKeys(id: string, text: string) { element(by.id(id)).sendKeys(text);那么 promise 还会从 page.sendKeys 返回吗?
0赞 pankaj 9/9/2014
是的,在它之前使用 return:return element(by.id(id)).sendKeys(text);
11赞 Jesus is Lord 9/9/2014 #2

潜在解决方案我认为无论你如何优化它,至少需要一点黑客 - 量角器不会给你开箱即用的东西。但是,像这样的小帮手功能会满足您的需求吗?你还需要什么来加速 s 和 s 的边?textinputng-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);
  });
});

为什么该解决方案有效?

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

关于解决方案的想法:

E2E 测试背后的整个想法是“模拟”使用您的应用程序的最终用户。可以说,这并不能像逐个发送键或复制粘贴键那样做到这一点(因为粘贴到元素中是输入输入的有效方式;由于闪存等原因很难设置,请参见下文)。

其他可能的解决方案:

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

  • 并行化测试。在此处阅读官方文档并搜索“分片”,然后搜索“多个”。如果您主要担心整个测试集合的持续时间,而不是单个测试,那么横向扩展浏览器计数可能是要走的路。但是,您很有可能是 TDD 或其他东西,因此需要每个测试运行得更快。

评论

1赞 Dave Alperovich 9/14/2014
经过深思熟虑
1赞 vonwolf 1/29/2016
简直太棒了,我的简单登录测试从 29.27 秒下降到 4.467 秒。
1赞 Jeremy Kahan 3/7/2018
这在 Angular>=2 中仍然有效吗?我试过了,似乎遇到了 stackoverflow.com/questions/36201691/......
2赞 artur grzesiak 9/9/2014 #3

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

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

这是它的脚手架 - 测试了它,它工作正常:

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.WebElementDOM element

0赞 binarygiant 8/5/2015 #4

我也用了.但我不需要使用$applybrowser.executeScriptwaitForAngular

我在 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);
    }; 
0赞 Bruno Degomme 1/18/2021 #5

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

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

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