对于我们的 API 调用,我们有一个名为 useApi
的自定义钩子,它返回 5 个函数(get、post、put、patch、del),每个函数都有端点、success、fail 作为参数。 post、put、patch另外还有一个body参数。
useApi.js
import React, { useContext, useState } from "react";
import * as api from "../../services/api";
import { GlobalContext } from "../../contexts/context";
export const useApi = () => {
const context = useContext(GlobalContext);
const [loading, setLoading] = useState(false);
const get = async ({ endpoint, success, fail }) => {
if (loading)
return;
try {
setLoading(true);
const result = await api.get("", endpoint, context);
context.dispatch({ type: success, result });
return result || {};
} catch (err) {
context.dispatch({ dispatch: fail, err });
return {
error: true,
message: err,
};
} finally {
setLoading(false);
}
};
... cut some stuff here to shorten
return {
loading,
get,
post,
put,
patch,
del,
};
};
这个想法是,我们在我们的功能组件中使用这个自定义钩子来与我们的 API 交互并根据 API 调用的结果分派一个动作。
示例.js
const Example = () => {
const { examples } = useContext(GlobalContext);
const { loading, get } = useApi();
const listExamples = async () => {
await get({
endpoint: '/example',
success: 'LIST_EXAMPLES',
fail: 'LIST_EXAMPLES_FAILED'
});
};
useEffect(() => {
listExamples();
}, []);
return (
<Page
title="Examples"
>
{
!loading && examples.map(example => (<h1>{example}</h1>))
}
{
loading &&
<ProgressSpinner message={'Loading Workflows...'}/>
}
</Page>
);
};
export default Example;
我们现在正在尝试围绕此实施测试,但我不确定如何处理它。我能够呈现我的组件并确保项目列表包含我期望的数据(使用虚拟数据),但它仍在使用实际的 API 调用。我不确定如何模拟可以检查自定义钩子返回的函数是否被调用的东西,我不确定如何在调用该函数时模拟全局状态更改。
import React from 'react';
import { GlobalContext } from '../../contexts/context';
import init from '../../__tools__/contextSetup';
import ExampleList from '../../pages/Example/ExampleList/ExampleList';
import { render, screen, act } from '@testing-library/react';
import { ThemeProvider } from "@material-ui/core";
import { light } from "../../theme";
const example = {
details: {
description: 'Test Example 1 - Description',
id: 'testingExample1',
name: 'Test Example 1',
},
list: {
data: [
{
description: 'Test Example 1 - Description',
id: 'testingExample1',
name: 'Test Example 1',
},
],
values: [
{
description: 'Test Example 1 - Description',
id: 'testingExample1',
name: 'Test Example 1',
},
],
}
};
describe('Example List', () => {
it('loads the example list on mount', async () => {
const dispatch = jest.fn();
const state = { ...init };
let ui;
await act(async () => {
ui = await render(
<GlobalContext.Provider
value={{
...state,
dispatch
}}
>
<ThemeProvider theme={light}>
<ExampleList/>
</ThemeProvider>
</GlobalContext.Provider>
)
});
expect(await screen.getByText('There\'s nothing here...')).toBeInTheDocument();
await (act(async () => {
await ui.rerender(
<GlobalContext.Provider
value={{
...state,
dispatch,
example,
}}
>
<ThemeProvider theme={light}>
<ExampleList/>
</ThemeProvider>
</GlobalContext.Provider>
)
}));
expect(await screen.getByText('Test Example 1')).toBeInTheDocument();
});
})