On this page
Test sanitizers
The deno test runner offers several sanitizers
that catch tests misbehaving in ways assertions don't see: leaking async
operations, unclosed resources, and unexpected process exits.
Resource sanitizer Jump to heading
The resource sanitizer ensures that all I/O resources created during a test are closed, to prevent leaks.
I/O resources are things like Deno.FsFile handles,
network connections, fetch bodies, timers, and other
resources that are not automatically garbage collected.
You should always close resources when you are done with them. For example, to close a file:
const file = await Deno.open("hello.txt");
// Do something with the file
file.close(); // <- Always close the file when you are done with it
To close a network connection:
const conn = await Deno.connect({ hostname: "example.com", port: 80 });
// Do something with the connection
conn.close(); // <- Always close the connection when you are done with it
To close a fetch body:
const response = await fetch("https://example.com");
// Do something with the response
await response.body?.cancel(); // <- Always cancel the body when you are done with it, if you didn't consume it otherwise
As of Deno 2.8 this sanitizer is off by default. Opt in with
sanitizeResources: true, or with one of the global mechanisms described in
Enabling sanitizers globally.
Deno.test({
name: "no leaks allowed",
async fn() {
using file = await Deno.open("hello.txt");
// ...
},
sanitizeResources: true,
});
Async operation sanitizer Jump to heading
The async operation sanitizer ensures that all async operations started in a test are completed before the test ends. This is important because if an async operation is not awaited, the test will end before the operation is completed, and the test will be marked as successful even if the operation may have actually failed.
You should always await all async operations in your tests. For example:
Deno.test({
name: "async operation test",
async fn() {
await new Promise((resolve) => setTimeout(resolve, 1000));
},
});
As of Deno 2.8 this sanitizer is off by default. Opt in with
sanitizeOps: true, or with one of the global mechanisms described below.
Deno.test({
name: "no leaked ops allowed",
async fn() {
await someAsyncWork();
},
sanitizeOps: true,
});
Enabling sanitizers globally Jump to heading
If you want the pre-2.8 behavior (resource and op sanitizers on for every test), you can re-enable them at any of five scopes. Higher-precedence settings override lower ones.
-
Per-test (highest precedence):
Deno.test({ name: "strict", sanitizeOps: true, sanitizeResources: true, fn() {/* … */}, }); -
Per-module with
Deno.test.sanitizer():Deno.test.sanitizer({ ops: true, resources: true }); Deno.test("uses module-level sanitizers", () => {/* … */}); -
CLI flags:
--sanitize-opsand--sanitize-resources. -
Environment variables:
DENO_TEST_SANITIZE_OPS=1andDENO_TEST_SANITIZE_RESOURCES=1. -
deno.json(lowest precedence):{ "test": { "sanitizeOps": true, "sanitizeResources": true } }
Exit sanitizer Jump to heading
The exit sanitizer ensures that tested code doesn’t call
Deno.exit(), which could signal a false test success.
This sanitizer is enabled by default, but can be disabled with
sanitizeExit: false.
Deno.test({
name: "false success",
fn() {
Deno.exit(0);
},
sanitizeExit: false,
});
// This test never runs, because the process exits during "false success" test
Deno.test({
name: "failing test",
fn() {
throw new Error("this test fails");
},
});