Priority Order in RTL Queries
The RTL query methods are categorized based on priority for testing. Always aim to use the most accessible queries:
getBy: Throws an error if no element is found. Use for synchronous assertions.queryBy: Returnsnullif no element is found. Use when testing for the absence of elements.findBy: Works with asynchronous elements that appear after some delay. It returns a promise.
Assertion Methods
RTL comes with various assertion methods to validate your queries:
toBeInTheDocument()not.toBeInTheDocument()toHaveTextContent()toHaveAttribute()toBeDisabled()toBeEnabled()
queryBy and queryByAll
queryBy: Use for testing an element's absence.queryByAll: Returns an empty array if no elements match. Use when checking multiple elements.
Example:
Testing for the absence of a conditional element.
test('queryBy example', () => {
render(<App />);
const div = screen.queryByText('Login');
expect(div).not.toBeInTheDocument();
});
findBy Query
Use findBy for elements that appear after some delay, often in cases like API loading states.
When to Use:
When elements take time to appear (e.g., API call or animation).
Example:
test('findBy example', async () => {
render(<App />);
const div = await screen.findByText('data is here', {}, { timeout: 4000 });
expect(div).toBeInTheDocument();
});
React Code:
const App = () => {
const [data, setData] = useState(false);
useEffect(() => {
setTimeout(() => {
setData(true);
}, 2000);
}, []);
return <div>{data ? 'data is here' : 'data is loading'}</div>;
};
Querying Within Elements
Use within to query elements inside a specific container.
Example:
test('within example', () => {
render(<App />);
const ele = screen.getByText('Hello');
expect(ele).toBeInTheDocument();
const subEle = within(ele).getByText('hi');
expect(subEle).toBeInTheDocument();
});
User Events
User events simulate real-world user interactions like clicks, typing, and more.
Difference Between userEvent and fireEvent:
fireEvent: Simulates an event but doesn’t mimic user interaction closely.userEvent: More realistic, handles interactions like typing delays.
Example - Click Event:
test('userEvent example', async () => {
userEvent.setup();
render(<App />);
const btn = screen.getByText('click me');
await userEvent.click(btn);
expect(screen.getByText('hello')).toBeInTheDocument();
});
Example - Keyboard Event:
test('keyboard event example', async () => {
userEvent.setup();
render(<App />);
const input = screen.getByRole('textbox');
await userEvent.type(input, 'shamim');
expect(screen.getByText('shamim')).toBeInTheDocument();
});
The act Function
The act function ensures all state updates and effects are processed before assertions.
Why Use act:
To avoid warnings when testing components with asynchronous updates.
Example:
test('onChange event with act', async () => {
userEvent.setup();
render(<App />);
const input = screen.getByRole('textbox');
await act(async () => {
await userEvent.type(input, 'shamim');
});
expect(screen.getByText('shamim')).toBeInTheDocument();
});
Testing Component Props
Test component props by rendering them with different values.
Example:
test('props test', () => {
const name = 'shamim';
render(<User name={name} />);
const user = screen.getByText(name);
expect(user).toBeInTheDocument();
});
Mocking Functions
Mock functions for testing callbacks or interactions.
Example:
test('mock function example', () => {
const mockFn = jest.fn();
render(<Button onClick={mockFn} />);
const btn = screen.getByText('Click Me');
userEvent.click(btn);
expect(mockFn).toHaveBeenCalledTimes(1);
});
Debugging in React Testing Library
Use debug or prettyDOM for debugging and printing failed test cases.
Example:
test('debugging example', () => {
render(<App />);
screen.debug(); // Prints the DOM in console
const btn = screen.getByText('Click Me');
expect(btn).toBeInTheDocument();
});
Automatic Debug: Use screen.logTestingPlaygroundURL() for suggestions.
Testing Playground Chrome Extension
A Chrome DevTools extension to identify RTL queries for elements in the DOM. It simplifies query selection during testing.
Conclusion
React Testing Library offers a robust framework for testing React applications effectively. Its focus on accessibility ensures your tests are user-centric, while tools like userEvent and debug make testing and debugging seamless.
