# 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.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"vitest/valid-describe-callback" = "error" # or "warn"
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 5} */}
```ts
import { describe, test } from "vitest";

describe("cart"); // no callback

describe("cart", "adds an item"); // not a function

describe("cart", (done) => {
  test("adds an item", () => {});
  done();
});

describe("cart", () => {
  return test("adds an item", () => {});
});

describe("cart", () => test("adds an item", () => {})); // returns the result of `test()`
```

Not reported:

{/* good */}
```ts
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:

{/* good */}
```ts
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:

{/* good */}
```ts
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:

{/* bad */}
```ts
import { describe } from "vitest";
import { cartTests } from "./shared";

describe("cart", cartTests);
```
