Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

366
Visualizações
Probando el componente funcional React con Hooks usando Jest

Así que me estoy alejando de los componentes basados en clases a los componentes funcionales, pero estoy atascado mientras escribo la prueba con broma/enzima para los métodos dentro de los componentes funcionales que usan ganchos explícitamente. Aquí está la versión simplificada de mi código.

 function validateEmail(email: string): boolean { return email.includes('@'); } const Login: React.FC<IProps> = (props) => { const [isLoginDisabled, setIsLoginDisabled] = React.useState<boolean>(true); const [email, setEmail] = React.useState<string>(''); const [password, setPassword] = React.useState<string>(''); React.useLayoutEffect(() => { validateForm(); }, [email, password]); const validateForm = () => { setIsLoginDisabled(password.length < 8 || !validateEmail(email)); }; const handleEmailChange = (evt: React.FormEvent<HTMLFormElement>) => { const emailValue = (evt.target as HTMLInputElement).value.trim(); setEmail(emailValue); }; const handlePasswordChange = (evt: React.FormEvent<HTMLFormElement>) => { const passwordValue = (evt.target as HTMLInputElement).value.trim(); setPassword(passwordValue); }; const handleSubmit = () => { setIsLoginDisabled(true); // ajax().then(() => { setIsLoginDisabled(false); }); }; const renderSigninForm = () => ( <> <form> <Email isValid={validateEmail(email)} onBlur={handleEmailChange} /> <Password onChange={handlePasswordChange} /> <Button onClick={handleSubmit} disabled={isLoginDisabled}>Login</Button> </form> </> ); return ( <> {renderSigninForm()} </>); }; export default Login;

Sé que puedo escribir pruebas para validateEmail correo electrónico exportándolo. Pero, ¿qué hay de probar los métodos validateForm o handleSubmit ? Si se tratara de componentes basados en clases, podría simplemente reducir el componente y usarlo desde la instancia como

 const wrapper = shallow(<Login />); wrapper.instance().validateForm()

Pero esto no funciona con componentes funcionales ya que no se puede acceder a los métodos internos de esta manera. ¿Hay alguna forma de acceder a estos métodos o los componentes funcionales deben tratarse como una caja negra durante la prueba?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

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(<Login />); 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 setTimeout :

 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 = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return regEx.test(email.trim().toLowerCase()) }

LoginComponent.jsx

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

De esta manera, podría probar individualmente isPasswordValid e isEmailValid , y luego, al probar el componente de inicio de Login , puede simular sus importaciones . Y luego, lo único que queda por probar para su componente de inicio de Login sería que al hacer clic, se llama a los métodos importados y luego el comportamiento basado 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 componente de inicio de Login solo debe manejar la actualización del formulario y nada más. Y eso se puede probar bastante sencillo. Cualquier otra lógica, debe manejarse por separado ( separación de preocupaciones ).

over 4 years ago · Santiago Trujillo Relatório

0

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 falsos positivos)

 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é, busco una respuesta yo mismo, porque por alguna razón el useLayoutEffect no se está probando para mí ...

over 4 years ago · Santiago Trujillo Relatório

0

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

 describe('<Login /> with no props', () => { const container = shallow(<Login />); 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 los componentes no controlados, configuré un accesorio de atributo de datos para establecer el valor y verifiqué el valor simulando eventos. También he escrito 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

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda