1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
Like the runtime, `bun:test` also supports `--preload` scripts. These scripts are loaded before any tests are run. This is useful for setting up test fixtures, mocking, and configuring the test environment.
{% codetabs %}
```ts#preloaded.ts
import { beforeAll, beforeEach, afterEach, afterAll } from "bun:test";
beforeAll(() => {
console.log("beforeAll");
});
beforeEach(() => {
console.log("beforeEach");
});
afterEach(() => {
console.log("afterEach");
});
afterAll(() => {
console.log("afterAll");
});
```
{% /codetabs %}
Test file:
```ts
import { expect, test } from "bun:test";
test("1 + 1", () => {
expect(1 + 1).toEqual(2);
console.log("1 + 1");
});
```
Run the test with `--preload`:
```sh
$ bun test --preload=preloaded.ts
```
It outputs:
```sh
beforeAll
beforeEach
1 + 1
afterEach
afterAll
```
## Configuration
To save yourself from having to type `--preload` every time you run tests, you can add it to your `bunfig.toml`:
```toml
[test]
preload = ["./preloaded.ts"]
```
## List of lifecycle hooks
The following lifecycle hooks are available in `--preload`:
| Hook | Description |
| ------------ | --------------------------- |
| `beforeAll` | Runs once before all tests. |
| `beforeEach` | Runs before each test. |
| `afterEach` | Runs after each test. |
| `afterAll` | Runs once after all tests. |
Calling `expect`, `test`, or any other test function inside a lifecycle hook will throw an error. Calling `test` inside `beforeAll`, `afterAll`, `beforeEach` or `afterEach` will also throw an error.
You can use `console.log` or any other function otherwise inside a lifecycle hook.
We haven't implemented timer simulation, test isolation, or `Math.random` mocking yet. If you need these features, please [open an issue](https://bun.sh/issues).
### The lifecycle of bun:test
The test runner is a single process that runs all tests. It loads all `--preload` scripts, then runs all tests. If a test fails, the test runner will exit with a non-zero exit code.
Before running each test, it transpiles the source code and all dependencies into vanilla JavaScript using Bun's transpiler and module resolver. This means you can use TypeScript, JSX, ESM, and CommonJS in your tests.
#### Globals
Like Jest, you can use `describe`, `test`, `expect`, and other functions without importing them.
But unlike Jest, they are not globals. They are imported from `bun:test` and are exclusively available in test files or when preloading scripts.
```ts
typeof globalThis.describe; // "undefined"
typeof describe; // "function"
```
This works via a transpiler integration in Bun. When `describe`, `expect`, `it`, etc are used in a test file, the transpiler auto-imports from `bun:test`. This transpiler plugin is only enabled inside test files and when preloading scripts. If you try to use Jest globals in other files, you will get an error.
Every `describe`, `test`, and `expect` is scoped to the current test file. Importing from `"bun:test"` creates a new scope. This means you can't use `describe` from one test file in another test file because belong to different scopes.
## Loaders & Resolvers
{% note %}
Plugin support is not implemented yet. **There is a bug and this feature is not working**.
{% /note %}
`bun:test` supports the same plugin API as bun's runtime and bun's bundler. See [Plugins](/docs/bundler/plugins#usage) for more information.
## Example loader
{% codetabs %}
```ts#loader.ts
import { plugin } from 'bun';
plugin({
name: 'My loader',
setup(build) {
build.onResolve({ filter: /\.txt$/ }, (args) => {
return {
path: args.path,
namespace: 'my-loader',
};
});
build.onLoad({ filter: /my-loader:.txt$/ }, (args) => {
return {
contents: 'Hello world!',
loader: 'text',
};
});
},
});
```
{% /codetabs %}
Now in your test file, you can import `.txt` files:
```ts#my-test.test.ts
import { expect, test } from "bun:test";
import text from "./hello.txt";
test("text is 'Hello world!'", () => {
expect(text).toEqual("Hello world!");
});
```
To run the test, you need to add `loader.ts` to `preload`:
```toml
[test]
preload = ["loader.ts"]
```
Or you can pass --preload to the command line:
```sh
$ bun test --preload=loader.ts
```
TODO: `expect.extend`
|