Add guides for test runner (#4308)

This commit is contained in:
Colin McDonnell
2023-08-24 22:28:07 -07:00
committed by GitHub
parent 2bcbafe7d3
commit 73b3fb7b0f
17 changed files with 787 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
---
name: Set a time zone in Bun
---
Bun supports programmatically setting a default time zone for the lifetime of the `bun` process. To do set, set the value of the `TZ` environment variable to a [valid timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
{% callout %}
When running a file with `bun`, the timezone defaults to your system's configured local time zone.
When running tests with `bun test`, the timezone is set to `UTC` to make tests more deterministic.
{% /callout %}
```ts
process.env.TZ = "America/New_York";
```
---
Alternatively, this can be set from the command line when running a Bun command.
```sh
$ TZ=America/New_York bun run dev
```
---
Once `TZ` is set, any `Date` instances will have that time zone. By default all dates use your system's configured time zone.
```ts
new Date().getHours(); // => 18
process.env.TZ = "America/New_York";
new Date().getHours(); // => 21
```

23
docs/guides/test/bail.md Normal file
View File

@@ -0,0 +1,23 @@
---
name: Bail early with the Bun test runner
---
Use the `--bail` flag to bail on a test run after a single failure. This is useful for aborting as soon as possible in a continuous integration environment.
```sh
# re-run each test 10 times
$ bun test --bail
```
---
To bail after a certain threshold of failures, optionally specify a number after the flag.
```sh
# bail after 10 failures
$ bun test --bail 10
```
---
See [Docs > Test runner](/docs/cli/test) for complete documentation of `bun test`.

View File

@@ -0,0 +1,58 @@
---
name: Set a code coverage threshold with the Bun test runner
---
Bun's test runner supports built-in code coverage reporting via the `--coverage` flag.
```sh
$ bun test --coverage
test.test.ts:
✓ math > add [0.71ms]
✓ math > multiply [0.03ms]
✓ random [0.13ms]
-------------|---------|---------|-------------------
File | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files | 66.67 | 77.78 |
math.ts | 50.00 | 66.67 |
random.ts | 50.00 | 66.67 |
-------------|---------|---------|-------------------
3 pass
0 fail
3 expect() calls
```
---
To set a minimum coverage threshold, add the following line to your `bunfig.toml`. This requires that 90% of your codebase is covered by tests.
```toml
[test]
# to require 90% line-level and function-level coverage
coverageThreshold = 0.9
```
---
If your test suite does not meet this threshold, `bun test` will exit with a non-zero exit code to signal a failure.
```sh
$ bun test --coverage
<test output>
$ echo $?
1 # this is the exit code of the previous command
```
Different thresholds can be set for line-level and function-level coverage.
```toml
[test]
# to set different thresholds for lines and functions
coverageThreshold = { line = 0.5, function = 0.7 }
```
---
See [Docs > Test runner > Coverage](/docs/test/coverage) for complete documentation on code coverage reporting in Bun.

View File

@@ -0,0 +1,44 @@
---
name: Generate code coverage reports with the Bun test runner
---
Bun's test runner supports built-in _code coverage reporting_. This makes it easy to see how much of the codebase is covered by tests, and find areas that are not currently well-tested.
---
Pass the `--coverage` flag to `bun test` to enable this feature. This will print a coverage report after the test run.
The coverage report lists the source files that were executed during the test run, the percentage of functions and lines that were executed, and the line ranges that were not executed during the run.
```sh
$ bun test --coverage
test.test.ts:
✓ math > add [0.71ms]
✓ math > multiply [0.03ms]
✓ random [0.13ms]
-------------|---------|---------|-------------------
File | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files | 66.67 | 77.78 |
math.ts | 50.00 | 66.67 |
random.ts | 50.00 | 66.67 |
-------------|---------|---------|-------------------
3 pass
0 fail
3 expect() calls
```
---
To always enable coverage reporting by default, add the following line to your `bunfig.toml`:
```toml
[test]
coverage = true # always enable coverage
```
---
Refer to [Docs > Test runner > Coverage](/docs/test/coverage) for complete documentation on code coverage reporting in Bun.

View File

@@ -0,0 +1,68 @@
---
name: Write browser DOM tests with Bun and happy-dom
---
You can write and run browser tests with Bun's test runner in conjunction with [Happy DOM](https://github.com/capricorn86/happy-dom). Happy DOM implements mocked versions of browser APIs like `document` and `location`.
---
To get started, install `happy-dom`.
```sh
$ bun add -d @happy-dom/global-registrator
```
---
This module exports a "registrator" that will adds the mocked browser APIs to the global scope.
```ts#happydom.ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";
GlobalRegistrator.register();
```
---
We need to make sure this file is executed before any of our test files. That's a job for Bun's built-in _preload_ functionality. Create a `bunfig.toml` file in the root of your project (if it doesn't already exist) and add the following lines.
The `./happydom.ts` file should contain the registration code above.
```toml#bunfig.toml
[test]
preload = "./happydom.ts"
```
---
Now running `bun test` inside our project will automatically execute `happydom.ts` first. We can start writing tests that use browser APIs.
```ts
import { test, expect } from "bun:test";
test("set button text", () => {
document.body.innerHTML = `<button>My button</button>`;
const button = document.querySelector("button");
expect(button?.innerText).toEqual("My button");
});
```
---
With Happy DOM propertly configured, this test runs as expected.
```sh
$ bun test
dom.test.ts:
✓ set button text [0.82ms]
1 pass
0 fail
1 expect() calls
Ran 1 tests across 1 files. 1 total [125.00ms]
```
---
Refer to the [Happy DOM repo](https://github.com/capricorn86/happy-dom) and [Docs > Test runner > DOM](/docs/test/dom) for complete documentation on writing browser tests with Bun.

View File

@@ -0,0 +1,4 @@
{
"name": "Test runner",
"description": "A collection of guides for writing, running, and configuring tests in Bun"
}

View File

@@ -0,0 +1,48 @@
---
name: Set the system time in Bun's test runner
---
Bun's test runner supports setting the system time programmatically with the `setSystemTime` function.
```ts
import { test, expect, beforeAll, setSystemTime } from "bun:test";
test("party like it's 1999", () => {
const date = new Date("1999-01-01T00:00:00.000Z");
setSystemTime(date); // it's now January 1, 1999
const now = new Date();
expect(now.getFullYear()).toBe(1999);
expect(now.getMonth()).toBe(0);
expect(now.getDate()).toBe(1);
});
```
---
The `setSystemTime` function is commonly used on conjunction with [Lifecycle Hooks](/docs/test/lifecycle) to configure a testing environment with a determinstic "fake clock".
```ts
import { test, expect, beforeAll, setSystemTime } from "bun:test";
beforeAll(() => {
const date = new Date("1999-01-01T00:00:00.000Z");
setSystemTime(date); // it's now January 1, 1999
});
// tests...
```
---
To reset the system clock to the actual time, call `setSystemTime` with no arguments.
```ts
import { test, expect, beforeAll, setSystemTime } from "bun:test";
setSystemTime(); // reset to actual time
```
---
See [Docs > Test Runner > Date and time](/docs/test/time) for complete documentation on mocking with the Bun test runner.

View File

@@ -0,0 +1,68 @@
---
name: Mock functions in `bun test`
---
Create mocks with the `mock` function from `bun:test`.
```ts
import { test, expect, mock } from "bun:test";
const random = mock(() => Math.random());
```
---
The mock function can accept arguments.
```ts
import { test, expect, mock } from "bun:test";
const random = mock((multiplier: number) => multiplier * Math.random());
```
---
The result of `mock()` is a new function that's been decorated with some additional properties.
```ts
import { mock } from "bun:test";
const random = mock((multiplier: number) => multiplier * Math.random());
random(2);
random(10);
random.mock.calls;
// [[ 2 ], [ 10 ]]
random.mock.results;
// [
// { type: "return", value: 0.6533907460954099 },
// { type: "return", value: 0.6452713933037312 }
// ]
```
---
These extra properties make it possible to write `expect` assertions about usage of the mock function, including how many times it was called, the arguments, and the return values.
```ts
import { test, mock } from "bun:test";
const random = mock((multiplier: number) => multiplier * Math.random());
test("random", async () => {
const a = random(1);
const b = random(2);
const c = random(3);
expect(random).toHaveBeenCalled();
expect(random).toHaveBeenCalledTimes(3);
expect(random.mock.args).toEqual([[1], [2], [3]]);
expect(random.mock.results[0]).toEqual({ type: "return", value: a });
});
```
---
See [Docs > Test Runner > Mocks](/docs/test/mocks) for complete documentation on mocking with the Bun test runner.

View File

@@ -0,0 +1,14 @@
---
name: Re-run tests multiple times with the Bun test runner
---
Use the `--rerun-each` flag to re-run every test multiple times with the Bun test runner. This is useful for finding flaky or non-deterministic tests.
```sh
# re-run each test 10 times
$ bun test --rerun-each 10
```
---
See [Docs > Test runner](/docs/cli/test) for complete documentation of `bun test`.

View File

@@ -0,0 +1,99 @@
---
name: Run your tests with the Bun test runner
---
Bun has a built-in test runner with a Jest-like `expect` API. To use it, run `bun test` from your project directory. The test runner will search for all files in the directory that match the following patterns:
- `*.test.{js|jsx|ts|tsx}`
- `*_test.{js|jsx|ts|tsx}`
- `*.spec.{js|jsx|ts|tsx}`
- `*_spec.{js|jsx|ts|tsx}`
```sh
$ bun test
bun test v0.8.0 (9c68abdb)
test.test.js:
✓ add [0.87ms]
✓ multiply [0.02ms]
test2.test.js:
✓ add [0.72ms]
✓ multiply [0.01ms]
test3.test.js:
✓ add [0.54ms]
✓ multiply [0.01ms]
6 pass
0 fail
6 expect() calls
Ran 6 tests across 3 files. [9.00ms]
```
---
To only run certain test files, pass a positional argument to `bun test`. The runner will only execute files that contain that argument in their path.
```sh
$ bun test test3
bun test v0.8.0 (9c68abdb)
test3.test.js:
✓ add [1.40ms]
✓ multiply [0.03ms]
2 pass
0 fail
2 expect() calls
Ran 2 tests across 1 files. [15.00ms]
```
---
All tests have a name, defined as the first parameter to the `test` function. Tests can also be inside a `describe` block.
```ts
import { test, expect } from "bun:test";
test("add", () => {
expect(2 + 2).toEqual(4);
});
test("multiply", () => {
expect(2 * 2).toEqual(4);
});
```
---
To filter which tests are executed by name, use the `-t`/`--test-name-pattern` flag.
Adding `-t add` will only run tests with "add" in the name. This flag also checks the name of the test suite (the first parameter to `describe`).
```sh
$ bun test -t add
bun test v0.8.0 (9c68abdb)
test.test.js:
✓ add [1.79ms]
» multiply
test2.test.js:
✓ add [2.30ms]
» multiply
test3.test.js:
✓ add [0.32ms]
» multiply
3 pass
3 skip
0 fail
3 expect() calls
Ran 6 tests across 3 files. [59.00ms]
```
---
See [Docs > Test Runner](/docs/cli/test) for complete documentation on the test runner.

View File

@@ -0,0 +1,37 @@
---
name: Skip tests with the Bun test runner
---
To skip a test with the Bun test runner, use the `test.skip` function.
```ts-diff
test.skip("unimplemented feature", ()=>{
expect(Bun.isAwesome()).toBe(true);
});
```
---
Running `bun test` will not execute this test. It will be marked as skipped in the terminal output.
```sh
$ bun test
test.test.ts:
✓ add [0.03ms]
✓ multiply [0.02ms]
» unimplemented feature
2 pass
1 skip
0 fail
2 expect() calls
Ran 3 tests across 1 files. [74.00ms]
```
---
See also:
- [Mark a test as a todo](/guides/test/todo-tests)
- [Docs > Test runner > Writing tests](/docs/test/writings-tests)

View File

@@ -0,0 +1,99 @@
---
name: Use snapshot testing in `bun test`
---
Bun's test runner supports Jest-style snapshot testing via `.toMatchSnapshot()`.
{% callout %}
The `.toMatchInlineSnapshot()` method is not yet supported.
{% /callout %}
```ts#snap.test.ts
import { test, expect } from "bun:test";
test("snapshot", () => {
expect({ foo: "bar" }).toMatchSnapshot();
});
```
---
The first time this test is executed, Bun will evaluate the value passed into `expect()` (`{ foo: "bar" }`) and write it to disk in a directory called `__snapshots__` that lives alongside the test file.
```sh
$ bun test test/snap
bun test v0.8.0 (9c68abdb)
test/snap.test.ts:
✓ snapshot [1.48ms]
1 pass
0 fail
snapshots: +1 added # note: the snapshot is created automatically the first run
1 expect() calls
Ran 1 tests across 1 files. [82.00ms]
```
---
The `__snapshots__` directory contains a `.snap` file for each test file in the directory.
```txt
test
├── __snapshots__
│   └── snap.test.ts.snap
└── snap.test.ts
```
---
The `snap.test.ts.snap` file is a JavaScript file that exports a serialized version of the value passed into `expect()`. The `{foo: "bar"}` object has been serialized to JSON.
```js
// Bun Snapshot v1, https://goo.gl/fbAQLP
exports[`snapshot 1`] = `
{
"foo": "bar",
}
`;
```
---
Later, when this test file is executed again, Bun will read the snapshot file and compare it to the value passed into `expect()`. If the values are different, the test will fail.
```sh
$ bun test
bun test v0.8.0 (9c68abdb)
test/snap.test.ts:
✓ snapshot [1.05ms]
1 pass
0 fail
1 snapshots, 1 expect() calls
Ran 1 tests across 1 files. [101.00ms]
```
---
To update snapshots, use the `--update-snapshots` flag.
```sh
$ bun test --update-snapshots
bun test v0.8.0 (9c68abdb)
test/snap.test.ts:
✓ snapshot [0.86ms]
1 pass
0 fail
snapshots: +1 added # the snapshot was regenerated
1 expect() calls
Ran 1 tests across 1 files. [102.00ms]
```
---
See [Docs > Test Runner > Snapshots](/docs/test/mocks) for complete documentation on mocking with the Bun test runner.

View File

@@ -0,0 +1,46 @@
---
name: Spy on methods in `bun test`
---
Use the `spyOn` utility to track method calls with Bun's test runner.
```ts
import { test, expect, spyOn } from "bun:test";
const leo = {
name: "Leonard",
sayHi(thing: string) {
console.log(`Sup I'm ${this.name} and I like ${thing}`);
},
};
const spy = spyOn(leo, "sayHi");
```
---
Once the spy is created, it can be used to write `expect` assertions relating to method calls.
```ts-diff
import { test, expect, spyOn } from "bun:test";
const leo = {
name: "Leonardo",
sayHi(thing: string) {
console.log(`Sup, I'm ${this.name} and I like ${thing}`);
},
};
const spy = spyOn(leo, "sayHi");
+ test("turtles", ()=>{
+ expect(spy).toHaveBeenCalledTimes(0);
+ leo.sayHi("pizza");
+ expect(spy).toHaveBeenCalledTimes(0);
+ expect(spy.mock.calls).toEqual([[ "pizza" ]]);
+ })
```
---
See [Docs > Test Runner > Mocks](/docs/test/mocks) for complete documentation on mocking with the Bun test runner.

View File

@@ -0,0 +1,15 @@
---
name: Set a per-test timeout with the Bun test runner
---
Use the `--timeout` flag to set a timeout for each test in milliseconds. If any test exceeds this timeout, it will be marked as failed.
The default timeout is `5000` (5 seconds).
```sh
$ bun test --timeout 3000 # 3 seconds
```
---
See [Docs > Test runner](/docs/cli/test) for complete documentation of `bun test`.

View File

@@ -0,0 +1,60 @@
---
name: Mark a test as a "todo" with the Bun test runner
---
To remind yourself to write a test later, use the `test.todo` function. There's no need to provide a test implementation.
```ts
import { test, expect } from "bun:test";
// write this later
test.todo("unimplemented feature");
```
---
Optionally, you can provide a test implementation.
```ts
import { test, expect } from "bun:test";
test.todo("unimplemented feature", () => {
expect(Bun.isAwesome()).toBe(true);
});
```
---
The output of `bun test` indicates how many `todo` tests were encountered.
```sh
$ bun test
test.test.ts:
✓ add [0.03ms]
✓ multiply [0.02ms]
✎ unimplemented feature
2 pass
1 todo
0 fail
2 expect() calls
Ran 3 tests across 1 files. [74.00ms]
```
---
Note that `todo` tests _are executed_ by the test runner! They are _expected to fail_; if a todo test passes, the `bun test` run will return a non-zero exit code to signal the failure.
```sh
$ bun test
$ echo $?
1 # this is the exit code of the previous command
```
---
See also:
- [Skip a test](/guides/test/skip-tests)
- [Docs > Test runner > Writing tests](/docs/test/writings-tests)

View File

@@ -0,0 +1,50 @@
---
name: Update snapshots in `bun test`
---
Bun's test runner supports Jest-style snapshot testing via `.toMatchSnapshot()`.
{% callout %}
The `.toMatchInlineSnapshot()` method is not yet supported.
{% /callout %}
```ts#snap.test.ts
import { test, expect } from "bun:test";
test("snapshot", () => {
expect({ foo: "bar" }).toMatchSnapshot();
});
```
---
The first time this test is executed, Bun will write a snapshot file to disk in a directory called `__snapshots__` that lives alongside the test file.
```txt
test
├── __snapshots__
│   └── snap.test.ts.snap
└── snap.test.ts
```
---
To regenerate snapshots, use the `--update-snapshots` flag.
```sh
$ bun test --update-snapshots
bun test v0.8.0 (9c68abdb)
test/snap.test.ts:
✓ snapshot [0.86ms]
1 pass
0 fail
snapshots: +1 added # the snapshot was regenerated
1 expect() calls
Ran 1 tests across 1 files. [102.00ms]
```
---
See [Docs > Test Runner > Snapshots](/docs/test/mocks) for complete documentation on mocking with the Bun test runner.

View File

@@ -0,0 +1,19 @@
---
name: Run tests in watch mode with Bun
---
Use the `--watch` flag to run your tests in watch mode.
```sh
$ bun test --watch
```
---
This will restart the running Bun process whenever a file change is detected. It's fast. In this example, the editor is configured to save the file on every keystroke.
{% image src="https://github.com/oven-sh/bun/assets/3084745/dc49a36e-ba82-416f-b960-1c883a924248" caption="Running tests in watch mode in Bun" /%}
---
See [Docs > Test Runner](/docs/cli/test) for complete documentation on the test runner.