{"record":{"id":"48bd59f433f51954","repo":"denoland/deno","slug":"aftereach-requires-a-function-argument","errorCode":null,"errorMessage":"afterEach() requires a function argument","messagePattern":"afterEach\\(\\) requires a function argument","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/testing.ts","lineNumber":2203,"sourceCode":"    return;\n  }\n  ArrayPrototypePush(rootAfterHooks, fn);\n}\n\nfunction beforeEach(fn, _options) {\n  if (typeof fn !== \"function\") {\n    throw new TypeError(\"beforeEach() requires a function argument\");\n  }\n  if (currentSuite) {\n    ArrayPrototypePush(currentSuite.beforeEachHooks, fn);\n    return;\n  }\n  ArrayPrototypePush(rootBeforeEachHooks, fn);\n}\n\nfunction afterEach(fn, _options) {\n  if (typeof fn !== \"function\") {\n    throw new TypeError(\"afterEach() requires a function argument\");\n  }\n  if (currentSuite) {\n    ArrayPrototypePush(currentSuite.afterEachHooks, fn);\n    return;\n  }\n  ArrayPrototypePush(rootAfterEachHooks, fn);\n}\n\ntest.it = test;\ntest.describe = suite;\ntest.suite = suite;\ntest.before = before;\ntest.after = after;\ntest.beforeEach = beforeEach;\ntest.afterEach = afterEach;\ntest.getTestContext = getTestContext;\n\nconst activeMocks = [];","sourceCodeStart":2185,"sourceCodeEnd":2221,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/testing.ts#L2185-L2221","documentation":"The module-level afterEach(fn) from node:test registers a hook run after each test in the current describe block, or on the root hooks outside any suite. Its implementation requires a function as the first argument and throws TypeError 'afterEach() requires a function argument' for any other value.","triggerScenarios":"afterEach() with no argument; afterEach(cleanup()) passing a value/Promise instead of the function; argument order swapped with options.","commonSituations":"Parenthesized helpers after refactors; conditional teardowns that end up undefined; migrating from other test frameworks' hook signatures.","solutions":["Pass the function reference: afterEach(dropRows)","Guard optional teardowns: if (cleanup) afterEach(cleanup)","Keep the (fn, options) argument order"],"exampleFix":"// before\nafterEach(truncateTables());\n\n// after\nafterEach(truncateTables);","handlingStrategy":"type-guard","validationCode":"import { afterEach } from 'node:test';\n\nif (typeof cleanup !== 'function') {\n  throw new TypeError(`afterEach: expected function, got ${typeof cleanup}`);\n}\nafterEach(cleanup);","typeGuard":"const isHookFn = (fn) => typeof fn === 'function';\n\nif (isHookFn(cleanup)) {\n  afterEach(cleanup);\n}","tryCatchPattern":null,"preventionTips":["Pass the cleanup function itself, never a called return value","Keep the (fn, options) argument order","Skip registration instead of passing undefined for optional cleanups"],"tags":["node-test","hooks","bdd","api-misuse"],"backgroundTag":"test-hook-requires-function","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}