Skip to content
Vitest 3
Main Navigation 指南 & API配置浏览器模式高级 API
3.2.0
2.1.9
1.6.1
0.34.6

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

主题

Sidebar Navigation

简介

为什么选择 Vitest

快速入门

特性

配置 Vitest

API

测试 API 参考

模拟函数

Vi

expect

expectTypeOf

assert

assertType

指南

命令行界面

测试过滤

测试项目

报告器

覆盖率

快照

模拟

并行

类型测试

Vitest UI

源内测试

测试上下文

测试注解

测试环境

扩展匹配器

IDE 集成

调试

常见错误

迁移指南

迁移到 Vitest 3.0

从 Jest 迁移

性能

分析测试性能

性能优化

浏览器模式

高级 API

与其他测试运行器的比较

页面导航

模拟 ​

在编写测试时,您迟早会需要为内部或外部服务创建一个“伪造”的版本。这通常称为模拟 (Mocking)。Vitest 通过其 vi 辅助函数提供了实用功能来帮助您。您可以从 vitest 导入它,或者如果启用了 global 配置,也可以全局访问它。

WARNING

请务必在每次测试运行前或后清除或恢复模拟,以撤销不同测试运行之间的模拟状态更改!有关更多信息,请参阅 mockReset 方法的文档。

如果您不熟悉 vi.fn、vi.mock 或 vi.spyOn 方法,请先查看 API 部分。

日期 ​

有时,您需要控制日期和时间以确保测试时的一致性。Vitest 使用 @sinonjs/fake-timers 包来操作计时器和系统时间。您可以在此处找到有关特定 API 的详细信息。

示例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const businessHours = [9, 17];

function purchase() {
  const currentHour = new Date().getHours();
  const [open, close] = businessHours;

  if (currentHour > open && currentHour < close) {
    return { message: 'Success' };
  }

  return { message: 'Error' };
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // 告诉 Vitest 我们使用模拟时间
    vi.useFakeTimers();
  });

  afterEach(() => {
    // 每次测试运行后恢复日期
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // 设置营业时间内的时段
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // 访问 Date.now() 将返回上面设置的日期
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // 设置营业时间外的时段
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // 访问 Date.now() 将返回上面设置的日期
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

函数 ​

模拟函数可以分为两种不同的类别:监听 (Spy) 和_模拟 (Mock)_。

有时您只需要验证特定函数是否已被调用(以及可能传递了哪些参数)。在这种情况下,一个监听器就足够了,您可以直接使用 vi.spyOn()(在此处阅读更多)。

然而,监听器只能帮助您监听函数,它们无法更改这些函数的实现。如果我们需要创建一个伪造(或模拟)版本的函数,可以使用 vi.fn()(在此处阅读更多)。

我们使用 Tinyspy 作为模拟函数的基础,但我们有自己的包装器,使其与 jest 兼容。vi.fn() 和 vi.spyOn() 共享相同的方法,但只有 vi.fn() 的返回结果可以被调用。

示例 ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // 如果支持,也可以是 `getter` 或 `setter`
};

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

describe('reading messages', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should get the latest message with a spy', () => {
    const spy = vi.spyOn(messages, 'getLatest');
    expect(spy.getMockName()).toEqual('getLatest');

    expect(messages.getLatest()).toEqual(
      messages.items[messages.items.length - 1]
    );

    expect(spy).toHaveBeenCalledTimes(1);

    spy.mockImplementationOnce(() => 'access-restricted');
    expect(messages.getLatest()).toEqual('access-restricted');

    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should get with a mock', () => {
    const mock = vi.fn().mockImplementation(getLatest);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(1);

    mock.mockImplementationOnce(() => 'access-restricted');
    expect(mock()).toEqual('access-restricted');

    expect(mock).toHaveBeenCalledTimes(2);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(3);
  });
});

更多 ​

  • Jest 的模拟函数

全局变量 ​

您可以使用 vi.stubGlobal 辅助函数模拟 jsdom 或 node 中不存在的全局变量。它会将全局变量的值放入 globalThis 对象中。

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// 现在您可以将其作为 `IntersectionObserver` 或 `window.IntersectionObserver` 访问

模块 ​

模拟模块处理在其他代码中调用的第三方库,允许您测试参数、输出甚至重新声明其实现。

有关更深入的详细 API 描述,请参阅 vi.mock() API 部分。

自动模拟算法 ​

如果您的代码正在导入一个被模拟的模块,而该模块没有任何关联的 __mocks__ 文件或 factory,Vitest 将通过调用并模拟其所有导出项来模拟该模块本身。

