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

如何在Vitest中为不同测试用例模拟单个导入变量

问题原因

你当前的mock方式是将isRootPresent导出为固定值,后续修改mocks.isRootPresent不会同步到导出的常量——这是一次值拷贝,模块导出后就不会再更新这个值了。


解决方案一:用Getter实现动态Mock

修改mock逻辑,通过getter让每次访问isRootPresent时都取最新的mock值:

import { render, screen } from '@testing-library/react';
import { afterEach } from 'vitest';

const mocks = vi.hoisted(() => {
  return {
    isRootPresent: true,
  }
})

vi.mock('./utils.ts', () => {
  return {
    // 使用getter动态返回mock值
    get isRootPresent() {
      return mocks.isRootPresent;
    }
  }
})

describe("App component", () => {
  // 每次测试后重置mock状态
  afterEach(() => {
    mocks.isRootPresent = true;
  })

  it("should render Root is present text", () => {
    mocks.isRootPresent = true;
    render(<App/>);
    expect(screen.getByTestId('test-heading')).toBeInTheDocument();
    expect(screen.getByTestId('test-heading').textContent).toBe('Root is present');
  })

  it("should not render Root is present text", () => {
    mocks.isRootPresent = false;
    render(<App/>);
    // 用queryByTestId避免找不到元素时抛出错误
    expect(screen.queryByTestId('test-heading')).not.toBeInTheDocument();
  })
})

解决方案二:直接Mock DOM环境(更贴近真实逻辑)

既然isRootPresent的本质是判断DOM中是否存在#root元素,直接模拟DOM场景,无需mock整个utils模块:

import { render, screen } from '@testing-library/react';
import { afterEach, vi } from 'vitest';

describe("App component", () => {
  afterEach(() => {
    // 清理DOM,避免测试间污染
    const rootEl = document.getElementById('root');
    if (rootEl) rootEl.remove();
    // 重置模块缓存,确保每次测试重新计算isRootPresent
    vi.resetModules();
  })

  it("should render Root is present text", async () => {
    // 在DOM中添加#root元素
    const rootEl = document.createElement('div');
    rootEl.id = 'root';
    document.body.appendChild(rootEl);

    // 重新导入App(模块缓存会保留之前的isRootPresent值)
    const { App } = await import('./App');
    render(<App/>);

    expect(screen.getByTestId('test-heading')).toBeInTheDocument();
  })

  it("should not render Root is present text", async () => {
    // DOM中没有#root元素,直接重新导入App
    const { App } = await import('./App');
    render(<App/>);

    expect(screen.queryByTestId('test-heading')).not.toBeInTheDocument();
  })
})

补充说明

  • 方案一的getter确保每次组件访问isRootPresent时,都会获取最新的mock值,解决了值拷贝导致的更新不生效问题。
  • 方案二更贴近真实业务逻辑,模拟了实际的DOM场景而非直接mock常量。
  • 检查元素是否不存在时,推荐用queryByTestId,getByTestId在找不到元素时会抛出错误,导致测试失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:54:54