量角器承诺在检索元素时会引起头痛

时间:2018-03-21 17:52:56

标签: angularjs protractor angular-promise

我们的网络应用程序有各种html表单,每个表单都包含一个表单字段列表。使用Protractor,我正在寻找一种方法来检索表单字段列表:字段标签,输入类型(文本框,选择,无线电等...)和输入控件(稍后用于设置值)。然后,我想动态地为表单中的字段填充某些值。

以下是表单字段标签的定义以及我想要设置的值:

this.fields = {
        'Listing Agent': 1,
        'Property Class': 1,
        'Property Type': 2,
        'Transaction Type': 'Sale',
        'Ownership Terms': 'Sole Ownership',
        'Listing Agreement': 'Yes',
        'Display Listing on Internet': 'Yes',
        'Display Address on Internet': 'Yes',
        'Allow Automated Valuation on Internet': 'Yes',
        'Allow Public Comment/Reviews on Internet': 'Yes'
    };

然后我通过标签文本检索与这些字段名称匹配的元素:

this.elements = form.find.allElements(this.fields);

调用该方法时,它会检索正确的元素,但是我在设置每个字段的输入类型时遇到问题。检查字段的输入类型会返回一个promise而不是实际值,所以我无法弄清楚如何检索每个元素的输入类型,然后返回所有元素的数组。

this.find = {
        allElements: function (fields) {
            var items = [];
            for (var key in fields) {
                var el = element(by.cssContainingText('.sheet-grid-row', key));
                this.getElementType(el).then(function (type) {
                    var item = {
                        type: type,
                        label: key,
                        isRequired: false,// TODO: el.getAttribute('class').indexOf('is-required-field') > -1
                        input: this.getElementInput(el, type)
                    };
                    items.push(item);
                });
            }
            return items;// TODO: Doesn't work, of course...
        },

        getElementType: function (el) {
            var deferred = protractor.promise.defer();

            el.element(by.css('select')).isPresent().then(function (exists) {
                if (exists)
                    deferred.fulfill(self.inputTypes.select);
                else {
                    el.element(by.css('input[type="text"]')).isPresent().then(function (exists) {
                        if (exists)
                            deferred.fulfill(self.inputTypes.textbox);
                        else {
                            el.element(by.css('input[type="radio"]')).isPresent().then(function (exists) {
                                if (exists)
                                    deferred.fulfill(self.inputTypes.textbox);
                                else
                                    deferred.fulfill(self.inputTypes.unknown);
                            });
                        }
                    });
                }
            });

            return deferred.promise;
        },

        getElementInput: function (el, type) {
            switch (type) {
                case self.inputTypes.select:
                    return new SelectWrapper(el.element(by.css('select')));
                    break;
                case self.inputTypes.textbox:
                    return el.element(by.css('input[type="text"]'));
                    break;
                case self.inputTypes.radio:
                    return el.element(by.css('input[type="radio"]'));
                    break;
            }
            return null;
        }
    };

此时,我希望我能够获得本机DOM元素,而不是处理承诺。有没有办法完成我追求的目标?

1 个答案:

答案 0 :(得分:0)

您正在尝试在同步循环element.isPresent()内执行异步操作for。您希望allElements函数看起来更像这样:

this.find = {
    allElements: function (fields) {
        var self = this;
        var items = [];
        var getItems = function(inputArray, currentIndex, outputArray) {
            outputArray = outputArray || [];
            currentIndex = currentIndex || 0;
            var key = inputArray[currentIndex];
            if (key) {
                var el = element(by.cssContainingText('.sheet-grid-row', key));
                return self.getElementType(el).then(function(type) {
                    var item = {
                        type: type,
                        label: key,
                        isRequired: false,// TODO: el.getAttribute('class').indexOf('is-required-field') > -1
                        input: self.getElementInput(el, type)
                    };
                    outputArray.push(item);
                }).then(function() {
                    return getItems(inputArray, currentIndex + 1, outputArray);
                });
            } else {
                return Promise.resolve(outputArray);
            }
        };
        return getItems(Object.keys(fields));
    },

    getElementType: function (el) {
        var self = this;
        return el.element(by.css('select')).isPresent().then(function(exists) {
            if (exists) {
                return self.inputTypes.select;
            } else {
                return el.element(by.css('input[type="text"]')).isPresent().then(function(exists) {
                    if (exists) {
                        return self.inputTypes.textbox;
                    } else {
                        return el.element(by.css('input[type="radio"]')).isPresent().then(function(exists) {
                            if (exists) {
                                return self.inputTypes.radio;
                            } else {
                                return self.inputTypes.unknown;
                            }
                        });
                    }
                });
            }
        });
    },

    getElementInput: function (el, type) {
        switch (type) {
            case self.inputTypes.select:
                return new SelectWrapper(el.element(by.css('select')));
                break;
            case self.inputTypes.textbox:
                return el.element(by.css('input[type="text"]'));
                break;
            case self.inputTypes.radio:
                return el.element(by.css('input[type="radio"]'));
                break;
        }
        return null;
    }
};

请记住,find.allElements的输出现在应该是一个承诺,因此它的用法如下:

this.find.allElements(this.fields).then(function(items) {
    console.log('this is an array of my ' + items.length + ' items');
});