以下原则适用:

  • 所有数组都将被清空
  • 所有原始类型和集合将保持不变
  • 所有对象都将被深层克隆
  • 所有类实例及其原型都将被深层克隆

虚拟模块 ​

Vitest 支持模拟 Vite 虚拟模块。它的工作方式与 Jest 处理虚拟模块的方式不同。您无需将 virtual: true 传递给 vi.mock 函数,而是需要告诉 Vite 该模块存在,否则它将在解析期间失败。您可以通过以下几种方式实现:

  1. 提供别名
ts
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
});
  1. 提供一个解析虚拟模块的插件
ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  plugins: [
    {
      name: 'virtual-modules',
      resolveId(id) {
        if (id === '$app/forms') {
          return 'virtual:$app/forms';
        }
      },
    },
  ],
});

第二种方法的优点是您可以动态创建不同的虚拟入口。如果您将多个虚拟模块重定向到单个文件,那么所有这些模块都将受 vi.mock 的影响,因此请确保使用唯一的标识符。

模拟陷阱 ​

请注意,无法模拟同一文件中其他方法内部调用的方法。例如,在此代码中:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

不可能从外部模拟 foo 方法,因为它被直接引用。因此,此代码不会影响 foobar 内部的 foo 调用(但会影响其他模块中的 foo 调用):

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// 这只会影响原始模块外部的 "foo"
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // 这只会影响原始模块外部的 "foo"
    foo: () => 'mocked',
  };
});

您可以通过直接为 foobar 方法提供实现来确认此行为:

ts
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// 导出的 foo 引用了被模拟的方法
mod.foobar(mod.foo);
ts
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo === foo; // false
}

这是预期行为。当模拟以这种方式使用时,通常是代码质量不佳的表现。考虑将代码重构为多个文件或通过使用依赖注入等技术来改进应用程序架构。

示例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// 获取待办事项
export async function getTodos(event, context) {
  const client = new Client({
    // ...clientOptions
  });

  await client.connect();

  try {
    const result = await client.query('SELECT * FROM todos;');

    client.end();

    return success({
      message: `${result.rowCount} item(s) returned`,
      data: result.rows,
      status: true,
    });
  } catch (e) {
    console.error(e.stack);

    client.end();

    return failure({ message: e, status: false });
  }
}

vi.mock('pg', () => {
  const Client = vi.fn();
  Client.prototype.connect = vi.fn();
  Client.prototype.query = vi.fn();
  Client.prototype.end = vi.fn();

  return { Client };
});

vi.mock('./handlers.js', () => {
  return {
    success: vi.fn(),
    failure: vi.fn(),
  };
});

describe('get a list of todo items', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should return items successfully', async () => {
    client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);

    expect(success).toBeCalledWith({
      message: '0 item(s) returned',
      data: [],
      status: true,
    });
  });

  it('should throw an error', async () => {
    const mError = new Error('Unable to retrieve rows');
    client.query.mockRejectedValueOnce(mError);

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);
    expect(failure).toBeCalledWith({ message: mError, status: false });
  });
});

文件系统 ​

模拟文件系统可确保测试不依赖于实际文件系统,从而使测试更可靠、可预测。这种隔离有助于避免之前测试的副作用。它允许测试错误条件和边缘情况,这些情况可能难以或不可能通过实际文件系统复制,例如权限问题、磁盘空间不足或读/写错误。

Vitest 不提供任何内置的文件系统模拟 API。您可以使用 vi.mock 手动模拟 fs 模块,但这维护起来很困难。相反,我们建议使用 memfs 来实现。memfs 创建一个内存中的文件系统,它模拟文件系统操作而无需触及实际磁盘。这种方法快速且安全,避免了对真实文件系统的任何潜在副作用。

示例 ​

要自动将每个 fs 调用重定向到 memfs,您可以在项目根目录创建 __mocks__/fs.cjs 和 __mocks__/fs/promises.cjs 文件:

ts
// 我们也可以使用 `import`,但这样
// 每个导出都应明确定义

const { fs } = require('memfs');
module.exports = fs;
ts
// 我们也可以使用 `import`,但这样
// 每个导出都应明确定义

const { fs } = require('memfs');
module.exports = fs.promises;
ts
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8');
}
ts
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';

// 告诉 Vitest 使用 __mocks__ 文件夹中的 fs 模拟实现
// 如果 fs 总是需要被模拟,这可以在 setup 文件中完成
vi.mock('node:fs');
vi.mock('node:fs/promises');

beforeEach(() => {
  // 重置内存文件系统的状态
  vol.reset();
});

it('should return correct text', () => {
  const path = '/hello-world.txt';
  fs.writeFileSync(path, 'hello world');

  const text = readHelloWorld(path);
  expect(text).toBe('hello world');
});

it('can return a value multiple times', () => {
  // 您可以使用 vol.fromJSON 定义多个文件
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // 默认 cwd
    '/tmp'
  );

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});

请求 ​

由于 Vitest 在 Node 中运行,模拟网络请求比较棘手;Web API 不可用,因此我们需要一些东西来模拟网络行为。我们建议使用 Mock Service Worker 来实现此目的。它允许您模拟 http、WebSocket 和 GraphQL 网络请求,并且不依赖于特定框架。

Mock Service Worker (MSW) 通过拦截您的测试发出的请求来发挥作用,允许您在不更改任何应用程序代码的情况下使用它。在浏览器中,它使用 Service Worker API。在 Node.js 中,Vitest 使用 @mswjs/interceptors 库。要了解更多关于 MSW 的信息,请阅读他们的介绍

配置 ​

您可以在设置文件中按如下方式使用它

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts);
  }),
];

const server = setupServer(...restHandlers);

// 在所有测试运行前启动服务器
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 在所有测试运行后关闭服务器
afterAll(() => server.close());

// 每次测试后重置处理程序,以确保测试隔离
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...graphqlHandlers);

// 在所有测试运行前启动服务器
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 在所有测试运行后关闭服务器
afterAll(() => server.close());

// 每次测试后重置处理程序以实现测试隔离
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';

const chat = ws.link('wss://chat.example.com');

const wsHandlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', event => {
      console.log('Received message from client:', event.data);
      // 将收到的消息回显给客户端
      client.send(`Server received: ${event.data}`);
    });
  }),
];

const server = setupServer(...wsHandlers);

// 在所有测试运行前启动服务器
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// 在所有测试运行后关闭服务器
afterAll(() => server.close());

// 每次测试后重置处理程序以实现测试隔离
afterEach(() => server.resetHandlers());

将服务器配置为 onUnhandledRequest: 'error' 可确保在请求没有相应的请求处理程序时抛出错误。

更多 ​

MSW 的功能远不止于此。您可以访问 cookie 和查询参数,定义模拟错误响应等等。要查看 MSW 的所有功能,请阅读他们的文档。

计时器 ​

当我们测试涉及超时或间隔的代码时,我们可以通过使用“假”计时器来模拟对 setTimeout 和 setInterval 的调用,从而加快测试速度,而不是让测试等待或超时。

有关更深入的详细 API 描述,请参阅 vi.useFakeTimers API 部分。

示例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2 小时
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1 分钟
}

const mock = vi.fn(() => console.log('executed'));

