Testowanie walidatorów w Angular

W jaki sposób testować Angularowe walidatory.

Przykład

Gdy tworze aplikacji często umieszczam kod odpowiedzialny za tworzenie FormGroup w dedykowanych serwisach dzięki czemu są one później łatwiejsze w testowaniu. W tym przykładzie stworze serwis o nazwie FormService. To prosty serwisy z wstrzykniętym serwisem FormBuilder i jedną metodą createForm, które buduje nasz form.

import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Injectable({
  providedIn: 'root',
})
export class FormService {
  constructor(private fb: FormBuilder) {}

  public createForm(): FormGroup {
    return this.fb.group({
      login: ['', [Validators.required, Validators.minLength(4)]]
    });
  }
}
Plik testowy

Jeśli używamy komendy ng g service form powinniśmy mieć drugi plik z rozszerzeniem .spec.ts. W innym przypadku musimy stworzyć go samego.

import { TestBed } from '@angular/core/testing';
import { FormService } from "./form.service";

describe('FormService', () => {
  beforeEach(() => TestBed.configureTestingModule({}));

  it('should be created', () => {
    const service: FormService = TestBed.get(FormService);
    expect(service).toBeTruthy();
  });
});

Potrzebujemy testowym module wstrzyknąć serwis FormBuilder – tak aby nasz bazowy test should be created wykonał się pozytywnie.

import { TestBed } from '@angular/core/testing';
import { FormService } from './form.service';
import { FormBuilder } from '@angular/forms';

describe('FormService', () => {
  beforeEach(() => TestBed.configureTestingModule({
    providers: [
      FormBuilder
    ]
  }));

  it('should be created', () => {
    const service: FormService = TestBed.get(FormService);
    expect(service).toBeTruthy();
  });
});

Testowanie

Niestety, ale Angular nie dostarcza żadnej pomocnej funkcjonalności do testowania walidatorów z klasy Validators takich jak np. hasRequiredValidator. Aby przetestować, któryś z walidatorów musimy wytworzyć odpowiedni stan danej kontrolki, tak aby walidatorów który jest do niej przypisany przypisał swoje polem z błędem do obiektu errors. Brzmi zawile, ale staje się o wiele jaśniejsze, gdy stworzymy taki test chociaż raz.

Stworzyłem podstawowe bloki ‘describe’ i ‘it’ w których umieszczę moją logikę, która przetestuje mój FormGroup — w tym przypadku tylko walidatory.

describe('createForm', () => {
  describe('login control', () => {
    it('should has required validator', () => {
       
    });

    it('should has min length validator', () => {
        
    });
  });
});

Zastanówmy się w jakich warunkach każdy z walidatorów doda swoje pole z błędem do obiektu errors.

  • Validators.required, gdy wartość FormControl jest np. null
  • Validators.minLength(4), gdy wartość FormControl jest krótsza niż cztery znaki

Dokonajmy symulacji owych warunków, aby sprawdzić czy FormControl posiada każdy z tych walidatorów.

describe('createForm', () => {
  describe('login control', () => {
    it('should has required validator', () => {
      const service: FormService = TestBed.get(FormService);
      const form: FormGroup = service.createForm();
      const control: AbstractControl = form.get('login');

      control.setValue(null);

      expect(control.hasError('required')).toBeTruthy();
    });

    it('should has min length validator', () => {
      const service: FormService = TestBed.get(FormService);
      const form: FormGroup = service.createForm();
      const control: AbstractControl = form.get('login');

      control.setValue('12');

      expect(control.hasError('minlength')).toBeTruthy();
    });
  });
});

W ten sposób możemy sprawdzić pozostałe walidatory z Angularowej klasy Validators lub też nasz własny.

Podsumowanie

Osobiście żałuje, że Angular nie posiada owej funkcjonalności, która pomogła by z testowaniem walidatorów. Byłoby to bardzo pomocne.

Udostępnij
Default image
Wojciech Szućko
Jestem Angular Developerem. Przedstawiam techniki i technologie, które wykorzystuje w codziennej pracy z web aplikacjami. Tworzyłem projekty między innymi dla Bank Pekao S.A., AlphaTauri czy Playmobil.