Skip to content
Vitest 2
Main Navigation 指南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

测试 API 索引

模拟函数

Vi

expect

expectTypeOf

assert(断言)

assertType

页面导航

测试 API 索引 ​

以下类型用于下面的类型签名中

ts
type Awaitable<T> = T | PromiseLike<T>;
type TestFunction = () => Awaitable<void>;

interface TestOptions {
  /**
   * 如果测试执行时间超过此时间,测试将会失败
   */
  timeout?: number;
  /**
   * 如果测试失败,将会重试指定的次数
   *
   * @default 0
   */
  retry?: number;
  /**
   * 即使每次都失败,仍会多次重复运行相同的测试
   * 如果您设置了 "retry" 选项,且测试失败,则每次重试都会在每个循环周期中执行。
   * 用于调试偶发性失败
   *
   * @default 0
   */
  repeats?: number;
}

当测试函数返回一个 Promise 时,运行器会等待其 resolve 以收集异步断言结果。如果 Promise 被 reject,测试将失败。

TIP

在 Jest 中,TestFunction 也可以是 (done: DoneCallback) => void 类型。如果使用这种形式,测试将不会结束,直到 done 被调用。您可以使用 async 函数实现相同的效果,请参阅 迁移指南 Done Callback 章节。

大多数选项同时支持点语法和对象语法,你可以选择你喜欢的写法。

ts
import { test } from 'vitest';

test.skip('skipped test', () => {
  // some logic that fails right now
});
ts
import { test } from 'vitest';

test('skipped test', { skip: true }, () => {
  // some logic that fails right now
});

test ​

  • 别名: it

test 定义了一组相关的期望。它接受测试名称和一个包含期望的函数。

可选地,您可以提供一个超时时间(以毫秒为单位),以指定在终止之前等待的最长时间。默认值为 5 秒,并且可以使用 testTimeout 进行全局配置。

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

test('should work as expected', () => {
  expect(Math.sqrt(4)).toBe(2);
});

test.extend ​

  • 别名: it.extend

使用 test.extend 可以使用自定义的 fixtures 扩展测试上下文。这将返回一个新的 test 实例,该实例也是可扩展的。因此,您可以根据需要通过扩展它来组合或覆盖现有的 fixtures。有关更多信息,请参见 扩展测试上下文。

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

const todos = [];
const archive = [];

const myTest = test.extend({
  todos: async ({ task }, use) => {
    todos.push(1, 2, 3);
    await use(todos);
    todos.length = 0;
  },
  archive,
});

myTest('add item', ({ todos }) => {
  expect(todos.length).toBe(3);

  todos.push(4);
  expect(todos.length).toBe(4);
});

test.skip ​

  • 别名: it.skip

如果您想跳过某些测试的运行,但又不想删除代码,则可以使用 test.skip 来避免运行它们。

ts
import { assert, test } from 'vitest';

test.skip('skipped test', () => {
  // 测试被跳过,没有错误
  assert.equal(Math.sqrt(4), 3);
});

您还可以通过在其 context 上动态调用 skip 来跳过测试:

ts
import { assert, test } from 'vitest';

test('skipped test', context => {
  context.skip();
  // 测试被跳过,没有错误
  assert.equal(Math.sqrt(4), 3);
});

test.skipIf ​

  • 别名: it.skipIf

在某些情况下,您可能会使用不同的环境多次运行测试,并且某些测试可能是特定于环境的。您可以不使用 if 语句包裹测试代码,而是使用 test.skipIf,当条件为真时跳过测试。

