diff --git a/src/assert.ts b/src/assert.ts index c06d2ab..02b0864 100644 --- a/src/assert.ts +++ b/src/assert.ts @@ -11,7 +11,7 @@ import { assert, Assertion } from 'chai' import Macroable from '@poppinss/macroable' import { AssertionError } from 'assertion-error' -import type { AssertContract, ChaiAssert } from './types.js' +import type { AnyErrorConstructor, AssertContract, ChaiAssert } from './types.js' /** * The Assert class is derived from chai.assert to allow support @@ -1169,17 +1169,17 @@ export class Assert extends Macroable implements AssertContract { * assert.throws(foo, 'blow up') // passes * assert.throws(foo, 'failed') // fails */ - throws(fn: () => void, message?: string): void - throws(fn: () => void, errType: RegExp | ErrorConstructor, message?: string): void + throws(fn: () => unknown, message?: string): void + throws(fn: () => unknown, errType: RegExp | AnyErrorConstructor, message?: string): void throws( - fn: () => void, - constructor: ErrorConstructor, + fn: () => unknown, + constructor: AnyErrorConstructor, regExp: RegExp | string, message?: string ): void throws( - fn: () => void, - errType?: RegExp | ErrorConstructor | string, + fn: () => unknown, + errType?: RegExp | AnyErrorConstructor | string, regExp?: RegExp | string, message?: string ): void { @@ -1201,18 +1201,18 @@ export class Assert extends Macroable implements AssertContract { * assert.doesNotThrow(foo, 'failed') // passes * assert.doesNotThrow(() => {}) // passes */ - doesNotThrow(fn: () => void, message?: string): void - doesNotThrow(fn: () => void, regExp: RegExp): void - doesNotThrow(fn: () => void, constructor: ErrorConstructor, message?: string): void + doesNotThrow(fn: () => unknown, message?: string): void + doesNotThrow(fn: () => unknown, regExp: RegExp): void + doesNotThrow(fn: () => unknown, constructor: AnyErrorConstructor, message?: string): void doesNotThrow( - fn: () => void, - constructor: ErrorConstructor, + fn: () => unknown, + constructor: AnyErrorConstructor, regExp: RegExp | string, message?: string ): void doesNotThrow( - fn: () => void, - errType?: RegExp | ErrorConstructor | string, + fn: () => unknown, + errType?: RegExp | AnyErrorConstructor | string, regExp?: RegExp | string, message?: string ): void { @@ -1916,21 +1916,21 @@ export class Assert extends Macroable implements AssertContract { * @example * await assert.reject(() => throw new Error('')) */ - async rejects(fn: () => void, message?: string): Promise + async rejects(fn: () => unknown, message?: string): Promise async rejects( - fn: () => void | Promise, - errType: RegExp | ErrorConstructor, + fn: () => unknown | Promise, + errType: RegExp | AnyErrorConstructor, message?: string ): Promise async rejects( - fn: () => void | Promise, - constructor: ErrorConstructor, + fn: () => unknown | Promise, + constructor: AnyErrorConstructor, regExp: RegExp | string, message?: string ): Promise async rejects( - fn: () => void | Promise, - errType?: RegExp | ErrorConstructor | string, + fn: () => unknown | Promise, + errType?: RegExp | AnyErrorConstructor | string, regExp?: RegExp | string, message?: string ): Promise { @@ -2056,21 +2056,21 @@ export class Assert extends Macroable implements AssertContract { * async () => return 'foo', * ) // passes */ - async doesNotReject(fn: () => void, message?: string): Promise + async doesNotReject(fn: () => unknown, message?: string): Promise async doesNotReject( - fn: () => void | Promise, - errType: RegExp | ErrorConstructor, + fn: () => unknown | Promise, + errType: RegExp | AnyErrorConstructor, message?: string ): Promise async doesNotReject( - fn: () => void | Promise, - constructor: ErrorConstructor, + fn: () => unknown | Promise, + constructor: AnyErrorConstructor, regExp: RegExp | string, message?: string ): Promise async doesNotReject( - fn: () => void | Promise, - errType?: RegExp | ErrorConstructor | string, + fn: () => unknown | Promise, + errType?: RegExp | AnyErrorConstructor | string, regExp?: RegExp | string, message?: string ): Promise { diff --git a/src/types.ts b/src/types.ts index 80d18e2..009aaaa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,3 +75,9 @@ export type AssertContract = Omit< > export type PluginConfig = {} + +/** + * A more flexible error constructor than `ErrorConstructor` type that allows custom + * error classes with any constructor signature + */ +export type AnyErrorConstructor = new (...args: any[]) => Error diff --git a/tests/assert/assert.spec.ts b/tests/assert/assert.spec.ts index ca6ffb3..9db1edd 100644 --- a/tests/assert/assert.spec.ts +++ b/tests/assert/assert.spec.ts @@ -1634,6 +1634,48 @@ test.describe('assert', function () { }, 'blah: expected {} to be a function') }) + test('throws with custom error constructor with multiple arguments', function () { + const assert = new Assert() + + class CustomError extends Error { + constructor( + public code: number, + message: string + ) { + super(message) + } + } + + assert.throws(() => { + throw new CustomError(500, 'Internal Server Error') + }, CustomError) + + assert.throws( + () => { + throw new CustomError(404, 'Not Found') + }, + CustomError, + 'Not Found' + ) + + expectError(() => { + assert.throws(() => { + throw new CustomError(500, 'Internal Server Error') + }, TypeError) + }, "expected [Function] to throw 'TypeError' but 'Error: Internal Server Error' was thrown") + }) + + test('throws with function returning non-void value', function () { + const assert = new Assert() + + function myThing(): string { + throw new Error('Something went wrong') + } + + assert.throws(() => myThing(), Error) + assert.throws(() => myThing(), 'Something went wrong') + }) + test('rejects', async function () { const assert = new Assert() @@ -1729,6 +1771,42 @@ test.describe('assert', function () { }, 'blah: expected {} to be a function') }) + test('rejects with custom error constructor with multiple arguments', async function () { + const assert = new Assert() + + class CustomError extends Error { + constructor( + public code: number, + message: string + ) { + super(message) + } + } + + await assert.rejects(async function () { + throw new CustomError(500, 'Internal Server Error') + }, CustomError) + + await assert.rejects( + async function () { + throw new CustomError(404, 'Not Found') + }, + CustomError, + 'Not Found' + ) + }) + + test('rejects with function returning non-void value', async function () { + const assert = new Assert() + + async function myThing(): Promise { + throw new Error('Something went wrong') + } + + await assert.rejects(() => myThing(), Error) + await assert.rejects(() => myThing(), 'Something went wrong') + }) + test('doesNotThrows', function () { const assert = new Assert()