{"id":"be95985854b098e1","repo":"jestjs/jest","slug":"package-pkg-name-declares-jest-test-utils","errorCode":null,"errorMessage":"Package '${pkg.name}' declares '@jest/test-utils' as dependency, but it must be declared as dev dependency","messagePattern":"Package '(.+?)' declares '@jest/test-utils' as dependency, but it must be declared as dev dependency","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/buildTs.mjs","lineNumber":104,"sourceCode":"    const references = tsConfig.references.map(({path}) => path);\n\n    assert.deepStrictEqual(\n      references,\n      jestDependenciesOfPackage,\n      `Expected declared references to match dependencies in package ${\n        pkg.name\n      }. Got:\\n\\n${references.join(\n        '\\n',\n      )}\\nExpected:\\n\\n${jestDependenciesOfPackage.join('\\n')}`,\n    );\n  }\n\n  let hasJestTestUtils = Object.keys(pkg.dependencies || {}).includes(\n    '@jest/test-utils',\n  );\n\n  if (hasJestTestUtils) {\n    throw new Error(\n      chalk.red(\n        `Package '${pkg.name}' declares '@jest/test-utils' as dependency, but it must be declared as dev dependency`,\n      ),\n    );\n  }\n\n  hasJestTestUtils = Object.keys(pkg.devDependencies || {}).includes(\n    '@jest/test-utils',\n  );\n\n  const tsConfigPaths = glob.sync('**/__tests__/tsconfig.json', {\n    absolute: true,\n    cwd: packageDir,\n  });\n\n  const testUtilsReferences = tsConfigPaths.filter(tsConfigPath => {\n    const tsConfig = JSON.parse(\n      stripJsonComments(fs.readFileSync(tsConfigPath, 'utf8')),","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/scripts/buildTs.mjs#L86-L122","documentation":"scripts/buildTs.mjs lints each monorepo package: @jest/test-utils is a test-only helper and must never ship as a runtime dependency. At buildTs.mjs:99-109 it checks pkg.dependencies for '@jest/test-utils'; if present (and it should never be), it throws. This keeps test utilities out of the published dependency graph.","triggerScenarios":"Running the TS build/validate script after someone added \"@jest/test-utils\" under `dependencies` (instead of `devDependencies`) in a package's package.json.","commonSituations":"Auto-generating a package.json that merged all requires into dependencies; copy-pasting a dependency entry into the wrong block; tooling that doesn't distinguish dep vs devDep.","solutions":["Move \"@jest/test-utils\": \"...\" from `dependencies` to `devDependencies` in the offending package's package.json.","Re-run scripts/buildTs.mjs to confirm the lint passes.","Audit CI to reject @jest/test-utils in the dependencies block going forward."],"exampleFix":"// before (package.json)\n\"dependencies\": { \"@jest/test-utils\": \"workspace:*\" }\n// after\n\"devDependencies\": { \"@jest/test-utils\": \"workspace:*\" }","handlingStrategy":"validation","validationCode":"function assertTestUtilsNotInDeps(pkg) {\n  const deps = Object.keys(pkg.dependencies || {});\n  if (deps.includes('@jest/test-utils')) {\n    throw new Error(`${pkg.name}: move @jest/test-utils to devDependencies`);\n  }\n}","typeGuard":"function isTestUtilsOnlyDevDep(pkg): boolean {\n  return !Object.keys(pkg.dependencies || {}).includes('@jest/test-utils');\n}","tryCatchPattern":null,"preventionTips":["Always place @jest/test-utils under devDependencies, never dependencies.","Add a package.json lint rule (or CI check) that rejects @jest/test-utils in the dependencies block.","When scaffolding new packages, start from a template that puts test-only helpers in devDependencies."],"tags":["build","monorepo","package-json","lint","test-utils"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}