07 kwi 2020
5 min

Spectator – kiedy testowanie staje się przyjemnością

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.comgorą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:
    const 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.

  1. Stan disabled przycisku:
      // SPECTATOR
      expect(spectator.query('.button')).toBeDisabled();
    
      // TEST BED
      const button = fixture.debugElement.query(By.css('.button'));
      expect(button.nativeElement.disabled).toBeTruthy();
    

    2. Czy *ngFor wyświetla 2 komponenty w liście:

      // SPECTATOR
      expect('app-tshirt-item').toHaveLength(2);
    
      // TEST BED
      const items = fixture.debugElement.queryAll(By.directive(TshirtItemComponent));
      expect(items.length).toBe(2);

    3. Zamokowanie serwisu jako zależności komponentu:

      // SPECTATOR
      providers: [mockProvider(AuthService)], // mockProvider ze Spectator
    
      // TEST BED
      providers: [
        {
          provide: AuthService,
          useClass: MockAuthService, // nasza zamockowana klasa
        },
      ]

    4. Wywołanie "enter' na inpucie:

      // SPECTATOR
      const input = spectator.query('input');
      spectator.keyboard.pressEnter(input);
    
      // TEST BED
      const input = fixture.debugElement.query(By.css('input'));
      input.triggerEventHandler('keydown.enter', {});

    5. Czy element zawiera text:

    // SPECTATOR
    const title = spectator.query('h1');
    expect(title).toContainText('Page title');
    
    // TEST BED
    const 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:

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:

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! 😉

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.