【问题标题】:E2E tests with multiple pages with information from browser使用来自浏览器的信息的多个页面进行 E2E 测试
【发布时间】:2017-02-19 04:00:47
【问题描述】:

我正在使用量角器编写 E2E 测试。我不得不从浏览器中获取信息并多次执行一个步骤。

我正在测试一个屏幕,它会在

  • 用户点击“开始”
  • 登陆新页面
  • 调用下面的工作流,计数作为参数传递
  • id html id 没有改变。提交当前表单后再次查询时,值会发生变化。
for(i = 0 ; i < count ; i++){
   console.log("counter is "+i);
   element(by('id')).evaluate('value').then(function(v) {
    // do some action on UI based on v
    element(by('id1')).sendKeys(v+v);
    // submit etc., 
    // some angular code runs in the frontend.
   }
   // need to wait since webdriver jumps to the next one without this completing
}

许多博客文章/文档建议您不能循环使用它,但没有建议任何替代方法来执行此操作。

任何建议表示赞赏。

永远不要在循环中使用量角器元素语句:简单的原因是 webdriverJS(量角器)API 是异步的。元素语句返回一个承诺,并且该承诺处于未解决状态,而语句下方的代码继续执行。这会导致不可预测的结果。因此,建议使用递归函数而不是循环。

来源:http://engineering.wingify.com/posts/angularapp-e2e-testing-with-protractor/

编辑:更新了包含工作流程细节的问题。

【问题讨论】:

  • 您能否在问题中添加更多详细信息 .. 比如 .. count 值是如何确定的,id 是否随循环中的每个值而变化。可能是一些上下文更好地回答这个问题
  • count 是从另一个函数传递的。 id 元素在前端发生变化,但评估期间的值没有变化。也会更新问题。

标签: angularjs selenium protractor


【解决方案1】:

当迭代有异步调用时,通常不建议使用循环。

原因是当i 已经等于count 时,第一个异步调用是在循环的最后一次迭代之后执行的。 因此,很难打破循环并跟踪i 的值。

解决这个问题的方法是使用递归函数:

var count = 3;
var results = [];

function iterate(i, n) {
  if(i < n) {
    console.log(`counter is ${i}`);

    browser.refresh();
    return element(by.id('h-top-questions')).getText().then(function(text) {
      results.push(`${i}:${text}`);
      return iterate(i + 1, n);
    });
  }
}

iterate(0, count).then(function(){
  console.log("done!", results);
});

但更好的方法是使用 promise.map 在大小为迭代次数的数组上进行迭代:

var count = 3;

protractor.promise.map(Array(count).fill(0), function(v, i) {
  console.log(`counter is ${i}`);

  browser.refresh();
  return element(by.id('h-top-questions')).getText().then(function(text) {
    return `${i}:${text}`;
  });
}).then(function(results){
  console.log("done!", results);
});

您也可以继续使用循环。首先,您必须使用 let 语句在异步函数 (ES6) 中获取 i 的值。 然后用browser.call调用所有同步代码来同步执行:

var count = 3;
var results = [];

for(let i = 0 ; i < count ; i++){
  browser.call(function(){
    console.log(`counter is ${i}`);

    browser.refresh();
    element(by.id('h-top-questions')).getText().then(function(text) {
      results.push(`${i}:${text}`);
    });
  });
}

browser.call(function() {
  console.log("done!", results);
});

【讨论】:

  • 该页面有一些动态数据被修改或从循环的上一次迭代中使用,不能使用refresh。页面中的视图只有一个文本字段和一个带有各种进度条的输入框。
  • @Sairam,这里的刷新只是作为例子来观察执行顺序。对于上一次迭代的结果,您可以在results[i - 1] 中获取。
【解决方案2】:

在量角器中循环是这样工作的

describe('Describe something', function() {
    var testParams = [1,2,3,4,5,6,7,8,9,10];
    beforeEach( function() {
        // ...
   });

for (var i = 0; i < testParams.length; i++) {
  (function (testSpec) {
    it('should do something', function() {
        // inside loop
    });

  })(testParams[i]);

};
});

编辑:我可能误解了您的问题,但在我看来,您想在进入下一个之前完成页面上的所有(动态计数)操作?

it('should clear old inspections', function() {  
                  inspectieModuleInspectieFixture.getRemoveInspectionButton().count().then(function (value) {
                        if(value == 0){
                            console.log('--- no inspections to remove ---');
                        }
                        for(var i = 0; i < value; i++){
                            //global.waitForClickable(inspectieModuleInspectieFixture.getRemoveInspectionButtonList(i+1));
                            inspectieModuleInspectieFixture.getRemoveInspectionButtonList(i+1).click();
                            console.log('iteration '+i + 'count '+value )
                        };
                    });
                    global.wait(5000);

            }); */

这会计算页面上的元素数量,然后对找到的元素数量执行操作

在上面的示例中,我使用容器来保存我的元素,因此我的代码仍然可读(即 inspectieModuleInspectieFixture.getRemoveInspectionButton() 保存 $(".elementSelectorExample")

还有一个 'global.waitForClickable' 被评论,它指的是我创建的一个'时间模块',它扩展了'等待'的功能,在这种情况下,它一直等到元素可见/可点击。

这很容易反映可能是这样的:

    waitForElementNoDisplay: function(element){
    return browser.wait(function() {
        return element.isDisplayed().then(function(present) {
            return !present;
        })
    });
},

这将使量角器等待,直到不再显示元素。(显示:无)

【讨论】:

  • 很好的解决方案。从来没有这样想过。如果我有 for 循环的 2 级嵌套,我该怎么办。我有一组要浏览的页面和每个页面中的一组操作。您能否指出 Protractor 的文档或最佳实践?
  • @Sairam 唉,我不认为量角器允许循环,所以我似乎找不到任何关于如何“正确”实现它的文档。这是我在 SO 上从其他人那里得到的一个 sn-p。我也放弃了尝试在真正的测试套件中实现它,我发现添加的“复杂性”并不是我们想要的测试,我最好复制配置文件并稍微调整它们。 [snip] 编辑:我认为嵌套循环可能不是你想要的,你可能想要这样的东西(见编辑帖)
  • global.wait 对我的情况不利,因为可能太多了。我主要在寻找for 循环并将it 放入其中。
  • @Sairam 老实说,不应该使用 global.wait!我只是把它放在那里是为了澄清,事后看来我应该把它排除在外,但我很高兴循环示例有用!
【解决方案3】:

如果您需要对每个元素执行一些操作,那么最好不要使用循环。改用 .map() 或 .each() 或 .filter()

仍然不太清楚你要做什么,但这里是我如何执行类似任务的示例,当你需要根据页面中的数据执行一些操作时:

class SomePage {

    typeValueForEachElement(elements) {
        elements.each((elem, index)=> {
            elem.getAttribute('value').then(value=> {
                elem.sendKeys(value + value)
                elem.submit()
            })
        })

    }
}

new SomePage().typeValueForEachElement($$('your locator here'))

这里是可能有帮助的 api 参考

http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.map http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.reduce http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.each http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.filter

【讨论】:

  • 我正在对同一个元素执行操作。但我需要根据前一个屏幕的输入执行n 次。
猜你喜欢
  • 2015-01-30
  • 1970-01-01
  • 2012-08-03
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 2021-03-11
  • 1970-01-01
相关资源
最近更新 更多