diff --git a/docs/08-common-pitfalls.md b/docs/08-common-pitfalls.md index e95e298de..9ee2330d2 100644 --- a/docs/08-common-pitfalls.md +++ b/docs/08-common-pitfalls.md @@ -4,6 +4,18 @@ Translations: [Français](https://github.com/avajs/ava-docs/blob/main/fr_FR/docs If you use [ESLint](https://eslint.org), you can install [eslint-plugin-ava](https://github.com/avajs/eslint-plugin-ava). It will help you use AVA correctly and avoid some common pitfalls. +## Error edge cases + +The `throws()` and `throwsAsync()` assertions use the Node.js built-in [`isNativeError()`](https://nodejs.org/api/util.html#utiltypesisnativeerrorvalue) to determine whether something is an error. This only recognizes actual instances of `Error` (and subclasses). + +Note that the following is not a native error: + +```js +const error = Object.create(Error.prototype); +``` + +This can be surprising, since `error instanceof Error` returns `true`. + ## AVA in Docker If you run AVA in Docker as part of your CI, you need to fix the appropriate environment variables. Specifically, adding `-e CI=true` in the `docker exec` command. See [#751](https://github.com/avajs/ava/issues/751). diff --git a/lib/assert.js b/lib/assert.js index 3d179b039..a1cd1c661 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -1,5 +1,6 @@ +import {isNativeError} from 'node:util/types'; + import concordance from 'concordance'; -import isError from 'is-error'; import isPromise from 'is-promise'; import concordanceOptions from './concordance-options.js'; @@ -163,7 +164,7 @@ function validateExpectations(assertion, expectations, numberArgs) { // eslint-d // Note: this function *must* throw exceptions, since it can be used // as part of a pending assertion for promises. function assertExpectations({assertion, actual, expectations, message, prefix, savedError}) { - if (!isError(actual)) { + if (!isNativeError(actual)) { throw new AssertionError({ assertion, message, diff --git a/lib/serialize-error.js b/lib/serialize-error.js index f9f6fd50d..f89cee06e 100644 --- a/lib/serialize-error.js +++ b/lib/serialize-error.js @@ -5,7 +5,6 @@ import {isNativeError} from 'node:util/types'; import cleanYamlObject from 'clean-yaml-object'; import concordance from 'concordance'; -import isError from 'is-error'; import StackUtils from 'stack-utils'; import {AssertionError} from './assert.js'; @@ -160,7 +159,7 @@ export function tagWorkerError(error) { const isWorkerError = error => workerErrors.has(error); export default function serializeError(origin, shouldBeautifyStack, error, testFile) { - if (!isError(error) && !isWorkerError(error)) { + if (!isNativeError(error) && !isWorkerError(error)) { return { avaAssertionError: false, nonErrorObject: true, diff --git a/package-lock.json b/package-lock.json index 8bd4475d8..66ac94158 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,6 @@ "globby": "^13.2.1", "ignore-by-default": "^2.1.0", "indent-string": "^5.0.0", - "is-error": "^2.2.2", "is-plain-object": "^5.0.0", "is-promise": "^4.0.0", "matcher": "^5.0.0", @@ -4805,7 +4804,8 @@ "node_modules/is-error": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", - "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==" + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "dev": true }, "node_modules/is-extglob": { "version": "2.1.1", diff --git a/package.json b/package.json index db55f216e..0ed60e733 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,6 @@ "globby": "^13.2.1", "ignore-by-default": "^2.1.0", "indent-string": "^5.0.0", - "is-error": "^2.2.2", "is-plain-object": "^5.0.0", "is-promise": "^4.0.0", "matcher": "^5.0.0", diff --git a/types/assertions.d.cts b/types/assertions.d.cts index 3fbd37556..009cd139e 100644 --- a/types/assertions.d.cts +++ b/types/assertions.d.cts @@ -103,12 +103,12 @@ export type Assertions = { snapshot: SnapshotAssertion; /** - * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. + * Assert that the function throws a native error. If so, returns the error value. */ throws: ThrowsAssertion; /** - * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error), or the promise rejects + * Assert that the async function throws a native error, or the promise rejects * with one. If so, returns a promise for the error value, which must be awaited. */ throwsAsync: ThrowsAsyncAssertion; @@ -295,7 +295,7 @@ export type SnapshotAssertion = { export type ThrowsAssertion = { /** - * Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value. + * Assert that the function throws a native error. If so, returns the error value. * The error must satisfy all expectations. Returns undefined when the assertion fails. */ (fn: () => any, expectations?: ThrowsExpectation, message?: string): ThrownError | undefined; @@ -306,13 +306,13 @@ export type ThrowsAssertion = { export type ThrowsAsyncAssertion = { /** - * Assert that the async function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error + * Assert that the async function throws a native error. If so, returns the error * value. Returns undefined when the assertion fails. You must await the result. The error must satisfy all expectations. */ (fn: () => PromiseLike, expectations?: ThrowsExpectation, message?: string): Promise | undefined>; /** - * Assert that the promise rejects with [an error](https://www.npmjs.com/package/is-error). If so, returns the + * Assert that the promise rejects with a native error. If so, returns the * rejection reason. Returns undefined when the assertion fails. You must await the result. The error must satisfy all * expectations. */