ReactNative使用RTK-Query的useLazyQuery时Jest无法正常退出问题
问题原因
Jest运行完成后1秒未退出的报错,核心原因是测试结束后仍有未完成的异步操作挂起,结合你的代码场景,具体是RTK Query的请求订阅未完全清理、测试用例没有等待所有异步逻辑执行完毕就结束,导致底层的Promise或者定时器仍在运行。
解决步骤
- 补全测试的异步等待逻辑
你当前只等待了Alert触发,但是RTK Query的请求状态更新、LoadingOverlay的卸载逻辑还没跑完就结束了测试,导致有挂起的异步任务。你可以在现有断言前增加等待Loading消失的逻辑,确保所有异步流程都执行完成:
fireEvent.press(getByText(/Retrieve Password/i)); // 先等加载态出现,再等加载态消失,确保请求全流程跑完 await waitFor(() => expect(getByText('Sending Email')).toBeTruthy()); await waitFor(() => expect(queryByText('Sending Email')).toBeFalsy()); await waitFor(() => expect(Alert.alert).toHaveBeenCalledWith( 'Error', 'An error has occured. Please contact us for help.' ) );
注意判断元素不存在时要用queryByText,不要用getByText。
- 调整RTK Query的缓存配置
RTK Query默认的缓存保留时间keepUnusedDataFor是60秒,测试环境下可以设置为0,避免缓存持有订阅导致异步资源不释放:
export const forgotPasswordApi = createApi({ reducerPath: 'forgotPassword', baseQuery: fetchBaseQuery({ baseUrl: API_ENDPOINT, }), // 测试环境下设置缓存保留时间为0 keepUnusedDataFor: process.env.NODE_ENV === 'test' ? 0 : 60, endpoints: (builder) => ({ resetPassword: builder.query({ query: (email) => ({ url: '/ResetPassword', params: { email }, }), }), }), });
- 每个测试用例使用独立的Store
你当前是在describe顶层创建store,所有测试用例复用同一个store,即使每次resetApiState也可能有残留状态。把store的创建移到testRender函数内部,每个渲染都生成新的独立store:
const testRender = () => { const storeRef = setupApiStore(forgotPasswordApi); return render( <Provider store={storeRef.store}> <ForgotPasswordForm /> </Provider> ); };
- Mock Alert.alert避免原生异步逻辑干扰
React Native的Alert.alert原生实现可能包含未被Jest捕获的异步逻辑,给spyOn增加空的mock实现,确保它是同步执行的:
beforeAll(() => { jest.spyOn(Alert, 'alert').mockImplementation(() => {}); server.listen(); });
额外优化建议
你的重置密码接口是写操作,建议把endpoint的类型从builder.query改成builder.mutation,更符合RESTful规范,也可以避免query默认的缓存逻辑带来的不必要问题。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

