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

使用Jest测试React类组件时如何Mock常量options.isShow

问题:无法Mock options.isShow 为true导致组件render返回null

options.isShow始终为false,导致render()仅返回null,尝试Mock该值为true但无效

组件代码(a.js)

// a.js
import React, {Component} from 'react';
import merge from 'lodash-es/merge';
export let options = {
  isShow: false,
  //....
};
export default class Button extends Component {
  constructor(props) {
    super(props);
  }
  renderBtn() {
    //...
  }
  render() {
    const {data = {}} = this.props;
    // console.log(options.isShow) // false
    merge(options, data);
    return options.isShow
      ? this.renderBtn()
      : null;
  }
}

最初的测试代码(a.spec.js)

// a.spec.js(最初版本)
import Button from 'a.js';
jest.mock('lodash-es/merge', () => jest.fn(fn => fn));
describe('Button', () => {
  it('a', done => {
    const ButtonI = new Button({
      data: {},
    });
    ButtonI.renderBtn = jest.fn();
    ButtonI.render();
    expect(ButtonI.renderBtn).toBeCalled();
    done();
  });
})

尝试的无效Mock方式

直接在测试文件中替换options对象,测试文件控制台显示options.isShow为true,但组件内部的options.isShow仍为false:

// a.spec.js(尝试修改后的版本)
import * as ButtonAll from 'a.js';
jest.mock('lodash-es/merge', () => jest.fn(fn => fn));
describe('Button', () => {
  it('a', done => {
    const Button = ButtonAll.default;
    ButtonAll.options = {
      isShow: true,
      // ....
    }
    // console.log(ButtonAll.options.isShow) // true
    const ButtonI = new Button({
      data: {},
    });
    ButtonI.renderBtn = jest.fn();
    ButtonI.render();
    expect(ButtonI.renderBtn).toBeCalled();
      done();
  });
})

解决方案

问题核心是Mock逻辑错误,以及直接替换options引用无法同步到组件内部变量,以下两种方式可以解决:

方式一:正确Mock merge并传入含isShow: true的props

之前Mock的merge仅返回第一个参数,未执行合并逻辑。修改Mock逻辑让其真正合并属性,同时传入带isShow: true的data:

// a.spec.js
import Button from './a.js';
import * as ButtonAll from './a.js';

// 让Mock的merge执行真实的对象合并逻辑
jest.mock('lodash-es/merge', () => 
  jest.fn((target, source) => Object.assign(target, source))
);

describe('Button', () => {
  it('should call renderBtn when isShow is true', () => {
    // 重置options状态,避免测试污染
    ButtonAll.options.isShow = false;
    
    const ButtonI = new Button({
      data: { isShow: true },
    });
    ButtonI.renderBtn = jest.fn();
    
    ButtonI.render();
    
    expect(ButtonI.renderBtn).toHaveBeenCalled();
  });
})

方式二:修改原options对象的属性(而非替换整个对象)

组件内部的options绑定了模块加载时的原对象引用,直接替换ButtonAll.options不会改变组件内部的变量指向,需修改原对象的属性:

// a.spec.js
import * as ButtonAll from './a.js';
jest.mock('lodash-es/merge', () => jest.fn(fn => fn));

describe('Button', () => {
  it('should call renderBtn when isShow is true', () => {
    // 修改原对象的isShow属性,而非替换整个options
    ButtonAll.options.isShow = true;
    
    const Button = ButtonAll.default;
    const ButtonI = new Button({
      data: {},
    });
    ButtonI.renderBtn = jest.fn();
    
    ButtonI.render();
    
    expect(ButtonI.renderBtn).toHaveBeenCalled();
    
    // 测试后重置状态,避免影响其他用例
    ButtonAll.options.isShow = false;
  });
})

补充说明

  • 直接替换ButtonAll.options无效的原因:组件内部的options变量在模块加载时就绑定了原对象的引用,测试中替换导出的options只是改变了外部引用,组件内部仍指向原对象。
  • 测试后务必重置options状态,防止不同测试用例之间互相干扰。

内容的提问来源于stack exchange,提问作者asui

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:04:51