deno test: run tests in Deno and filter a single test
- tool
- Deno
- versions
- Deno 2.x
- os
- any
deno test finds the test files in the current folder and its subfolders, type-checks them and runs every Deno.test() case, then prints a summary and exits with code 1 if any test failed. No test framework has to be installed: the runner, assertions (@std/assert from JSR) and coverage are part of Deno. deno test --filter "name" runs only the tests whose name matches.
Write and run tests
cat > math.ts <<'EOF'
export const add = (a: number, b: number): number => a + b;
EOF
cat > math_test.ts <<'EOF'
import { add } from "./math.ts";
Deno.test("add returns the sum", () => {
if (add(1, 2) !== 3) throw new Error("expected 3");
});
Deno.test("add handles negatives", () => {
if (add(-2, 2) !== 1) throw new Error("expected 1");
});
EOF
export NO_COLOR=1
npx --yes deno@2 test 2>&1 | sed -E 's/ \([0-9.]+(µs|ms|s)\)//; /^ at /d'
exit "${PIPESTATUS[0]}"Output · exit 1
Check math_test.ts
running 2 tests from ./math_test.ts
add returns the sum ... ok
add handles negatives ... FAILED
ERRORS
add handles negatives => ./math_test.ts:7:6
error: Error: expected 1
if (add(-2, 2) !== 1) throw new Error("expected 1");
^
FAILURES
add handles negatives => ./math_test.ts:7:6
FAILED | 1 passed | 1 failed
error: Test failedThe second test is wrong on purpose. Deno prints each test with ok or FAILED, then an ERRORS section with the thrown error and its location, a FAILURES list and the totals; the command exits with code 1. The example runs Deno through npx deno@2 so it needs only Node.js; with Deno installed the command is just deno test.
Run one test with --filter
cat > math_test.ts <<'EOF'
Deno.test("add returns the sum", () => {});
Deno.test("add handles negatives", () => {});
Deno.test("subtract", () => {});
EOF
export NO_COLOR=1
npx --yes deno@2 test --filter "negatives" 2>&1 | sed -E 's/ \([0-9.]+(µs|ms|s)\)//'Output
Check math_test.ts running 1 test from ./math_test.ts add handles negatives ... ok ok | 1 passed | 0 failed | 2 filtered out
Tests that do not match are counted as filtered out, not as passed. Use --filter "/^add/" for a regular expression.
Common options
| Command | What it does |
|---|---|
| deno test | Run every test file under the current folder |
| deno test src/math_test.ts | Run one file (or pass a folder) |
| deno test --filter "name" | Only tests whose name contains the text; /regex/ for a pattern |
| deno test --allow-read --allow-net | Grant permissions; tests start with none, like deno run |
| deno test --watch | Re-run tests when files change |
| deno test --coverage=cov | Collect coverage, then show it with deno coverage cov |
| deno test --fail-fast | Stop after the first failing test |
| deno test --parallel | Run test files in parallel worker processes |
| deno test --no-check | Skip type-checking to start faster |
| deno test --doc | Also evaluate code blocks in JSDoc comments and Markdown files |
Pitfalls
- Permissions. A test that reads a file or opens a socket fails with
NotCapableunless you pass the matching--allow-*flag; see Requires read access. - Type errors stop the run.
deno testtype-checks local test files first, so a type error fails before any test runs.--no-checkskips it, at the cost of catching those errors later. - Leaks. Deno checks that each test closes the timers, files and network resources it opens, and fails the test with a leak report when it does not. Await your promises and close what you open.
- File names. A file called
math.spec.tsis not picked up automatically; name itmath_test.tsormath.test.ts, or pass it explicitly.
How to confirm it worked
The last line shows ok or FAILED with the number of passed, failed and filtered tests, and echo $? after the command prints 0 only when every test passed. In CI, that exit code is all you need. Format and lint checks fit in the same job: deno fmt --check and deno lint.
FAQ
Why does deno test fail with a permission error when deno run works?
Tests run with no permissions unless you grant them, exactly like deno run. If the command you use for the program has --allow-read or --allow-net, add the same flags to deno test, or set permissions for one test with the permissions option of Deno.test.
How do I run only one test?
Pass --filter with the test name, or a /regex/ between slashes. For a temporary focus inside the file, use Deno.test.only or Deno.test({ only: true, ... }); deno test then reports a failure at the end so the focus is not committed by accident.
Where does deno test look for test files?
Without arguments it searches the current folder recursively for files named *_test, *.test or test with a .ts, .tsx, .mts, .js, .mjs, .jsx or .cjs extension. Pass files or folders to limit it, and use the test.include and test.exclude keys of deno.json to change the defaults.