ts
import { assert, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

test.skipIf(isDev)('prod only test', () => {
  // 此测试仅在生产环境中运行
});

WARNING

当使用 Vitest 作为 类型检查器 时,您不能使用此语法。

test.runIf ​

  • 别名: it.runIf

与 test.skipIf 的功能相反。

ts
import { assert, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

test.runIf(isDev)('dev only test', () => {
  // 此测试仅在开发环境中运行
});

WARNING

当使用 Vitest 作为 类型检查器 时,您不能使用此语法。

test.only ​

  • 别名: it.only

使用 test.only 仅运行给定套件中的某些测试。这在调试时非常有用。

可选地,您可以提供一个超时时间(以毫秒为单位),以指定在终止之前等待的最长时间。默认值为 5 秒,并且可以使用 testTimeout 进行全局配置。

ts
import { assert, test } from 'vitest';

test.only('test', () => {
  // 仅运行此测试(以及其他标记为 only 的测试)
  assert.equal(Math.sqrt(4), 2);
});

有时,只运行某个文件中的 only 测试非常有用,可以忽略整个测试套件中的其他测试,避免输出信息混淆。

为了做到这一点,请使用包含相关测试的特定文件运行 vitest。

# vitest interesting.test.ts

test.concurrent ​

  • 别名: it.concurrent

test.concurrent 用于标记需要并行运行的测试。它接收测试名称、一个包含要收集的测试的异步函数和一个可选的超时时间(以毫秒为单位)。

ts
import { describe, test } from 'vitest';

// 标记为 concurrent 的两个测试将并行运行
describe('suite', () => {
  test('serial test', async () => {
    /* ... */
  });
  test.concurrent('concurrent test 1', async () => {
    /* ... */
  });
  test.concurrent('concurrent test 2', async () => {
    /* ... */
  });
});

test.skip、test.only 和 test.todo 可以与并发测试一起使用。以下所有组合都是有效的:

ts
test.concurrent(/* ... */);
test.skip.concurrent(/* ... */); // or test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */); // or test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */); // or test.concurrent.todo(/* ... */)

当运行并发测试时,快照和断言必须使用来自本地 测试上下文 的 expect,以确保检测到正确的测试。

ts
test.concurrent('test 1', async ({ expect }) => {
  expect(foo).toMatchSnapshot();
});
test.concurrent('test 2', async ({ expect }) => {
  expect(foo).toMatchSnapshot();
});

WARNING

当使用 Vitest 作为 类型检查器 时,您不能使用此语法。

test.sequential ​

  • 别名: it.sequential

test.sequential 将一个测试标记为顺序执行。如果您想在 describe.concurrent 中或使用 --sequence.concurrent 命令行选项时按顺序运行测试,这将非常有用。

ts
import { describe, test } from 'vitest';

// 使用配置选项 { sequence: { concurrent: true } }
test('concurrent test 1', async () => {
  /* ... */
});
test('concurrent test 2', async () => {
  /* ... */
});

test.sequential('sequential test 1', async () => {
  /* ... */
});
test.sequential('sequential test 2', async () => {
  /* ... */
});

// 在并发套件中
describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  test('concurrent test 2', async () => {
    /* ... */
  });

  test.sequential('sequential test 1', async () => {
    /* ... */
  });
  test.sequential('sequential test 2', async () => {
    /* ... */
  });
});

test.todo ​

  • 别名: it.todo

使用 test.todo 来标记待实现的测试。测试报告中会显示这些条目,方便您了解还有多少测试需要实现。

ts
// 报告中将显示此测试的条目
test.todo('unimplemented test');

test.fails ​

  • 别名: it.fails

使用 test.fails 来指示断言将显式失败。

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

function myAsyncFunc() {
  return new Promise(resolve => resolve(1));
}
test.fails('fail test', async () => {
  await expect(myAsyncFunc()).rejects.toBe(1);
});

WARNING

当使用 Vitest 作为 类型检查器 时,您不能使用此语法。

test.each ​

  • 别名: it.each

TIP

test.each 是为了兼容 Jest 而提供的,但 Vitest 也提供了 test.for,它额外增加了集成 TestContext 的功能。

当您需要使用不同的变量多次运行相同的测试时,请使用 test.each。 您可以使用 printf 格式 ,按照测试函数参数的顺序,在测试名称中注入参数。

  • %s: 字符串
  • %d: 数字
  • %i: 整数
  • %f: 浮点值
  • %j: JSON
  • %o: 对象
  • %#: 测试用例的索引
  • %%: 单个百分号 ('%')
ts
import { expect, test } from 'vitest';

test.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
  expect(a + b).toBe(expected);
});

// 运行结果如下
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3

当使用对象作为参数时,您还可以使用 $ 前缀访问对象属性:

ts
test.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 1, expected: 3 },
])('add($a, $b) -> $expected', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

// 运行结果如下
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3

当使用对象作为参数时,您还可以使用 . 访问对象属性:

ts
test.each`
  a             | b      | expected
  ${{ val: 1 }} | ${'b'} | ${'1b'}
  ${{ val: 2 }} | ${'b'} | ${'2b'}
  ${{ val: 3 }} | ${'b'} | ${'3b'}
`('add($a.val, $b) -> $expected', ({ a, b, expected }) => {
  expect(a.val + b).toBe(expected);
});

// 运行结果如下
// ✓ add(1, b) -> 1b
// ✓ add(2, b) -> 2b
// ✓ add(3, b) -> 3b

从 Vitest 0.25.3 开始,您还可以使用模板字符串表。

  • 第一行应该是列名,用 | 分隔;
  • 后续的一行或多行数据作为使用 ${value} 语法的模板字面量表达式提供。
ts
import { expect, test } from 'vitest';

test.each`
  a             | b      | expected
  ${1}          | ${1}   | ${2}
  ${'a'}        | ${'b'} | ${'ab'}
  ${[]}         | ${'b'} | ${'b'}
  ${{}}         | ${'b'} | ${'[object Object]b'}
  ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('returns $expected when $a is added $b', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

TIP

Vitest 使用 chai format 方法处理 $values。如果值被截断得太多,您可以在配置文件中增加 chaiConfig.truncateThreshold。

WARNING

当使用 Vitest 作为 类型检查器 时,您不能使用此语法。

test.for ​

  • 别名: it.for

test.each 的另一种替代方案,用于提供 TestContext。

与 test.each 的区别在于数组情况在参数中的提供方式。 其他非数组情况(包括模板字符串用法)工作方式完全相同。

ts
// `each` 会展开数组情况
test.each([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => { 
  expect(a + b).toBe(expected);
});

// `for` 不展开数组情况
test.for([
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => { 
  expect(a + b).toBe(expected);
});

第二个参数是 TestContext,可用于并发快照,例如:

ts
test.concurrent.for([
  [1, 1],
  [1, 2],
  [2, 1],
])('add(%i, %i)', ([a, b], { expect }) => {
  expect(a + b).matchSnapshot();
});

bench ​

  • 类型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

bench 定义一个基准测试。在 Vitest 中,基准测试是指定义了一系列操作的函数。Vitest 会多次运行此函数,以展示不同的性能指标。

Vitest 在底层使用 tinybench 库,继承了所有可用作第三个参数的选项。

ts
import { bench } from 'vitest';

bench(
  'normal sorting',
  () => {
    const x = [1, 5, 4, 2, 3];
    x.sort((a, b) => {
      return a - b;
    });
  },
  { time: 1000 }
);
ts
export interface Options {
  /**
   * 执行基准测试任务的时间限制(毫秒)
   * @default 500
   */
  time?: number;

  /**
   * 即使时间选项已完成,任务也应运行的次数
   * @default 10
   */
  iterations?: number;

  /**
   * 获取当前时间戳(以毫秒为单位)的函数
   */
  now?: () => number;

  /**
   * 用于中止基准测试的 AbortSignal
   */
  signal?: AbortSignal;

  /**
   * 如果任务失败则抛出错误(如果为 true,则事件将不起作用)
   */
  throws?: boolean;

  /**
   * 预热时间(毫秒)
   * @default 100ms
   */
  warmupTime?: number;

  /**
   * 预热迭代次数
   * @default 5
   */
  warmupIterations?: number;

  /**
   * 在每个基准测试任务(周期)之前运行的 setup 函数
   */
  setup?: Hook;

  /**
   * 在每个基准测试任务(周期)之后运行的 teardown 函数
   */
  teardown?: Hook;
}

运行基准测试后,输出结构信息如下:

  name                      hz     min     max    mean     p75     p99    p995    p999     rme  samples
· normal sorting  6,526,368.12  0.0001  0.3638  0.0002  0.0002  0.0002  0.0002  0.0004  ±1.41%   652638
ts
export interface TaskResult {
  /*
   * 任务运行期间抛出的最后一个错误
   */
  error?: unknown;

  /**
   * 运行基准测试任务(周期)所需的总时间(毫秒)。
   */
  totalTime: number;

  /**
   * 样本中的最小值
   */
  min: number;
  /**
   * 样本中的最大值
   */
  max: number;

  /**
   * 每秒操作数
   */
  hz: number;

  /**
   * 每次操作所需的时间(毫秒)
   */
  period: number;

  /**
   * 每个任务迭代时间的任务样本(毫秒)
   */
  samples: number[];

  /**
   * 样本均值/平均值(总体均值的估计值)
   */
  mean: number;

  /**
   * 样本方差(总体方差的估计值)
   */
  variance: number;

  /**
   * 样本标准差(总体标准差的估计值)
   */
  sd: number;

  /**
   * 平均值标准误差(即样本均值抽样分布的标准差)
   */
  sem: number;

  /**
   * 自由度
   */
  df: number;

  /**
   * 样本的临界值
   */
  critical: number;

  /**
   * 误差范围
   */
  moe: number;

  /**
   * 相对误差范围
   */
  rme: number;

  /**
   * 中位数绝对差
   */
  mad: number;

  /**
   * p50/中位数百分位数
   */
  p50: number;

  /**
   * p75 百分位数
   */
  p75: number;

  /**
   * p99 百分位数
   */
  p99: number;

  /**
   * p995 百分位数
   */
  p995: number;

  /**
   * p999 百分位数
   */
  p999: number;
}

bench.skip ​

  • 类型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

您可以使用 bench.skip 来跳过某些基准测试的运行。

ts
import { bench } from 'vitest';

bench.skip('normal sorting', () => {
  const x = [1, 5, 4, 2, 3];
  x.sort((a, b) => {
    return a - b;
  });
});

bench.only ​

  • 类型: (name: string | Function, fn: BenchFunction, options?: BenchOptions) => void

使用 bench.only 可以仅运行指定测试套件中的某些基准测试,这在调试时非常有用。

ts
import { bench } from 'vitest';

bench.only('normal sorting', () => {
  const x = [1, 5, 4, 2, 3];
  x.sort((a, b) => {
    return a - b;
  });
});

bench.todo ​

  • 类型: (name: string | Function) => void

使用 bench.todo 来存根以后要实现的基准测试。

ts
import { bench } from 'vitest';

bench.todo('unimplemented test');

describe ​

当你在文件的顶层使用 test 或 bench 时,它们会被收集为该文件的默认测试套件。使用 describe 你可以在当前上下文中定义一个新的测试套件,用于组织一组相关的测试、基准测试或其他嵌套套件。一个测试套件可以让你更好地组织测试和基准测试,使报告更加清晰。

ts
// basic.spec.ts
// 组织测试

import { describe, expect, test } from 'vitest';

const person = {
  isActive: true,
  age: 32,
};

describe('person', () => {
  test('person is defined', () => {
    expect(person).toBeDefined();
  });

  test('is active', () => {
    expect(person.isActive).toBeTruthy();
  });

  test('age limit', () => {
    expect(person.age).toBeLessThanOrEqual(32);
  });
});
ts
// basic.bench.ts
// 组织基准测试

import { bench, describe } from 'vitest';

describe('sort', () => {
  bench('normal', () => {
    const x = [1, 5, 4, 2, 3];
    x.sort((a, b) => {
      return a - b;
    });
  });

  bench('reverse', () => {
    const x = [1, 5, 4, 2, 3];
    x.reverse().sort((a, b) => {
      return a - b;
    });
  });
});

如果你有测试或基准测试的层次结构,你也可以嵌套 describe 代码块:

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

function numberToCurrency(value: number | string) {
  if (typeof value !== 'number') {
    throw new TypeError('Value must be a number');
  }

  return value
    .toFixed(2)
    .toString()
    .replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

describe('numberToCurrency', () => {
  describe('given an invalid number', () => {
    test('composed of non-numbers to throw error', () => {
      expect(() => numberToCurrency('abc')).toThrowError();
    });
  });

  describe('given a valid number', () => {
    test('returns the correct currency format', () => {
      expect(numberToCurrency(10000)).toBe('10,000.00');
    });
  });
});

describe.skip ​

  • Alias: suite.skip

在测试套件中使用 describe.skip 可以跳过特定的 describe 代码块。

ts
import { assert, describe, test } from 'vitest';

describe.skip('skipped suite', () => {
  test('sqrt', () => {
    // 套件已跳过,不会报错
    assert.equal(Math.sqrt(4), 3);
  });
});

describe.skipIf ​

  • Alias: suite.skipIf

在某些情况下,你可能会在不同的环境多次运行测试套件,并且某些套件可能是特定于某个环境的。你可以使用 describe.skipIf 跳过测试套件,而无需使用 if 语句包裹,只要条件为真值(truthy)就会跳过。

ts
import { describe, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

describe.skipIf(isDev)('prod only test', () => {
  // 这个测试只在生产环境中运行
});

WARNING

当使用 Vitest 作为类型检查器时,你不能使用此语法。

describe.runIf ​

  • 别名: suite.runIf

与 describe.skipIf 相反。

ts
import { assert, describe, test } from 'vitest';

const isDev = process.env.NODE_ENV === 'development';

describe.runIf(isDev)('dev only test suite', () => {
  // this test suite only runs in development
});

WARNING

当使用 Vitest 作为类型检查器时,你不能使用此语法。

describe.only ​

  • 类型: (name: string | Function, fn: TestFunction, options?: number | TestOptions) => void

使用 describe.only 仅运行特定的测试套件。

ts
import { assert, describe, test } from 'vitest';

// 仅运行此套件(以及其他标记为 only 的套件)
describe.only('suite', () => {
  test('sqrt', () => {
    assert.equal(Math.sqrt(4), 3);
  });
});

describe('other suite', () => {
  // ... 将被跳过
});

有时,在特定文件中运行 only 测试非常方便,可以忽略整个测试套件中的其他测试,避免输出信息冗余。

为了做到这一点,请使用包含相关测试的特定文件运行 vitest。

# vitest interesting.test.ts

describe.concurrent ​

  • Alias: suite.concurrent

describe.concurrent 并行运行所有内部套件和测试

ts
import { describe, test } from 'vitest';

// 此套件内的所有套件和测试将并行运行
describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  describe('concurrent suite 2', async () => {
    test('concurrent test inner 1', async () => {
      /* ... */
    });
    test('concurrent test inner 2', async () => {
      /* ... */
    });
  });
  test.concurrent('concurrent test 3', async () => {
    /* ... */
  });
});

.skip、.only 和 .todo 可以与并发套件一起使用。以下所有组合都是有效的:

ts
describe.concurrent(/* ... */);
describe.skip.concurrent(/* ... */); // or describe.concurrent.skip(/* ... */)
describe.only.concurrent(/* ... */); // or describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */); // or describe.concurrent.todo(/* ... */)

当运行并发测试时,快照和断言必须使用来自本地测试上下文的 expect,以确保检测到正确的测试。

ts
describe.concurrent('suite', () => {
  test('concurrent test 1', async ({ expect }) => {
    expect(foo).toMatchSnapshot();
  });
  test('concurrent test 2', async ({ expect }) => {
    expect(foo).toMatchSnapshot();
  });
});

WARNING

当使用 Vitest 作为类型检查器时,你不能使用此语法。

describe.sequential ​

  • Alias: suite.sequential

describe.sequential 会将测试套件中的每个测试标记为顺序执行。如果你希望在 describe.concurrent 内部,或者使用 --sequence.concurrent 命令行选项来顺序运行测试,这将非常有用。

ts
import { describe, test } from 'vitest';

describe.concurrent('suite', () => {
  test('concurrent test 1', async () => {
    /* ... */
  });
  test('concurrent test 2', async () => {
    /* ... */
  });

  describe.sequential('', () => {
    test('sequential test 1', async () => {
      /* ... */
    });
    test('sequential test 2', async () => {
      /* ... */
    });
  });
});

describe.shuffle ​

  • Alias: suite.shuffle

Vitest 提供了通过 CLI 标志 --sequence.shuffle 或配置选项 sequence.shuffle 以随机顺序运行所有测试的方式。但如果你只想让测试套件中的一部分以随机顺序运行,可以使用此标志标记。

ts
import { describe, test } from 'vitest';

describe.shuffle('suite', () => {
  test('random test 1', async () => {
    /* ... */
  });
  test('random test 2', async () => {
    /* ... */
  });
  test('random test 3', async () => {
    /* ... */
  });
});
// 顺序取决于配置中的 sequence.seed 选项(默认为 Date.now())

.skip、.only 和 .todo 可以与随机套件一起使用。

WARNING

当使用 Vitest 作为类型检查器时,你不能使用此语法。

describe.todo ​

  • Alias: suite.todo

使用 describe.todo 可以为稍后实现的测试套件创建占位符。 报告中会显示这些套件的条目,方便你了解还需要实现多少测试。

ts
// 报告中将显示此套件的条目
describe.todo('unimplemented suite');

describe.each ​

  • Alias: suite.each

如果你有多个依赖于相同数据的测试,请使用 describe.each。

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

describe.each([
  { a: 1, b: 1, expected: 2 },
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 1, expected: 3 },
])('describe object add($a, $b)', ({ a, b, expected }) => {
  test(`returns ${expected}`, () => {
    expect(a + b).toBe(expected);
  });

  test(`returned value not be greater than ${expected}`, () => {
    expect(a + b).not.toBeGreaterThan(expected);
  });

  test(`returned value not be less than ${expected}`, () => {
    expect(a + b).not.toBeLessThan(expected);
  });
});

从 Vitest 0.25.3 开始,你还可以使用模板字符串表格。

  • 第一行应该是列名,用 | 分隔;
  • 一行或多行后续数据作为模板字面量表达式提供,使用 ${value} 语法。
ts
import { describe, expect, test } from 'vitest';

describe.each`
  a             | b      | expected
  ${1}          | ${1}   | ${2}
  ${'a'}        | ${'b'} | ${'ab'}
  ${[]}         | ${'b'} | ${'b'}
  ${{}}         | ${'b'} | ${'[object Object]b'}
  ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('describe template string add($a, $b)', ({ a, b, expected }) => {
  test(`returns ${expected}`, () => {
    expect(a + b).toBe(expected);
  });
});

WARNING

当使用 Vitest 作为类型检查器时,你不能使用此语法。

设置与清理 ​

这些函数允许你介入测试的生命周期,从而避免重复编写设置和清理代码。它们的作用域取决于它们的使用位置:如果在顶层使用,则作用于整个文件;如果在 describe 代码块中使用,则作用于当前测试套件。当你将 Vitest 作为类型检查器运行时,不会调用这些钩子。

beforeEach ​

  • 类型: beforeEach(fn: () => Awaitable<void>, timeout?: number)

注册一个回调函数,该函数会在当前作用域内的每个测试运行之前被调用。 如果该函数返回一个 Promise,Vitest 会等待该 Promise 解析完成后再运行测试。

你可以选择传递一个超时时间(以毫秒为单位),定义在终止之前等待的时间。默认值为 5 秒。

ts
import { beforeEach } from 'vitest';

beforeEach(async () => {
  // 在每次测试运行之前清除模拟数据并添加一些测试数据
  await stopMocking();
  await addUser({ name: 'John' });
});

在这里,beforeEach 确保每个测试都有用户添加。

beforeEach 也支持一个可选的清理函数(功能与 afterEach 类似)。

ts
import { beforeEach } from 'vitest';

beforeEach(async () => {
  // 在每次测试运行之前调用
  await prepareSomething();

  // 清理函数,在每次测试运行之后调用一次
  return async () => {
    await resetSomething();
  };
});

afterEach ​

  • 类型: afterEach(fn: () => Awaitable<void>, timeout?: number)

注册一个回调函数,该函数会在当前作用域内的每个测试完成后被调用。 如果该函数返回一个 Promise,Vitest 会等待该 Promise 解析完成后再继续。

你可以选择提供一个超时时间(以毫秒为单位),用于指定在终止之前等待的时间。默认值为 5 秒。

ts
import { afterEach } from 'vitest';

afterEach(async () => {
  await clearTestingData(); // 在每次测试运行后清除测试数据
});

在这里,afterEach 确保在每次测试运行后清除测试数据。

TIP

Vitest 1.3.0 添加了 onTestFinished hook。你可以在测试执行期间调用它,以便在测试运行结束后清理任何状态。

beforeAll ​

  • 类型: beforeAll(fn: () => Awaitable<void>, timeout?: number)

注册一个回调函数,该函数会在开始运行当前作用域内的所有测试之前被调用一次。 如果该函数返回一个 Promise,Vitest 会等待该 Promise 解析完成后再运行测试。

你可以选择提供一个超时时间(以毫秒为单位),用于指定在终止之前等待的时间。默认值为 5 秒。

ts
import { beforeAll } from 'vitest';

beforeAll(async () => {
  await startMocking(); // 在所有测试运行之前调用一次
});

在这里,beforeAll 确保在测试运行之前设置模拟数据。

beforeAll 也支持一个可选的清理函数(功能与 afterAll 类似)。

ts
import { beforeAll } from 'vitest';

beforeAll(async () => {
  // 在所有测试运行之前调用一次
  await startMocking();

  // 清理函数,在所有测试运行之后调用一次
  return async () => {
    await stopMocking();
  };
});

afterAll ​

  • 类型: afterAll(fn: () => Awaitable<void>, timeout?: number)

注册一个回调函数,该函数会在当前作用域内的所有测试运行完毕后被调用一次。 如果该函数返回一个 Promise,Vitest 会等待该 Promise 解析完成后再继续。

你可以选择提供一个超时时间(以毫秒为单位),用于指定在终止之前等待的时间。默认值为 5 秒。

ts
import { afterAll } from 'vitest';

afterAll(async () => {
  await stopMocking(); // 此方法在所有测试运行后被调用
});

在这里,afterAll 确保在所有测试运行后调用 stopMocking 方法。

测试钩子 ​

Vitest 提供了一些钩子,你可以在测试执行期间调用它们,以便在测试运行完毕后清理状态。

WARNING

如果在测试主体之外调用这些钩子,将会抛出错误。

onTestFinished ​

此钩子总是在测试运行完毕后调用。 它在 afterEach 钩子之后调用,因为它们可能会影响测试结果。 它接收一个 TaskResult 对象,其中包含当前的测试结果。

ts
import { onTestFinished, test } from 'vitest';

test('执行查询', () => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

WARNING

如果正在并发运行测试,则应始终使用测试上下文中的 onTestFinished 钩子,因为 Vitest 不会在全局钩子中跟踪并发测试:

ts
import { test } from 'vitest';

test.concurrent('执行查询', ({ onTestFinished }) => {
  const db = connectDb();
  onTestFinished(() => db.close());
  db.query('SELECT * FROM users');
});

此钩子在创建可重用逻辑时特别有用:

ts
// 这可以放在单独的文件中
function getTestDb() {
  const db = connectMockedDb();
  onTestFinished(() => db.close());
  return db;
}

test('执行用户查询', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from users').perform()).toEqual([]);
});

test('执行组织查询', async () => {
  const db = getTestDb();
  expect(await db.query('SELECT * from organizations').perform()).toEqual([]);
});

TIP

此钩子始终以相反的顺序调用,并且不受 sequence.hooks 选项的影响。

onTestFailed ​

此钩子仅在测试失败后调用。 它在 afterEach 钩子之后调用,因为它们可能会影响测试结果。 它接收一个 TaskResult 对象,其中包含当前的测试结果。 此钩子对于调试很有用。

ts
import { onTestFailed, test } from 'vitest';

test('执行查询', () => {
  const db = connectDb();
  onTestFailed(e => {
    console.log(e.result.errors);
  });
  db.query('SELECT * FROM users');
});

WARNING

如果正在并发运行测试,则应始终使用测试上下文中的 onTestFailed 钩子,因为 Vitest 不会在全局钩子中跟踪并发测试:

ts
import { test } from 'vitest';

test.concurrent('执行查询', ({ onTestFailed }) => {
  const db = connectDb();
  onTestFailed(result => {
    console.log(result.errors);
  });
  db.query('SELECT * FROM users');
});
Pager
下一页模拟函数

基于 MIT 许可证 发布。

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

https://v2.vitest.dev/api/

基于 MIT 许可证 发布。

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