Tengo un componente que usa useContext y luego su salida depende del valor en el contexto. Un ejemplo sencillo:
import React, { useContext } from 'react'; const MyComponent = () => { const name = useContext(NameContext); return <div>{name}</div>; }; Al probar este componente con el renderizador superficial de instantáneas de reacción y broma. ¿Cómo puedo cambiar el valor de NameContext ?
En general, el uso de ganchos no debería cambiar mucho la estrategia de prueba. El mayor problema aquí en realidad no es el gancho, sino el uso del contexto, lo que complica un poco las cosas.
Hay varias formas de hacer que esto funcione, pero el único enfoque que he encontrado que funciona con 'react-test-renderer/shallow' es inyectar un gancho simulado:
import ShallowRenderer from 'react-test-renderer/shallow'; let realUseContext; let useContextMock; // Setup mock beforeEach(() => { realUseContext = React.useContext; useContextMock = React.useContext = jest.fn(); }); // Cleanup mock afterEach(() => { React.useContext = realUseContext; }); test("mock hook", () => { useContextMock.mockReturnValue("Test Value"); const element = new ShallowRenderer().render( <MyComponent /> ); expect(element.props.children).toBe('Test Value'); });Sin embargo, esto es un poco sucio y específico de la implementación, por lo que si puede comprometer el uso del renderizador superficial, hay algunas otras opciones disponibles:
Si no está renderizando superficialmente, puede envolver el componente en un proveedor de contexto para inyectar el valor que desea:
import TestRenderer from 'react-test-renderer'; test("non-shallow render", () => { const element = new TestRenderer.create( <NameContext.Provider value="Provided Value"> <MyComponent /> </NameContext.Provider> ); expect(element.root.findByType("div").children).toEqual(['Provided Value']); });(Descargo de responsabilidad: esto debería funcionar, pero cuando lo pruebo, aparece un error que creo que es un problema en mi configuración)
Como comentó @skyboyer, el renderizador superficial de enzima es compatible con .dive , lo que le permite renderizar profundamente una parte de un componente renderizado superficial:
import { shallow } from "./enzyme"; test("enzyme dive", () => { const TestComponent = () => ( <NameContext.Provider value="Provided Value"> <MyComponent /> </NameContext.Provider> ); const element = shallow(<TestComponent />); expect(element.find(MyComponent).dive().text()).toBe("Provided Value"); }); Finalmente, las Preguntas frecuentes sobre ganchos tienen un ejemplo de prueba de ganchos con ReactDOM , que también funciona. Naturalmente, usar ReactDOM significa que este también es un renderizado profundo, no superficial.
let container; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); container = null; }); test("with ReactDOM", () => { act(() => { ReactDOM.render(( <NameContext.Provider value="Provided Value"> <MyComponent /> </NameContext.Provider> ), container); }); expect(container.textContent).toBe("Provided Value"); });Traté de usar Enzyme + .dive , pero al bucear, no reconoce los accesorios de contexto, obtiene los predeterminados. En realidad, es un problema conocido por el equipo de Enzyme. Mientras tanto, se me ocurrió una solución más simple que consiste en crear un enlace personalizado solo para devolver useContext con su contexto y simular el regreso de este enlace personalizado en la prueba:
AppContext.js: crea el contexto.
import React, { useContext } from 'react'; export const useAppContext = () => useContext(AppContext); const defaultValues = { color: 'green' }; const AppContext = React.createContext(defaultValues); export default AppContext;App.js — Proporcionar el contexto
import React from 'react'; import AppContext from './AppContext'; import Hello from './Hello'; export default function App() { return ( <AppContext.Provider value={{ color: 'red' }}> <Hello /> </AppContext.Provider> ); }Hello.js - Consumir el contexto
import React from 'react'; import { useAppContext } from './AppContext'; const Hello = props => { const { color } = useAppContext(); return <h1 style={{ color: color }}>Hello {color}!</h1>; }; export default Hello;Hello.test.js - Prueba de useContext con Enzyme superficial
import React from 'react'; import { shallow } from 'enzyme'; import * as AppContext from './AppContext'; import Hello from './Hello'; describe('<Hello />', () => { test('it should mock the context', () => { const contextValues = { color: 'orange' }; jest .spyOn(AppContext, 'useAppContext') .mockImplementation(() => contextValues); const wrapper = shallow(<Hello />); const h1 = wrapper.find('h1'); expect(h1.text()).toBe('Hello orange!'); }); });Consulte el artículo completo de Medium en https://medium.com/7shifts-engineering-blog/testing-usecontext-react-hook-with-enzyme-shallow-da062140fc83
O si está probando su componente de forma aislada sin montar los componentes principales, simplemente puede burlarse de useContext:
jest.mock('react', () => { const ActualReact = jest.requireActual('react') return { ...ActualReact, useContext: () => ({ }), // what you want to return when useContext get fired goes here } })