You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest模拟Firebase 9.0.0的onValue函数不生效,正确实现方式是什么?

问题根源

  • 你创建的局部firebase对象和组件实际导入的./Firebase模块没有关联,spy监听的是局部对象的方法,组件里调用的还是原模块的onValue,自然不会触发模拟逻辑
  • onValue的模拟实现逻辑错误:onValue接收2个参数(引用对象、快照回调),调用后会立即触发回调,返回值是取消订阅的函数。你之前的实现是调用onValue后返回了一个新函数,没有直接触发回调,自然不会执行setFeature更新状态

正确模拟方案

完整的测试代码如下:

import React from 'react'
import Acerca from './Acerca'
import { render } from 'react-dom'
import { act } from 'react-dom/test-utils'
// 导入模拟后的模块方法
import { onValue, ref } from './Firebase'

// 模拟整个Firebase模块,所有导入的该模块都会被mock
jest.mock('./Firebase', () => ({
  db: {}, // 模拟空的db实例即可
  ref: jest.fn(), // 模拟ref方法
  onValue: jest.fn()
}))

let container
beforeEach(() => {
  // 初始化挂载节点
  container = document.createElement('div')
  document.body.appendChild(container)
})

afterEach(() => {
  // 清理节点和mock状态
  document.body.removeChild(container)
  container = null
  jest.clearAllMocks()
})

it("Acerca -> displays title", async () => {
  // 按你的业务逻辑,feature节点的值为字符串"New feature"
  const mockFeatureVal = "New feature"
  const snapshot = { val: () => mockFeatureVal }
  // 模拟取消订阅函数
  const mockUnsubscribe = jest.fn()

  // 修正onValue的模拟实现
  onValue.mockImplementation((ref, callback) => {
    // 调用时直接触发快照回调,传入模拟数据
    callback(snapshot)
    // 返回取消订阅函数
    return mockUnsubscribe
  })

  await act(async () => {
    render(<Acerca/>, container)
  })

  // 验证结果
  expect(onValue).toHaveBeenCalledTimes(1)
  expect(container.querySelector('h3').textContent).toBe(mockFeatureVal)
  expect(mockUnsubscribe).toBeDefined() // 可选:验证返回了取消订阅函数
})

补充说明

如果你的业务逻辑中feature节点存储的是对象结构,比如{title: "New feature"},只需要调整两个地方即可:

  1. 模拟snapshot.val()的返回值:const snapshot = { val: () => ({ title: "New feature" }) }
  2. 修改组件中渲染逻辑:<h3>{feature.title}</h3>,避免直接渲染对象报错

内容的提问来源于stack exchange,提问作者Erik Martín Jordán

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:39:01