denoland/deno · error · TypeError

Expected the second argument to assertSnapshot() to be an…

Error message

Expected the second argument to assertSnapshot() to be an options object or a message string

What it means

Deno.TestContext.assertSnapshot(actual, options?) accepts as its second user-visible argument either an options object ({ name, msg, serializer, dir, path }) or, as a legacy convenience, a plain message string (cli/js/40_test_snapshot.js). Anything else — a number, boolean, null, or a function — throws this TypeError at call time. The message says "second argument" because the test context is the method receiver, so from the caller's seat the options are the second argument after `actual`.

Solutions

  1. Pass an options object: `await t.assertSnapshot(value, { name: "render" })`.
  2. Or pass a message string: `await t.assertSnapshot(value, "renders correctly")`.
  3. Wrap custom serializers: `t.assertSnapshot(value, { serializer: mySerializer })`, not `t.assertSnapshot(value, mySerializer)`.
  4. Omit the argument entirely if no options are needed.

Example fix

// before
await t.assertSnapshot(result, 5);
await t.assertSnapshot(result, mySerializer);

// after
await t.assertSnapshot(result, { name: "result" });
await t.assertSnapshot(result, { serializer: mySerializer });
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof opts !== "undefined" && !isValidSnapshotOptions(opts)) {
  throw new Error("assertSnapshot options must be an object or a message string");
}
await t.assertSnapshot(value, opts);

Type guard

/** @param {unknown} o @returns {o is string | Record<string, unknown>} */
function isValidSnapshotOptions(o) {
  return typeof o === "string" || (typeof o === "object" && o !== null);
}

Prevention

When it happens

Trigger: Calling `await t.assertSnapshot(value, 5)`, `t.assertSnapshot(value, null)`, or passing a serializer function directly (`t.assertSnapshot(value, mySerializer)`) instead of an options object (`{ serializer: mySerializer }`).

Common situations: Refactoring from std/testing snapshot APIs with different signatures; passing a message that ends up non-string (e.g. a template variable); passing null explicitly as 'no options'.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at cli/js/40_test_snapshot.js:319

}

function getErrorMessage(message, options) {
  return typeof options.msg === "string" ? options.msg : message;
}

/**
 * Implementation of `Deno.TestContext.assertSnapshot()`. `tContext` is the
 * test context object the method was called on.
 */
export function assertSnapshot(
  tContext,
  actual,
  options = { __proto__: null },
) {
  if (typeof options === "string") {
    options = { __proto__: null, msg: options };
  } else if (typeof options !== "object" || options === null) {
    throw new TypeError(
      "Expected the second argument to assertSnapshot() to be an options object or a message string",
    );
  }

  const context = getSnapshotContext(options);
  const testName = options.name ?? getFullTestName(tContext);
  const count = (MapPrototypeGet(context.counts, testName) ?? 0) + 1;
  MapPrototypeSet(context.counts, testName, count);
  const name = `${testName} ${count}`;

  if (!ArrayPrototypeIncludes(context.updateQueue, name)) {
    ArrayPrototypePush(context.updateQueue, name);
  }

  const serializer = options.serializer ?? serialize;
  const actualSnapshot = serializer(actual);
  if (typeof actualSnapshot !== "string") {
    throw new TypeError("Snapshot serializer must return a string");

View on GitHub (pinned to 9ad36f7a2c)