Testing
Robust testing and benchmarking capabilities to ensure code quality and performance.
Eg Deno.test, Deno.bench
Functions
Register a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
Interfaces
Context that is passed to a benchmarked function. The instance is shared between iterations of the benchmark. Its methods can be used for example to override of the measured portion of the function.
The interface for defining a benchmark test using Deno.bench.
Context that is passed to a testing function, which can be used to either gain information about the current test, or register additional test steps within the current test.
Options which can be set when calling
Deno.TestContext.assertSnapshot.
Variables
Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
function Deno.bench
Overload 1
#bench(b: BenchDefinition): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
A module "looks like a bench module" when deno bench selects it for
execution. When you pass explicit file paths to deno bench, those files
are always run. When you run deno bench without paths, it walks the
directory looking for files whose name (ignoring the extension) ends with
_bench or .bench, or is exactly bench. Examples are foo_bench.ts,
foo.bench.js, or bench.ts. Supported extensions are the same as for
tests (.ts, .tsx, .js, .jsx, .mjs, .mts, .cjs, .cts).
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench({
name: "example test",
fn() {
assertEquals("world", "world");
},
});
Deno.bench({
name: "example ignored test",
ignore: Deno.build.os === "windows",
fn() {
// This test is ignored only on Windows machines
},
});
Deno.bench({
name: "example async test",
async fn() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
});
Parameters #
Return Type #
void Overload 2
#bench(name: string,fn: (b: BenchContext) => void | Promise<void>,): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench("My test description", () => {
assertEquals("hello", "hello");
});
Deno.bench("My async test description", async () => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
});
Parameters #
#name: string #fn: (b: BenchContext) => void | Promise<void> Return Type #
void Overload 3
#bench(fn: (b: BenchContext) => void | Promise<void>): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench(function myTestName() {
assertEquals("hello", "hello");
});
Deno.bench(async function myOtherTestName() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
});
Parameters #
#fn: (b: BenchContext) => void | Promise<void> Return Type #
void Overload 4
#bench(name: string,options: Omit<BenchDefinition, "fn" | "name">,fn: (b: BenchContext) => void | Promise<void>,): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench(
"My test description",
{ permissions: { read: true } },
() => {
assertEquals("hello", "hello");
}
);
Deno.bench(
"My async test description",
{ permissions: { read: false } },
async () => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
);
Parameters #
#name: string #options: Omit<BenchDefinition, "fn" | "name"> #fn: (b: BenchContext) => void | Promise<void> Return Type #
void Overload 5
#bench(options: Omit<BenchDefinition, "fn">,fn: (b: BenchContext) => void | Promise<void>,): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench(
{ name: "My test description", permissions: { read: true } },
() => {
assertEquals("hello", "hello");
}
);
Deno.bench(
{ name: "My async test description", permissions: { read: false } },
async () => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
);
Parameters #
#options: Omit<BenchDefinition, "fn"> #fn: (b: BenchContext) => void | Promise<void> Return Type #
void Overload 6
#bench(options: Omit<BenchDefinition, "fn" | "name">,fn: (b: BenchContext) => void | Promise<void>,): voidRegister a benchmark test which will be run when deno bench is used on
the command line and the containing module looks like a bench module.
If the test function (fn) returns a promise or is async, the test runner
will await resolution to consider the test complete.
import { assertEquals } from "jsr:@std/assert";
Deno.bench(
{ permissions: { read: true } },
function myTestName() {
assertEquals("hello", "hello");
}
);
Deno.bench(
{ permissions: { read: false } },
async function myOtherTestName() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
);
Parameters #
#options: Omit<BenchDefinition, "fn" | "name"> #fn: (b: BenchContext) => void | Promise<void> Return Type #
void interface Deno.BenchContext
Context that is passed to a benchmarked function. The instance is shared between iterations of the benchmark. Its methods can be used for example to override of the measured portion of the function.
Properties #
Methods #
Restarts the timer for the bench measurement. This should be called after doing setup work which should not be measured.
Warning: This method should not be used for benchmarks averaging less than 10μs per iteration. In such cases it will be disabled but the call will still have noticeable overhead, resulting in a warning.
Deno.bench("foo", async (t) => {
const data = await Deno.readFile("data.txt");
t.start();
// some operation on `data`...
});
End the timer early for the bench measurement. This should be called before doing teardown work which should not be measured.
Warning: This method should not be used for benchmarks averaging less than 10μs per iteration. In such cases it will be disabled but the call will still have noticeable overhead, resulting in a warning.
Deno.bench("foo", async (t) => {
using file = await Deno.open("data.txt");
t.start();
// some operation on `file`...
t.end();
});
interface Deno.BenchDefinition
The interface for defining a benchmark test using Deno.bench.
Properties #
#fn: (b: BenchContext) => void | Promise<void> The test function which will be benchmarked.
Group name for the benchmark.
Grouped benchmarks produce a group time summary, where the difference in performance between each test of the group is compared.
Benchmark should be used as the baseline for other benchmarks.
If there are multiple baselines in a group, the first one is used as the baseline.
If at least one bench has only set to true, only run benches that have
only set to true and fail the bench suite.
#sanitizeExit: boolean = true Ensure the bench case does not prematurely cause the process to exit,
for example via a call to Deno.exit.
#permissions: PermissionOptions = "inherit" Specifies the permissions that should be used to run the bench.
Set this to "inherit" to keep the calling thread's permissions.
Set this to "none" to revoke all permissions.
interface Deno.DenoTest
Call Signatures #
(t: TestDefinition): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required.
import { assertEquals } from "jsr:@std/assert";
Deno.test({
name: "example test",
fn() {
assertEquals("world", "world");
},
});
Deno.test({
name: "example ignored test",
ignore: Deno.build.os === "windows",
fn() {
// This test is ignored only on Windows machines
},
});
Deno.test({
name: "example async test",
async fn() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
});
(name: string,fn: (t: TestContext) => void | Promise<void>,): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required.
import { assertEquals } from "jsr:@std/assert";
Deno.test("My test description", () => {
assertEquals("hello", "hello");
});
Deno.test("My async test description", async () => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
});
(fn: (t: TestContext) => void | Promise<void>): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required. Declared function must have a name.
import { assertEquals } from "jsr:@std/assert";
Deno.test(function myTestName() {
assertEquals("hello", "hello");
});
Deno.test(async function myOtherTestName() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
});
(name: string,options: Omit<TestDefinition, "fn" | "name">,fn: (t: TestContext) => void | Promise<void>,): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required.
import { assert, fail, assertEquals } from "jsr:@std/assert";
Deno.test("My test description", { permissions: { read: true } }, (): void => {
assertEquals("hello", "hello");
});
Deno.test("My async test description", { permissions: { read: false } }, async (): Promise<void> => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
});
(options: Omit<TestDefinition, "fn" | "name">,fn: (t: TestContext) => void | Promise<void>,): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required.
import { assertEquals } from "jsr:@std/assert";
Deno.test(
{
name: "My test description",
permissions: { read: true },
},
() => {
assertEquals("hello", "hello");
},
);
Deno.test(
{
name: "My async test description",
permissions: { read: false },
},
async () => {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
},
);
(options: Omit<TestDefinition, "fn">,fn: (t: TestContext) => void | Promise<void>,): void Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required. Declared function must have a name.
import { assertEquals } from "jsr:@std/assert";
Deno.test(
{ permissions: { read: true } },
function myTestName() {
assertEquals("hello", "hello");
},
);
Deno.test(
{ permissions: { read: false } },
async function myOtherTestName() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
},
);
Properties #
Register a parameterized group of tests, one per case in cases.
Returns a function that takes a name template and a test function. For
each case the name template is interpolated and the test function is
called with the case's value(s) followed by the TestContext.
Array cases are spread as positional arguments; object (or primitive) cases are passed as a single argument.
The name template supports printf-style tokens that consume the case's
values in order (%s, %d/%i, %f, %j, %o/%O), %# for the
zero-based case index, and %% for a literal %. For object cases,
$key (and $key.nested) interpolates the corresponding property.
import { assertEquals } from "jsr:@std/assert";
Deno.test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])("add(%i, %i) = %i", (a, b, expected) => {
assertEquals(a + b, expected);
});
Deno.test.each([
{ a: 1, b: 1, sum: 2 },
{ a: 1, b: 2, sum: 3 },
])("$a + $b = $sum", ({ a, b, sum }) => {
assertEquals(a + b, sum);
});
Shorthand property for ignoring a particular test case.
Methods #
Register a function to be called before all tests in the current scope.
These functions are run in FIFO order (first in, first out).
If an exception is raised during execution of this hook, the remaining beforeAll hooks will not be run.
Deno.test.beforeAll(() => {
// Setup code that runs once before all tests
console.log("Setting up test suite");
});
#beforeEach(fn: () => void | Promise<void>): void Register a function to be called before each test in the current scope.
These functions are run in FIFO order (first in, first out).
If an exception is raised during execution of this hook, the remaining hooks will not be run and the currently running test case will be marked as failed.
Deno.test.beforeEach(() => {
// Setup code that runs before each test
console.log("Setting up test");
});
Register a function to be called after each test in the current scope.
These functions are run in LIFO order (last in, first out).
If an exception is raised during execution of this hook, the remaining hooks will not be run and the currently running test case will be marked as failed.
Deno.test.afterEach(() => {
// Cleanup code that runs after each test
console.log("Cleaning up test");
});
Register a function to be called after all tests in the current scope have finished running.
These functions are run in the LIFO order (last in, first out).
If an exception is raised during execution of this hook, the remaining afterAll hooks will not be run.
Deno.test.afterAll(() => {
// Cleanup code that runs once after all tests
console.log("Cleaning up test suite");
});
Configure sanitizers at the module level. This overrides CLI flags and
config file settings, but can still be overridden per-test via
sanitizeOps / sanitizeResources in test options.
Should be called at the top of the module, before any Deno.test()
registrations — each call sets the defaults that subsequently registered
tests inherit, so tests registered before the call use the previous
defaults.
// Enable both sanitizers for all tests in this file
Deno.test.sanitizer({ ops: true, resources: true });
Deno.test("my test", () => {
// This test will have ops and resources sanitizers enabled
});
Deno.test({
name: "override per-test",
sanitizeOps: false,
fn() {
// This test opts out of ops sanitizer
},
});
interface Deno.TestContext
Context that is passed to a testing function, which can be used to either gain information about the current test, or register additional test steps within the current test.
Properties #
Methods #
#step(definition: TestStepDefinition): Promise<boolean> Run a sub step of the parent test or step. Returns a promise that resolves to a boolean signifying if the step completed successfully.
The returned promise never rejects unless the arguments are invalid.
If the test was ignored the promise returns false.
Deno.test({
name: "a parent test",
async fn(t) {
console.log("before the step");
await t.step({
name: "step 1",
fn(t) {
console.log("current step:", t.name);
}
});
console.log("after the step");
}
});
#step(name: string,fn: (t: TestContext) => void | Promise<void>,): Promise<boolean> Run a sub step of the parent test or step. Returns a promise that resolves to a boolean signifying if the step completed successfully.
The returned promise never rejects unless the arguments are invalid.
If the test was ignored the promise returns false.
Deno.test(
"a parent test",
async (t) => {
console.log("before the step");
await t.step(
"step 1",
(t) => {
console.log("current step:", t.name);
}
);
console.log("after the step");
}
);
#step(fn: (t: TestContext) => void | Promise<void>): Promise<boolean> Run a sub step of the parent test or step. Returns a promise that resolves to a boolean signifying if the step completed successfully.
The returned promise never rejects unless the arguments are invalid.
If the test was ignored the promise returns false.
Deno.test(async function aParentTest(t) {
console.log("before the step");
await t.step(function step1(t) {
console.log("current step:", t.name);
});
console.log("after the step");
});
#assertSnapshot<T>(actual: T,options?: TestSnapshotOptions<T>,): Promise<void> Assert that actual matches a snapshot stored in a snapshot file.
The snapshot is stored in __snapshots__/<test file name>.snap next
to the test file, under a key derived from the test (and step) name.
On the first run, create the snapshot file by running the tests with
the --update-snapshots flag; commit it alongside the test. On
subsequent runs the assertion fails if the serialized value no longer
matches the stored snapshot. To intentionally change snapshots, run
the tests with --update-snapshots again.
No read or write permissions are needed for snapshot files in the
default location; a custom dir or path requires them.
The snapshot file format is compatible with
assertSnapshot from
@std/testing/snapshot.
Deno.test("matches snapshot", async (t) => {
await t.assertSnapshot({ hello: "world", example: 123 });
});
#assertSnapshot<T>(actual: T,message?: string,): Promise<void> Assert that actual matches a snapshot stored in a snapshot file,
using message as the failure message if it does not.
Deno.test("matches snapshot", async (t) => {
await t.assertSnapshot(2 + 3, "should be five");
});
interface Deno.TestDefinition
Properties #
#fn: (t: TestContext) => void | Promise<void> If truthy the current test step will be ignored.
It is a quick way to skip over a step, but also can be used for conditional logic, like determining if an environment feature is present.
If at least one test has only set to true, only run tests that have
only set to true and fail the test suite.
#sanitizeOps: boolean = false Check that the number of async completed operations after the test step is the same as number of dispatched operations. This ensures that the code tested does not start async operations which it then does not await. This helps in preventing logic errors and memory leaks in the application code.
Can also be enabled globally with the --sanitize-ops CLI flag,
the DENO_TEST_SANITIZE_OPS=1 environment variable, or the
test.sanitizeOps option in deno.json. Can be set per-module
with Deno.test.sanitizer.
#sanitizeResources: boolean = false Ensure the test step does not "leak" resources - like open files or network connections - by ensuring the open resources at the start of the test match the open resources at the end of the test.
Can also be enabled globally with the --sanitize-resources CLI flag,
the DENO_TEST_SANITIZE_RESOURCES=1 environment variable, or the
test.sanitizeResources option in deno.json. Can be set per-module
with Deno.test.sanitizer.
#sanitizeExit: boolean = true Ensure the test case does not prematurely cause the process to exit,
for example via a call to Deno.exit.
#permissions: PermissionOptions = "inherit" Specifies the permissions that should be used to run the test.
Set this to "inherit" to keep the calling runtime permissions, set this
to "none" to revoke all permissions, or set a more specific set of
permissions using a PermissionOptionsObject.
Maximum duration in milliseconds that the test is allowed to run before being marked as a failed test. Both asynchronous hangs and synchronous hot loops are caught.
If unset or 0, the test runs without a deadline.
Number of times to re-run the test if it fails. The test is considered to have passed if any attempt passes. Useful for tolerating flaky tests.
When set, this takes precedence over the --retry flag, including an
explicit 0 which opts the test out of a flag-provided default.
Number of additional times to run the test. Every repetition must pass
for the test to pass. Useful for surfacing flaky tests. When combined
with TestDefinition.retry, each repetition may itself be
retried.
When set, this takes precedence over the --repeats flag, including an
explicit 0 which opts the test out of a flag-provided default.
interface Deno.TestEach
Register a parameterized group of tests. See DenoTest.each.
The first overload handles array cases (their values are spread as
positional arguments); the second handles object or primitive cases (each
passed as a single argument followed by the TestContext).
The TestContext is also passed as the final argument to array
case functions at runtime, but is not reflected in their parameter types so
that the case values stay correctly typed.
Call Signatures #
<T extends readonly unknown[]>(cases: readonly T[]): { (name: string,fn: (...args: [...T]) => void | Promise<void>,): void; (name: string,options: Omit<TestDefinition, "fn" | "name">,fn: (...args: [...T]) => void | Promise<void>,): void; } <T>(cases: readonly T[]): { (name: string,fn: (value: T,t: TestContext,) => void | Promise<void>,): void; (name: string,options: Omit<TestDefinition, "fn" | "name">,fn: (value: T,t: TestContext,) => void | Promise<void>,): void; } interface Deno.TestIgnore
Shorthand property for ignoring a particular test case. See
DenoTest.ignore.
Call Signatures #
(t: Omit<TestDefinition, "ignore">): void (name: string,fn: (t: TestContext) => void | Promise<void>,): void (fn: (t: TestContext) => void | Promise<void>): void (name: string,options: Omit<TestDefinition, "fn"
| "name"
| "ignore">,fn: (t: TestContext) => void | Promise<void>,): void (options: Omit<TestDefinition, "fn"
| "name"
| "ignore">,fn: (t: TestContext) => void | Promise<void>,): void (options: Omit<TestDefinition, "fn" | "ignore">,fn: (t: TestContext) => void | Promise<void>,): void Properties #
Register a parameterized group of ignored tests. See
DenoTest.each.
interface Deno.TestOnly
Shorthand property for focusing a particular test case. See
DenoTest.only.
Call Signatures #
(t: Omit<TestDefinition, "only">): void (name: string,fn: (t: TestContext) => void | Promise<void>,): void (fn: (t: TestContext) => void | Promise<void>): void (name: string,options: Omit<TestDefinition, "fn"
| "name"
| "only">,fn: (t: TestContext) => void | Promise<void>,): void (options: Omit<TestDefinition, "fn"
| "name"
| "only">,fn: (t: TestContext) => void | Promise<void>,): void (options: Omit<TestDefinition, "fn" | "only">,fn: (t: TestContext) => void | Promise<void>,): void Properties #
Register a parameterized group of focused tests. See
DenoTest.each.
interface Deno.TestSnapshotOptions
Options which can be set when calling
Deno.TestContext.assertSnapshot.
Type Parameters #
#T = unknown Properties #
Snapshot output directory, relative to the directory of the test
file (or absolute). Snapshot files are written to this directory
instead of the default __snapshots__ directory. Requires read (and,
with --update-snapshots, write) permission for the directory.
If both dir and path are specified, dir is ignored.
Snapshot output path, relative to the directory of the test file (or
absolute). The snapshot is stored in this file instead of the default
__snapshots__/<test file name>.snap file. Requires read (and, with
--update-snapshots, write) permission for the file.
If both dir and path are specified, dir is ignored.
Name of the snapshot to use in the snapshot file instead of the name derived from the test and step names.
Failure message to use when the assertion fails, instead of the generated diff message.
#serializer: (actual: T) => string Function used to serialize the value to a string before comparing it
with the stored snapshot. Defaults to a Deno.inspect()-based
serializer.
interface Deno.TestStepDefinition
Properties #
#fn: (t: TestContext) => void | Promise<void> The test function that will be tested when this step is executed. The function can take an argument which will provide information about the current step's context.
If truthy the current test step will be ignored.
This is a quick way to skip over a step, but also can be used for conditional logic, like determining if an environment feature is present.
#sanitizeOps: boolean Check that the number of async completed operations after the test step is the same as number of dispatched operations. This ensures that the code tested does not start async operations which it then does not await. This helps in preventing logic errors and memory leaks in the application code.
Defaults to the parent test or step's value.
#sanitizeResources: boolean Ensure the test step does not "leak" resources - like open files or network connections - by ensuring the open resources at the start of the step match the open resources at the end of the step.
Defaults to the parent test or step's value.
#sanitizeExit: boolean Ensure the test step does not prematurely cause the process to exit,
for example via a call to Deno.exit.
Defaults to the parent test or step's value.
variable Deno.test
Register a test which will be run when deno test is used on the command
line and the containing module looks like a test module.
fn can be async if required.
Tests are discovered before they are executed, so registrations must happen
at module load time.
Nested Deno.test() calls are not supported.
Use t.step() for nested tests.
import { assertEquals } from "jsr:@std/assert";
Deno.test({
name: "example test",
fn() {
assertEquals("world", "world");
},
});
Deno.test({
name: "example ignored test",
ignore: Deno.build.os === "windows",
fn() {
// This test is ignored only on Windows machines
},
});
Deno.test({
name: "example async test",
async fn() {
const decoder = new TextDecoder("utf-8");
const data = await Deno.readFile("hello_world.txt");
assertEquals(decoder.decode(data), "Hello world");
}
});