En mi componente de reacción, tengo un elemento que aparece después de 5 segundos.
Quiero hacer una prueba que verifique si el elemento aparece después de 5 segundos con jest fake timers , pero no puedo hacerlo funcionar...
¿Qué estoy haciendo mal aquí?
Uno de los ejemplos no funciona:
it('check step 2 labels text, status "Submitted"', async () => { render(<ProgressIndicator appStatus="submitted" />); jest.advanceTimersByTime(5005); await waitFor(() => { expect( screen.getByText('Beep. Boop. Still doing our thing here.'), ).toBeInTheDocument(); }); await waitFor(() => { expect(screen.getByText('Verifying identity...')).toBeInTheDocument(); }); });Segundo ejemplo:
it('check step 2 labels text, status "Submitted"', async () => { render(<ProgressIndicator appStatus="submitted" />); act(() => { jest.advanceTimersByTime(5005); }); expect( screen.getByText('Beep. Boop. Still doing our thing here.'), ).toBeInTheDocument(); expect(screen.getByText('Verifying identity...')).toBeInTheDocument(); });La regla general de usar await findBy findBy query y await waitFor es que debe usar
await findBycuando espera que aparezca un elemento, pero es posible que el cambio en el DOM no ocurra de inmediato.
y
await waitForcuando tenga una prueba unitaria que simula llamadas API y necesite esperar a que se resuelvan sus promesas simuladas.
Lo mismo se menciona en la documentación oficial de dom-testing-library .
Ahora, en cuanto a su preocupación, debe usar jest.useFakeTimer() para habilitar temporizadores falsos que ayudarán a burlarse de setTimeout y otras funciones de temporizador.
Lo mismo se menciona aquí en documentos oficiales .
useFakeTimer funciona con los métodos asíncronos , sin embargo, si queremos trabajar con métodos de sincronización como las consultas getBy , entonces tenemos que usar jest.advanceTimersByTime(5000) para adelantar su prueba 5 (cualquier tiempo especificado) segundos. (ejemplo dado a continuación)
En el siguiente ejemplo reproduzco la inquietud que me has planteado. Creo que esto podría ayudar.
import { useState } from 'react'; import { act, render, screen, waitForElementToBeRemoved } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; const data = { name: 'subrato', age: 24, }; function App() { const [myData, setState] = useState({}); const [loading, setLoading] = useState(false); function clickHandler() { setLoading(true); setTimeout(() => { setState(data); setLoading(false); }, 5000); } return ( <div className='App'> {loading && <div aria-label='loading'>loading....</div>} <p>{myData?.name}</p> <p>{myData?.age}</p> <button onClick={clickHandler}>Click me</button> </div> ); } describe('Test my app', () => { beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); it('display data', async () => { render(<App />); userEvent.click(screen.getByText('Click me')); expect(screen.getByLabelText(/loading/i)).toBeInTheDocument(); expect(await screen.findByText('subrato')).toBeInTheDocument(); expect(screen.getByText('24')).toBeInTheDocument(); }); it('display data second time', async () => { render(<App />); userEvent.click(screen.getByText('Click me')); expect(screen.getByLabelText(/loading/i)).toBeInTheDocument(); act(() => jest.advanceTimersByTime(5000)); expect(screen.getByText('subrato')).toBeInTheDocument(); expect(screen.getByText('24')).toBeInTheDocument(); }); });Resultado de la prueba
PASS src/TimerExample.spec.tsx (9.001 s) Test my app √ display data (487 ms) √ display data second time (35 ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 14.997 s Ran all test suites matching /TimerExample.spec.tsx/i.