我正在尝试测试我使用RTK-Query编写的一些功能。我使用createApi创建了一个api,并导出了useLazyQuery钩子。我正在调用这个钩子,然后在一个useEffect钩子中监听结果变化。这在应用程序中是预期的。当我尝试使用msw和@testing-library/react-native为这个逻辑编写测试时,我遇到了错误。
当我运行测试时,我看到以下控制台输出:
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
——detectOpenHandles标志没有帮助。
我的测试是这样的:
const server = setupServer();
const mockedNavigate = jest.fn();
jest.mock('@react-navigation/native', () => {
return {
...jest.requireActual('@react-navigation/native'),
useNavigation: () => ({
navigate: mockedNavigate,
}),
};
});
describe('ForgotPasswordForm', () => {
const storeRef = setupApiStore(forgotPasswordApi);
const testRender = () =>
render(
<Provider store={storeRef.store}>
<ForgotPasswordForm />
</Provider>
);
beforeAll(() => {
jest.spyOn(Alert, 'alert');
server.listen();
});
beforeEach(() => {
storeRef.store.dispatch(forgotPasswordApi.util.resetApiState());
});
afterEach(() => {
jest.resetAllMocks();
server.resetHandlers();
cleanup();
});
afterAll(() => {
server.close();
});
it('should display an error alert if the email is not registered', async () => {
server.use(
rest.get(`${API_ENDPOINT}/ResetPassword`, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ status: 'error' }))
)
);
const { getByText, getByPlaceholderText } = testRender();
fireEvent.changeText(
getByPlaceholderText('Registered email address'),
'unregistered@test.com'
);
fireEvent.press(getByText(/Retrieve Password/i));
await waitFor(() =>
expect(Alert.alert).toHaveBeenCalledWith(
'Error',
'An error has occured. Please contact us for help.'
)
);
});
});
我的API是这样的:
export const forgotPasswordApi = createApi({
reducerPath: 'forgotPassword',
baseQuery: fetchBaseQuery({
baseUrl: API_ENDPOINT,
}),
endpoints: (builder) => ({
resetPassword: builder.query({
query: (email) => ({
url: '/ResetPassword',
params: { email },
}),
}),
}),
});
export const { useLazyResetPasswordQuery } = forgotPasswordApi;
我的组件是这样的:
const ForgotPasswordForm = () => {
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();
const [email, setEmail] = useState('');
const [showInvalidEmailMessage, setShowInvalidEmailMessage] = useState(false);
const handleEmailChange = (value: string) => {
setEmail(value);
};
const [triggerResetPasswordQuery, results] = useLazyResetPasswordQuery();
useEffect(() => {
if (results.isUninitialized || results.isFetching) return;
if (results?.data?.status === 'error') {
Alert.alert('Error', 'An error has occured. Please contact us for help.');
} else {
Alert.alert('An email has been sent with further instructions.');
}
}, [results]);
const handleForgotPassword = () => {
const isEmailFormatValid = /^S+@S+.S+$/.test(email);
if (isEmailFormatValid) {
setShowInvalidEmailMessage(false);
triggerResetPasswordQuery(email);
} else {
setShowInvalidEmailMessage(true);
}
};
return (
<>
<Wrapper width="100%" mt={40} mb={20}>
<TextInput
value={email}
placeholder="Registered email address"
handleOnChangeText={handleEmailChange}
accessibilityLabel="forgot-password-email"
/>
</Wrapper>
<Wrapper mb={10} width="100%">
<Button
fullWidth
title="Retrieve Password"
onPress={handleForgotPassword}
/>
</Wrapper>
{results.isLoading && <LoadingOverlay text="Sending Email" />}
</>
);
};
export default ForgotPasswordForm;
谢谢。
我也面临着类似的问题,但在我的情况下,我没有使用RTK Query生成的lazy版本的钩子。当代码在测试环境中运行时,我通过防止API保存数据来修复它。我的解决方案的代码示例:
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({
baseUrl: 'any-base-url',
}),
keepUnusedDataFor: process.env.NODE_ENV !== 'test' ? 60 : 0, // <- here
endpoints: () => {
return {
// your endpoints
};
},
});
参考keepUnusedDataFor
: https://redux-toolkit.js.org/rtk-query/api/createApi#keepunuseddatafor