嗨,我不确定模拟反应钩子的最佳方法是什么。 我想测试具有输入的Page.js,然后通过POST请求将输入的数据发送到服务器。 请求成功后,就会出现另一种形式。
我要测试成功案例。
我使用自定义钩子调用api,其名称为useApi。 因此,我嘲笑useApi返回成功状态。 我有2个useAPI挂钩,并且每次重新渲染都会调用该挂钩。
由于useState的setState导致重新呈现,因此在调用它时,将再次调用每个useApi。 因此应该有许多useApi.mockReturnValueOnce()。
如果有更多useApi,将有太多useApi.mockReturnValueOnce()。 这将非常烦人,所以我正在寻找是否有更好的方法。
你有什么主意吗?
// Page.js
const Page = () => {
const [api, requestApi] = useApi(
'/v1/users/me/marketing_agreement',
{
method: 'post',
manual: true,
}
)
const [verifyApi, requestVerifyApi] = useApi(
'/v1/users/me/verify_password',
{
method: 'post',
manual: true,
}
)
...
return (
<div>
{api.status === 'success' ? <p>success</p> : null}
<form
onSubmit={e => {
requestApi();
}}
>
<input name="a" />
...
</form>
</div>
)
}
// Page.test.js
test('test', async () => {
// api
useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);
// verifyApi
useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);
// api
useApi.mockReturnValueOnce([{ status: 'success' }, requestApi]);
// verifyApi
useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);
// api
useApi.mockReturnValueOnce([{ status: 'success' }, requestApi]);
// verifyApi
useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);
...some tests changing state of Page (and the page call useApi again because of rerendering)
})
// useApi.js
import { useReducer, useEffect } from 'react';
import request from 'libs/request';
const initialState = { status: 'init', data: null, error: null };
function reducer(_, action) {
switch (action.type) {
case 'request':
return { status: 'loading' };
case 'success':
return { status: 'success', data: action.data };
case 'failure':
return { status: 'failure', error: action.error };
default:
throw new Error();
}
}
export default (url, options = { method: 'get', manual: false }) => {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
let cancelled = false;
if (!options.manual) {
dispatch({ type: 'request' });
const { manual, ...others } = options;
request({ url, ...others })
.then(result => {
if (!cancelled) {
dispatch({ type: 'success', data: result.data });
}
})
.catch(e => {
if (!cancelled) {
dispatch({ type: 'success', error: e });
}
});
}
return () => {
cancelled = true;
};
}, [options, url]);
if (options.manual) {
const requestApi = async props => {
dispatch({ type: 'request' });
try {
const { manual, ...others } = options;
const result = await request({
url,
method: options.method,
...others,
...props,
});
dispatch({ type: 'success', data: result.data });
return result;
} catch (e) {
dispatch({ type: 'failure', error: e });
return null;
}
};
return [state, requestApi];
}
return [state];
};