In order to run all tests use command:
npm run test
To execute specific test(s), utilize the -t
option followed by a string that must be present in the test path. This allows you to filter and run only the desired tests based on the specified criteria.
npm run test -t Image # runs tests for both BackgrounImage and Image
npm run test -t /Image # runs a test for Image only
To perform component testing within the package, we employ the @testing-library/react library, which leverages the underlying functionality of jest.
The configuration files are located in the ./test-utils
folder. Alongside the standard configurations, we have included a ./test-utils/custom-environment.ts
file. This file addresses the issue of missing window
methods, like matchMedia
, in the testing environment.
Additionally, we store all shared tests in this folder. There are two categories of shared tests. The first is common.tsx
, which consists of tests that can be utilized independently in multiple components. The second is {component}.tsx
, which includes tests specific to a particular component that can be reused in other components. For instance, ./src/components/BackgroundImage/BackgroundImage.tsx
utilizes ./src/components/Image/Image.tsx
as a child. Consequently, many tests for the Image
component can be utilized to test the BackgroundImage
component as well.
✅ The shared tests of the second type are named after the component that possesses a lower level of abstraction.
For instance, since the Image
component is a part of the BackgroundImage
component, the shared test should be named image.tsx
rather than background-image.tsx
.
All tests for a component are stored in the __tests__
folder. Typically, there is a single *.test.tsx
file within the folder, named after the component. However, there is no strict rule that restricts the number of test files that can be present.
...
|- BackgroundImage
|- __stories__
|- __tests__
|- BackgroundImage.test.tsx
|- BackgroundImage.tsx
|- BackgroundImage.scss
...
Typically, when working with jest
tests, it's common to organize them into suites. These suites serve as containers for a group of related tests. Essentially, a suite is contained within a single file and brings together all the tests associated with a specific component.
Follow the steps below to write your own test:
- Use the describe function from
Jest
to define your test suites. - Inside each suite, use the test or it function to define your test cases.
- Render your component using the render function.
- Use the screen object from
@testing-library/react
to query and interact with the rendered component. - Use the
expect
function from@testing-library/jest-dom
to make assertions about the rendered component.
describe('BackgroundImage', () => {
test('Render BackgroundImage by default', async () => {
render(<BackgroundImage qa={qaId} />);
const component = screen.getByTestId(qaId);
expect(component).toBeInTheDocument();
expect(component).toBeVisible();
});
...
There are list of default roles.
// ✅ usage
const image = getByRole('img');
🚫 Although it is possible to extend the list of roles with custom ones, it is strongly discouraged due to the creation of invalid HTML code.
// ⚠️ DO NOT USE
// Component.tsx
<div role="custom-role">
// Test.ts
const component = getByRole("custom-role");
Another option, you have to access any tags in a component is to add data-qa
prop.
To add a data-qa attribute to elements in your components and access those elements in your tests using @testing-library/react
, you can follow these steps:
- Add data-qa attributes to elements: In your component's TSX code, add the
data-qa
attribute to the elements you want to target in your tests. Assign a meaningful value to the attribute that helps identify the purpose or role of the element.
const BackgroundImage = (props: React.PropsWithChildren<BackgroundImageProps>) => {
const {qa} = props;
return <div data-qa="background-image">{/* Other components */}</div>;
};
- Access elements using data-qa attributes: Use the
getByTestId
or other query methods provided by@testing-library/react
to access the elements based on their data-qa attributes.
const submitButton = getByTestId('background-image');
It is possible to change data-qa
dinamically:
const BackgroundImage = (props: React.PropsWithChildren<BackgroundImageProps>) => {
const {qa} = props;
return <div data-qa={qa}>{/* Other components */}</div>;
};
Avoiding direct Node access in testing is essential for several reasons. Testing Library methods emulate user behavior, ensuring that tests focus on the actual user experience. They encourage best practices by prioritizing output over implementation details, resulting in more resilient tests. Additionally, using Testing Library methods improves test maintainability by shielding tests from structural changes in components, enhances test readability, and makes tests more portable and reusable. Overall, this approach promotes testing best practices, improves maintainability, and ensures effective tests as your codebase evolves.
It is important to avoid direct Node access when writing tests. This means refraining from using methods like querySelector
or querySelectorAll
. Instead, we should rely on testing library methods such as getByRole
, getByText
, or getByTestId
to access components.
In some cases, the prop being tested may have an impact on a deeply nested container within the component. It can be tempting to access this container using querySelector
or similar methods. However, it is advised to resist this temptation and continue utilizing the recommended testing library methods for accessing and interacting with components.
// ⚠️ DO NOT USE
screen.getByTestId(id).querySelector('p');
✅ Reusing common tests ensures efficiency, consistency, and scalability in software testing, reducing duplication, improving maintenance, and promoting standardized behavior across components.
Testing common props like className
, style
, and others is a recurring task that appears in nearly every test scenario.
Shared test implementation:
import {testCustomClassName} from './test-utils/shared/common';
...
test('add className', () => {
testCustomClassName<BackgroundImageProps>({
component: BackgroundImage,
props: {qa: qaId},
});
});
It is recommended to prefix branch names with test/...
when working on test-related branches. Additionally, commits and Pull Requests can follow a naming convention such as test({ComponentName}): test for {ComponentName} added
to clearly indicate the addition of tests for a specific component.