Saltar al contenido

Probando el componente funcional React con Hooks usando Jest

Este grupo de trabajo ha pasado mucho tiempo investigando la respuesta a tus búsquedas, te ofrecemos la solución y nuestro objetivo es resultarte de gran ayuda.

Solución:

En mi opinión, no debería preocuparse por probar individualmente los métodos dentro del FC, sino por probar sus efectos secundarios. p.ej:

  it('should disable submit button on submit click', () => 
    const wrapper = mount();
    const submitButton = wrapper.find(Button);
    submitButton.simulate('click');

    expect(submitButton.prop('disabled')).toBeTruthy();
  );

Dado que podría estar usando useEffect, que es asíncrono, es posible que desee envolver su expectativa en un establecer tiempo de espera:

setTimeout(() => 
  expect(submitButton.prop('disabled')).toBeTruthy();
);

Otra cosa que podría querer hacer es extraer cualquier lógica que no tenga nada que ver con la interacción con las funciones puras de introducción de formulario. por ejemplo: en lugar de:

setIsLoginDisabled(password.length < 8 || !validateEmail(email));

Puedes refactorizar:

Ayudantes.js

export const isPasswordValid = (password) => password.length > 8;
export const isEmailValid    = (email) => 
  const regEx = /^(([^<>()[]\.,;:[email protected]"]+(.[^<>()[]\.,;:[email protected]"]+)*)

LoginComponent.jsx

import  isPasswordValid, isEmailValid  from './Helpers';
....
  const validateForm = () => 
    setIsLoginDisabled(!isPasswordValid(password) ;
....

De esta manera podría probar individualmente isPasswordValid y isEmailValidy luego al probar el Login componente, puede simular sus importaciones. Y luego las únicas cosas que quedan por probar para su Login El componente sería que al hacer clic, se llama a los métodos importados y luego el comportamiento se basa en esa respuesta, por ejemplo:

- it('should invoke isPasswordValid on submit')
- it('should invoke isEmailValid on submit')
- it('should disable submit button if email is invalid') (isEmailValid mocked to false)
- it('should disable submit button if password is invalid') (isPasswordValid mocked to false)
- it('should enable submit button if email is invalid') (isEmailValid and isPasswordValid mocked to true)

La principal ventaja de este enfoque es que el Login el componente solo debe manejar actualizando el formulario y nada más. Y eso se puede probar bastante sencillo. Cualquier otra lógica, debe manejarse por separado (separación de intereses).

No puede escribir comentarios, pero debe tener en cuenta que lo que dijo Alex Stoicuta está mal:

setTimeout(() => 
  expect(submitButton.prop('disabled')).toBeTruthy();
);

esta afirmación siempre pasará, porque... nunca se ejecuta. Cuente cuántas afirmaciones hay en su prueba y escriba lo siguiente, porque solo se realiza una afirmación en lugar de dos. Así que revise sus pruebas ahora para false positivo)

it('should fail',()=>
 expect.assertions(2);

 expect(true).toEqual(true);

 setTimeout(()=>
  expect(true).toEqual(true)
 )
)

Respondiendo a su pregunta, ¿cómo prueba los ganchos? No sé, buscando una respuesta yo mismo, porque por alguna razón el useLayoutEffect no me estan probando...

Entonces, tomando la respuesta de Alex, pude formular el siguiente método para probar el componente.

describe(' with no props', () => 
  const container = shallow();
  it('should match the snapshot', () => 
    expect(container.html()).toMatchSnapshot();
  );

  it('should have an email field', () => 
    expect(container.find('Email').length).toEqual(1);
  );

  it('should have proper props for email field', () => 
    expect(container.find('Email').props()).toEqual(
      onBlur: expect.any(Function),
      isValid: false,
    );
  );

  it('should have a password field', () => 
    expect(container.find('Password').length).toEqual(1);
  );

  it('should have proper props for password field', () => 
    expect(container.find('Password').props()).toEqual(
      onChange: expect.any(Function),
      value: '',
    );
  );

  it('should have a submit button', () => 
    expect(container.find('Button').length).toEqual(1);
  );

  it('should have proper props for submit button', () => 
    expect(container.find('Button').props()).toEqual(
      disabled: true,
      onClick: expect.any(Function),
    );
  );
);

Para probar las actualizaciones de estado como Alex mencionó, probé los efectos secundarios:

it('should set the password value on change event with trim', () => 
    container.find('input[type="password"]').simulate('change', 
      target: 
        value: 'somenewpassword  ',
      ,
    );
    expect(container.find('input[type="password"]').prop('value')).toEqual(
      'somenewpassword',
    );
  );

pero para probar los ganchos del ciclo de vida sigo usando mount en lugar de superficial, ya que aún no es compatible con el renderizado superficial. Separé los métodos que no están actualizando el estado en un archivo de utilidades separado o fuera del componente React Function. Y para probar componentes no controlados configuro un dato attribute prop para establecer el valor y verificó el valor simulando eventos. También escribí un blog sobre la prueba de los componentes de la función React para el ejemplo anterior aquí: https://medium.com/@acesmndr/testing-react-funcional-components-with-hooks-using-enzyme-f732124d320a

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *