Skip to content
Vitest 0
Main Navigation 指南API配置高级
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

快速开始

特性

工作区

命令行界面

测试筛选

代码覆盖率

快照(Snapshot)

模拟(Mocking)

类型测试

Vitest UI

浏览器模式(实验性)

源码内测试

测试上下文

测试环境

扩展匹配器

IDE 集成

调试

与其他测试运行器的比较

迁移指南

常见错误

API

测试 API 索引

Mock Functions

Vi

expect

expectTypeOf

assertType

配置

配置 Vitest

页面导航

Vi ​

Vitest 通过 vi 辅助工具提供实用函数来帮助你。你可以全局访问它(当 globals 配置 启用 时),或者从 vitest 导入:

js
import { vi } from 'vitest';

vi.advanceTimersByTime ​

  • 类型: (ms: number) => Vitest

    与 runAllTimers 功能类似,但会在经过指定的毫秒数后结束。例如,以下代码会记录 1, 2, 3,且不会抛出错误:

    ts
    let i = 0;
    setInterval(() => console.log(++i), 50);
    
    vi.advanceTimersByTime(150);

vi.advanceTimersByTimeAsync ​

  • 类型: (ms: number) => Promise<Vitest>

    与 runAllTimersAsync 功能类似,但会在经过指定的毫秒数后结束。此方法会处理异步设置的定时器。例如,以下代码会记录 1, 2, 3,且不会抛出错误:

    ts
    let i = 0;
    setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
    
    await vi.advanceTimersByTimeAsync(150);

vi.advanceTimersToNextTimer ​

  • 类型: () => Vitest

    执行下一个可用的定时器。可用于在定时器调用之间进行断言。你可以链式调用此方法来手动管理定时器。

    ts
    let i = 0;
    setInterval(() => console.log(++i), 50);
    
    vi.advanceTimersToNextTimer() // 记录 1
      .advanceTimersToNextTimer() // 记录 2
      .advanceTimersToNextTimer(); // 记录 3

vi.advanceTimersToNextTimerAsync ​

  • 类型: () => Promise<Vitest>

    执行下一个可用的定时器,即使是异步设置的定时器也会被处理。可用于在定时器调用之间进行断言。你可以链式调用此方法来手动管理定时器。

    ts
    let i = 0;
    setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
    
    vi.advanceTimersToNextTimerAsync() // 记录 1
      .advanceTimersToNextTimerAsync() // 记录 2
      .advanceTimersToNextTimerAsync(); // 记录 3

vi.getTimerCount ​

  • 类型: () => number

    获取待执行的定时器数量。

vi.clearAllMocks ​

对所有间谍调用 .mockClear()。这将清除模拟历史记录,但不会将实现重置为默认实现。

vi.clearAllTimers ​

移除所有已计划但尚未执行的定时器。这些定时器将不会再运行。

vi.dynamicImportSettled ​

等待所有动态导入完成加载。如果存在一个同步调用,它会开始导入一个模块,而你又无法以其他方式等待其完成,那么此方法会非常有用。

vi.fn ​

  • 类型: (fn?: Function) => Mock

    创建一个函数的间谍,也可以不使用函数进行初始化。每次函数被调用时,都会记录调用参数、返回值和实例。此外,你可以使用 方法 来修改其行为。 如果没有提供函数,则在调用时,模拟将返回 undefined。

    ts
    const getApples = vi.fn(() => 0);
    
    getApples();
    
    expect(getApples).toHaveBeenCalled();
    expect(getApples).toHaveReturnedWith(0);
    
    getApples.mockReturnValueOnce(5);
    
    const res = getApples();
    expect(res).toBe(5);
    expect(getApples).toHaveNthReturnedWith(2, 5);

vi.getMockedSystemTime ​

  • 类型: () => Date | null

    返回通过 setSystemTime 设置的模拟当前日期。如果日期未被模拟,则返回 null。

vi.getRealSystemTime ​

  • 类型: () => number

    当使用 vi.useFakeTimers 时,Date.now 的调用会被模拟。如果你需要获取真实的毫秒时间,可以调用此函数。

