Подтвердить что ты не робот

Возьмите элементы, пока условие оценивается как true (расширяя ElementArrayFinder)

У нас есть меню, представленное в виде списка 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 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.


Кроме того, дайте мне знать, если я смущаю проблему.

4b9b3361

Ответ 1

Может, мне что-то не хватает, но не могли бы вы просто пройти через элементы ul li a, пока они дали вам что-то из getText(), и сохранили их в каком-либо массиве или что-то с ними делали непосредственно в этом цикле?

var i = 0;
var el = element.all(by.css('ul li a'));
var tableItems = [];
(function loop() {
    el.get(i).getText().then(function(text){
        if(text){
            tableItems.push(el.get(i));
            i+=1;
            loop();
        }
    });
}());

Ответ 2

takewhile() действительно работал у меня, как только я удалил protractor.promise = require("q"); из onPrepare() - это было там, чтобы заменить protractor.promise на q на лету, чтобы иметь возможность использовать синтаксический сахар, например spread() функция. По-видимому, не стоит использовать 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;
    });
});

FYI, предложил сделать takewhile() встроенный.