diff options
-rw-r--r-- | docs/guides/runtime/timezone.md | 35 | ||||
-rw-r--r-- | docs/guides/test/bail.md | 23 | ||||
-rw-r--r-- | docs/guides/test/coverage-threshold.md | 58 | ||||
-rw-r--r-- | docs/guides/test/coverage.md | 44 | ||||
-rw-r--r-- | docs/guides/test/happy-dom.md | 68 | ||||
-rw-r--r-- | docs/guides/test/index.json | 4 | ||||
-rw-r--r-- | docs/guides/test/mock-clock.md | 48 | ||||
-rw-r--r-- | docs/guides/test/mock-functions.md | 68 | ||||
-rw-r--r-- | docs/guides/test/rerun-each.md | 14 | ||||
-rw-r--r-- | docs/guides/test/run-tests.md | 99 | ||||
-rw-r--r-- | docs/guides/test/skip-tests.md | 37 | ||||
-rw-r--r-- | docs/guides/test/snapshot.md | 99 | ||||
-rw-r--r-- | docs/guides/test/spy-on.md | 46 | ||||
-rw-r--r-- | docs/guides/test/timeout.md | 15 | ||||
-rw-r--r-- | docs/guides/test/todo-tests.md | 60 | ||||
-rw-r--r-- | docs/guides/test/update-snapshots.md | 50 | ||||
-rw-r--r-- | docs/guides/test/watch-mode.md | 19 |
17 files changed, 787 insertions, 0 deletions
diff --git a/docs/guides/runtime/timezone.md b/docs/guides/runtime/timezone.md new file mode 100644 index 000000000..528f759fa --- /dev/null +++ b/docs/guides/runtime/timezone.md @@ -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 +``` diff --git a/docs/guides/test/bail.md b/docs/guides/test/bail.md new file mode 100644 index 000000000..06129314f --- /dev/null +++ b/docs/guides/test/bail.md @@ -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`. diff --git a/docs/guides/test/coverage-threshold.md b/docs/guides/test/coverage-threshold.md new file mode 100644 index 000000000..4180c6f1a --- /dev/null +++ b/docs/guides/test/coverage-threshold.md @@ -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. diff --git a/docs/guides/test/coverage.md b/docs/guides/test/coverage.md new file mode 100644 index 000000000..6103dbb90 --- /dev/null +++ b/docs/guides/test/coverage.md @@ -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. diff --git a/docs/guides/test/happy-dom.md b/docs/guides/test/happy-dom.md new file mode 100644 index 000000000..42e225a5d --- /dev/null +++ b/docs/guides/test/happy-dom.md @@ -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. diff --git a/docs/guides/test/index.json b/docs/guides/test/index.json new file mode 100644 index 000000000..d990068ac --- /dev/null +++ b/docs/guides/test/index.json @@ -0,0 +1,4 @@ +{ + "name": "Test runner", + "description": "A collection of guides for writing, running, and configuring tests in Bun" +} diff --git a/docs/guides/test/mock-clock.md b/docs/guides/test/mock-clock.md new file mode 100644 index 000000000..315c33f9f --- /dev/null +++ b/docs/guides/test/mock-clock.md @@ -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. diff --git a/docs/guides/test/mock-functions.md b/docs/guides/test/mock-functions.md new file mode 100644 index 000000000..c7e8af411 --- /dev/null +++ b/docs/guides/test/mock-functions.md @@ -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. diff --git a/docs/guides/test/rerun-each.md b/docs/guides/test/rerun-each.md new file mode 100644 index 000000000..f27d8f251 --- /dev/null +++ b/docs/guides/test/rerun-each.md @@ -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`. diff --git a/docs/guides/test/run-tests.md b/docs/guides/test/run-tests.md new file mode 100644 index 000000000..6d72f43ec --- /dev/null +++ b/docs/guides/test/run-tests.md @@ -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. diff --git a/docs/guides/test/skip-tests.md b/docs/guides/test/skip-tests.md new file mode 100644 index 000000000..c067c8fc7 --- /dev/null +++ b/docs/guides/test/skip-tests.md @@ -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) diff --git a/docs/guides/test/snapshot.md b/docs/guides/test/snapshot.md new file mode 100644 index 000000000..352cfa81c --- /dev/null +++ b/docs/guides/test/snapshot.md @@ -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. diff --git a/docs/guides/test/spy-on.md b/docs/guides/test/spy-on.md new file mode 100644 index 000000000..3a43b2367 --- /dev/null +++ b/docs/guides/test/spy-on.md @@ -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. diff --git a/docs/guides/test/timeout.md b/docs/guides/test/timeout.md new file mode 100644 index 000000000..394c4e7b6 --- /dev/null +++ b/docs/guides/test/timeout.md @@ -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`. diff --git a/docs/guides/test/todo-tests.md b/docs/guides/test/todo-tests.md new file mode 100644 index 000000000..301cd2e00 --- /dev/null +++ b/docs/guides/test/todo-tests.md @@ -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) diff --git a/docs/guides/test/update-snapshots.md b/docs/guides/test/update-snapshots.md new file mode 100644 index 000000000..360f4add2 --- /dev/null +++ b/docs/guides/test/update-snapshots.md @@ -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. diff --git a/docs/guides/test/watch-mode.md b/docs/guides/test/watch-mode.md new file mode 100644 index 000000000..6176ed31f --- /dev/null +++ b/docs/guides/test/watch-mode.md @@ -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. |