Tengo una instancia de 'cliente' de una clase JS como esta:
class Client { async fetchRandomUser() { let response = await fetch("https://randomuser.me/api/?gender=male") if (response.status >= 400) { throw new Error("Error fetching random user"); } return (await response.json()).results[0]; } }Entonces tengo un componente React como este:
import React from 'react'; import client from "./service/Client"; class Person extends React.Component { constructor(props) { super(props); this.state = {image: ''} } async componentDidMount() { const user = await client.fetchRandomUser(); this.setState({image: user.picture.large}); } setError(error) { return this.setState({errorStatus: error}); } render() { return ( <img src={this.state.image} width="128" height="128"/> ); } } export default Person;Y una prueba para acompañarlo:
import React from "react"; import { render, screen, waitFor } from '@testing-library/react'; import Person from './Person'; test('fetches image from random user API', async () => { const mockFetchRandomUser = jest.fn().mockImplementation(async () => Promise.resolve({picture:{large: 'personImage'}})); jest.mock("./service/Client", () => { return { fetchRandomUser: mockFetchRandomUser }; }); const {container} = render(<Person data-testid="person"/>); const image = screen.getByRole('img'); await waitFor(() => expect(image.src !== "").toBeTruthy()) .then(() => { screen.debug(image); expect(mockFetchRandomUser).toHaveBeenCalledTimes(1); }); });Dentro de esta prueba, no puedo obtener el waitFor o findByRole ni nada por el estilo para esperar hasta que la etiqueta haya obtenido su conjunto de atributos src. ¿Cómo hago esto?
En el alcance de la función del caso de prueba, use el método jest.mock() no se elevará a la parte superior del código (antes de cualquier import de es6). Eso significa que el componente ./Person importado utilizará el módulo ./service/Client original al ejecutar el caso de prueba. Es tarde para el simulacro.
Desde Uso con importaciones de módulos ES :
Si está utilizando importaciones de módulos ES, normalmente se inclinará a colocar sus declaraciones de importación en la parte superior del archivo de prueba. Pero a menudo necesita indicarle a Jest que use un simulacro antes de que los módulos lo usen. Por esta razón, Jest elevará automáticamente las llamadas
jest.mocka la parte superior del módulo (antes de cualquier importación).
Así que tienes dos opciones:
1. Use import() para importar los módulos dinámicamente después de llamar a jest.mock() en el alcance funcional del caso de prueba.
Person.test.jsx :
import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; test('fetches image from random user API', async () => { jest.mock('./service/Client'); const Person = (await import('./Person')).default; const client = (await import('./service/Client')).default; client.fetchRandomUser.mockResolvedValueOnce({ picture: { large: 'personImage' } }); render(<Person data-testid="person" />); const image = screen.getByRole('img'); await waitFor(() => expect(image.src !== '').toBeTruthy()); expect(client.fetchRandomUser).toHaveBeenCalledTimes(1); }); 2. Use jest.mock() en el alcance del módulo del archivo de prueba, luego puede usar la import estática para importar los módulos
Person.test.jsx :
import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import Person from './Person'; import client from './service/Client'; jest.mock('./service/Client'); test('fetches image from random user API', async () => { client.fetchRandomUser.mockResolvedValueOnce({ picture: { large: 'personImage' } }); render(<Person data-testid="person" />); const image = screen.getByRole('img'); await waitFor(() => expect(image.src !== '').toBeTruthy()); expect(client.fetchRandomUser).toHaveBeenCalledTimes(1); }); versión de jestjs: "jest": "^26.6.3"