Як перевірити, чи має елемент клас за допомогою транспортира?


90

Я випробовую Protractor для тестування e2e програми Angular і не з’ясував, як визначити, чи має елемент певний клас чи ні.

У моєму випадку тест натискає кнопку "Відправити", і тепер я хочу знати, чи має форма [name = "getoffer"] клас .ngDirty. Які можуть бути рішення?

describe('Contact form', function() {
    beforeEach(function(){
        browser.get('http://localhost:9000');
        element(by.linkText('Contact me')).click();
    });

    it('should fail form validation, all fields pristine', function() {
        element(by.css('.form[name="getoffer"] input[type="submit"]')).click();
        expect(element(by.name('getoffer'))).toHaveClass('ngDirty'); // <-- This line
    });
});

Відповіді:


110

Однією з проблем, на яку ви повинні звернути увагу, використовуючи toMatch(), як у прийнятій відповіді, є часткові збіги. Наприклад, припустимо, у вас є елемент, який може мати класи correctі incorrect, і ви хочете перевірити, чи має він клас correct. Якщо ви використовували expect(element.getAttribute('class')).toMatch('correct'), це поверне true, навіть якщо елемент маєincorrect клас.

Моя пропозиція:

Якщо ви хочете прийняти лише точні збіги, ви можете створити для нього допоміжний метод:

var hasClass = function (element, cls) {
    return element.getAttribute('class').then(function (classes) {
        return classes.split(' ').indexOf(cls) !== -1;
    });
};

Ви можете використовувати його таким чином (скориставшись тим, що expectавтоматично вирішує обіцянки в Protractor):

expect(hasClass(element(by.name('getoffer')), 'ngDirty')).toBe(true);

1
Це спрацювало для мене, з модом, що назва класу повинна бути дефісом, а не верблюдом справою, тобтоexpect(hasClass(element(by.name('getoffer')), 'ng-dirty')).toBe(true);
Ackroydd

Мені трохи незрозуміло, що робить функція, яку робить клас, особливо де або які класи, коли переходять у функцію .then, хтось міг би мене просвітлити?
ErikAGriffin

@ErikAGriffin: Функція hasClass передає два аргументи - елемент html та ім'я класу для перевірки. Потім функція отримує атрибут "class" (класи), який має елемент. Він розділяє рядок класів, щоб отримати масив класів. Потім він перевіряє, чи знаходиться у класі, який ви шукаєте, позитивний індекс масиву. Я припускаю, що це спосіб перевірити наявність.
VSO

Я переписав вашу функцію з чотирьох рядків на цей сексуальний вкладиш ES6: hasClass = (element, className) => element.getAttribute ('class'). Then ((classes) => classes.split ('') .indexOf ( className)! == -1);
Лорен Мекель,

У TypeScript: функція async hasClass (elm: ElementFinder, className: string): Promise <boolean> {const classNamesStr: string = await elm.getAttribute ('class'); const classNamesArr: string [] = classNamesStr.split (''); повернути classNamesArr.includes (className); }
tedw

56

Якщо ви використовуєте транспортир з жасмином, ви можете використовувати toMatchйого як регулярний вираз ...

expect(element(by.name('getoffer')).getAttribute('class')).toMatch('ngDirty');

Також зауважте, що toContainякщо вам це потрібно, відповідатиме елементам списку.


1
Я не впевнений, що це ідеальний спосіб зробити це, але принаймні це працює, як очікувалось :)
Аллан Таттер

1
Ні, я б сказав, що це, мабуть, ні. Я очікував elementби повернути об’єкт із hasClassметодом, який ви могли б обернути всередині expectвиклику ...
ryan.l

2
toContainможе бути кращим вибором, ніж toMatchу цьому випадку.
TrueWill

Якщо ви хочете захиститися від часткових матчів, спробуйте щось на зразок /(^|\s)ngDirty($|\s)/.
Ендрю Майерс,

ви, мабуть, можете скористатися .not.toContainдля перевірки, чи немає в ньому конкретного класу, або .toContainдля перевірки, чи існує він
Джек

18

Найпростішим є:

expect(element.getAttribute('class')).toContain("active");

