assert.throws(fn[, error][, message])


期望 fn 函数抛出错误。

如果指定,则 error 可以是 ClassRegExp、验证函数,每个属性将被测试严格的深度相等的验证对象、或每个属性(包括不可枚举的 messagename 属性)将被测试严格的深度相等的错误实例。 使用对象时,还可以在对字符串属性进行验证时使用正则表达式。 请参见下面的示例。

如果指定 message,则当 fn 调用无法抛出或错误验证失败时, message 将附加到 AssertionError 提供的消息。

自定义的验证对象/错误实例:

const err = new TypeError('错误值');
err.code = 404;
err.foo = 'bar';
err.info = {
  nested: true,
  baz: 'text'
};
err.reg = /abc/i;

assert.throws(
  () => {
    throw err;
  },
  {
    name: 'TypeError',
    message: '错误值',
    info: {
      nested: true,
      baz: 'text'
    }
    // 仅测试验证对象上的属性。
    // 使用嵌套对象需要存在所有属性。
    // 否则验证将失败。
  }
);

// 使用正则表达式验证错误属性:
assert.throws(
  () => {
    throw err;
  },
  {
    // `name` 和 `message` 属性是字符串,使用正则表达式将匹配字符串。 
    // 如果失败,则会抛出错误。
    name: /^TypeError$/,
    message: /错误/,
    foo: 'bar',
    info: {
      nested: true,
      // 无法对嵌套属性使用正则表达式!
      baz: 'text'
    },
    // `reg` 属性包含一个正则表达式,
    // 并且只有当验证对象包含相同的正则表达式时,
    // 它才会通过。
    reg: /abc/i
  }
);

// 由于 `message` 和 `name` 属性不同而失败:
assert.throws(
  () => {
    const otherErr = new Error('未找到');
    // 将所有可枚举的属性从 `err` 拷贝到 `otherErr`。
    for (const [key, value] of Object.entries(err)) {
      otherErr[key] = value;
    }
    throw otherErr;
  },
  // 当使用错误作为验证对象时,也会检查错误的 `message`  和 `name` 属性。
  err
);

使用构造函数验证 instanceof:

assert.throws(
  () => {
    throw new Error('错误值');
  },
  Error
);

使用 RegExp 验证错误消息:

使用正则表达式在错误对象上运行 .toString,因此也将包含错误名称。

assert.throws(
  () => {
    throw new Error('错误值');
  },
  /^Error: 错误值$/
);

自定义的错误验证函数:

该函数必须返回 true,以表明已通过所有的内部验证。 否则它将会失败并带上 AssertionError

assert.throws(
  () => {
    throw new Error('错误值');
  },
  (err) => {
    assert(err instanceof Error);
    assert(/value/.test(err));
    // 避免从验证函数返回 `true` 以外的任何东西。 
    // 否则,会不清楚验证的哪一部分失败。 
    // 应该抛出有关失败的特定验证的错误(如本例所示),并向该错误添加尽可能多的有用的调试信息。
    return true;
  },
  '不是期望的错误'
);

error 不能是字符串。 如果提供了一个字符串作为第二个参数,则假定 error 被忽略,而字符串将用于 message。 这可能导致容易错过的错误。 使用与抛出的错误消息相同的消息将导致 ERR_AMBIGUOUS_ARGUMENT 错误。 如果使用字符串作为第二个参数,请仔细阅读下面的示例:

function throwingFirst() {
  throw new Error('错误一');
}

function throwingSecond() {
  throw new Error('错误二');
}

function notThrowing() {}

// 第二个参数是一个字符串,输入函数抛出一个错误。
// 第一种情况不会抛出,因为它与输入函数抛出的错误消息不匹配!
assert.throws(throwingFirst, '错误二');
// 在下一个示例中,传入的消息类似来自错误的消息,
// 并且由于不清楚用户是否打算实际匹配错误消息,
// 因此 Node.js 抛出了 `ERR_AMBIGUOUS_ARGUMENT` 错误。
assert.throws(throwingSecond, '错误二');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// 该字符串仅在函数未抛出时使用(作为消息):
assert.throws(notThrowing, '错误二');
// AssertionError [ERR_ASSERTION]: Missing expected exception: 错误二

