Получить все атрибуты элемента с помощью транспортира

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

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

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

Информация об этом случае/функциях отсутствует в API-интерфейсе протрансформатора.

Ответ 1

Вы можете расширить тип javascript Element и добавить функцию 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', ... });

Ответ 2

Используйте executeScript() для выполнения script, который формирует список атрибутов, читающих их из 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 будет содержать словарь/объект атрибутов элемента с ключами как имена атрибутов и значения как значения атрибута.

Demo (используя страницу обучения 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);
});

Ответ 3

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

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

Ответ 4

Вы должны использовать вызов функции browser.executeScript() вместо API-интерфейса protractor, поскольку 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`
    });

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

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