Skip to content

Latest commit

 

History

History
164 lines (107 loc) · 7.48 KB

README.md

File metadata and controls

164 lines (107 loc) · 7.48 KB

Tests

Run Tests

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

Utils

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.

Component Test

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();
    });

    ...

Rules

Roles

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");

Testing ID

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:

  1. 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>;
};
  1. 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>;
};

Avoid Direct Node Access

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');

⚠️ Engaging in such practices is strictly discouraged, and there are compelling reasons for doing so. You can find detailed explanations regarding the importance of avoiding direct node access and the associated reasons by referring to the documentation available at avoid-direct-node-access.md.

Shared Test

✅ 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},
    });
});

Tests Development

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.