Angular to przyjemny framework, czyż nie? 😉 Ale tak jak każde narzędzie, ma niestety też i słabsze strony. Zdecydowanym mankamentem jest chociażby pisanie testów integracyjnych templatki i klasy komponentu. Udostępniony moduł do testowania TestBed jest po prostu nieprzyjemny. Czy możemy stwierdzić śmiało, że tak podstawowe czynności jak chociażby:
- mokowanie zależności komponentu
- dostęp do bogatego zbioru asercji (tylko podstawowe z Jasmine)
- łapanie elementów (fixture.debugElement, brrr!!)
- proste przypadki testowe, np. czy „is button disabled”
Są proste i czytelne? Wg mnie… zdecydowanie nie! I w tym momencie wchodzi cały na biało:
Spectator!
Spectator to całkiem przemyślana abstrakcja na wbudowany angularowy moduł do testowania. Głównym autorem jest Netanel Basal, który również prowadzi angularowego bloga – https://netbasal.com, gorąco polecam! Biblioteka znacząco ułatwia pisanie testów, ich czytelność i utrzymanie.
Główne zalety biblioteki:
- wsparcie dla testowania pipes, komponentów, dyrektyw, serwisów HTTP oraz routingu
- uproszczone łapanie elementów drzewa DOM (tak jak w jQuery ?)
- bogatsze API do uruchamiania eventów (Mouse helpers i Keyboard helpers)
- wygodne testowanie z użyciem HostComponent
- wsparcie dla testowania ng-content
- większa liczba matchers, takich jak chociażby .toBeDisabled() czy .toBeFocused()
- wsparcie dla entry components i component providers
- automokowanie serwisów, wow!
- wsparcie dla JEST
- global queries:
123const element = spectator.query('.overlay', {root: true,})
Let’s check it!
Porównajmy, jak mogą wyglądać elementy testów w Spectatorze w porównaniu z TestBed Module, na prostych przykładach.
- Stan disabled przycisku:
123456// SPECTATORexpect(spectator.query('.button')).toBeDisabled();// TEST BEDconst button = fixture.debugElement.query(By.css('.button'));expect(button.nativeElement.disabled).toBeTruthy();
2. Czy *ngFor wyświetla 2 komponenty w liście:
123456// SPECTATORexpect('app-tshirt-item').toHaveLength(2);// TEST BEDconst items = fixture.debugElement.queryAll(By.directive(TshirtItemComponent));expect(items.length).toBe(2);
3. Zamokowanie serwisu jako zależności komponentu:
12345678910// SPECTATORproviders: [mockProvider(AuthService)], // mockProvider ze Spectator// TEST BEDproviders: [{provide: AuthService,useClass: MockAuthService, // nasza zamockowana klasa},]
4. Wywołanie „enter’ na inpucie:
1234567// SPECTATORconst input = spectator.query('input');spectator.keyboard.pressEnter(input);// TEST BEDconst input = fixture.debugElement.query(By.css('input'));input.triggerEventHandler('keydown.enter', {});
5. Czy element zawiera text:
1234567// SPECTATORconst title = spectator.query('h1');expect(title).toContainText('Page title');// TEST BEDconst title = fixture.debugElement.query(By.css('h1'));expect(title.nativeElement.textContent).toContain('Page title');
Nie da się zaprzeczyć, że w Spectatorze wygląda to znacznie prościej i czytelniej! Dziesiątki przykładów znajdziesz w dokumentacji:
https://github.com/ngneat/spectator
Instalacja
Jeśli przekonałem Cię do Spectatora, to nie pozostaje nic innego, jak dodanie go do projektu wraz z ng-mocks poprzez npm:
1 |
npm i -D @netbasal/spectator ng-mocks |
Schematics
Warto też dodać, że Spectator posiada własne Schematics. Na przykład w celu wygenerowania pliku z testem dla komponentu, możemy posłużyć się poleceniem:
1 |
ng g cs path/component-name |
Bonus!
A ja jeśli kodujesz z użyciem Visual Studio Code, to koniecznie dodaj wtyczkę do snippetów:
oraz poćwicz z playground od autorów:
PLAYGROUND
Miłego testowania! 😉
Nawet odświerzyłem na potrzeby szkolenia moje repo z porównaniem Angular Testing Library a Spectator 😉
https://github.com/michalczukm/spectator-make-angular-tests-great-again-presentation
A jak wygląda różnica w czasie odpalenia testów?