aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/api/http.md107
-rw-r--r--docs/api/streams.md6
-rw-r--r--docs/cli/install.md52
-rw-r--r--docs/cli/test.md18
-rw-r--r--docs/nav.ts11
-rw-r--r--docs/project/development.md31
-rw-r--r--docs/runtime/nodejs-apis.md6
-rw-r--r--docs/runtime/typescript.md11
-rw-r--r--docs/test/lifecycle.md2
-rw-r--r--docs/test/mocks.md55
-rw-r--r--docs/test/time.md14
-rw-r--r--docs/test/writing.md82
-rw-r--r--packages/bun-types/tests/serve.test-d.ts13
13 files changed, 355 insertions, 53 deletions
diff --git a/docs/api/http.md b/docs/api/http.md
index aed9da27c..8520604e8 100644
--- a/docs/api/http.md
+++ b/docs/api/http.md
@@ -67,7 +67,7 @@ Bun.serve({
fetch(req) {
throw new Error("woops!");
},
- error(error: Error) {
+ error(error) {
return new Response(`<pre>${error}\n${error.stack}</pre>`, {
headers: {
"Content-Type": "text/html",
@@ -95,37 +95,37 @@ server.stop();
## TLS
-Bun supports TLS out of the box, powered by [OpenSSL](https://www.openssl.org/). Enable TLS by passing in a value for `key` and `cert`; both are required to enable TLS. If needed, supply a `passphrase` to decrypt the `keyFile`.
+Bun supports TLS out of the box, powered by [BoringSSL](https://boringssl.googlesource.com/boringssl). Enable TLS by passing in a value for `key` and `cert`; both are required to enable TLS.
-```ts
-Bun.serve({
- fetch(req) {
- return new Response("Hello!!!");
- },
-
- // can be string, BunFile, TypedArray, Buffer, or array thereof
- key: Bun.file("./key.pem"),
- cert: Bun.file("./cert.pem"),
+```ts-diff
+ Bun.serve({
+ fetch(req) {
+ return new Response("Hello!!!");
+ },
- // passphrase, only required if key is encrypted
- passphrase: "super-secret",
-});
++ tls: {
++ key: Bun.file("./key.pem"),
++ cert: Bun.file("./cert.pem"),
++ }
+ });
```
-The `key` and `cert` fields expect the _contents_ of your TLS key and certificate. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
+The `key` and `cert` fields expect the _contents_ of your TLS key and certificate, _not a path to it_. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
```ts
Bun.serve({
fetch() {},
- // BunFile
- key: Bun.file("./key.pem"),
- // Buffer
- key: fs.readFileSync("./key.pem"),
- // string
- key: fs.readFileSync("./key.pem", "utf8"),
- // array of above
- key: [Bun.file('./key1.pem'), Bun.file('./key2.pem')],
+ tls: {
+ // BunFile
+ key: Bun.file("./key.pem"),
+ // Buffer
+ key: fs.readFileSync("./key.pem"),
+ // string
+ key: fs.readFileSync("./key.pem", "utf8"),
+ // array of above
+ key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")],
+ },
});
```
@@ -135,17 +135,35 @@ Bun.serve({
{% /callout %}
+If your private key is encrypted with a passphrase, provide a value for `passphrase` to decrypt it.
+
+```ts-diff
+ Bun.serve({
+ fetch(req) {
+ return new Response("Hello!!!");
+ },
+
+ tls: {
+ key: Bun.file("./key.pem"),
+ cert: Bun.file("./cert.pem"),
++ passphrase: "my-secret-passphrase",
+ }
+ });
+```
+
Optionally, you can override the trusted CA certificates by passing a value for `ca`. By default, the server will trust the list of well-known CAs curated by Mozilla. When `ca` is specified, the Mozilla list is overwritten.
-```ts
-Bun.serve({
- fetch(req) {
- return new Response("Hello!!!");
- },
- key: Bun.file("./key.pem"), // path to TLS key
- cert: Bun.file("./cert.pem"), // path to TLS cert
- ca: Bun.file("./ca.pem"), // path to root CA certificate
-});
+```ts-diff
+ Bun.serve({
+ fetch(req) {
+ return new Response("Hello!!!");
+ },
+ tls: {
+ key: Bun.file("./key.pem"), // path to TLS key
+ cert: Bun.file("./cert.pem"), // path to TLS cert
++ ca: Bun.file("./ca.pem"), // path to root CA certificate
+ }
+ });
```
To override Diffie-Helman parameters:
@@ -153,7 +171,10 @@ To override Diffie-Helman parameters:
```ts
Bun.serve({
// ...
- dhParamsFile: "./dhparams.pem", // path to Diffie Helman parameters
+ tls: {
+ // other config
+ dhParamsFile: "/path/to/dhparams.pem", // path to Diffie Helman parameters
+ },
});
```
@@ -274,11 +295,21 @@ interface Bun {
port?: number;
development?: boolean;
error?: (error: Error) => Response | Promise<Response>;
- keyFile?: string;
- certFile?: string;
- caFile?: string;
- dhParamsFile?: string;
- passphrase?: string;
+ tls?: {
+ key?:
+ | string
+ | TypedArray
+ | BunFile
+ | Array<string | TypedArray | BunFile>;
+ cert?:
+ | string
+ | TypedArray
+ | BunFile
+ | Array<string | TypedArray | BunFile>;
+ ca?: string | TypedArray | BunFile | Array<string | TypedArray | BunFile>;
+ passphrase?: string;
+ dhParamsFile?: string;
+ };
maxRequestBodySize?: number;
lowMemoryMode?: boolean;
}): Server;
diff --git a/docs/api/streams.md b/docs/api/streams.md
index 7f3e3bcb4..210090927 100644
--- a/docs/api/streams.md
+++ b/docs/api/streams.md
@@ -28,8 +28,6 @@ for await (const chunk of stream) {
}
```
-For a more complete discusson of streams in Bun, see [API > Streams](/docs/api/streams).
-
## Direct `ReadableStream`
Bun implements an optimized version of `ReadableStream` that avoid unnecessary data copying & queue management logic. With a traditional `ReadableStream`, chunks of data are _enqueued_. Each chunk is copied into a queue, where it sits until the stream is ready to send more data.
@@ -154,7 +152,9 @@ export class ArrayBufferSink {
stream?: boolean;
}): void;
- write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
+ write(
+ chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
+ ): number;
/**
* Flush the internal buffer
*
diff --git a/docs/cli/install.md b/docs/cli/install.md
index 4489a0d4a..f7b081ba8 100644
--- a/docs/cli/install.md
+++ b/docs/cli/install.md
@@ -49,7 +49,7 @@ To install in production mode (i.e. without `devDependencies`):
$ bun install --production
```
-To install dependencies without allowing changes to lockfile (useful on CI):
+To install with reproducible dependencies, use `--frozen-lockfile`. If your `package.json` disagrees with `bun.lockb`, Bun will exit with an error. This is useful for production builds and CI environments.
```bash
$ bun install --frozen-lockfile
@@ -124,6 +124,26 @@ To add a package as an optional dependency (`"optionalDependencies"`):
$ bun add --optional lodash
```
+To add a package and pin to the resolved version, use `--exact`. This will resolve the version of the package and add it to your `package.json` with an exact version number instead of a version range.
+
+```bash
+$ bun add react --exact
+```
+
+This will add the following to your `package.json`:
+
+```jsonc
+{
+ "dependencies": {
+ // without --exact
+ "react": "^18.2.0", // this matches >= 18.2.0 < 19.0.0
+
+ // with --exact
+ "react": "18.2.0" // this matches only 18.2.0 exactly
+ }
+}
+```
+
To install a package globally:
```bash
@@ -206,6 +226,36 @@ In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencie
}
```
+## Trusted dependencies
+
+Unlike other npm clients, Bun does not execute arbitrary lifecycle scripts for installed dependencies, such as `postinstall`. These scripts represent a potential security risk, as they can execute arbitrary code on your machine.
+
+<!-- Bun maintains an allow-list of popular packages containing `postinstall` scripts that are known to be safe. To run lifecycle scripts for packages that aren't on this list, add the package to `trustedDependencies` in your package.json. -->
+
+To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
+
+```json-diff
+ {
+ "name": "my-app",
+ "version": "1.0.0",
++ "trustedDependencies": {
++ "my-trusted-package": "*"
++ }
+ }
+```
+
+Bun reads this field and will run lifecycle scripts for `my-trusted-package`. If you specify a version range, Bun will only execute lifecycle scripts if the resolved package version matches the range.
+
+```json
+{
+ "name": "my-app",
+ "version": "1.0.0",
+ "trustedDependencies": {
+ "my-trusted-package": "^1.0.0"
+ }
+}
+```
+
## Git dependencies
To add a dependency from a git repository:
diff --git a/docs/cli/test.md b/docs/cli/test.md
index d19a45a12..7af8dcc20 100644
--- a/docs/cli/test.md
+++ b/docs/cli/test.md
@@ -65,6 +65,24 @@ $ bun test --preload ./setup.ts
See [Test > Lifecycle](/docs/test/lifecycle) for complete documentation.
+## Mocks
+
+Create mocks with the `mock` function. Mocks are automatically reset between tests.
+
+```
+import { test, expect, mock } from "bun:test";
+const random = mock(() => Math.random());
+
+test("random", async () => {
+ const val = random();
+ expect(val).toBeGreaterThan(0);
+ expect(random).toHaveBeenCalled();
+ expect(random).toHaveBeenCalledTimes(1);
+});
+```
+
+See [Test > Mocks](/docs/test/mocks) for complete documentation.
+
## Snapshot testing
Snapshots are supported by `bun test`. See [Test > Snapshots](/docs/test/snapshots) for complete documentation.
diff --git a/docs/nav.ts b/docs/nav.ts
index 2832a53cf..5b35036d3 100644
--- a/docs/nav.ts
+++ b/docs/nav.ts
@@ -135,13 +135,13 @@ export default {
description:
"Install all dependencies with `bun install`, or manage dependencies with `bun add` and `bun remove`.",
}),
- page("install/workspaces", "Workspaces", {
- description: "Bun's package manager supports workspaces and mono-repo development workflows.",
- }),
page("install/cache", "Global cache", {
description:
"Bun's package manager installs all packages into a shared global cache to avoid redundant re-downloads.",
}),
+ page("install/workspaces", "Workspaces", {
+ description: "Bun's package manager supports workspaces and mono-repo development workflows.",
+ }),
page("install/lockfile", "Lockfile", {
description:
"Bun's binary lockfile `bun.lockb` tracks your resolved dependency ytrr, making future installs fast and repeatable.",
@@ -190,10 +190,13 @@ export default {
page("test/lifecycle", "Lifecycle hooks", {
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
}),
+ page("test/mocks", "Mocks", {
+ description: "Mocks functions and track method calls",
+ }),
page("test/snapshots", "Snapshots", {
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
}),
- page("test/time", "Time", {
+ page("test/time", "Dates and times", {
description: "Control the date & time in your tests for more reliable and deterministic tests",
}),
page("test/dom", "DOM testing", {
diff --git a/docs/project/development.md b/docs/project/development.md
index d21641aff..e50f53215 100644
--- a/docs/project/development.md
+++ b/docs/project/development.md
@@ -217,6 +217,37 @@ You'll need a very recent version of Valgrind due to DWARF 5 debug symbols. You
$ valgrind --fair-sched=try --track-origins=yes bun-debug <args>
```
+## Updating `WebKit`
+
+The Bun team will occasionally bump the version of WebKit used in Bun. When this happens, you may see something like this with you run `git status`.
+
+```bash
+$ git status
+On branch my-branch
+Changes not staged for commit:
+ (use "git add <file>..." to update what will be committed)
+ (use "git restore <file>..." to discard changes in working directory)
+ modified: src/bun.js/WebKit (new commits)
+```
+
+For performance reasons, `bun submodule update` does not automatically update the WebKit submodule. To update, run the following commands from the root of the Bun repo:
+
+```bash
+$ bun install
+$ make bindings
+```
+
+<!-- Check the [Bun repo](https://github.com/oven-sh/bun/tree/main/src/bun.js) to get the hash of the commit of WebKit is currently being used.
+
+{% image width="270" src="https://github.com/oven-sh/bun/assets/3084745/51730b73-89ef-4358-9a41-9563a60a54be" /%} -->
+
+<!--
+```bash
+$ cd src/bun.js/WebKit
+$ git fetch
+$ git checkout <hash>
+``` -->
+
## Troubleshooting
### libarchive
diff --git a/docs/runtime/nodejs-apis.md b/docs/runtime/nodejs-apis.md
index ac42559a0..593954aae 100644
--- a/docs/runtime/nodejs-apis.md
+++ b/docs/runtime/nodejs-apis.md
@@ -51,7 +51,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_crypto" %} [`node:crypto`](https://nodejs.org/api/crypto.html) {% /anchor %}
- 🟡
-- Missing `crypto.Certificate` `crypto.ECDH` `crypto.KeyObject` `crypto.X509Certificate` `crypto.checkPrime{Sync}` `crypto.createPrivateKey` `crypto.createPublicKey` `crypto.createSecretKey` `crypto.diffieHellman` `crypto.generateKey{Sync}` `crypto.generateKeyPair{Sync}` `crypto.generatePrime{Sync}` `crypto.getCipherInfo` `crypto.getCurves` `crypto.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.randomInt` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`
+- Missing `crypto.Certificate` `crypto.ECDH` `crypto.KeyObject` `crypto.X509Certificate` `crypto.checkPrime{Sync}` `crypto.createPrivateKey` `crypto.createPublicKey` `crypto.createSecretKey` `crypto.diffieHellman` `crypto.generateKey{Sync}` `crypto.generateKeyPair{Sync}` `crypto.generatePrime{Sync}` `crypto.getCipherInfo` `crypto.getCurves` `crypto.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`
---
@@ -87,7 +87,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %}
- 🟡
-- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.readv{Sync}` `fs.{watch|watchFile|unwatchFile}` `fs.writev{Sync}`.
+- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.{watchFile|unwatchFile}` `fs.{cp|cpSync}`.
---
@@ -558,7 +558,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
- {% anchor id="node_require" %} [`require()`](https://nodejs.org/api/globals.html#require) {% /anchor %}
- 🟢
-- Fully implemented.
+- Fully implemented, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options)
---
diff --git a/docs/runtime/typescript.md b/docs/runtime/typescript.md
index d466bb016..b79b1ec6d 100644
--- a/docs/runtime/typescript.md
+++ b/docs/runtime/typescript.md
@@ -93,6 +93,17 @@ These are the recommended `compilerOptions` for a Bun project.
}
```
+### Add DOM types
+
+Settings `"types": ["bun-types"]` means TypeScript will ignore other global type definitions, including `lib: ["dom"]`. To add DOM types into your project, add the following [triple-slash directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) at the top of any TypeScript file in your project.
+
+```ts
+/// <reference lib="dom" />
+/// <reference lib="dom.iterable" />
+```
+
+The same applies to other global type definition _libs_ like `webworker`.
+
## Path mapping
When resolving modules, Bun's runtime respects path mappings defined in [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in your `tsconfig.json`. No other runtime does this.
diff --git a/docs/test/lifecycle.md b/docs/test/lifecycle.md
index 176c476de..fd804c9bb 100644
--- a/docs/test/lifecycle.md
+++ b/docs/test/lifecycle.md
@@ -70,7 +70,7 @@ afterAll(() => {
Then use `--preload` to run the setup script before any test files.
```ts
-bun test --preload ./setup.ts
+$ bun test --preload ./setup.ts
```
To avoid typing `--preload` every time you run tests, it can be added to your `bunfig.toml`:
diff --git a/docs/test/mocks.md b/docs/test/mocks.md
new file mode 100644
index 000000000..31b5dab41
--- /dev/null
+++ b/docs/test/mocks.md
@@ -0,0 +1,55 @@
+Create mocks with the `mock` function.
+
+```ts
+import { test, expect, mock } from "bun:test";
+const random = mock(() => Math.random());
+
+test("random", async () => {
+ const val = random();
+ expect(val).toBeGreaterThan(0);
+ expect(random).toHaveBeenCalled();
+ expect(random).toHaveBeenCalledTimes(1);
+});
+```
+
+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 }
+// ]
+```
+
+## `.spyOn()`
+
+It's possible to track calls to a function without replacing it with a mock. Use `spyOn()` to create a spy; these spies can be passed to `.toHaveBeenCalled()` and `.toHaveBeenCalledTimes()`.
+
+```ts
+import { test, expect, spyOn } from "bun:test";
+
+const ringo = {
+ name: "Ringo",
+ sayHi() {
+ console.log(`Hello I'm ${this.name}`);
+ },
+};
+
+const spy = spyOn(ringo, "sayHi");
+
+test("spyon", () => {
+ expect(spy).toHaveBeenCalledTimes(0);
+ ringo.sayHi();
+ expect(spy).toHaveBeenCalledTimes(1);
+});
+```
diff --git a/docs/test/time.md b/docs/test/time.md
index ef741fc6f..4a0f98407 100644
--- a/docs/test/time.md
+++ b/docs/test/time.md
@@ -51,7 +51,9 @@ test("unlike in jest", () => {
});
```
-Note that we have not implemented builtin support for mocking timers yet, but this is on the roadmap.
+{% callout %}
+**Timers** — Note that we have not implemented builtin support for mocking timers yet, but this is on the roadmap.
+{% /callout %}
### Reset the system time
@@ -74,7 +76,13 @@ test("it was 2020, for a moment.", () => {
## Set the time zone
-To change the time zone, either pass the `$TZ` environment variable to `bun test`, or set `process.env.TZ` at runtime:
+To change the time zone, either pass the `$TZ` environment variable to `bun test`.
+
+```sh
+TZ=America/Los_Angeles bun test
+```
+
+Or set `process.env.TZ` at runtime:
```ts
import { test, expect } from "bun:test";
@@ -88,7 +96,7 @@ test("Welcome to California!", () => {
});
test("Welcome to New York!", () => {
- // Unlike in jest, you can set the timezone multiple times at runtime and it will work.
+ // Unlike in Jest, you can set the timezone multiple times at runtime and it will work.
process.env.TZ = "America/New_York";
expect(new Date().getTimezoneOffset()).toBe(240);
expect(new Intl.DateTimeFormat().resolvedOptions().timeZone).toBe(
diff --git a/docs/test/writing.md b/docs/test/writing.md
index 029418a48..6a29bf81f 100644
--- a/docs/test/writing.md
+++ b/docs/test/writing.md
@@ -63,6 +63,21 @@ test("2 * 2", done => {
});
```
+## Timeouts
+
+Optionally specify a per-test timeout in milliseconds by passing a number as the third argument to `test`.
+
+```ts
+import { test } from "bun:test";
+
+test.skip("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.
```ts
@@ -74,6 +89,8 @@ test.skip("wat", () => {
});
```
+## `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.
```ts
@@ -84,6 +101,71 @@ test.todo("fix this", () => {
});
```
+To exlusively run tests marked as _todo_, use `bun test --todo`.
+
+```sh
+$ 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 --skip` will only execute tests/suites that have been marked with `.only()`.
+
+```ts
+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.
+
+```sh
+$ bun test --only
+```
+
+## `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.
+
+```ts
+test.if(Math.random() > 0.5)("runs half the time", () => {
+ // ...
+});
+```
+
+```ts
+test.if(Math.random() > 0.5)("runs half the time", () => {
+ // ...
+});
+
+const macOS = process.arch === "darwin";
+test.if(macOS)("runs on macOS", () => {
+ // runs if macOS
+});
+```
+
+To instead skip a test based on some condition, use `test.skipIf()` or `describe.skipIf()`.
+
+```ts
+const macOS = process.arch === "darwin";
+
+test.skipIf(macOS)("runs on non-macOS", () => {
+ // runs if *not* macOS
+});
+```
+
## Matchers
Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825).
diff --git a/packages/bun-types/tests/serve.test-d.ts b/packages/bun-types/tests/serve.test-d.ts
index 2477433dc..4ba3144b8 100644
--- a/packages/bun-types/tests/serve.test-d.ts
+++ b/packages/bun-types/tests/serve.test-d.ts
@@ -79,4 +79,17 @@ Bun.serve<User>({
},
});
+Bun.serve({
+ fetch(req) {
+ throw new Error("woops!");
+ },
+ error(error) {
+ return new Response(`<pre>${error}\n${error.stack}</pre>`, {
+ headers: {
+ "Content-Type": "text/html",
+ },
+ });
+ },
+});
+
export {};