angularunit-testingjestjsangular-reactive-formsangular-custom-validators

Angular Unit Test for Custom Validator FormGroup


How to unit test (Jest here) custom validator, which has FormGroup? I've seen this question, but it's about FormControl.

The function to be tested.

import { FormGroup } from '@angular/forms';

/**
 * @description Validate if passwords are different.
 * @function validatePasswords
 * @param {string} passwordControlName - reference to formControlPassword of the contactForm.
 * @param {string} confirmPasswordControlName - reference to formControlConfirmPassword of the contactForm.
 * @returns {(formGroup: FormGroup) => void}
 */
export function validatePasswords(
  passwordControlName: string,
  confirmPasswordControlName: string
): (formGroup: FormGroup) => void {
  return (formGroup: FormGroup) => {
    // Get values of desired controls of the form.
    const passwordControl = formGroup.controls[passwordControlName];
    const confirmPasswordControl =
      formGroup.controls[confirmPasswordControlName];

    if (
      // Don't show the error if any different error occured in password confirmation.
      confirmPasswordControl.errors &&
      !confirmPasswordControl.errors.passwordMismatch
    ) {
      return; // Different validator shown an error, therefore return.
    }

    // Check if password and password confirmation are different.
    if (passwordControl.value !== confirmPasswordControl.value) {
      confirmPasswordControl.setErrors({ passwordMismatch: true }); // Password and confirm password are different, therefore show passwordMismatch error.
    } else {
      confirmPasswordControl.setErrors(null); // Password and confirm password are the same, therefore don't display any error.
    }
  };
}

Solution

  • You can create a test FormGroup which consists of 2 password controls and apply validatePasswords validator to this group:

    describe('validatePasswords', () => {
      const password = 'password';
      const confirmPassword = 'confirmPassword';
      let formGroup: FormGroup;
    
      beforeEach(() => {
        formGroup = new FormGroup({
          [password]: new FormControl(),
          [confirmPassword]: new FormControl(),
        }, validatePasswords(password, confirmPassword));
      });
    
      it('should has "passwordMismatch" error if passwords do not match', () => {
        formGroup.patchValue({
          [password]: '123',
          [confirmPassword]: '321'
        });
        
        expect(formGroup.get(confirmPassword).hasError('passwordMismatch')).toBe(true);
      });
      
      it('should be valid if passwords match', () => {
        formGroup.patchValue({
          [password]: '123',
          [confirmPassword]: '123'
        });
        
        expect(formGroup.get(confirmPassword).valid).toBe(true);
      });
    });