{"id":"f2bf65cbb5d6727e","repo":"vitest-dev/vitest","slug":"done-callback-is-deprecated-use-promise-instead","errorCode":null,"errorMessage":"done() callback is deprecated, use promise instead","messagePattern":"done\\(\\) callback is deprecated, use promise instead","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/runner/context.ts","lineNumber":163,"sourceCode":"const abortControllers = new WeakMap<TestContext, AbortController>()\n\nexport function abortIfTimeout([context]: [TestContext?, unknown?], error: Error): void {\n  if (context) {\n    abortContextSignal(context, error)\n  }\n}\n\nexport function abortContextSignal(context: TestContext, error: Error): void {\n  const abortController = abortControllers.get(context)\n  abortController?.abort(error)\n}\n\nexport function createTestContext(\n  test: Test,\n  runner: VitestRunner,\n): TestContext {\n  const context = function () {\n    throw new Error('done() callback is deprecated, use promise instead')\n  } as unknown as WriteableTestContext\n\n  let abortController = abortControllers.get(context)\n\n  if (!abortController) {\n    abortController = new AbortController()\n    abortControllers.set(context, abortController)\n  }\n\n  context.signal = abortController.signal\n  context.task = test\n\n  context.skip = (condition?: boolean | string, note?: string): never => {\n    if (condition === false) {\n      // do nothing\n      return undefined as never\n    }\n    test.result ??= { state: 'skip' }","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/runner/context.ts#L145-L181","documentation":"The test context object is itself a callable function in Vitest. Vitest intentionally throws this error when the context is invoked directly, because the old Node.js/Tapas-style `done()` callback pattern (where you call `done()` to signal test completion) is deprecated. Vitest expects tests to return a Promise or be async instead of calling a completion callback. The error is thrown at context construction time in `createTestContext` (context.ts:162-164).","triggerScenarios":"Writing a test as `test('x', (done) => { doWork(); done(); })` and then invoking the context argument as a function; calling the `TestContext` object directly, e.g. `ctx()` inside a fixture or custom matcher that received the context.","commonSituations":"Migrating from Mocha/Jasmine/Jest done-callback tests to Vitest; third-party libraries that call a context-like argument as a function; legacy test code using `done`-callback style.","solutions":["Convert the test to async/await: `test('x', async () => { await doWork(); })` and remove all `done()` calls.","If `done` is passed to a callback-based API, wrap it: `await new Promise(resolve => apiCall(resolve))` instead of calling `done`.","Ensure no code treats the `TestContext` object as a callable function."],"exampleFix":"// before\ntest('loads data', (done) => {\n  fetchData((err, data) => {\n    expect(data).toBeTruthy()\n    done()\n  })\n})\n// after\ntest('loads data', async () => {\n  const data = await new Promise((resolve, reject) =>\n    fetchData((err, d) => err ? reject(err) : resolve(d))\n  )\n  expect(data).toBeTruthy()\n})","handlingStrategy":"validation","validationCode":"// Ensure test functions are async and never invoke the context as a callable.\n// Lint rule: disallow a parameter named 'done' in test callbacks.\n// eslintrc example: { 'rules': { 'no-restricted-syntax': ['error', { 'selector': \"CallExpression[callee.name='test'][arguments.0.type!='ArrowFunction']\", 'message': 'Use async tests, not done callbacks' }] } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write test callbacks as `async () => {}`.","Never name a test parameter `done`.","When wrapping callback APIs, promisify them instead of using done."],"tags":["deprecated","test-context","done-callback","migration"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}