تايب سكريبت - اختبار الوحدة لحدث النقر في أنغولار
أحاول إضافة اختبارات وحدة لتطبيق Angular 2 الخاص بي. في أحد المكونات، هناك زر به معالج (click). عندما ينقر المستخدم على الزر، يتم استدعاء دالة معرفة في ملف .ts الخاص بالفئة. تقوم هذه الدالة بطباعة رسالة في نافذة console.log تقول أن الزر تم الضغط عليه. يختبر كود الاختبار الحالي الخاص بي طباعة رسالة console.log:
describe('Component: ComponentToBeTested', () => {
var component: ComponentToBeTested;
beforeEach(() => {
component = new ComponentToBeTested();
spyOn(console, 'log');
});
it('should call onEditButtonClick() and print console.log', () => {
component.onEditButtonClick();
expect(console.log).toHaveBeenCalledWith('Edit button has been clicked!);
});
});
ومع ذلك، هذا يختبر فقط فئة المتحكم، وليس HTML. أنا لا أريد فقط اختبار أن تسجيل الدخول يحدث عندما يتم استدعاء onEditButtonClick؛ أنا أيضًا أريد اختبار أن onEditButtonClick يتم استدعاؤه عندما ينقر المستخدم على زر التحرير المحدد في ملف HTML الخاص بالمكون. كيف يمكنني القيام بذلك؟
الإجابة رقم 1
هدفي هو التحقق مما إذا كان 'onEditButtonClick' يتم استدعاؤه عندما ينقر المستخدم على زر التعديل وليس مجرد التحقق من طباعة console.log.
ستحتاج أولاً إلى إعداد الاختبار باستخدام TestBed في Angular. بهذه الطريقة يمكنك فعليًا الحصول على الزر والنقر عليه. ما ستفعله هو تكوين وحدة، تمامًا كما تفعل مع @NgModule، ولكن من أجل بيئة الاختبار فقط.
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
describe('', () => {
let fixture: ComponentFixture<TestComponent>;
let component: TestComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ ],
declarations: [ TestComponent ],
providers: [ ]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
});
}));
});
ثم تحتاج إلى التجسس على طريقة onEditButtonClick، انقر على الزر، وتحقق من أن الطريقة تم استدعاؤها
it('should', async(() => {
spyOn(component, 'onEditButtonClick');
let button = fixture.debugElement.nativeElement.querySelector('button');
button.click();
fixture.whenStable().then(() => {
expect(component.onEditButtonClick).toHaveBeenCalled();
});
}));
هنا نحتاج إلى تشغيل اختبار async حيث أن نقر الزر يحتوي على معالجة أحداث غير متزامنة، ونحتاج إلى الانتظار حتى تتم معالجة الحدث عن طريق استدعاء fixture.whenStable()
تحديث
يُفضل الآن استخدام توليفة fakeAsync/tick بدلاً من توليفة async/whenStable. يجب استخدام الأخيرة إذا تم إجراء مكالمة XHR، حيث أن fakeAsync لا يدعمها. لذا بدلاً من الكود أعلاه، بعد إعادة هيكلته، سيبدو هكذا
it('should', fakeAsync(() => {
spyOn(component, 'onEditButtonClick');
let button = fixture.debugElement.nativeElement.querySelector('button');
button.click();
tick();
expect(component.onEditButtonClick).toHaveBeenCalled();
}));
لا تنسَ استيراد fakeAsync و tick.
انظر أيضًا:
- اختبار التوثيق
- ما الفرق بين fakeAsync و async في اختبار Angular؟
الإجابة رقم 2
يمكن اختبار الأحداث باستخدام الدالتين async/fakeAsync المقدمتين من '@angular/core/testing'، حيث أن أي حدث في المتصفح غير متزامن ويتم دفعه إلى حلقة/قائمة انتظار الأحداث.
فيما يلي مثال أساسي جداً لاختبار حدث النقر باستخدام fakeAsync.
تُمكّن دالة fakeAsync من نمط ترميز خطي من خلال تشغيل جسم الاختبار في منطقة اختبار fakeAsync خاصة.
ها أنا أختبر طريقة يتم استدعاؤها بواسطة حدث النقر.
it('should', fakeAsync( () => {
fixture.detectChanges();
spyOn(componentInstance, 'method name'); //method attached to the click.
let btn = fixture.debugElement.query(By.css('button'));
btn.triggerEventHandler('click', null);
tick(); // simulates the passage of time until all pending asynchronous activities finish
fixture.detectChanges();
expect(componentInstance.methodName).toHaveBeenCalled();
}));
فيما يلي ما تقوله وثائق Angular:
الميزة الأساسية لـ fakeAsync مقارنة بـ async هي أن الاختبار يبدو متزامنًا. لا يوجد
then(...)ليعطل تدفق التحكم المرئي. وعودfixture.whenStableالمختصة بالرجوع قد اختفت، واستُبدلت بـtick()هناك قيود. على سبيل المثال، لا يمكنك إجراء استدعاء XHR من داخل
fakeAsync
الإجابة رقم 3
أنا أستخدم Angular 6. اتبعت إجابة Mav55 وقد نجحت. ومع ذلك، أردت التأكد إذا كان fixture.detectChanges(); ضروريًا حقًا، لذا قمت بإزالته وما زال يعمل. ثم أزلت tick(); لأرى إذا كان سيعمل وفعلاً عمل. وأخيرًا أزلت الاختبار من غلاف fakeAsync()، والمفاجأة، لقد عمل.
لذلك انتهى بي الأمر بهذا:
it('should call onClick method', () => {
const onClickMock = spyOn(component, 'onClick');
fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null);
expect(onClickMock).toHaveBeenCalled();
});
وتم العمل بشكل جيد تمامًا.
