This post provides comprehensive guidelines and best practices for web automation testing using tools like Jest and React Testing Library. It covers essential tips for writing effective tests, debugging techniques, and common pitfalls to avoid. Additionally, it includes practical examples and commands to help developers implement robust testing strategies in their projects.
Vanilla JS
+ Jest
+ Mock
Purpose | Command | Comment |
Run single test file | npx jest src\folder\yourComponent1.test.js | Find the file first |
Run single test case by case name (Recommended) | npx jest -t='keyword' --watch | Provide a keyword and run test with keyword |
screen.debug()
:
DEBUG_PRINT_LIMIT=20000
. Or you can set the env var in test cases: process.env.DEBUG_PRINT_LIMIT = 20000;
screen.logTestingPlaygroundURL()
:
it.only/describe.only
to run only single test case/suitehttps://kentcdodds.com/blog/common-mistakes-with-react-testing-library
Usually used for feature with animation or loading indicator.
WaitFor
must return an boolean
await
before WaitFor
, otherwise it may not workwaitFor + timeout
data-testid="This-Is-A-Test-Id"
)jest.mock
will be hoist to the top so mocking is used for whole file. We can use jest.spyOn
to mock the implementation on each test case.jest.mock
will ignore the original behaviour but jest.spyOn
won't. We can use both to check if certain function have been called.spyOn
on the top of each test case, especially before the render()
__mocks__/module.js
subdirectory immediately adjacent to the modulejest.mock('./moduleName')
at top of the test__mocks__/module.js
at ROOT pathjest.mock
explicitly, it will be mocked automaticallyhttps://jestjs.io/docs/mock-functions#mocking-partials
SpyOn
would be more convenient to do the mock.
/* import all */
import * as RequestUtils from 'src/utils';
/* DO NOT DO THIS */
// import RequestUtils from 'src/utils';
jest.spyOn(RequestUtils, 'requestUtil').mockImplementationOnce(() => {
return Promise.reject('mocked error');
})
Another example:
import { createChannel, createClient } from "nice-grpc";
const foo = { createChannel, createClient };
jest.spyOn(foo, "createClient").mockReturnValue({});
jest.spyOn(foo, "createChannel").mockReturnValue({});
import React from "react";
import { render } from "@testing-library/react";
import { FixedButton } from "src/components/button";
describe("Button Component", () => {
it("should renders correctly", () => {
const { container } = render(<FixedButton />);
expect(container).not.toBeUndefined();
expect(container).toMatchSnapshot();
});
});
const title = await findByRole('heading', { name: /search results/i });
expect(await title).toBeVisible();
within(title).findByRole('progressbar');
import { useData } from "src/hooks";
/* required to set mockdata into a variable with name pattern "mock*" */
const mockData = {
data: 123456
}
jest.mock("src/hooks", () => ({
useData: jest.fn(),
}));
describe('Test for the mock data', () => {
it('should return mocked data', () => {
(useData as any).mockReturnValue(mockData);
/* assertions */
})
})
jest.mock(
"src/NativeCommentBox",
() => ({
/* make sure for the correct export name */
NativeCommentContainer: () => (
<span data-testid={nativeCommentContainerTestId}>children</span>
),
})
);
jest.mock("react-markdown", () => ({
default: () => <>children</>,
}));
Delete .only()
Similar Scenario:
Potentially you are import the component with providers.
Try to write a renderer function with isolated providers.
export const renderWithState = (
component,
{ initialState, ...renderOptions } = {}
) => {
const initialStore = getInitialStore(initialState);
const Wrapper = ({ children }) => {
return (
<StoreProvider store={initialStore}>
<OtherProvider>
{children}
</OtherProvider>
</StoreProvider>
);
};
return render(component, { wrapper: Wrapper, ...renderOptions });
};
const { container } = renderer(
<MyComponent />
);
expect(container).not.toBeNull(); /* This works */
const { container, getByRole } = renderWithState( /* renderWithState may render 'MyComponent' with Providers */
<MyComponent />
);
/* Potentially this will be always true because we have wrap 'MyComponent' with Providers */
expect(container).not.toBeNull();
/* Try to do other assertions on the elements within container instead of just check container */
jest.mock()
hoists mocks to the top of your module’s scope
import {
fireEvent,
queryByRole, /* DO NOT DO THIS */
render,
waitFor
} from '@testing-library/react';
const {
container, queryByRole /* DO THIS */
} = render(<App />);
Prevent to put the data-testid
to custom components.
Otherwise we need to pass the data-testid
to children components explicitly.
ß
const Panel = ({
attr1,
attr2
...rest
}) => {
return (
<PanelHeader
attr1={attr1}
attr2={attr2}
{...rest}
>
)
}
https://davidwcai.medium.com/react-testing-library-and-the-not-wrapped-in-act-errors-491a5629193b
This is usually same request happend in same period.
Check if you forget to add 'await' before find*
or waitFor
SpyOn and should write before the render.
文章标题 | Web-Automation Testing |
发布日期 | 2022-06-25 |
文章分类 | Tech |
相关标签 | #Jest #UI Testing #React Testing Library |