vitest/valid-describe-callback
Require describe to get a title and a callback with no parameters and no return
Vitest runs the describe callback to collect the tests inside it. Without a callback there's nothing to collect. The callback isn't a test, so it has no done to call, and returning the result of test() from it does nothing.
Configure#
Off by default. To turn it on:
bunfig.toml
[lint.rules]
"vitest/valid-describe-callback" = "error" # or "warn"Examples#
example.ts5 problems
import { describe, test } from "vitest";
describe("cart"Describe requires name and callback arguments); // no callback
describe("cart", "adds an item"Second argument must be a function); // not a function
describe("cart", (done) => {Unexpected argument(s) in describe callback
test("adds an item", () => {});
done();
});
describe("cart", () => {
return test("adds an item", () => {});Unexpected return statement in describe callback
});
describe("cart", () => test("adds an item", () => {})Unexpected return statement in describe callback); // returns the result of `test()`example.tsNo problems
import { describe, expect, test } from "vitest";
describe("cart", () => {
test("adds an item", () => {
expect(add(item).length).toBe(1);
});
});An async callback is allowed. Options can come before the callback, and describe.todo only needs a title:
example.tsNo problems
import { describe, expect, test } from "vitest";
describe("checkout", async () => {
const rates = await loadRates();
test("adds the tax", () => {
expect(total(100, rates)).toBe(108);
});
});
describe("search", { timeout: 10_000 }, () => {
test("finds the item", () => {});
});
describe.todo("refunds");The callback of describe.each and describe.for gets the values of a row, so it can have parameters:
example.tsNo problems
import { describe, expect, test } from "vitest";
describe.each([1, 2, 3])("cart with %i items", (count) => {
test("counts them", () => {
expect(fill(count).length).toBe(count);
});
});
describe.for(["USD", "EUR"])("prices in %s", (currency) => {
test("formats the total", () => {
expect(format(108, currency)).toContain(currency);
});
});When not to use it#
The rule only looks at the call, so a callback passed by name is reported as not being a function. Turn the rule off if you share groups of tests that way:
example.ts1 problem
import { describe } from "vitest";
import { cartTests } from "./shared";
describe("cart", cartTestsSecond argument must be a function);