จะทดสอบได้อย่างไรว่าองค์ประกอบมีคลาสโดยใช้ไม้โปรแทรกเตอร์?


90

ฉันกำลังลองใช้ Protractor เพื่อทดสอบ e2e แอพ Angular และยังไม่ได้หาวิธีตรวจสอบว่าองค์ประกอบมีคลาสเฉพาะหรือไม่

ในกรณีของฉันการทดสอบคลิกที่ปุ่มส่งและตอนนี้ฉันต้องการทราบว่า form [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

gotcha หนึ่งที่คุณต้องระวังในการใช้toMatch()เช่นเดียวกับในคำตอบที่ยอมรับคือการจับคู่บางส่วน ตัวอย่างเช่นสมมติว่าคุณมีองค์ประกอบที่อาจมีคลาสcorrectและincorrectและคุณต้องการทดสอบว่ามีคลาสcorrectหรือไม่ หากคุณต้องการใช้expect(element.getAttribute('class')).toMatch('correct')สิ่งนั้นจะคืนค่าจริงแม้ว่าองค์ประกอบนั้นจะมี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
สิ่งนี้ใช้ได้ผลสำหรับฉันด้วย mod ที่ชื่อคลาสต้องเป็นรูปแบบยัติภังค์ไม่ใช่ตัวอักษรอูฐเช่นexpect(hasClass(element(by.name('getoffer')), 'ng-dirty')).toBe(true);
Ackroydd

ฉันไม่ค่อยชัดเจนว่าฟังก์ชันนี้มีคลาสทำอะไรอยู่โดยเฉพาะที่ใดหรือคลาสใดเมื่อถูกส่งผ่านไปยังฟังก์ชัน. แล้วใครบางคนจะสามารถให้ความกระจ่างแก่ฉันได้หรือไม่?
ErikAGriffin

@ErikAGriffin: ฟังก์ชัน hasClass จะส่งผ่านสองอาร์กิวเมนต์ - องค์ประกอบ html และชื่อของคลาสที่จะตรวจสอบ จากนั้นฟังก์ชันจะได้รับแอตทริบิวต์ "class" (คลาส) ที่องค์ประกอบนั้นมี มันแยกสตริงคลาสเพื่อรับอาร์เรย์ของคลาส จากนั้นตรวจสอบว่าคลาสที่คุณกำลังมองหาอยู่ในดัชนีบวกของอาร์เรย์หรือไม่ ฉันคิดว่าเป็นวิธีตรวจสอบการมีอยู่จริง
VSO

ฉันได้เขียนฟังก์ชันสี่บรรทัดของคุณใหม่เป็นซับใน ES6 อันเซ็กซี่นี้: hasClass = (element, className) => element.getAttribute ('class') แล้ว ((คลาส) => class.split ('') .indexOf ( className)! == -1);
Laurens Mäkel

ใน TypeScript: async function hasClass (elm: ElementFinder, className: string): Promise <boolean> {const classNamesStr: string = await elm.getAttribute ('class'); const classNamesArr: สตริง [] = classNamesStr.split (''); ส่งคืน classNamesArr. รวม (className); }
tedw

57

หากคุณใช้ไม้โปรแทรกเตอร์กับจัสมินคุณสามารถใช้toMatchเพื่อจับคู่เป็นนิพจน์ทั่วไป ...

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

นอกจากนี้โปรดทราบว่าtoContainจะตรงกับรายการหากคุณต้องการ


1
ฉันไม่แน่ใจว่าเป็นวิธีที่ดีที่สุดในการทำสิ่งนี้หรือไม่ แต่อย่างน้อยมันก็ได้ผลตามที่คาดไว้ :)
Allan Tatter

1
ไม่ฉันจะบอกว่ามันอาจจะไม่ใช่ ฉันคาดหวังว่าelementจะส่งคืนวัตถุด้วยhasClassวิธีการซึ่งคุณสามารถห่อไว้ภายในการexpectโทร ...
ryan.l

2
toContainอาจเป็นทางเลือกที่ดีกว่าtoMatchในกรณีนี้
TrueWill

/(^|\s)ngDirty($|\s)/หากคุณต้องการที่จะป้องกันการแข่งขันบางส่วนพยายามบางอย่างเช่น
Andrew Myers

คุณอาจใช้.not.toContainตรวจสอบได้ว่าไม่มีคลาสนั้น ๆ หรือ.toContainเพื่อตรวจสอบว่ามีอยู่หรือไม่
แจ็ค

18

ง่ายที่สุดคือ:

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

สิ่งนี้ส่งคืนข้อผิดพลาดjava.util.ArrayList cannot be cast to java.lang.Stringบน Microsoft Edge
Manolis

@Manolis คุณได้รับข้อยกเว้นจาวาในเว็บคอนโซลสำหรับ angularjs ได้อย่างไร?
vasia

4

จากคำตอบของ Sergey K คุณสามารถเพิ่มตัวจับคู่ที่กำหนดเองเพื่อทำสิ่งนี้:

(กาแฟ)

  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
ปัญหาคือแบบฟอร์มมีมากกว่าหนึ่งคลาสที่แนบมา
Allan Tatter

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

นอกจากนี้ยังใช้งานได้เมื่อองค์ประกอบมีหลายคลาสหรือเมื่อองค์ประกอบไม่มีแอตทริบิวต์คลาสเลย


1

นี่คือtoHaveClassตัวจับคู่แบบกำหนดเองของจัสมิน 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;
    });
}

นี่เป็นวิธีที่ฉันทำอย่างน้อยที่สุดโดยไม่จำเป็นต้องใช้ฟังก์ชันคาดหวัง ฟังก์ชันนี้จะคืนค่าจริงหากคลาสอยู่ภายในองค์ประกอบและเป็นเท็จถ้าไม่ นอกจากนี้ยังใช้คำสัญญาดังนั้นคุณจะใช้มันเช่น:

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

แก้ไข: ฉันเพิ่งรู้ว่านี่เป็นสิ่งเดียวกับคำตอบด้านบน


1

วิธีหนึ่งในการบรรลุสิ่งนี้คือการใช้ xpath และใช้ 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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.