denoland/deno · error · TypeError

before() requires a function argument

Error message

before() requires a function argument

What it means

The module-level before(fn) exported by node:test (BDD-style, also active under describe/it) registers a one-time setup hook — on the current suite in TAP mode, otherwise on the root hooks. The implementation immediately checks typeof fn === 'function' and throws TypeError 'before() requires a function argument' otherwise. This is the module-level hook; the per-test-context variant is t.before (error message without 'argument').

Source

Thrown at ext/node/polyfills/testing.ts:2148

  return prepareDenoTestForSuite(name, options, fn, overrides);
}

suite.skip = function skip(name, options, fn) {
  return suite(name, options, fn, { skip: true });
};
suite.todo = function todo(name, options, fn) {
  return suite(name, options, fn, { todo: true });
};
suite.only = function only(name, options, fn) {
  return suite(name, options, fn, { only: true });
};

const it = test;
const describe = suite;

function before(fn, _options) {
  if (typeof fn !== "function") {
    throw new TypeError("before() requires a function argument");
  }
  if (isTapMode()) {
    const tapSuite = getTapCurrentSuite();
    if (tapSuite !== null) {
      ArrayPrototypePush(tapSuite.beforeAllHooks ??= [], fn);
      return;
    }
    ArrayPrototypePush(rootBeforeHooks, fn);
    // A bare top-level `before()` with no tests must still produce TAP
    // output (`before` runs, then `TAP version 13`, then `1..0`).
    scheduleTapRun();
    return;
  }
  if (currentSuite) {
    ArrayPrototypePush(currentSuite.beforeAllHooks, fn);
    return;
  }
  ArrayPrototypePush(rootBeforeHooks, fn);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass the function reference: before(setupDb)
  2. Wrap expressions that must run later: before(() => init()) — but prefer passing init itself so it is awaited
  3. Check typeof before registering config-driven hooks

Example fix

// before
before(setupDatabase());

// after
before(setupDatabase);
Defensive patterns

Strategy: type-guard

Validate before calling

import { before } from 'node:test';

if (typeof setup !== 'function') {
  throw new TypeError(`before: expected function, got ${typeof setup}`);
}
before(setup);

Type guard

const isHookFn = (fn) => typeof fn === 'function';

if (isHookFn(setup)) {
  before(setup);
}

Prevention

When it happens

Trigger: before() with no argument; before(setup()) passing the result of an immediate call (a value or Promise) instead of the function; before('connect', fn) using a name-first convention from other frameworks.

Common situations: Migrating from frameworks where hooks take a name; refactors that parenthesize the helper; wiring hooks from configuration objects where the entry can be undefined.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/be377a526602c2f9. Report an issue: GitHub.