Tengo el siguiente código para probar el valor del elemento Seleccionar después de cambiar:
it("changes value after selecting another field", () => { doSetupWork(); let field = screen.getByLabelText("MySelectField"); expect(field).toHaveValue(""); fireEvent.change(field, { target: { value: "1" } }); // Insert one of two options from below });Sin embargo, cuando inserto lo siguiente en la parte inferior, no funciona:
field = screen.getByLabelText("MySelectField"); expect(field).toHaveValue("1");y da el siguiente mensaje de error:
Expected the element to have value: 1 Received: Pero, cuando lo envuelvo en un setTimeout con solo 1 ms de retraso, funciona:
setTimeout(() => { field = screen.getByLabelText("MySelectField"); expect(field).toHaveValue("1"); }, 1); Parece que debería haber una forma más elegante de escribir esto sin setTimeout . ¿Algún consejo?
Cuando uso react-testing-library, tiendo a usar render cuando tengo eventos con los que interactuar. Por ejemplo:
En mi App.js tengo este código en el método de retorno
const handleChoice = () => {}; const attributes = [ { label: "One", value: "1" }, { label: "Two", value: "2" }, { label: "Three", value: "3" } ]; return ( <div className="App"> <h1>Hello CodeSandbox</h1> <select onChange={handleChoice} data-testid="MySelectField"> <option value="0">Zero</option> {attributes.map((item) => { return ( <option key={item.value} value={item.value}> {item.label} </option> ); })} </select> </div> );entonces mi prueba sería algo como esto:
import { fireEvent, render } from "@testing-library/react"; import "@testing-library/jest-dom"; import App from "./App"; it("changes value after selecting another field", () => { const { getByTestId } = render(<App />); let field = getByTestId("MySelectField"); expect(field).toHaveValue("0"); fireEvent.change(field, { target: { value: "1" } }); expect(field.value).toBe("1"); fireEvent.change(field, { target: { value: "3" } }); expect(field.value).toBe("3"); // Insert one of two options from below });Eche un vistazo a este sandbox para ver cómo funciona. https://codesandbox.io/s/ecstatic-https-hzi5n?file=/src/App.spec.js
Lo que está viendo es que su aplicación tarda una cantidad finita de tiempo en reaccionar (disculpe el juego de palabras) al cambio que se ha producido; específicamente, necesita volver a renderizarse.
Y sí, hay una mejor manera: la función waitFor de testing-library/react :
import { screen, waitFor } from '@testing-library/react'; ... it("changes value after selecting another field", async () => { ... fireEvent.change(field, { target: { value: "1" } }); await waitFor(async () => { field = screen.getByLabelText("MySelectField"); expect(field).toHaveValue("1"); }); } Tenga en cuenta que todo el cuerpo de la prueba (es decir, después del nombre de la prueba) debe declararse async para poder await el nuevo bloque waitFor .