Matchers Jest para Angular Reactive Forms

A biblioteca adiciona asserções específicas para FormGroup ao expect do Jest. Ela cobre estrutura de controles, validadores, erros e valores sem repetir chamadas a form.get() em cada teste.

FormGroup

Todos os matchers recebem um FormGroup em expect(form). O registro é feito uma vez no setup do Jest com registerAngularFormMatchers().

Instalação e configuração

Instale o pacote como dependência de desenvolvimento no projeto que executa os testes.

1. Instalar

npm install --save-dev @mazzuco-dev/jest-angular-forms

2. Registrar os matchers

src/test-setup.ts
import { setupZonelessTestEnv } from 'jest-preset-angular/setup-env/zoneless';
import { registerAngularFormMatchers } from '@mazzuco-dev/jest-angular-forms';

setupZonelessTestEnv();
registerAngularFormMatchers();

3. Configurar o Jest

jest.config.ts
export default {
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
};

Inclua o arquivo de setup também no tsconfig.spec.json para que as declarações dos matchers estejam disponíveis no TypeScript. Se você usa ambiente com Zone.js, prepare esse ambiente antes de chamar registerAngularFormMatchers().

Exemplos de uso

Os caminhos seguem a sintaxe de AbstractControl.get(), inclusive grupos aninhados e índices de FormArray.

Controles aninhados e FormArray

const form = new FormGroup({
  profile: new FormGroup({ name: new FormControl('', Validators.required) }),
  addresses: new FormArray([
    new FormGroup({ street: new FormControl('', Validators.required) }),
  ]),
});

expect(form).toHaveControls('profile.name', 'addresses.0.street');
expect(form).toHaveRequiredControls(['profile.name', 'addresses.0.street']);

Valores e controles desabilitados

const form = new FormGroup({
  email: new FormControl('ada@example.com'),
  id: new FormControl({ value: 42, disabled: true }),
});

expect(form).toHaveFormValue({ email: 'ada@example.com' });
expect(form).toHaveRawValue({ email: 'ada@example.com', id: 42 });
expect(form).toHaveDisabledControl('id');

Erros e validadores

const minLength = Validators.minLength(8);
const password = new FormControl('short', { validators: [minLength] });
const form = new FormGroup({ password });

expect(form).toHaveValidator('password', minLength);
expect(form).toHaveControlError('password', 'minlength');
expect(form).toBeInvalidForm();

Referência da API

Os matchers retornam o resultado da asserção com mensagem de falha e aceitam .not. Os métodos que recebem vários caminhos aceitam strings e arrays de strings.

Estrutura e estado

MatcherComportamento
toHaveControl(path)O controle existe no caminho informado.
toHaveControls(...paths)Todos os controles informados existem.
toHaveEnabledControl(path)O controle existe e está habilitado.
toHaveDisabledControl(path)O controle existe e está desabilitado.

Validação

MatcherComportamento
toHaveRequiredControl(path)O controle possui Validators.required.
toHaveRequiredControls(...paths)Todos os controles possuem Validators.required.
toHaveValidator(path, validator)O controle possui a mesma referência de ValidatorFn.
toHaveValidators(path, ...validators)O controle possui todas as referências de ValidatorFn.
toHaveControlError(path, error)O controle tem o erro no estado atual.
toHaveControlErrors(path, ...errors)O controle tem todos os erros no estado atual.
toHaveFormError(error)O FormGroup tem o erro no estado atual.
toBeValidForm()O FormGroup está válido.
toBeInvalidForm()O FormGroup está inválido.

Valores

MatcherComportamento
toHaveControlValue(path, expected)Compara profundamente o valor do controle.
toHaveFormValue(expected)Compara profundamente form.value.
toHaveRawValue(expected)Compara profundamente form.getRawValue().

Detalhes de comportamento

Paths
Os caminhos são resolvidos por FormGroup.get(). Exemplos: profile.name e addresses.0.street. Um caminho inexistente faz a asserção falhar.
ValidatorFn
toHaveValidator e toHaveValidators usam hasValidator(), que compara a referência da função. Guarde e reutilize a mesma instância de ValidatorFn usada no controle.
hasError()
Os matchers de erro usam hasError() no estado de validação atual. Eles não executam validação por conta própria.
value / rawValue
toHaveFormValue compara form.value, que omite controles desabilitados. toHaveRawValue usa getRawValue() e inclui esses controles. A comparação é profunda, via Jest.
.not
A negação padrão do Jest também funciona: expect(form).not.toBeValidForm().
jest-angular-forms

Código-fonte e acompanhamento de issues no GitHub.

GitHub ↗