# 单测
- mock外部库引入函数返回值
const fileTypeMock = jest.fn().mockReturnValue({ type: "image" });
// 对象的这个方法执行后被返回指定值
jest.spyOn(Helper, "getFileType").mockImplementation(fileTypeMock);
1
2
3
4
2
3
4
- 更改外部库的某个函数
const mockNav = jest.fn();
const mockedUseNavigate = jest.fn().mockReturnValue(mockNav);
jest.mock("react-router-dom", () => ({
...(jest.requireActual("react-router-dom") as object),
// mock某一个使用的函数,直接给返回值
// useSearchParams: () => [new URLSearchParams({ sjmsgToken: "1", v: "1" })],
useNavigate: () => mockedUseNavigate,
}));
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 执行hook
const { result, rerender } = renderHook(() => useFileDropzone(), {
wrapper: MemoryRouter,
});
1
2
3
2
3
- 替代外部复杂方法
const createObjectURLMock = jest.fn();
URL.createObjectURL = createObjectURLMock;
1
2
2
- 执行hook返回的函数
const res = result.current.acceptedFilesFormat(filesMock);
1
- 替代ref
// mock
const idInput: any = { value: "testUser" };
// 执行hook
const { result, rerender } = renderHook(() => useLogin(), {
wrapper: MemoryRouter,
});
// 给ref赋值并等待执行异步函数
await act(async () => {
if (result.current.idRef) {
result.current.idRef.current = idInput;
}
if (result.current.pwdRef) {
result.current.pwdRef.current = pwdInput;
}
await result.current.login();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 断言函数被执行
expect(Service.loginService).not.toHaveBeenCalled();
1
- 导入外部常量
jest.mock("utils/constants.ts", () => ({
...(jest.requireActual("utils/constants.ts") as object),
INTERVAL_TIME: 1,
}));
1
2
3
4
2
3
4
- 重复渲染
- 执行一遍,rerender
- 修改参数,rerender
- 断言结果,要用
result.current.xxx
act(() => {
const {
replyContentTopRef,
replyContentFootRef,
contentTopHeight,
contentFootHeight,
} = result.current;
if (replyContentTopRef) {
replyContentTopRef.current = { clientHeight: 100 } as any;
}
if (replyContentFootRef) {
replyContentFootRef.current = { clientHeight: 100 } as any;
}
rerender();
});
act(() => {
props.fixed = false;
rerender();
});
// ASSERT:確認
expect(result.current.contentTopHeight).toEqual(100);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 单个it修改外部库导入函数
// 全局更改一个默认的,让此库变为可修改的
jest.mock("react-router-dom", () => ({
...(jest.requireActual("react-router-dom") as object),
useParams: jest.fn().mockReturnValue({}),
}));
// 单个it自己修改(不修改也要默认给一个)
it(() => {
jest.spyOn(RouterDom, "useParams").mockReturnValue({});
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 防抖单测
it("change searchText should debounce fetch tip list", async () => {
// 模拟时间流逝
jest.useFakeTimers();
// ARRANGE:準備
// ACT:実行
const { result, rerender } = renderHook(() => useRecipientSelect(), {
wrapper: MemoryRouter,
});
await act(async () => {
result.current.onMenuClick();
rerender();
});
await act(async () => {
result.current.changeInputText("xxx");
rerender();
// 模拟时间流逝 1000
await jest.advanceTimersByTime(1000);
// await jest.runAllTimers();
});
// ASSERT:確認
expect(result.current.tipList).toEqual(1);
// 关闭模拟时间流逝
jest.useRealTimers();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- 清理函数
beforeEach(() => {
jest.clearAllMocks();
});
1
2
3
2
3
- 确认时异步等待
await waitFor(() => {
expect(mockSetEditing).toBeCalled();
});
1
2
3
2
3