如何在React中对Firebase云函数进行单元测试?
React中Firebase云函数signInWithPhoneNumber的单元测试完整方案
1. 先Mock Firebase依赖,隔离外部调用
单元测试要避免实际触发云函数,所以需要用Jest mock掉Firebase的httpsCallable方法,模拟它的返回结果。
// 在测试文件顶部添加mock import { httpsCallable } from 'firebase/functions'; jest.mock('firebase/functions');
2. 成功场景的测试
需要处理异步逻辑,确保函数执行完成后再断言状态变化,同时验证云函数的调用参数是否正确。
import { renderHook, act, waitFor } from '@testing-library/react'; import useAuth from './useAuth'; import AuthProvider from './AuthProvider'; test('signInWithPhoneNumber 成功调用后切换验证界面并结束加载', async () => { // 模拟云函数返回成功结果 const mockSendSms = jest.fn().mockResolvedValue({ result: { success: true } }); (httpsCallable as jest.Mock).mockReturnValue(mockSendSms); const { result } = renderHook(() => useAuth(), { wrapper: AuthProvider }); // 异步调用函数,用act包裹确保状态更新被捕获 await act(async () => { await result.current.signInWithPhoneNumber('99999999999'); }); // 验证状态变化 await waitFor(() => { expect(result.current.loadingAuth).toBe(false); expect(result.current.activeCredentialVerificationScreen).toBe(true); }); // 验证云函数调用的正确性 expect(httpsCallable).toHaveBeenCalledWith(expect.anything(), 'sendSms'); expect(mockSendSms).toHaveBeenCalledWith({ phone_number: '99999999999' }); });
3. 错误场景的测试
还要覆盖调用失败的情况,确保错误被抛出,同时加载状态被重置。
test('signInWithPhoneNumber 调用失败时抛出错误并恢复加载状态', async () => { const mockError = new Error('短信发送失败'); const mockSendSms = jest.fn().mockRejectedValue(mockError); (httpsCallable as jest.Mock).mockReturnValue(mockSendSms); const { result } = renderHook(() => useAuth(), { wrapper: AuthProvider }); // 调用函数并验证错误抛出 await act(async () => { await expect(result.current.signInWithPhoneNumber('99999999999')).rejects.toThrow(mockError); }); // 验证状态恢复 await waitFor(() => { expect(result.current.loadingAuth).toBe(false); expect(result.current.activeCredentialVerificationScreen).toBe(false); }); });
原测试的问题说明
你之前的测试存在几个关键问题:
- 没有处理
signInWithPhoneNumber的异步逻辑,测试会在函数执行完成前就执行断言,导致结果不准确 - 没有mock Firebase云函数依赖,会实际发起外部请求,不符合单元测试的隔离原则
- 断言的
user状态在当前函数逻辑中并没有被修改,应该针对loadingAuth和activeCredentialVerificationScreen这些与函数直接相关的状态做断言
内容的提问来源于stack exchange,提问作者Thiago Sousa
相关产品推荐
相关产品推荐

