it-roy-ru.com

Получить все атрибуты элемента, используя транспортир

Согласно документации, для получения одного атрибута по имени вы можете использовать .getAttribute() для WebElement:

var myElement = element(by.id('myId'));
expect(myElement.getAttribute('myAttr')).toEqual('myValue');

Но как я могу получить все атрибуты элемента?

Информация об этом сценарии использования/функциональности отсутствует в Protractor API .

14
alecxe

Вы можете расширить тип Element в JavaScript и добавить функцию getAttributes():

Element.prototype.getAttributes = function() {
    return (function (node) {
        var attrs = {};
        for (var i=0;i<node.length;i++) {
            attrs[node.item(i).name] = node.item(i).value;
        }
        return attrs;
    })(this.attributes);
};

демо

тогда вы можете проверить целостность атрибутов, используя тот же метод, который вы используете для одного атрибута:

var myElement = element(by.id('myId'));
expect(myElement.getAttributes()).toEqual({'attr1': 'value1', 'attr1': 'value1', ... });
9
neo

Используйте executeScript() для выполнения скрипта, который формирует список атрибутов, считывающих их из element.attributes (часть js внутри взята из здесь ):

var Elm = element(by.id('runButton')).getWebElement();
browser.executeScript(
    'var items = {}; \
     for (index = 0; index < arguments[0].attributes.length; ++index) { \
         items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value \
     }; \
     return items;', Elm).then(function (attrs) {
        console.log(attrs);
    });

Здесь attrs будет содержать словарь/объект атрибутов элемента с ключами в качестве имен атрибутов и значениями в качестве значений атрибутов.

Демо (используя страницу учебника angularjs.org , получая все атрибуты для header):

$ node node_modules/protractor/bin/elementexplorer.js https://docs.angularjs.org/tutorial
Getting page at: https://docs.angularjs.org/tutorial
> var Elm = element(by.tagName('header')).getWebElement();
> browser.executeScript('var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;', Elm).then(function (attrs) {
...     console.log(attrs);
... });
{ class: 'header header-fixed', 'scroll-y-offset-element': '' }

Не очень красиво и компактно, но у меня работает. Будем рады видеть лучшие альтернативы.


ОБНОВЛЕНИЕ (улучшение подхода выше):

Это также сработало бы, если бы я определил обычную функцию и передал ее:

function getAllAttributes (arguments) {
    var items = {}; 
    for (index = 0; index < arguments[0].attributes.length; ++index) { 
        items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value; 
    }
    return items;
}

browser.executeScript(getAllAttributes, Elm).then(function (attrs) {
    console.log(attrs);
});
1
alecxe

Если ваши нужные атрибуты имеют префикс данных, вы сможете использовать набор данных для элемента, который немного сократит ваш исполняемый скрипт:

browser.executeScript('return arguments[0].dataset;', Elm).then(function (attrs) {
    console.log(attrs);
});
1
Mathew Berg

Вы должны использовать вызов функции browser.executeScript() вместо API транспортира, поскольку Element.attributes находится вне реализации API транспортира:

var elem = element(by.id('runButton'));
browser.executeScript("return arguments[0].attributes", elem.getWebElement())
    .then(function (attrs) {
        console.log(attrs.length);    // outputs numbers of attributes.
        // access collection of Attr objects
        console.log(attrs[0].isId);   // outputs `true`
        console.log(attrs[0].name);   // outputs `id`
        console.log(attrs[0].value);  // outputs `runButton`
    });

Помните, что когда говорится attribute, это означает именованную структуру карты вместо массива в контексте модели DOM. Это означает, что вы должны использовать NamedNodeMap для доступа к коллекции Attr объектов.

Он работает так же, как в ответе @ alecxe без итерационной части.

1
shawnzhu