如何用Jest模拟Firestore v9的getDocs()方法?
解决Firebase v9 + Jest模拟getDocs的问题
问题根源
- 第一个错误
Cannot read properties of undefined (reading 'docs'):你模拟的getDocs返回的docs是单个对象,但原代码中调用了forEach,要求docs必须是数组。 - 第二个错误
_firestore.getDocs.mockImplementation is not a function:你没有通过Jest正确mock整个firebase/firestore模块,直接修改getDocs本身不会让它变成Jest mock函数,自然没有mockImplementation方法。
正确的模拟步骤
1. 先Mock整个Firebase Firestore模块
在测试文件最顶部,用jest.mock将firebase/firestore的核心方法转为Jest mock函数:
import { getFirestore, collection, query, where, getDocs } from 'firebase/firestore'; // Mock整个firestore模块 jest.mock('firebase/firestore', () => ({ getFirestore: jest.fn(), collection: jest.fn(), query: jest.fn(), where: jest.fn(), getDocs: jest.fn() }));
2. 在测试用例中配置Mock返回值
在具体测试用例里,根据业务逻辑设置各个mock函数的返回值:
test('你的测试用例名称', async () => { // 1. 模拟getFirestore返回假的实例 const mockFirestoreInstance = {}; (getFirestore as jest.Mock).mockReturnValue(mockFirestoreInstance); // 2. 模拟collection返回假的集合引用 const mockCollectionRef = {}; (collection as jest.Mock).mockReturnValue(mockCollectionRef); // 3. 模拟query返回假的查询对象(where返回任意值即可,仅用于构建查询条件) const mockQuery = {}; (query as jest.Mock).mockReturnValue(mockQuery); (where as jest.Mock).mockReturnValue({}); // 4. 关键:模拟getDocs返回符合要求的结构 // docs必须是数组,每个元素要有data()方法返回测试数据 (getDocs as jest.Mock).mockResolvedValue({ docs: [ { data: () => ({ id: 'test-id-1', name: '测试名称1' }) }, { data: () => ({ id: 'test-id-2', name: '测试名称2' }) } ] }); // 5. 执行你要测试的函数 await yourFunctionToTest(); // 6. 可选:添加断言验证mock函数调用情况 expect(getDocs).toHaveBeenCalledWith(mockQuery); });
3. 修复原代码的潜在问题
原代码中dataDict[data['id']].name = data.name存在风险:如果dataDict中没有data['id']对应的键,会抛出Cannot set properties of undefined错误,建议提前初始化:
const dataDict: { [key: string]: {id: string, name: string} } = {}; (await getDocs(dataList)).docs.forEach((dataItem) => { const data = dataItem.data(); // 先初始化键对应的对象,避免报错 if (!dataDict[data.id]) { dataDict[data.id] = { id: data.id, name: '' }; } dataDict[data.id].name = data.name; });
为什么之前的模拟失败?
- 你直接修改
getDocs的mockImplementation,但此时getDocs还不是Jest mock函数,必须先通过jest.mock将其转为mock函数后,才能使用mockImplementation或mockResolvedValue。 - 你模拟的
docs是单个对象,而原代码需要它是数组才能调用forEach,这是第一个错误的直接原因。
内容的提问来源于stack exchange,提问作者Ailete619
相关产品推荐
相关产品推荐

