Skip to content
NewBun 1.4.5 is out. Release notes
AphrodyBun

Linter · Rules

vitest/expect-expect

Require every test to make at least one assertion

A test with no assertion passes as long as the code doesn't throw, whether the result is right or wrong. Usually someone forgot the expect, or lost it while changing the test.

Calls to expect, expectTypeOf, assert and assertType count as assertions. test.todo and test.skip aren't checked.

Configure

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"vitest/expect-expect" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"vitest/expect-expect" = ["error", {
  assertFunctionNames = ["expect", "expectTypeOf", "assert", "assertType"],
  additionalTestBlockFunctions = [], # list of strings
}]

Examples

Reported:

import { test } from "vitest";

test("parses the port", () => {
  parseConfig("port = 3000");
});

Not reported:

import { assert, expect, test } from "vitest";

test("parses the port", () => {
  expect(parseConfig("port = 3000")).toEqual({ port: 3000 });
});

test("parses the host", () => {
  assert.equal(parseConfig("host = localhost").host, "localhost");
});

test.todo("rejects a negative port");

test.skip("reads the file", () => {
  readConfig("app.conf");
});

Options

OptionDefaultWhat it does
assertFunctionNames["expect", "expectTypeOf", "assert", "assertType"]The functions that count as an assertion. Your list replaces the default, so keep "expect" in it.
additionalTestBlockFunctions[]Other Vitest functions to check like test, such as "afterEach".

assertFunctionNames

The rule doesn't look inside the helpers that a test calls. This test is reported even though checkUser calls expect:

import { expect, test } from "vitest";

function checkUser(user) {
  expect(user.id).toBeGreaterThan(0);
}

test("creates a user", () => {
  checkUser(createUser());
});

Add the helper's name and the test is no longer reported:

bunfig.toml
[lint.rules]
"vitest/expect-expect" = ["error", {
  assertFunctionNames = ["expect", "checkUser"],
}]
import { expect, test } from "vitest";

function checkUser(user) {
  expect(user.id).toBeGreaterThan(0);
}

test("creates a user", () => {
  checkUser(createUser());
});

A name can be a chain, such as request.get.expect. * matches any letters and digits in one part of the chain, and ** matches one or more parts. Case is ignored.

With "request.**.expect" in the list, this isn't reported:

import { test } from "vitest";

test("is healthy", async () => {
  await request(app).get("/health").expect(200);
});

additionalTestBlockFunctions

This option only works for functions that come from Vitest. With ["afterEach"], this is reported:

import { afterEach } from "vitest";

afterEach(() => {
  closeDatabase();
});

Your own wrappers aren't checked, even if you list them. With ["testWithDatabase"], this isn't reported:

import { afterAll } from "vitest";
import { closeDatabase, testWithDatabase } from "./helpers";

afterAll(closeDatabase);

testWithDatabase("saves the user", (db) => {
  db.save(createUser());
});