vi.hoisted ​

  • 类型: <T>(factory: () => T) => T

  • 版本: 自 Vitest 0.31.0 起

    ES 模块中所有静态 import 语句都会被提升到文件顶部,因此在导入语句之前定义的任何代码,实际上会在导入语句被执行之后执行。

    但是,在导入模块之前调用一些副作用(如模拟日期)可能很有用。

    要解决这个问题,可以将静态导入重写为动态导入,如下所示:

    diff
    callFunctionWithSideEffect()
    - import { value } from './some/module.ts'
    + const { value } = await import('./some/module.ts')

    在运行 vitest 时,可以使用 vi.hoisted 方法自动执行此操作。

    diff
    - callFunctionWithSideEffect()
    import { value } from './some/module.ts'
    + vi.hoisted(() => callFunctionWithSideEffect())

    此方法返回工厂函数返回的值。如果需要轻松访问本地定义的变量,可以在 vi.mock 工厂函数中使用该值:

    ts
    import { expect, vi } from 'vitest';
    import { originalMethod } from './path/to/module.js';
    
    const { mockedMethod } = vi.hoisted(() => {
      return { mockedMethod: vi.fn() };
    });
    
    vi.mock('./path/to/module.js', () => {
      return { originalMethod: mockedMethod };
    });
    
    mockedMethod.mockReturnValue(100);
    expect(originalMethod()).toBe(100);

vi.mock ​

  • 类型: (path: string, factory?: () => unknown) => void

    将指定路径导入的所有模块替换为另一个模块。可以在路径中使用配置的 Vite 别名。vi.mock 的调用会被提升,因此调用位置并不重要。它总是在所有导入之前执行。如果需要引用其范围之外的一些变量,你可以在 vi.hoisted 中定义它们,并在 vi.mock 中引用。

    WARNING

    vi.mock 仅适用于通过 import 关键字导入的模块。它不适用于 require。

    Vitest 会静态分析文件以提升 vi.mock。这意味着不能使用未直接从 vitest 包导入的 vi,例如从某些实用工具文件中导入的 vi。要解决此问题,请始终使用从 vitest 导入的 vi 来使用 vi.mock,或启用 globals 配置选项。

    WARNING

    在 浏览器模式 中,模拟模块的功能目前不支持。可以在 GitHub issue 中跟踪此功能的进展。

    如果定义了 factory,则所有导入将返回其结果。Vitest 只会调用工厂函数一次,并将结果缓存起来,供后续所有导入操作使用,直到调用 vi.unmock 或 vi.doUnmock 为止。

    与 jest 不同,工厂函数可以是异步的,因此可以在其中使用 vi.importActual 或作为第一个参数接收的辅助函数来获取原始模块。

    ts
    vi.mock('./path/to/module.js', async importOriginal => {
      const mod = await importOriginal();
      return {
        ...mod,
        // 替换一些导出
        namedExport: vi.fn(),
      };
    });

    WARNING

    vi.mock 会被提升(换句话说,移动)到 文件顶部。这意味着无论在哪里编写它(无论是在 beforeEach 还是 test 中),它实际上都会在之前被调用。

    这也意味着不能在工厂函数内部使用在外部定义的任何变量。

    如果需要在工厂函数内部使用变量,请尝试 vi.doMock。它的工作方式相同,但不会被提升。请注意,它只会模拟后续导入。

    如果在 vi.mock 之前声明,也可以引用在 vi.hoisted 方法中定义的变量:

    ts
    import { namedExport } from './path/to/module.js';
    
    const mocks = vi.hoisted(() => {
      return {
        namedExport: vi.fn(),
      };
    });
    
    vi.mock('./path/to/module.js', () => {
      return {
        namedExport: mocks.namedExport,
      };
    });
    
    vi.mocked(namedExport).mockReturnValue(100);
    
    expect(namedExport()).toBe(100);
    expect(namedExport).toBe(mocks.namedExport);

    WARNING

    如果要模拟一个具有默认导出的模块,你需要在返回的工厂函数对象中提供一个 default 属性。这是一个 ES 模块特有的注意事项,因此 jest 文档可能会有所不同,因为 jest 使用 CommonJS 模块。例如,

    ts
    vi.mock('./path/to/module.js', () => {
      return {
        default: { myDefaultKey: vi.fn() },
        namedExport: vi.fn(),
        // 等等...
      };
    });

    如果有一个与你要模拟的文件并排的 __mocks__ 文件夹,并且未提供工厂函数,Vitest 将尝试在 __mocks__ 子文件夹中找到同名文件,并将其用作实际模块。如果要模拟一个依赖项,Vitest 将尝试在项目的 root(默认为 process.cwd())中找到一个 __mocks__ 文件夹。可以通过 deps.moduleDirectories 配置选项告诉 Vitest 依赖项的位置。

    例如,你有以下文件结构:

    - __mocks__
      - axios.js
    - src
      __mocks__
        - increment.js
      - increment.js
    - tests
      - increment.test.js

    如果在测试文件中调用 vi.mock 而不提供工厂函数,它将找到 __mocks__ 文件夹中的文件作为模块。

    ts
    // increment.test.js
    import { vi } from 'vitest';
    
    // axios 是来自 `__mocks__/axios.js` 的默认导出
    import axios from 'axios';
    
    // increment 是来自 `src/__mocks__/increment.js` 的命名导出
    import { increment } from '../increment.js';
    
    vi.mock('axios');
    vi.mock('../increment.js');
    
    axios.get(`/apples/${increment(1)}`);

    WARNING

    请注意,如果不调用 vi.mock,则模块 不会 自动模拟。要复制 Jest 的自动模拟行为,可以为 setupFiles 中的每个必需模块调用 vi.mock。

    如果没有 __mocks__ 文件夹或提供工厂函数,Vitest 将导入原始模块并自动模拟所有导出。有关应用的规则,请参见 算法。

