jest/prefer-expect-assertions
Require expect.assertions() or expect.hasAssertions() at the start of every test
An expect in a catch, a callback or a loop might never run, and a test where no expect runs still passes. expect.hasAssertions() makes the test fail unless at least one assertion ran. expect.assertions(2) makes it fail unless exactly two ran.
The first statement in every test must be one of the two. The rule also reports expect.hasAssertions() with an argument, and expect.assertions() with anything other than one number literal.
--fix-suggestions adds expect.hasAssertions().
Configure#
Off by default. To turn it on:
[lint.rules]
"jest/prefer-expect-assertions" = "error" # or "warn"Every option, set to its default:
[lint.rules]
"jest/prefer-expect-assertions" = ["error", {
onlyFunctionsWithAsyncKeyword = false,
onlyFunctionsWithExpectInCallback = false,
onlyFunctionsWithExpectInLoop = false,
}]Examples#
import { expect, test } from "@jest/globals";
test("rejects a wrong password", async () => {Every test should have either expect.assertions(<number of assertions>) or expect.hasAssertions() as its first expression.
try {
await login("ada", "wrong");
} catch (error) {
expect(error).toBeInstanceOf(AuthError);
}
});import { expect, test } from "@jest/globals";
test("adds", () => {
expect.assertions("1"This argument should be a number.);
expect(1 + 1).toBe(2);
});import { expect, test } from "@jest/globals";
test("rejects a wrong password", async () => {
expect.assertions(1);
try {
await login("ada", "wrong");
} catch (error) {
expect(error).toBeInstanceOf(AuthError);
}
});A beforeEach or afterEach hook that calls expect.hasAssertions() covers the tests after it in the same describe, or in the rest of the file if it's at the top level:
import { beforeEach, expect, test } from "@jest/globals";
beforeEach(() => {
expect.hasAssertions();
});
test("adds", () => {
expect(1 + 1).toBe(2);
});Options#
Without options, every test is checked. If you turn on one or more options, only the tests that match at least one of them are checked.
| Option | Default | What it does |
|---|---|---|
onlyFunctionsWithAsyncKeyword | false | Check tests that are async functions. |
onlyFunctionsWithExpectInCallback | false | Check tests that call expect inside a nested function. |
onlyFunctionsWithExpectInLoop | false | Check tests that call expect inside a loop. |
{ "onlyFunctionsWithExpectInCallback": true }1 problemimport { expect, test } from "@jest/globals";
test("emits the saved user", () => {Every test should have either expect.assertions(<number of assertions>) or expect.hasAssertions() as its first expression.
store.on("save", (user) => {
expect(user.name).toBe("Ada");
});
store.save({ name: "Ada" });
});{ "onlyFunctionsWithExpectInCallback": true }No problemsimport { expect, test } from "@jest/globals";
test("adds", () => {
expect(1 + 1).toBe(2);
});When not to use it#
In a test that only calls expect at its top level, the extra line adds nothing. Use the options to check only the tests where an assertion can be skipped.