在条件求值为true时获取元素(扩展ElementArrayFinder)

时间:2015-09-14 19:19:29

标签: javascript selenium selenium-webdriver iteration protractor

我们有一个菜单,表示为ul->li列表(简化):

<ul class="dropdown-menu" role="menu">
    <li ng-repeat="filterItem in filterCtrl.filterPanelCfg track by filterItem.name"
        ng-class="{'divider': filterItem.isDivider}" class="ng-scope">
        <a href="" class="ng-binding"> Menu Item 1</a>
    </li>
    ...
    <li ng-repeat="filterItem in filterCtrl.filterPanelCfg track by filterItem.name"
        ng-class="{'divider': filterItem.isDivider}" class="ng-scope">
        <a href="" class="ng-binding"> Menu Item 2</a>
    </li>
</ul>

在位置N的某处,有一个分隔符,可以通过评估 filterItem.isDivider或通过检查a链接的文本来识别(如果是分手,它是空的。

现在,目标是获取位于分隔符之前的所有菜单项。你会如何处理这个问题?

我目前的做法非常通用 - 扩展ElementArrayFinder并添加takewhile()功能(受Python&#39; itertools.takewhile()启发)。以下是我实施它的方式(基于filter()):

protractor.ElementArrayFinder.prototype.takewhile = function(whileFn) {
    var self = this;
    var getWebElements = function() {
        return self.getWebElements().then(function(parentWebElements) {
            var list = [];
            parentWebElements.forEach(function(parentWebElement, index) {
                var elementFinder =
                    protractor.ElementFinder.fromWebElement_(self.ptor_, parentWebElement, self.locator_);

                list.push(whileFn(elementFinder, index));
            });
            return protractor.promise.all(list).then(function(resolvedList) {
                var filteredElementList = [];
                for (var index = 0; index < resolvedList.length; index++) {
                    if (!resolvedList[index]) {
                        break;
                    }
                    filteredElementList.push(parentWebElements[index])
                }
                return filteredElementList;
            });
        });
    };
    return new protractor.ElementArrayFinder(this.ptor_, getWebElements, this.locator_);
};

而且,以下是我使用它的方式:

this.getInclusionFilters = function () {
    return element.all(by.css("ul.dropdown-menu li")).takewhile(function (inclusionFilter) {
        return inclusionFilter.evaluate("!filterItem.isDivider");
    });
};

但是,测试只是暂停,直到jasmine.DEFAULT_TIMEOUT_INTERVAL来电达到takewhile()为止。

如果我将console.log放入循环中,之后,我可以看到它正确地在分隔符之前推送元素并在到达它时停止。我可能会在这里遗漏一些东西。

使用量角器2.2.0。

另外,如果我过度复杂化问题,请告诉我。

2 个答案:

答案 0 :(得分:7)

也许我错过了一些东西,但是当你从getText()给你一些东西时,你不能只通过> dput(profile) structure(list(`Source no` = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), Source = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Stack 1", "Stack 2"), class = "factor"), Period = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), Day = structure(c(2L, 6L, 7L, 5L, 1L, 3L, 4L, 2L, 6L, 7L, 5L, 1L, 3L, 4L, 2L, 6L, 7L, 5L, 1L, 3L, 4L), .Label = c("Fri", "Mon", "Sat", "Sun", "Thu", "Tue", "Wed"), class = "factor"), `Spring On` = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 15L, 15L, 15L, 15L, 15L, 15L, 15L), `Spring Off` = c(23L, 23L, 23L, 23L, 23L, 23L, 23L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), `Summer On` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "off", class = "factor"), `Summer Off` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "off", class = "factor"), `Autumn On` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "off", class = "factor"), `Autumn Off` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "off", class = "factor"), `Winter On` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("0", "off"), class = "factor"), `Winter Off` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("23", "off"), class = "factor")), .Names = c("Source no", "Source", "Period", "Day", "Spring On", "Spring Off", "Summer On", "Summer Off", "Autumn On", "Autumn Off", "Winter On", "Winter Off"), class = "data.frame", row.names = c(NA, -21L)) 元素,并将它们存储到某个数组中,或者直接在那个循环中做些什么?

ul li a

答案 1 :(得分:3)

我从takewhile()移除了protractor.promise = require("q");后,

onPrepare()实际上对我有用了 - 这就是为了能够protractor.promise替换q使用像spread() function这样的句法糖。显然,使用q代替protractor.promise 是不安全的。

我现在要做的就是将其添加到onPrepare()

protractor.ElementArrayFinder.prototype.takewhile = function(whileFn) {
    var self = this;
    var getWebElements = function() {
        return self.getWebElements().then(function(parentWebElements) {
            var list = [];
            parentWebElements.forEach(function(parentWebElement, index) {
                var elementFinder =
                    protractor.ElementFinder.fromWebElement_(self.ptor_, parentWebElement, self.locator_);

                list.push(whileFn(elementFinder, index));
            });
            return protractor.promise.all(list).then(function(resolvedList) {
                var filteredElementList = [];
                for (var index = 0; index < resolvedList.length; index++) {
                    if (!resolvedList[index]) {
                        break;
                    }
                    filteredElementList.push(parentWebElements[index])
                }
                return filteredElementList;
            });
        });
    };
    return new protractor.ElementArrayFinder(this.ptor_, getWebElements, this.locator_);
};

用法与filter()非常相似:

element.all(by.css("ul li a")).takewhile(function (elm) {
    return elm.getText().then(function (text) {
        return text;
    });
});

仅供参考,proposed to make takewhile() built-in