Це повертає помилку java.util.ArrayList cannot be cast to java.lang.Stringна Microsoft Edge
Manolis

@Manolis, як ти отримуєш винятки Java у веб-консолі для angularjs ??
vasia

4

На основі відповіді Сергія К, ви також можете додати спеціальний збіг, щоб зробити це:

(coffeescript)

  beforeEach(()->
    this.addMatchers({
      toHaveClass: (expected)->
        @message = ()->
          "Expected #{@actual.locator_.value} to have class '#{expected}'"

        @actual.getAttribute('class').then((classes)->
          classes.split(' ').indexOf(expected) isnt -1
        )
    })
  )

Тоді ви можете використовувати його в таких тестах:

expect($('div#ugly')).toHaveClass('beautiful')

І ви отримаєте таку помилку, якщо її немає:

 Message:
   Expected div#ugly to have class beautiful
 Stacktrace:
   Error: Expected div#ugly to have class 'beautiful'

3

Ти намагався...

var el = element(by.name('getoffer'));
expect(e.getAttribute('class')).toBe('ngDirty')

або варіація вищезазначеного ...


5
Проблема в тому, що до форми приєднано більше одного класу.
Аллан Таттер

2

Я зробив цей збіг, мені довелося обернути його обіцянкою та використати 2 повернення

this.addMatchers({
    toHaveClass: function(a) {
        return this.actual.getAttribute('class').then(function(cls){
            var patt = new RegExp('(^|\\s)' + a + '(\\s|$)');
            return patt.test(cls);
        });
    }
});

в моєму тесті я зараз можу робити такі штуфи:

   var myDivs = element.all(by.css('div.myClass'));
   expect(myDivs.count()).toBe(3);

   // test for class
   expect(myDivs.get(0)).not.toHaveClass('active');

це також працює, коли елемент має кілька класів або коли елемент взагалі не має атрибута class.


1

Тут спеціальний toHaveClassзбіг Jasmine 1.3.x із запереченням.not підтримкою плюс зачекайте до 5 секунд (або що завгодно ви вказали).

Знайдіть повний спеціальний збіг, який потрібно додати до блоку onPrepare, у цій суті

Зразок використання:

it('test the class finder custom matcher', function() {
    // These guys should pass OK given your user input
    // element starts with an ng-invalid class:
    expect($('#user_name')).toHaveClass('ng-invalid');
    expect($('#user_name')).not.toHaveClass('ZZZ');
    expect($('#user_name')).toNotHaveClass('ZZZ');
    expect($('#user_name')).not.toNotHaveClass('ng-invalid');
    // These guys should each fail:
    expect($('#user_name')).toHaveClass('ZZZ');
    expect($('#user_name')).not.toHaveClass('ng-invalid');
    expect($('#user_name')).toNotHaveClass('ng-invalid');
    expect($('#user_name')).not.toNotHaveClass('ZZZ');
});

1
function checkHasClass (selector, class_name) {
    // custom function returns true/false depending if selector has class name

    // split classes for selector into a list
    return $(selector).getAttribute('class').then(function(classes){
        var classes = classes.split(' ');
        if (classes.indexOf(class_name) > -1) return true;
        return false;
    });
}

Ось як я це роблю принаймні, без необхідності використовувати функцію очікування. Ця функція просто повертає true, якщо клас знаходиться всередині елемента, і false, якщо ні. Тут також використовуються обіцянки, тому ви б використовували це як:

checkHasClass('#your-element', 'your-class').then(function(class_found){
    if (class_found) console.log("Your element has that class");
});

Редагувати: Я щойно зрозумів, що це, по суті, те саме, що і відповідь у верхній частині сторінки


1

Одним із способів досягти цього було б використання xpath та use contains()

Приклад:

var expectElementToHaveClass = function (className) {
    var path = by.xpath("//div[contains(@class,'"+ className +"')]");
    expect(element.all(path).count()).to.eventually.be.eq(1);
};

0

Ви можете використати синтаксичний аналізатор CSS для обробки цього, перевіривши, чи існує елемент із заданим класом:

expect(element(by.css('.form[name="getoffer"].ngDirty')).isPresent()).toBe(true);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.