Jest Screen Queries: Navigating the DOM Tree
This challenge focuses on leveraging Jest and the screen object from the @testing-library/react (or equivalent for other frameworks) to query elements on a virtual DOM. Mastering screen queries is crucial for writing robust and user-centric tests that accurately reflect how users interact with your application.
Problem Description
Your task is to write Jest tests for a simple React component (or a similar framework component) that displays a list of items. You will use Jest's screen object to find and assert on various elements within this component's rendered output. The goal is to demonstrate proficiency in using different screen query methods to locate elements by their text, role, label, and other accessible attributes.
What needs to be achieved:
- Write Jest tests for a given React component.
- Use
screenqueries to find specific elements. - Make assertions about the presence, content, and attributes of these elements.
Key requirements:
- Utilize a variety of
screenquery methods (e.g.,getByText,getByRole,getByLabelText,queryByText,getAllByRole). - Ensure tests are readable and clearly indicate what is being tested.
- Handle cases where an element might or might not be present.
Expected behavior:
- Tests should pass if the correct elements are found and assertions are met.
- Tests should fail if elements are not found as expected or if assertions are incorrect.
Important edge cases to consider:
- What happens when an element is not found? (Use
queryBymethods). - How to find multiple elements? (Use
getAllBymethods). - How to deal with case sensitivity and whitespace in text queries?
Examples
Example 1: Finding an element by text
Let's assume a component renders the following HTML:
<div>
<h1>Welcome!</h1>
<p>This is a sample paragraph.</p>
</div>
Input: A React component that renders the above HTML.
Test Snippet (Conceptual):
import { render, screen } from '@testing-library/react';
// Assume MyComponent renders the HTML above
test('should find the heading by text', () => {
render(<MyComponent />);
const headingElement = screen.getByText('Welcome!');
expect(headingElement).toBeInTheDocument();
});
Output:
The test should pass, confirming the presence of the <h1> element with the text "Welcome!".
Explanation:
screen.getByText('Welcome!') searches for an element containing the exact text "Welcome!". If found, it returns the element; otherwise, it throws an error. toBeInTheDocument() is a Jest-DOM matcher that asserts the element exists in the DOM.
Example 2: Finding an element by role
Consider a component rendering a button:
<button type="button">Click Me</button>
Input: A React component that renders the above HTML.
Test Snippet (Conceptual):
import { render, screen } from '@testing-library/react';
// Assume ButtonComponent renders the button above
test('should find the button by role', () => {
render(<ButtonComponent />);
const buttonElement = screen.getByRole('button', { name: 'Click Me' });
expect(buttonElement).toBeInTheDocument();
});
Output: The test should pass, confirming the presence of the button with the accessible name "Click Me".
Explanation:
screen.getByRole('button', { name: 'Click Me' }) queries for an element with the ARIA role of "button" and an accessible name that matches "Click Me". This is a more robust way to find interactive elements.
Example 3: Handling a missing element
Suppose a component conditionally renders an element:
<div>
{showDetails && <p>More details here</p>}
</div>
Input:
A React component where showDetails is initially false.
Test Snippet (Conceptual):
import { render, screen } from '@testing-library/react';
// Assume ConditionalComponent renders the above HTML
test('should not find details when not shown', () => {
render(<ConditionalComponent showDetails={false} />);
const detailsElement = screen.queryByText('More details here');
expect(detailsElement).not.toBeInTheDocument();
});
Output: The test should pass, confirming that the paragraph is not present in the DOM.
Explanation:
screen.queryByText('More details here') is used here. Unlike getByText, queryByText returns null if the element is not found, instead of throwing an error. This allows us to assert that an element does not exist.
Constraints
- The target framework for the component is React.
- You will be provided with simple React components to test.
- Each test file should be written in TypeScript.
- Aim for clear and concise tests.
- Avoid using
data-testidunless absolutely necessary (prefer accessible queries).
Notes
- Familiarize yourself with the various
screenquery types available in@testing-library/react. - Consider the order of specificity when choosing queries. For example,
getByRolewith anameis often preferred overgetByTextfor interactive elements. - Think about how a user would perceive and interact with your component when deciding what to test.
- The core idea is to test the behavior of your component from a user's perspective, not its internal implementation details.