{"record":{"id":"964b316731e0b9c2","repo":"denoland/deno","slug":"before-requires-a-function","errorCode":null,"errorMessage":"before() requires a function","messagePattern":"before\\(\\) requires a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/testing.ts","lineNumber":1606,"sourceCode":"  // which are commonly not awaited (e.g. fastify's suites), still run to\n  // completion before the parent test settles.\n  async _drainSubtests() {\n    if (this.#subtestPromises.length === 0) return;\n    const promises = ArrayPrototypeSplice(\n      this.#subtestPromises,\n      0,\n      this.#subtestPromises.length,\n    );\n    for (const p of new SafeArrayIterator(promises)) {\n      try {\n        await p;\n      } catch { /* failures already reported through the subtest's own step */ }\n    }\n  }\n\n  before(fn, _options) {\n    if (typeof fn !== \"function\") {\n      throw new TypeError(\"before() requires a function\");\n    }\n    ArrayPrototypePush(this.#beforeHooks, fn);\n  }\n\n  after(fn, _options) {\n    if (typeof fn !== \"function\") {\n      throw new TypeError(\"after() requires a function\");\n    }\n    ArrayPrototypePush(this.#afterHooks, fn);\n  }\n\n  beforeEach(fn, _options) {\n    if (typeof fn !== \"function\") {\n      throw new TypeError(\"beforeEach() requires a function\");\n    }\n    ArrayPrototypePush(this.#beforeEachHooks, fn);\n  }\n","sourceCodeStart":1588,"sourceCodeEnd":1624,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/testing.ts#L1588-L1624","documentation":"The node:test context exposes t.before(fn) to register a hook that runs once before this test's subtests. It stores fn in an internal hooks array and requires it to be a function; anything else (including undefined or the result of calling a function) throws TypeError 'before() requires a function'.","triggerScenarios":"t.before() with no argument; t.before({ timeout: 1000 }, hook) with arguments in the wrong order (signature is (fn, options)); t.before(initDb()) passing a Promise instead of the function.","commonSituations":"Calling the setup function instead of referencing it; options-first habit carried over from other hook APIs; wiring hooks from config where the value can be undefined.","solutions":["Pass the function reference: t.before(initDb)","Keep argument order (fn, options) — options are the second parameter","For async setup, pass the async function itself so the runner can await it"],"exampleFix":"// before\nt.before({ timeout: 1000 }, connectDb);\n\n// after\nt.before(connectDb, { timeout: 1000 });","handlingStrategy":"type-guard","validationCode":"if (typeof hook !== 'function') {\n  throw new TypeError(`t.before: expected function, got ${typeof hook}`);\n}\nt.before(hook, { timeout: 1000 });","typeGuard":"const isHookFn = (fn) => typeof fn === 'function';\n\nif (isHookFn(setup)) {\n  t.before(setup);\n}","tryCatchPattern":null,"preventionTips":["Pass the function reference, never its invocation result","Hook signature is (fn, options) — options come second","For async setup, pass the async function itself so the runner awaits it","Guard config-driven hook wiring with a typeof check"],"tags":["node-test","hooks","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-14T00:17:10.932Z"}