vi.doMock ​

  • 类型: (path: string, factory?: () => unknown) => void

    与 vi.mock 相同,但它不会被提升到文件顶部,因此可以在全局文件范围内引用变量。该模块的下一次 动态导入 将会被模拟。这不会模拟在此调用之前导入的模块。

ts
// ./increment.js
export function increment(number) {
  return number + 1;
}
ts
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';

// 该模块未被模拟,因为尚未调用 vi.doMock
increment(1) === 2;

let mockedIncrement = 100;

beforeEach(() => {
  // 可以在工厂函数内部访问变量
  vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});

test('导入下一个模块会导入模拟的模块', async () => {
  // 原始导入没有被模拟,因为 vi.doMock 是在导入操作之后才执行的
  expect(increment(1)).toBe(2);
  const { increment: mockedIncrement } = await import('./increment.js');
  // 新的动态导入返回模拟模块
  expect(mockedIncrement(1)).toBe(101);
  expect(mockedIncrement(1)).toBe(102);
  expect(mockedIncrement(1)).toBe(103);
});

vi.mocked ​

  • 类型: <T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>

  • 类型: <T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>

    这是一个 TypeScript 的类型辅助函数,实际上它只是返回传入的对象。

    当 partial 为 true 时,期望返回值为 Partial<T>。

    ts
    import example from './example.js';
    
    vi.mock('./example.js');
    
    test('1+1 等于 2', async () => {
      vi.mocked(example.calc).mockRestore();
    
      const res = example.calc(1, '+', 1);
    
      expect(res).toBe(2);
    });

vi.importActual ​

  • 类型: <T>(path: string) => Promise<T>

    导入模块,并跳过所有关于是否需要进行模拟的检查。这在需要部分模拟模块时非常有用。

    ts
    vi.mock('./example.js', async () => {
      const axios = await vi.importActual('./example.js');
    
      return { ...axios, get: vi.fn() };
    });

vi.importMock ​

  • 类型: <T>(path: string) => Promise<MaybeMockedDeep<T>>

    导入一个模块,所有属性(包括嵌套属性)都被模拟。遵循与 vi.mock 相同的规则。有关应用的规则,请参见 算法。

vi.resetAllMocks ​

将调用所有间谍的 .mockReset()。这将清除模拟历史记录,并将其实现重置为空函数(返回 undefined)。

vi.resetConfig ​

  • 类型: RuntimeConfig

    如果之前调用了 vi.setConfig,则将配置重置为原始状态。

vi.resetModules ​

  • 类型: () => Vitest

    通过清除所有模块缓存来重置模块注册表。这允许在重新导入时重新评估模块。顶级导入无法被重新评估。这可能有助于隔离那些在不同测试之间存在本地状态冲突的模块。

    ts
    import { vi } from 'vitest';
    
    import { data } from './data.js'; // 将不会在每个测试之前重新评估
    
    beforeEach(() => {
      vi.resetModules();
    });
    
    test('更改状态', async () => {
      const mod = await import('./some/path.js'); // 将被重新评估
      mod.changeLocalState('new value');
      expect(mod.getLocalState()).toBe('new value');
    });
    
    test('模块具有旧状态', async () => {
      const mod = await import('./some/path.js'); // 将被重新评估
      expect(mod.getLocalState()).toBe('old value');
    });

WARNING

不会重置模拟注册表。要清除模拟注册表,请使用 vi.unmock 或 vi.doUnmock。

vi.restoreAllMocks ​

将调用所有间谍的 .mockRestore()。这将清除模拟历史记录,并将其实现重置为原始实现。

vi.stubEnv ​

  • 类型: (name: string, value: string) => Vitest

  • 版本: 自 Vitest 0.26.0 起

    更改 process.env 和 import.meta.env 中环境变量的值。可以通过调用 vi.unstubAllEnvs 来恢复其值。

ts
import { vi } from 'vitest';

// 在调用 "vi.stubEnv" 之前,`process.env.NODE_ENV` 和 `import.meta.env.NODE_ENV` 的值为 "development"

vi.stubEnv('NODE_ENV', 'production');

process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// 不会更改其他环境变量的值
import.meta.env.MODE === 'development';

TIP

也可以通过简单赋值来更改该值,但无法使用 vi.unstubAllEnvs 恢复先前的值:

ts
import.meta.env.MODE = 'test';

vi.unstubAllEnvs ​

  • 类型: () => Vitest

  • 版本: 自 Vitest 0.26.0 版本起

    恢复所有被 vi.stubEnv 修改过的 import.meta.env 和 process.env 的值。首次调用 vi.stubEnv 时,Vitest 会记住并存储原始值,直到再次调用 vi.unstubAllEnvs()。

ts
import { vi } from 'vitest';

// 在调用 `stubEnv` 之前,`process.env.NODE_ENV` 和 `import.meta.env.NODE_ENV` 的值均为 "development"

vi.stubEnv('NODE_ENV', 'production');

process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';

vi.stubEnv('NODE_ENV', 'staging');

process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';

vi.unstubAllEnvs();

// 恢复到第一次 "stubEnv" 调用之前存储的值
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';

vi.stubGlobal ​

  • 类型: (name: string | number | symbol, value: unknown) => Vitest

    修改全局变量的值。可以通过调用 vi.unstubAllGlobals() 来恢复其原始值。

ts
import { vi } from 'vitest';

// 在调用 `stubGlobal` 之前,`innerWidth` 的值为 "0"

vi.stubGlobal('innerWidth', 100);

innerWidth === 100;
globalThis.innerWidth === 100;
// 如果您正在使用 jsdom 或 happy-dom
window.innerWidth === 100;

TIP

您也可以简单地将其赋值给 globalThis 或 window(如果使用 jsdom 或 happy-dom 环境)来更改该值,但是您将无法使用 vi.unstubAllGlobals 来恢复原始值:

ts
globalThis.innerWidth = 100;
// 如果您正在使用 jsdom 或 happy-dom
window.innerWidth = 100;

vi.unstubAllGlobals ​

  • 类型: () => Vitest

  • 版本: 自 Vitest 0.26.0 版本起

    恢复所有通过 vi.stubGlobal() 更改的 globalThis/global (以及 window/top/self/parent,如果使用 jsdom 或 happy-dom 环境) 上的全局值。首次调用 vi.stubGlobal() 时,Vitest 会记住并存储原始值,直到再次调用 vi.unstubAllGlobals()。

ts
import { vi } from 'vitest';

const Mock = vi.fn();

// 在调用 "stubGlobal" 之前,IntersectionObserver 为 "undefined"

vi.stubGlobal('IntersectionObserver', Mock);

IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// 如果您正在使用 jsdom 或 happy-dom
window.IntersectionObserver === Mock;

vi.unstubAllGlobals();

globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// 抛出 ReferenceError,因为它未定义
IntersectionObserver === undefined;

vi.runAllTicks ​

  • 类型: () => Vitest

    调用所有排队的微任务 process.nextTick。 这也会运行所有由这些微任务自身调度的微任务。

vi.runAllTimers ​

  • 类型: () => Vitest

    此方法会执行所有已启动的计时器,直到计时器队列为空。 这意味着在 vi.runAllTimers() 执行期间调用的所有计时器也会被触发。 如果存在无限间隔的计时器,它将在尝试 10000 次后抛出一个错误。 例如,以下代码会输出 1, 2, 3:

    ts
    let i = 0;
    setTimeout(() => console.log(++i));
    const interval = setInterval(() => {
      console.log(++i);
      if (i === 3) clearInterval(interval);
    }, 50);
    
    vi.runAllTimers();

vi.runAllTimersAsync ​

  • 类型: () => Promise<Vitest>

    此方法会异步执行所有已启动的计时器,直到计时器队列为空。 这意味着在 vi.runAllTimersAsync() 执行期间调用的每个计时器都将被触发,包括异步计时器。 如果存在无限间隔的计时器,它将在尝试 10000 次后抛出一个错误。 例如,以下代码会输出 result:

    ts
    setTimeout(async () => {
      console.log(await Promise.resolve('result'));
    }, 100);
    
    await vi.runAllTimersAsync();

vi.runOnlyPendingTimers ​

  • 类型: () => Vitest

    此方法会执行在 vi.useFakeTimers() 调用之后启动的所有计时器。 它不会触发在其调用期间启动的任何计时器。 例如,以下代码只会输出 1:

    ts
    let i = 0;
    setInterval(() => console.log(++i), 50);
    
    vi.runOnlyPendingTimers();

vi.runOnlyPendingTimersAsync ​

  • 类型: () => Promise<Vitest>

    此方法会异步执行在 vi.useFakeTimers() 调用之后启动的所有计时器,包括异步计时器。 它不会触发在其调用期间启动的任何计时器。 例如,以下代码会输出 2, 3, 3, 1:

    ts
    setTimeout(() => {
      console.log(1);
    }, 100);
    setTimeout(() => {
      Promise.resolve().then(() => {
        console.log(2);
        setInterval(() => {
          console.log(3);
        }, 40);
      });
    }, 10);
    
    await vi.runOnlyPendingTimersAsync();

vi.setSystemTime ​

  • 类型: (date: string | number | Date) => void

    将当前日期设置为指定的日期。 所有 Date 相关的调用都将返回此日期。

    如果需要测试依赖于当前日期的代码(例如,代码中使用了 luxon),这将非常有用。

    ts
    const date = new Date(1998, 11, 19);
    
    vi.useFakeTimers();
    vi.setSystemTime(date);
    
    expect(Date.now()).toBe(date.valueOf());
    
    vi.useRealTimers();

vi.setConfig ​

  • 类型: RuntimeConfig

    更新当前测试文件的配置项。 您只能影响执行测试时使用的配置值。

vi.spyOn ​

  • 类型: <T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance

    在对象的方法或 getter/setter 上创建一个 spy。

    ts
    let apples = 0;
    const cart = {
      getApples: () => 13,
    };
    
    const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
    apples = 1;
    
    expect(cart.getApples()).toBe(1);
    
    expect(spy).toHaveBeenCalled();
    expect(spy).toHaveReturnedWith(1);

vi.stubGlobal ​

  • 类型: (key: keyof globalThis & Window, value: any) => Vitest

    将值设置为全局变量。 如果您正在使用 jsdom 或 happy-dom,也会将该值设置到 window 对象上。

    请参阅 "模拟全局变量" 部分 了解更多信息。

vi.unmock ​

  • 类型: (path: string) => void

    从模拟注册表中移除模块。 所有后续的导入调用都将返回原始模块,即使它之前被模拟过。 此调用会被提升到文件顶部,因此只会取消模拟在 setupFiles 中定义的模块。

vi.doUnmock ​

  • 类型: (path: string) => void

    与 vi.unmock 相同,但不会被提升到文件顶部。 模块的下一次导入会导入原始模块,而不是模拟模块。 这不会影响先前已经导入的模块。

ts
// ./increment.js
export function increment(number) {
  return number + 1;
}
ts
import { increment } from './increment.js';

// increment 已经被模拟,因为 vi.mock 被提升了
increment(1) === 100;

// 这会被提升,并在第 1 行导入之前调用工厂函数
vi.mock('./increment.js', () => ({ increment: () => 100 }));