// 如果要匹配错误消息,请执行以下操作:
// 它不会抛出错误,因为错误消息匹配。
assert.throws(throwingSecond, /错误二$/);

// 如果错误消息不匹配,则抛出 AssertionError。
assert.throws(throwingFirst, /错误二$/);
// AssertionError [ERR_ASSERTION]

由于令人困惑的表示法,建议不要使用字符串作为第二个参数。 这可能会导致难以发现的错误。

Expects the function fn to throw an error.

If specified, error can be a Class, RegExp, a validation function, a validation object where each property will be tested for strict deep equality, or an instance of error where each property will be tested for strict deep equality including the non-enumerable message and name properties. When using an object, it is also possible to use a regular expression, when validating against a string property. See below for examples.

If specified, message will be appended to the message provided by the AssertionError if the fn call fails to throw or in case the error validation fails.

Custom validation object/error instance:

const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
  nested: true,
  baz: 'text'
};
err.reg = /abc/i;

assert.throws(
  () => {
    throw err;
  },
  {
    name: 'TypeError',
    message: 'Wrong value',
    info: {
      nested: true,
      baz: 'text'
    }
    // Only properties on the validation object will be tested for.
    // Using nested objects requires all properties to be present. Otherwise
    // the validation is going to fail.
  }
);

// Using regular expressions to validate error properties:
assert.throws(
  () => {
    throw err;
  },
  {
    // The `name` and `message` properties are strings and using regular
    // expressions on those will match against the string. If they fail, an
    // error is thrown.
    name: /^TypeError$/,
    message: /Wrong/,
    foo: 'bar',
    info: {
      nested: true,
      // It is not possible to use regular expressions for nested properties!
      baz: 'text'
    },
    // The `reg` property contains a regular expression and only if the
    // validation object contains an identical regular expression, it is going
    // to pass.
    reg: /abc/i
  }
);

// Fails due to the different `message` and `name` properties:
assert.throws(
  () => {
    const otherErr = new Error('Not found');
    // Copy all enumerable properties from `err` to `otherErr`.
    for (const [key, value] of Object.entries(err)) {
      otherErr[key] = value;
    }
    throw otherErr;
  },
  // The error's `message` and `name` properties will also be checked when using
  // an error as validation object.
  err
);

Validate instanceof using constructor:

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  Error
);

Validate error message using RegExp:

Using a regular expression runs .toString on the error object, and will therefore also include the error name.

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  /^Error: Wrong value$/
);

Custom error validation:

The function must return true to indicate all internal validations passed. It will otherwise fail with an AssertionError.

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  (err) => {
    assert(err instanceof Error);
    assert(/value/.test(err));
    // Avoid returning anything from validation functions besides `true`.
    // Otherwise, it's not clear what part of the validation failed. Instead,
    // throw an error about the specific validation that failed (as done in this
    // example) and add as much helpful debugging information to that error as
    // possible.
    return true;
  },
  'unexpected error'
);

error cannot be a string. If a string is provided as the second argument, then error is assumed to be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Using the same message as the thrown error message is going to result in an ERR_AMBIGUOUS_ARGUMENT error. Please read the example below carefully if using a string as the second argument gets considered:

function throwingFirst() {
  throw new Error('First');
}

function throwingSecond() {
  throw new Error('Second');
}

function notThrowing() {}

// The second argument is a string and the input function threw an Error.
// The first case will not throw as it does not match for the error message
// thrown by the input function!
assert.throws(throwingFirst, 'Second');
// In the next example the message has no benefit over the message from the
// error and since it is not clear if the user intended to actually match
// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// The string is only used (as message) in case the function does not throw:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second

// If it was intended to match for the error message do this instead:
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);

// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]

Due to the confusing error-prone notation, avoid a string as the second argument.