Bagaimana cara menguji apakah suatu elemen memiliki kelas menggunakan Busur derajat?


90

Saya mencoba Protractor untuk menguji aplikasi Angular e2e dan belum menemukan cara untuk mendeteksi apakah suatu elemen memiliki kelas tertentu atau tidak.

Dalam kasus saya, pengujian mengklik tombol kirim dan sekarang saya ingin tahu apakah form [name = "getoffer"] memiliki class .ngDirty. Apa solusinya?

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
    });
});

Jawaban:


110

Satu gotcha yang harus Anda perhatikan dengan menggunakan toMatch(), seperti dalam jawaban yang diterima, adalah kecocokan parsial. Misalnya, Anda memiliki elemen yang mungkin memiliki kelas correctdan incorrect, dan Anda ingin menguji bahwa ia memiliki kelas correct. Jika Anda menggunakannya expect(element.getAttribute('class')).toMatch('correct'), itu akan mengembalikan nilai true meskipun elemen tersebut memiliki incorrectkelas.

Saran saya:

Jika Anda hanya ingin menerima pencocokan persis, Anda dapat membuat metode pembantu untuk itu:

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

Anda dapat menggunakannya seperti ini (memanfaatkan fakta yang expectsecara otomatis menyelesaikan promise di Protractor):

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

1
Ini berhasil untuk saya, dengan mod bahwa nama kelas harus dalam format tanda hubung bukan kotak unta, yaituexpect(hasClass(element(by.name('getoffer')), 'ng-dirty')).toBe(true);
Ackroydd

Saya sedikit tidak jelas tentang fungsi yang dilakukan kelas, terutama di mana atau kelas apa ketika diteruskan ke fungsi .then, dapatkah seseorang mencerahkan saya?
ErikAGriffin

@ErikAGriffin: Fungsi hasClass melewati dua argumen - elemen html dan nama kelas untuk diperiksa. Fungsi tersebut kemudian mendapatkan atribut "class" (kelas) yang dimiliki elemen tersebut. Ini membagi string kelas untuk mendapatkan array kelas. Ia kemudian memeriksa apakah kelas yang Anda cari ada dalam indeks positif dari array. Saya berasumsi itu adalah cara untuk memeriksa keberadaan.
VSO

Saya telah menulis ulang fungsi empat baris Anda menjadi ES6 one liner yang seksi ini: hasClass = (element, className) => element.getAttribute ('class'). Then ((class) => class.split ('') .indexOf ( className)! == -1);
Laurens Mäkel

Dalam TypeScript: async function hasClass (elm: ElementFinder, className: string): Promise <boolean> {const classNamesStr: string = await elm.getAttribute ('class'); const classNamesArr: string [] = classNamesStr.split (''); return classNamesArr.includes (className); }
tedw

57

Jika Anda menggunakan Busur derajat dengan Jasmine, Anda dapat menggunakan toMatchpencocokan sebagai ekspresi reguler ...

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

Juga, perhatikan bahwa toContainakan cocok dengan item daftar, jika Anda membutuhkannya.


1
Saya tidak yakin apakah itu cara ideal untuk melakukan ini, tetapi setidaknya berfungsi seperti yang diharapkan :)
Allan Tatter

1
Tidak, menurutku mungkin tidak. Saya berharap elementuntuk mengembalikan objek dengan hasClassmetode, yang dapat Anda bungkus di dalam expectpanggilan ...
ryan.l

2
toContainmungkin pilihan yang lebih baik daripada toMatchdalam kasus ini.
TrueWill

Jika Anda ingin waspada terhadap pertandingan parsial, cobalah sesuatu seperti /(^|\s)ngDirty($|\s)/.
Andrew Myers

Anda mungkin dapat menggunakan .not.toContainuntuk memeriksa apakah itu tidak memiliki kelas tertentu atau .toContainuntuk memeriksa apakah itu ada
Jack

18

Yang paling sederhana adalah:

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

Ini mengembalikan kesalahan java.util.ArrayList cannot be cast to java.lang.Stringpada Microsoft Edge
Manolis

@Manolis bagaimana Anda mendapatkan pengecualian java di konsol web untuk angularjs ??
vasia

4

Berdasarkan jawaban dari Sergey K, Anda juga bisa menambahkan custom matcher untuk melakukan ini:

(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
        )
    })
  )

Kemudian Anda bisa menggunakannya dalam tes seperti ini:

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

Dan Anda akan mendapatkan kesalahan berikut jika tidak:

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

3

Sudahkah kamu mencoba ...

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

atau variasi di atas ...


5
Masalahnya adalah, formulir tersebut memiliki lebih dari satu kelas yang dilampirkan.
Allan Tatter

2

Saya membuat matcher ini, saya harus membungkusnya dengan janji dan menggunakan 2 pengembalian

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

dalam pengujian saya, saya sekarang dapat melakukan stuf seperti ini:

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

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

ini juga berfungsi ketika sebuah elemen memiliki beberapa kelas atau ketika sebuah elemen tidak memiliki atribut kelas sama sekali.


1

Di sinitoHaveClass pencocokan khusus Jasmine 1.3.x dengan .notdukungan negasi plus tunggu hingga 5 detik (atau apa pun yang Anda tentukan).

Temukan pencocokan kustom lengkap untuk ditambahkan ke blok onPrepare Anda di inti ini

Penggunaan sampel:

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;
    });
}

Ini adalah cara saya melakukannya setidaknya, tanpa perlu menggunakan fungsi ekspektasi. Fungsi ini hanya mengembalikan nilai true jika kelas ada di dalam elemen dan false jika tidak. Ini juga menggunakan promise sehingga Anda akan menggunakannya seperti:

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

Sunting: Saya baru menyadari ini pada dasarnya sama dengan jawaban teratas


1

Salah satu cara untuk mencapai ini adalah dengan menggunakan xpath dan use contains()

Contoh:

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

0

Anda dapat menggunakan pengurai CSS untuk menangani ini dengan memeriksa apakah elemen dengan kelas yang diberikan ada:

expect(element(by.css('.form[name="getoffer"].ngDirty')).isPresent()).toBe(true);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.