跳到主要内容

编写测试用例

Define tests with a Jest-like API imported from the built-in bun:test module. Long term, Bun aims for complete Jest compatibility; at the moment, a limited set of expect matchers are supported.

Basic usage

To define a simple test:

import { expect, test } from "bun:test";

test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
Jest-style globals

As in Jest, you can use describe, test, expect, and other functions without importing them. Unlike Jest, they are not injected into the global scope. Instead, the Bun transpiler will automatically inject an import from bun:test internally.

typeof globalThis.describe; // "undefined"
typeof describe; // "function"

This transpiler integration only occurs during bun test, and only for test files & preloaded scripts. In practice there's no significant difference to the end user.

Tests can be grouped into suites with describe.

import { expect, test, describe } from "bun:test";

describe("arithmetic", () => {
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});

test("2 * 2", () => {
expect(2 * 2).toBe(4);
});
});

Tests can be async.

import { expect, test } from "bun:test";

test("2 * 2", async () => {
const result = await Promise.resolve(2 * 2);
expect(result).toEqual(4);
});

Alternatively, use the done callback to signal completion. If you include the done callback as a parameter in your test definition, you must call it or the test will hang.

import { expect, test } from "bun:test";

test("2 * 2", done => {
Promise.resolve(2 * 2).then(result => {
expect(result).toEqual(4);
done();
});
});

Timeouts

Optionally specify a per-test timeout in milliseconds by passing a number as the third argument to test.

import { test } from "bun:test";

test("wat", async () => {
const data = await slowOperation();
expect(data).toBe(42);
}, 500); // test must run in <500ms

test.skip

Skip individual tests with test.skip. These tests will not be run.

import { expect, test } from "bun:test";

test.skip("wat", () => {
// TODO: fix this
expect(0.1 + 0.2).toEqual(0.3);
});

test.todo

Mark a test as a todo with test.todo. These tests will be run, and the test runner will expect them to fail. If they pass, you will be prompted to mark it as a regular test.

import { expect, test } from "bun:test";

test.todo("fix this", () => {
myTestFunction();
});

To exclusively run tests marked as todo, use bun test --todo.

$ bun test --todo

test.only

To run a particular test or suite of tests use test.only() or describe.only(). Once declared, running bun test --only will only execute tests/suites that have been marked with .only(). Running bun test without the --only option with test.only() declared will result in all tests in the given suite being executed up to the test with .only(). describe.only() functions the same in both execution scenarios.

import { test, describe } from "bun:test";

test("test #1", () => {
// does not run
});

test.only("test #2", () => {
// runs
});

describe.only("only", () => {
test("test #3", () => {
// runs
});
});

The following command will only execute tests #2 and #3.

$ bun test --only

The following command will only execute tests #1, #2 and #3.

$ bun test

test.if

To run a test conditionally, use test.if(). The test will run if the condition is truthy. This is particularly useful for tests that should only run on specific architectures or operating systems.

test.if(Math.random() > 0.5)("runs half the time", () => {
// ...
});

const macOS = process.arch === "darwin";
test.if(macOS)("runs on macOS", () => {
// runs if macOS
});

test.skipIf

To instead skip a test based on some condition, use test.skipIf() or describe.skipIf().

const macOS = process.arch === "darwin";

test.skipIf(macOS)("runs on non-macOS", () => {
// runs if *not* macOS
});

test.todoIf

If instead you want to mark the test as TODO, use test.todoIf() or describe.todoIf(). Carefully choosing skipIf or todoIf can show a difference between, for example, intent of "invalid for this target" and "planned but not implemented yet."

const macOS = process.arch === "darwin";

// TODO: we've only implemented this for Linux so far.
test.todoIf(macOS)("runs on posix", () => {
// runs if *not* macOS
});

test.each

To return a function for multiple cases in a table of tests, use test.each.

const cases = [
[1, 2, 3],
[3, 4, 5],
];

test.each(cases)("%p + %p should be %p", (a, b, expected) => {
// runs once for each test case provided
});

There are a number of options available for formatting the case label depending on its type.

Matchers

Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress here.