// 所有调用都被模拟,并且 `increment` 总是返回 100
increment(1) === 100;
increment(30) === 100;

// 这没有被提升,因此后续的导入将返回未模拟的模块
vi.doUnmock('./increment.js');

// 这仍然返回 100,因为 `vi.doUnmock` 不会重新评估模块
increment(1) === 100;
increment(30) === 100;

// 下一个导入为未模拟的,此时 `increment` 是返回 count + 1 的原始函数
const { increment: unmockedIncrement } = await import('./increment.js');

unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;

vi.useFakeTimers ​

  • 类型: () => Vitest

    要启用计时器模拟,您需要调用此方法。 它会拦截所有后续的定时器调用(例如 setTimeout、setInterval、clearTimeout、clearInterval、nextTick、setImmediate、clearImmediate 和 Date),直到调用 vi.useRealTimers()。

    在 node:child_process 中使用 --no-threads 运行 Vitest 时,不支持模拟 nextTick。 因为 NodeJS 在 node:child_process 内部使用 process.nextTick,模拟后会导致程序挂起。 使用 --threads 运行 Vitest 时,则支持模拟 nextTick。

    该实现内部基于 @sinonjs/fake-timers。

    TIP

    从 0.35.0 版本开始,vi.useFakeTimers() 不再自动模拟 process.nextTick。 如果需要模拟,可以在 toFake 参数中指定:vi.useFakeTimers({ toFake: ['nextTick'] })。

vi.isFakeTimers ​

  • 类型: () => boolean

  • 版本: 自 Vitest 0.34.5 起

    如果启用了 fake timers,则返回 true。

vi.useRealTimers ​

  • 类型: () => Vitest

    调用此方法可以将模拟定时器恢复为原始实现。 之前运行的所有定时器不受影响。

vi.waitFor ​

  • 类型: <T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
  • 版本: 自 Vitest 0.34.5 起

等待回调函数成功执行。 如果回调函数抛出错误或返回 rejected 状态的 Promise,vi.waitFor 将持续等待,直到成功或超时。

当需要等待某些异步操作完成时,此方法非常有用。 例如,在启动服务器后,需要等待服务器启动完成。

ts
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';

test('Server started successfully', async () => {
  const server = createServer();

  await vi.waitFor(
    () => {
      if (!server.isReady) throw new Error('Server not started');

      console.log('Server started');
    },
    {
      timeout: 500, // 默认值为 1000
      interval: 20, // 默认值为 50
    }
  );
  expect(server.isReady).toBe(true);
});

同样适用于异步回调。

ts
// @vitest-environment jsdom

import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';

test('Element exists in a DOM', async () => {
  // 开始填充 DOM
  populateDOMAsync();

  const element = await vi.waitFor(
    async () => {
      // 尝试获取元素,直到它存在
      const element = (await getDOMElementAsync()) as HTMLElement | null;
      expect(element).toBeTruthy();
      expect(element.dataset.initialized).toBeTruthy();
      return element;
    },
    {
      timeout: 500, // 默认值为 1000
      interval: 20, // 默认值为 50
    }
  );
  expect(element).toBeInstanceOf(HTMLElement);
});

如果使用 vi.useFakeTimers,则 vi.waitFor 会在每次检查回调时自动调用 vi.advanceTimersByTime(interval)。

vi.waitUntil ​

  • 类型: <T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
  • 版本: 自 Vitest 0.34.5 起

与 vi.waitFor 类似,但如果回调函数抛出任何错误,执行会立即中断并抛出错误。 如果回调函数返回一个 falsy 值,则会继续进行下一次检查,直到返回一个 truthy 值。 当需要等待某个条件成立后才能执行下一步操作时,此方法非常有用。

以下示例展示了如何使用 vi.waitUntil 等待页面元素出现,然后再执行后续操作。

ts
import { expect, test, vi } from 'vitest';

test('Element render correctly', async () => {
  const element = await vi.waitUntil(() => document.querySelector('.element'), {
    timeout: 500, // 默认值为 1000
    interval: 20, // 默认值为 50
  });

  // 对该元素执行某些操作
  expect(element.querySelector('.element-child')).toBeTruthy();
});
Pager
上一页Mock Functions
下一页expect

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors

https://v0.vitest.dev/api/vi

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors