Frontend Handbook - React - Testing Best Practices
Frontend Handbook - React - Testing Best Practices
Other handbooks
Setup
"scripts": {
"test": "jest",
...
module.exports = {
};
https://infinum.com/handbook/books/frontend/react/testing-best-practices 1/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
"presets": [
"next/babel"
User events
Testing hooks
https://infinum.com/handbook/books/frontend/react/testing-best-practices 2/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
module.exports = {
...
transform: {
'^.+\\.tsx?$': 'babel-jest',
'^.+\\.svg$': 'jest-svg-transformer',
},
Utils
<ChakraProvider theme={theme}>{children}</ChakraProvider>
);
https://infinum.com/handbook/books/frontend/react/testing-best-practices 3/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
return (
<StoreMockContext.Provider value={store}>
</StoreMockContext.Provider>
);
};
return WithMockStore;
};
// re-export everything
https://infinum.com/handbook/books/frontend/react/testing-best-practices 4/18
8/24/2021 Frontend Handbook | React / Testing best practices
"compilerOptions": {
...
"paths": {
...
"@test-utils": ["__tests__/test-utils.tsx"]
},
Folder structure
All tests should be defined in the same directory where the file being
tested is. There is one exception, and that is the pages folder because
Next.js doesn't allow tests in the pages folder. That's why we have the
__tests__ folder in the root of our application.
https://infinum.com/handbook/books/frontend/react/testing-best-practices 5/18
8/24/2021 Frontend Handbook | React / Testing best practices
Example:
Other handbooks
src
├── __mocks__
│ └── react-i18next.tsx
├── __tests__
│ ├── pages
│ │ └── user.test.ts
│ └── test-utils.tsx
├── pages
│ └── user.ts
├── fetchers
│ └── users
│ ├── users.ts
│ └── users.test.ts
└── components
└── shared
└── Button
├── Button.test.tsx
└── Button.tsx
__mocks__
Manual mocks are used to stub out functionality with mock data. For
example, instead of accessing a resource from node_modules you might
want to create a mock module that allows you to use fake data. Manual
mocks are defined by writing a module in the __mocks__/ subdirectory
immediately adjacent to the module. (docs)
https://infinum.com/handbook/books/frontend/react/testing-best-practices 6/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
import {
I18nextProvider,
initReactI18next,
setDefaults,
getDefaults,
setI18n,
getI18n,
} from "react-i18next";
useMock.i18n = {
language: "en-GB",
};
module.exports = {
// this mock makes sure any components using the translate HoC rec
withTranslation: () => (Component) => (props) => (
),
// mock if needed
I18nextProvider,
initReactI18next,
setDefaults,
getDefaults,
setI18n,
getI18n,
};
Based on the Guiding Principles, your tests should resemble how users
interact with your code (component, page, etc.) as much as possible. In
this context, the user is not the end application user, but some parent
component that would use the component that is being tested.
https://infinum.com/handbook/books/frontend/react/testing-best-practices 7/18
8/24/2021 Frontend Handbook | React / Testing best practices
1. Test IDs
getByTestId - The user cannot see (or hear) these, so this is only
recommended for cases where you can't match by role or text or it
https://infinum.com/handbook/books/frontend/react/testing-best-practices 8/18
8/24/2021 Frontend Handbook | React / Testing best practices
Component:
<button {...rest}>{children}</button>
);
Test:
describe("Button", () => {
expect(getByText(buttonText)).toBeDefined();
});
<Button onClick={testOnClick}>{buttonText}</Button>
);
userEvent.click(getByText(buttonText));
expect(testOnClick).toBeCalledTimes(1);
});
});
https://infinum.com/handbook/books/frontend/react/testing-best-practices 9/18
8/24/2021 Frontend Handbook | React / Testing best practices
Component:
Other handbooks
<Card>
<h3>{label}</h3>
<Button>click</Button>
</Card>
);
Test:
jest.mock("components/button");
describe("UserCard", () => {
expect(getByText(username)).toBeDefined();
});
});
Page example:
https://infinum.com/handbook/books/frontend/react/testing-best-practices 10/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
const UserPage: NextPage = () => {
USER_KEY,
fetchUsers
);
if (error) {
if (!data) {
};
It this page example we should test all three states of the page
component. To do that we should mock <ErrorPage>, <LoadingPage>
and <UserTemplate> and check if it's rendered based on fetcher
response.
Test example:
https://infinum.com/handbook/books/frontend/react/testing-best-practices 11/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
jest.mock("components/error-page");
jest.mock("components/loading-page");
jest.mock("components/user-template");
jest.mock("fetchers/users");
(ErrorPage as jest.Mock).mockReturnValue(
);
(LoadingPage as jest.Mock).mockReturnValue(
);
(UserTemplate as jest.Mock).mockReturnValue(
);
expect(findByTestId("error-page-testid")).toBeDefined();
});
(fetchUsers as jest.Mock).mockResolvedValue(null);
expect(findByTestId("loading-page-testid")).toBeDefined();
});
expect(findByTestId("user-template-page-testid")).toBeDefined()
});
});
https://infinum.com/handbook/books/frontend/react/testing-best-practices 12/18
8/24/2021 Frontend Handbook | React / Testing best practices
SWR testing
Other handbooks
Testing swr has a few known issues. One is cache persistency across
tests. To fix that we need to add this:
afterEach(async () => {
});
<ChakraProvider theme={theme}>{children}</ChakraProvider>
</SWRConfig>
);
https://infinum.com/handbook/books/frontend/react/testing-best-practices 13/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
const UserPage: NextPage<any> = ({ data }) => {
};
Test example:
(fetchUsers as jest.Mock).mockResolvedValue([
new User({
id: "1",
}),
]);
route: "/user",
});
render();
expect(screen.getByText("Buzz")).toBeDefined();
});
});
Fetchers
https://infinum.com/handbook/books/frontend/react/testing-best-practices 14/18
8/24/2021 Frontend Handbook | React / Testing best practices
Using datx:
When testing fetchers that use Datx, we create mocked store Datx store
and instead of making API calls with request we need to mock
request and test the functionality of the fetcher.
In the example below our fetcher fetches one User model and if the user
doesn't have a relationship to Role model we add a default one.
store: AppCollection,
id: string
): Promise<User> {
try {
});
user.role = newRole;
return user;
} catch (resError) {
throw resError.error;
Test example:
https://infinum.com/handbook/books/frontend/react/testing-best-practices 15/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
describe("user fetchers", () => {
expect(fetchResponse).toBeInstanceOf(User);
expect(fetchResponse.role).toBeDefined();
expect(fetchResponse.role.name).toBe(RoleTypes.User);
});
expect(fetchResponse).toBeInstanceOf(User);
expect(fetchResponse.role).toBeDefined();
expect(fetchResponse.role.name).toBe(RoleTypes.Superadmin);
});
try {
} catch (fetchError) {
expect(fetchError.length).toBe(1);
expect(fetchError[0]).toBe(mockError);
});
});
Hooks
https://infinum.com/handbook/books/frontend/react/testing-best-practices 16/18
8/24/2021 Frontend Handbook | React / Testing best practices
Example hook:
setIsOpen(!isOpen);
}, [isOpen]);
setIsOpen(false);
}, []);
Example test:
https://infinum.com/handbook/books/frontend/react/testing-best-practices 17/18
8/24/2021 Frontend Handbook | React / Testing best practices
Other handbooks
describe("useModal", () => {
act(() => {
result.current.toggle();
});
expect(result.current.isOpen).toBe(true);
});
act(() => {
result.current.close();
});
expect(result.current.isOpen).toBe(false);
});
});
Libraries
Visit infinum.com
Login
https://infinum.com/handbook/books/frontend/react/testing-best-practices 18/18