{"record":{"id":"c2c4ec58586aa014","repo":"jestjs/jest","slug":"jest-concurrent-test-spec-getfullname-must","errorCode":null,"errorMessage":"Jest: concurrent test \"${spec.getFullName()}\" must return a Promise.","messagePattern":"Jest: concurrent test \"(.+?)\" must return a Promise\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-jasmine2/src/jasmineAsyncInstall.ts","lineNumber":220,"sourceCode":"  const concurrentFn = function (\n    specName: Global.TestNameLike,\n    fn: Global.ConcurrentTestFn,\n    timeout?: number,\n  ) {\n    let promise: Promise<unknown> = Promise.resolve();\n\n    const spec = originalFn.call(env, specName, () => promise, timeout);\n    if (env != null && !env.specFilter(spec)) {\n      return spec;\n    }\n\n    try {\n      promise = mutex(() => {\n        const promise = fn();\n        if (isPromise(promise)) {\n          return promise;\n        }\n        throw new Error(\n          `Jest: concurrent test \"${spec.getFullName()}\" must return a Promise.`,\n        );\n      });\n    } catch (error) {\n      promise = Promise.reject(error);\n    }\n    // Avoid triggering the uncaught promise rejection handler in case the test errors before\n    // being awaited on.\n    // eslint-disable-next-line @typescript-eslint/no-empty-function\n    promise.catch(() => {});\n\n    return spec;\n  };\n\n  // eslint-disable-next-line unicorn/consistent-function-scoping\n  const failing = () => {\n    throw new Error(\n      'Jest: `failing` tests are only supported in `jest-circus`.',","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-jasmine2/src/jasmineAsyncInstall.ts#L202-L238","documentation":"Thrown by the concurrent test wrapper in jest-jasmine2 (jasmineAsyncInstall.ts:220) when the body of a concurrent test (it.concurrent / test.concurrent) does not return a Promise. Concurrent tests run through a mutex that awaits the returned value, so a synchronous return is treated as a programming error.","triggerScenarios":"test.concurrent('x', () => { doSyncWork(); }) with no async/return, test.concurrent('x', (done) => { done(); }) using the legacy done callback instead of returning a promise, or test.concurrent('x', () => someSyncResult) where the function returns a plain value.","commonSituations":"Converting a sync test to concurrent without making it async; mixing jest done-style callbacks with concurrent mode; returning undefined from an arrow function whose body is a block; bumping Jest versions where concurrent semantics tightened.","solutions":["Make the body async and return/await: test.concurrent('x', async () => { await doAsyncWork(); }).","If the work is genuinely synchronous, use plain test()/it() instead of test.concurrent().","Replace jest done-callback style with promise-returning async functions when using concurrent.","Add a lint rule banning test.concurrent bodies that are not async functions."],"exampleFix":"// before\ntest.concurrent('sync', () => { compute(); });\n// after\ntest.concurrent('async', async () => { await computeAsync(); });","handlingStrategy":"type-guard","validationCode":"const body = () => doWork();\nif (!body.toString().includes('async') && typeof body() !== 'object') {\n  // sanity check; better to just always use async\n}\ntest.concurrent('x', async () => { await doWork(); });","typeGuard":"const returnsPromise = (fn: (...a: any[]) => unknown): fn is (...a: any[]) => Promise<unknown> =>\n  fn.constructor.name === 'AsyncFunction';","tryCatchPattern":null,"preventionTips":["Always make concurrent test bodies async.","Avoid the done-callback style under concurrent mode.","Use plain test() for synchronous work."],"tags":["jest","concurrent","async","promise","api-misuse"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}