describe('delayed execution', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('should execute the function', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('should not execute the function', () => {
    executeAfterTwoHours(mock);
    // 快进 2ms 不会触发函数
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('should execute every minute', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

类 ​

您可以通过单个 vi.fn 调用来模拟整个类——因为所有类也都是函数,所以这开箱即用。请注意,目前 Vitest 不支持 new 关键字,因此函数体中的 new.target 始终是 undefined。

ts
class Dog {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  static getType(): string {
    return 'animal';
  }

  greet = (): string => {
    return `Hi! My name is ${this.name}!`;
  };

  speak(): string {
    return 'bark!';
  }

  isHungry() {}
  feed() {}
}

我们可以用 ES5 函数重新创建这个类:

ts
const Dog = vi.fn(function (name) {
  this.name = name;
  // 在构造函数中模拟实例方法,每个实例都将有自己的监听器
  this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});

// 注意静态方法直接在函数上模拟,
// 而不是在类的实例上
Dog.getType = vi.fn(() => 'mocked animal');

// 模拟类的每个实例上的 "speak" 和 "feed" 方法
// 所有 `new Dog()` 实例都将继承并共享这些监听器
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();

WARNING

如果构造函数返回非基本类型值,则该值将成为 new 表达式的结果。在这种情况下,[[Prototype]] 可能无法正确绑定:

ts
const CorrectDogClass = vi.fn(function (name) {
  this.name = name;
});

const IncorrectDogClass = vi.fn(name => ({
  name,
}));

const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');

Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!

何时使用?

一般来说,如果类是从另一个模块重新导出的,您会在模块工厂中重新创建此类:

ts
import { Dog } from './dog.js';

vi.mock(import('./dog.js'), () => {
  const Dog = vi.fn();
  Dog.prototype.feed = vi.fn();
  // ... 其他模拟
  return { Dog };
});

此方法还可以用于将类的实例传递给接受相同接口的函数:

ts
function feed(dog: Dog) {
  // ...
}
ts
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';

const Dog = vi.fn();
Dog.prototype.feed = vi.fn();

test('can feed dogs', () => {
  const dogMax = new Dog('Max');

  feed(dogMax);

  expect(dogMax.feed).toHaveBeenCalled();
  expect(dogMax.isHungry()).toBe(false);
});

现在,当我们创建 Dog 类的新实例时,其 speak 方法(以及 feed 和 greet)已被模拟:

ts
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!

// 您可以使用内置断言来检查调用的有效性
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();

const Max = new Dog('Max');

// 分配给原型的方法在实例之间共享
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();

我们可以为特定实例重新分配返回值:

ts
const dog = new Dog('Cooper');

// "vi.mocked" 是一个类型辅助工具,因为
// TypeScript 不知道 Dog 是一个模拟类,
// 它会将任何函数包装在 MockInstance<T> 类型中
// 而不验证该函数是否是模拟
vi.mocked(dog.speak).mockReturnValue('woof woof');

dog.speak(); // woof woof

要模拟属性,我们可以使用 vi.spyOn(dog, 'name', 'get') 方法。这使得可以在模拟属性上使用监听器断言:

ts
const dog = new Dog('Cooper');

const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');

expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);

TIP

您还可以使用相同的方法监听 getter 和 setter。

速查表 ​

INFO

以下示例中的 vi 直接从 vitest 导入。如果您的配置中将 globals 设置为 true,您也可以全局使用它。

我想…

模拟导出的变量 ​

js
export const getter = 'variable';
ts
import * as exports from './example.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

模拟导出的函数 ​

  1. vi.mock 示例:

WARNING

请注意,vi.mock 调用会被提升到文件顶部。它将始终在所有导入之前执行。

ts
export function method() {}
ts
import { method } from './example.js';

vi.mock('./example.js', () => ({
  method: vi.fn(),
}));
  1. vi.spyOn 示例:
ts
import * as exports from './example.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

模拟导出的类实现 ​

  1. vi.mock 和 .prototype 示例:
ts
export class SomeClass {}
ts
import { SomeClass } from './example.js';

vi.mock(import('./example.js'), () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instances 将是 SomeClass 的实例
  1. vi.spyOn 示例:
ts
import * as mod from './example.js';

const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();

vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);

侦察从函数返回的对象 ​

  1. 使用缓存的示例:
ts
export function useObject() {
  return { method: () => true };
}
ts
import { useObject } from './example.js';

const obj = useObject();
obj.method();
ts
import { useObject } from './example.js';

vi.mock(import('./example.js'), () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // 现在每次调用 useObject(),它都会
    // 返回相同的对象引用
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method 在 some-path 内部被调用
expect(obj.method).toHaveBeenCalled();

模拟模块的一部分 ​

ts
import { mocked, original } from './some-path.js';

vi.mock(import('./some-path.js'), async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // 具有原始行为
mocked(); // 是一个监听函数

WARNING

请注意,这只会模拟_外部_访问。在此示例中,如果 original 在内部调用 mocked,它将始终调用模块中定义的函数,而不是模拟工厂中的函数。

模拟当前日期 ​

要模拟 Date 的时间,您可以使用 vi.setSystemTime 辅助函数。此值不会在不同测试之间自动重置。

请注意,使用 vi.useFakeTimers 也会更改 Date 的时间。

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// 重置模拟时间
vi.useRealTimers();

模拟全局变量 ​

您可以通过将值分配给 globalThis 或使用 vi.stubGlobal 辅助函数来设置全局变量。使用 vi.stubGlobal 时,它不会在不同测试之间自动重置,除非您启用 unstubGlobals 配置选项或调用 vi.unstubAllGlobals。

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

模拟 import.meta.env ​

  1. 要更改环境变量,您只需为其分配一个新值。

WARNING

环境变量值不会在不同测试之间自动重置。

ts
import { beforeEach, expect, it } from 'vitest';

// 在运行测试之前,"VITE_ENV" 是 "test"
const originalViteEnv = import.meta.env.VITE_ENV;

beforeEach(() => {
  import.meta.env.VITE_ENV = originalViteEnv;
});

it('changes value', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});
  1. 如果您想自动重置值,可以使用 vi.stubEnv 辅助函数,并启用 unstubEnvs 配置选项(或在 beforeEach 钩子中手动调用 vi.unstubAllEnvs):
ts
import { expect, it, vi } from 'vitest';

// 在运行测试之前 "VITE_ENV" 是 "test"
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('the value is restored before running an other test', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
上一页快照
下一页并行

基于 MIT 许可证 发布。

版权所有 (c) 2021-Present Vitest Team

https://vitest.dev/guide/mocking

基于 MIT 许可证 发布。

版权所有 (c) 2021-Present Vitest Team