【问题标题】:Breaking out of a Protractor .filter() or .map() loop打破量角器 .filter() 或 .map() 循环
【发布时间】:2016-12-11 04:20:51
【问题描述】:

我正在使用量角器和黄瓜框架;如何摆脱 .filter 或 .map 循环?如果找到匹配项,我不想继续进一步迭代!

Page.prototype.getElementByKey = function (key) {
      var foundElement = null;
      return someElement.all(by.css('.someClass')).map(function (rawItem, index) {
        var itemObject = new ItemObjectClass(rawItem);
        return itemObject.getItemKey().then(function (foundItemKey) {
          var matched = String(foundItemKey).trim() === String(key).trim();

         console.log(' Matched: { ' + matched + ' }  index {'+index+'}');
          //if we have a match break out of the .filter function
          if (matched) {
            foundElement = itemObject;
            throw new Error("Just our way of breaking out of .filter() above");
          }
        });
      }).then(function () {
        //callback
        throw new Error('\n!!!!!Callback should not be called; 
       this means that we could not find an element that matched the passed in key above');
      }, function (error) {
        //error
        console.log('\n*******************errorCallback was called; '+error);
        return foundElement;
      });
    };

上面的代码找到了元素,但继续迭代直到结束,而不是在匹配时停止并通过调用 errorCallback 函数中断。

鉴于 .map 函数返回“解析为 map 函数返回的值数组的承诺http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.map,我正在利用如果 promise 无法解决,promise 将调用它的 errCallback。

通过抛出一个虚假的错误,应该调用 errorCallback 从而跳出 .map 循环。

不幸的是,它成功抛出错误但继续循环而不是中断。我知道,因为当我

console.log("boolean "+matched+" and index "+index);

我明白了:

matched: false index: 0
matched: false index: 1
matched: true index 2 //it should have stopped here since matched = true
matched false index 3 // this should NOT have printed

所以突破没有任何想法?

【问题讨论】:

  • return (String(foundItemKey).trim() === String(key).trim());应该工作。

标签: selenium protractor browser-automation e2e-testing webautomation


【解决方案1】:

您返回的是单个元素,所以.reduce 会更好。

这是一个使用示例,用于返回文本为“mylink”的第一个链接:

var link = element.all(by.css('a')).reduce(function (result, elem, index) {
    if(result) return result;

    return elem.getText().then(function(text){
        if(text === "mylink") return elem;
    });

}).then(function(result){
    if(!result) throw new Error("Element not found");
    return result;
});

【讨论】:

  • 嘿 Florent,我测试了您的解决方案并且它有效;一旦有匹配,它就会爆发并停止迭代其他元素。问题:为什么会这样?我阅读了有关 .reduce() 的文档,但仍然有些困惑。 if(result) 返回结果;这就是魔法发生的地方吗?基本上,一旦设置了累加器(结果),您就会立即返回,从而跳出循环,对吗?使用 .filter() 或 .map() 的类似设置不起作用,您能否解释一下为什么/如何工作?再次感谢这个有效的解决方案
  • 最后,如何使用该函数/方法返回的值?出于某种原因,我能够正确突破并在找到匹配项后立即返回,但我无法在外部使用返回值(在该函数之外)。感谢您在这方面的帮助;如果我在您回复之前弄清楚了,那么我会在这里发布,因为我认为知道如何使用返回的值会很好地补充您的答案。
  • @pelican,不同之处在于mapfilter 迭代每个调用,而reduce 链接调用并等待第一个调用被解析以继续进行第二个调用。 reduce 方法返回一个承诺。因此,您可以使用 .then 在函数外部访问它,就像从 .getText() 访问结果一样。
  • 我知道这个方法返回一个你可以用 .then() 调用解决的承诺,但由于某种原因,我无法从外部读取它的值;如果您要将上述方法打包到名为“getLink()”的函数中并执行以下操作: return getLink().then(function(resolvedLink){ console.log(resolvedLink);...});你会看到你没有得到链接文本但未定义。 getLink(0 在我的情况下实际上属于一个类文件;我只是在这里进行 sudo 编码以进行说明。也许这是我做错了,不确定;如果找到解决方案,将更新此答案。谢谢
  • 嗨@Florent,我终于找到了问题所在;我没有从回调中返回 result;您能否更新上面的答案以返回结果?这将有助于其他访问此页面的人。再次非常感谢 Florent 的回答 :)
【解决方案2】:

我从您的帖子中了解到,您想在找到匹配元素时退出循环(迭代)。

如果是,那么最好使用 .filter() 方法。因为它迭代所有可用的元素查找器列表并在找到匹配项时返回。

Code Snippet:

element.all(by.css('.items li')).filter(function(elem, index) {
          return elem.getText().then(function(text) {
                                if(text === 'RequiredElementFind'){
                                      return ele;//return matched element
                                 };
    });
}).click();//only matched element comes from the loop do what would you like    
  to do

【讨论】:

  • 而不是 if() 语句,您可以只返回 "return text ==="RequiredElementFind"; 但此解决方案不会在第一次匹配时退出。它将过滤正确的元素 TRUE; 但是它将继续迭代列表中的其他元素,直到它到达列表的底部,然后返回一个 ElementArrayFinder,它表示满足过滤器功能的元素数组。即使你正在评估其余元素只对第一个匹配或匹配过滤条件的第一个元素感兴趣。所以这个解决方案不起作用,但谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-11
  • 2018-02-28
  • 2021-05-02
  • 1970-01-01
相关资源
最近更新 更多