admin管理员组文章数量:1277377
I have a very simple ponent where I am trying to simulate an API call to get some movies with a slight delay.
I want to write a test which tests that the movies are gathered and then rendered to screen.
I am trying to use screen.getAllByTestId
to do this, however it always fails. It is as if it doesn't re-render and therefore does not get the updated change.
I have added a testid onto the elements and can see these in the DOM.
Can anyone help as to why this isn't finding them after they appear?
Here is the full ponent code...
import './App.css';
import { useEffect, useState } from 'react';
function App() {
const [movies, setMovies] = useState([]);
useEffect(() => {
// simulate API call to get
setTimeout(() => {
const movies = [{ title: 'Titanic' }, { title: 'Back To The Future' }];
setMovies(movies);
}, 1000);
}, []);
return (
<div>
{movies.length > 0 && (
<div>
{movies.map((x) => (
<div data-testid='movies'>{x.title}</div>
))}
</div>
)}
</div>
);
}
export default App;
Here is the full test code...
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const movieTiles = screen.getAllByTestId('movies');
expect(movieTiles).toHaveLength(2);
});
Here is the error from the test
I have a very simple ponent where I am trying to simulate an API call to get some movies with a slight delay.
I want to write a test which tests that the movies are gathered and then rendered to screen.
I am trying to use screen.getAllByTestId
to do this, however it always fails. It is as if it doesn't re-render and therefore does not get the updated change.
I have added a testid onto the elements and can see these in the DOM.
Can anyone help as to why this isn't finding them after they appear?
Here is the full ponent code...
import './App.css';
import { useEffect, useState } from 'react';
function App() {
const [movies, setMovies] = useState([]);
useEffect(() => {
// simulate API call to get
setTimeout(() => {
const movies = [{ title: 'Titanic' }, { title: 'Back To The Future' }];
setMovies(movies);
}, 1000);
}, []);
return (
<div>
{movies.length > 0 && (
<div>
{movies.map((x) => (
<div data-testid='movies'>{x.title}</div>
))}
</div>
)}
</div>
);
}
export default App;
Here is the full test code...
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const movieTiles = screen.getAllByTestId('movies');
expect(movieTiles).toHaveLength(2);
});
Here is the error from the test
Share Improve this question edited Jul 20, 2021 at 19:14 user3284707 asked Jul 20, 2021 at 19:07 user3284707user3284707 3,3513 gold badges46 silver badges80 bronze badges2 Answers
Reset to default 5You should use Fake Timers when your code uses timers (setTimeout
, setInterval
, clearTimeout
, clearInterval
).
Use jest.advanceTimersByTime(1000)
to move ahead in time by 1000ms.
Don't forget act()
helper function:
When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. react-dom/test-utils provides a helper called
act()
that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions:
Since we run the setState
function that will change the ponent state 1000ms ahead of time, we must wrap this operation (jest.advanceTimersByTime(1000)
) in the act()
function.
Otherwise, you will get warning:
Warning: An update to App inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
E.g.
App.jsx
:
import React, { useEffect, useState } from 'react';
function App() {
const [movies, setMovies] = useState([]);
useEffect(() => {
setTimeout(() => {
const movies = [{ title: 'Titanic' }, { title: 'Back To The Future' }];
setMovies(movies);
}, 1000 * 10);
}, []);
return (
<div>
{movies.length > 0 && (
<div>
{movies.map((x, idx) => (
<div key={idx} data-testid="movies">
{x.title}
</div>
))}
</div>
)}
</div>
);
}
export default App;
App.test.jsx
:
import { render, screen, act } from '@testing-library/react';
import React from 'react';
import App from './App';
describe('68460159', () => {
test('renders learn react link', async () => {
jest.useFakeTimers();
render(<App />);
act(() => {
jest.advanceTimersByTime(1000 * 10);
});
const movieTiles = screen.getAllByTestId('movies');
expect(movieTiles).toHaveLength(2);
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
});
test result:
PASS examples/68460159/App.test.jsx (7.878 s)
68460159
✓ renders learn react link (33 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
App.jsx | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.678 s, estimated 10 s
I've experienced this issue without having setTimeout
s in hooks or anything. What worked for me was transitioning from getAllBy*
to await findAllBy*
and making the whole test async
of course. Everything else stayed the same and it suddenly passed
本文标签:
版权声明:本文标题:javascript - React Testing Library does not find elements using getAllByTestId after initial render - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741292184a2370616.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论