我有一个带有react钩子的以下组件,该钩子包含用打字稿编写的嵌套异步调用。
const sampleComponent: FunctionComponent = (): ReactElement => {
const [ detail, setDetail ] = useState<detailObject>(undefined);
useEffect(() => {
getConfigs();
}, [ detail != undefined ]);
const getConfigs = () => {
getConfig().then((configResp: any) => {
if(response.status === 200) {
getConfigDetail(configResp.data.id).then((response) => {
if(response.status === 200) {
setDetail(response.data)
}
})
}
})
}
return (
//Some UI related to the responses.
)
}
我通过以下测试对此进行测试。
const configList = jest.spyOn(api, "getConfigList");
const configDetail = jest.spyOn(api, "getConfig");
configList.mockImplementation(() => {
return Promise.resolve(configListRequestResponse); // these are sample responses
});
configDetail.mockImplementation(() => {
return Promise.resolve(configDetailsRequestResponse); // these are sample responses
})
test("Test proper rendering config component", async () => {
await act(async () => {
render(
<Provider store={ store }>
<sampleComponent/>
</Provider>
);
await waitFor(() => expect(configList).toHaveBeenCalledTimes(1));
await waitFor(() => expect(configDetail).toHaveBeenCalledTimes(1));
expect(screen.getByTestId("remote-configs")).toBeInTheDocument();
});
});
运行此测试时,出现以下错误。
警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。
> 95 | setDetail(response.data);
| ^
我在做什么错了?
答案 0 :(得分:0)
您应该创建一个renderWithState函数,在其中您将提供程序定义为包装器,就像这样
import React, { FC, ReactElement } from 'react';
import { Provider } from 'react-redux';
import { render } from '@testing-library/react';
import { createTestStore } from '../redux';
import { AppStore } from '../redux/types';
import { createStore } from 'redux';
import { rootReducer } from './reducers';
const createTestStore = (store: AppStore) => createStore(rootReducer, store);
export const renderWithState = (Component: ReactElement, options?: { state: AppStore }) => {
const store = createTestStore({dummystate:"hello"});
const Wrapper: FC = ({ children }) => <Provider store={store}>{children}</Provider>;
return render(Component, { wrapper: Wrapper });
};
describe('index tsx', () => {
it('it should render mocked state provider', () => {
const Hello = () => <div>hello world</div>;
renderWithState(<Hello />, { state: initStore });
});
});
还要测试异步行为,如下所示
it('it renders text dummy dummies on click', async () => {
const { queryByRole, getByText } = renderWithState(
<Router>
<CustomDropDown/>
</Router>,
{
state: sb.store,
},
);
const toggler = queryByRole('dropdown-toggle');
await act(async () => {
fireEvent.click(toggler!);
await waitForElement(() => getByText('dummy'));
await waitForElement(() => getByText('dummies'));
});
});
希望这对您有所帮助