我正在尝试测试我使用 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;
谢谢。