ReactJS中如何在Jest测试用例中使用Firebase模拟器?
问题:如何在Jest测试中使用Firebase模拟器获取数据?
我已经成功搭建Firebase模拟器,但不清楚如何在Jest测试用例中从模拟器存储获取数据,尝试实现后出现错误。以下是我的测试文件与Redux动作代码,恳请指导:
user.test.js
import { firestore } from 'firebase-admin'; import { collection, doc } from 'firebase/firestore'; import { initializeTestApp, loadFirestoreRules } from '@firebase/rules-unit-testing'; import { setUserData, companyRef, stored, company, product } from '../mock';import userSlice, { hasError, initialState, resetStateData, setUser, } from '../src/redux/slices/user'; beforeAll(async () => { await loadFirestoreRules({ projectId, rules: '../firestore.rules' }); }); afterAll(async () => { await app.delete(); }); const mockStore = configureMockStore(); const store = mockStore(stored); describe('User test case :-', () => { const error = { status: '401', message: 'Something went to wrong' }; const userId = 'VOmxX13c7ygUhOmzXZefXfnLLwZ2'; const otherUserData = setUserData; const companyRefMock = companyRef; const dispatch = jest.fn(); beforeEach(async () => { // Set up necessary data before each test // You can create documents in the Firestore emulator using 'setDoc' await setDoc(doc(collection(db, 'users'), '5e86809283e28b96d2d38537'), { /* user data */ }); await setDoc(doc(collection(db, 'super-user'), '5e86809283e28b96d2d38537'), { /* super user data */ }); }); afterEach(() => { jest.clearAllMocks(); }); // Test of Success for updateUser test('setUser action should set user profile data correctly', async () => { const snapshot = await firestore.collection('your_collection').get(); // const snapshot = await jest.mock(firestore.collection('user').get()); console.log('snapshot', snapshot); await dispatch(setUser(userId, otherUserData)); // check loading state expect(dispatch).toBeCalled(dispatch(userLoading())); // check setAuthentication state expect(dispatch).toBeCalled(dispatch(setAuthentication(true))); expect(dispatch).toBeCalled(dispatch(hasError(error))); // Compare with the store expect(store.getState().isUserLoading).toBe(false); expect(store.getState().isAuthenticated).toBe(true); expect(store.getState().error).toEqual(error); }); });
user.js(Redux动作)
export function setUser(userId, otherUserData) { return async (dispatch) => { dispatch(slice.actions.userLoading(true)); try { const userRef = doc(DB, 'users', userId); const userDocumentSnap = await getDoc(userRef); const docSuperUserRef = await doc(collection(DB, 'super-user'), userId); const docSuperUserSnapshot = await getDoc(docSuperUserRef); const isSuperUser = docSuperUserSnapshot.exists(); let userProfile = userDocumentSnap.data(); if (otherUserData) { userProfile = { ...otherUserData, ...userProfile, isSuperUser }; } if (isSuperUser) { dispatch(getAllCompanies()); } dispatch(slice.actions.setUserSuccess({ userProfile, userRef })); dispatch(setUserInvitations(userProfile)); dispatch(setAllProducts()); if (userProfile.companies) { dispatch(slice.actions.setCompanies(userProfile.companies)); } dispatch(slice.actions.setAuthentication(true)); } catch (error) { // console.error(error); dispatch(slice.actions.hasError(error)); dispatch(slice.actions.setAuthentication(false)); } finally { dispatch(slice.actions.userLoading(false)); } }; }
解决方案
1. 修正测试环境初始化逻辑
你的测试代码未正确初始化Firebase测试应用和Firestore实例,需补充如下:
import { firestore } from 'firebase-admin'; import { collection, doc, setDoc, getDoc } from 'firebase/firestore'; import { initializeTestApp, loadFirestoreRules, clearFirestoreData } from '@firebase/rules-unit-testing'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; // 补充缺失的action导入 import { userLoading, setAuthentication } from '../src/redux/slices/user'; const projectId = 'test-project-id'; // 自定义测试项目ID let app; let db; beforeAll(async () => { // 初始化测试应用 app = initializeTestApp({ projectId }); db = firestore(app); // 加载Firestore规则 await loadFirestoreRules({ projectId, rules: '../firestore.rules' }); }); afterAll(async () => { // 清理测试数据,避免用例间污染 await clearFirestoreData({ projectId }); await app.delete(); }); // 配置mock store,添加thunk中间件支持异步action const mockStore = configureMockStore([thunk]);
2. 完善测试数据准备
beforeEach中需使用初始化好的db实例,且填充与测试用例匹配的真实数据:
beforeEach(async () => { const testUserId = 'VOmxX13c7ygUhOmzXZefXfnLLwZ2'; // 与测试用例的userId保持一致 // 创建普通用户数据 await setDoc(doc(db, 'users', testUserId), { name: 'Test User', email: 'test@example.com', companies: ['company1'] }); // 创建超级用户数据(若需测试超级用户分支) await setDoc(doc(db, 'super-user', testUserId), { role: 'super' }); });
3. 修正测试用例逻辑
移除无效代码,使用mock store测试异步action的正确行为:
test('setUser action should set user profile data correctly', async () => { const userId = 'VOmxX13c7ygUhOmzXZefXfnLLwZ2'; const otherUserData = { nickname: 'Nick' }; const store = mockStore(initialState); await store.dispatch(setUser(userId, otherUserData)); const actions = store.getActions(); // 断言loading状态变化 expect(actions).toContainEqual(userLoading(true)); expect(actions).toContainEqual(userLoading(false)); // 断言认证状态设置成功 expect(actions).toContainEqual(setAuthentication(true)); // 断言无错误触发 expect(actions.some(action => action.type === userSlice.actions.hasError.type)).toBe(false); // 断言用户数据正确合并 const setUserSuccessAction = actions.find(action => action.type === userSlice.actions.setUserSuccess.type); expect(setUserSuccessAction.payload.userProfile).toEqual(expect.objectContaining({ name: 'Test User', nickname: 'Nick', isSuperUser: true })); });
4. 确保Redux中的Firestore指向模拟器
在Firestore初始化文件中添加测试环境判断,强制连接到模拟器:
import { initializeApp } from 'firebase/app'; import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore'; const firebaseConfig = { /* 你的Firebase配置 */ }; const app = initializeApp(firebaseConfig); const DB = getFirestore(app); // 测试环境下连接到模拟器 if (process.env.NODE_ENV === 'test') { connectFirestoreEmulator(DB, 'localhost', 8080); } export { DB };
内容的提问来源于stack exchange,提问作者Nayan Bhakhar
相关产品推荐
相关产品推荐

