Skip to content

Commit

Permalink
Return undefined when throws assertions fail
Browse files Browse the repository at this point in the history
  • Loading branch information
mcecode committed Aug 22, 2021
1 parent ddda6ed commit dc93f37
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 28 deletions.
4 changes: 2 additions & 2 deletions docs/03-assertions.md
Expand Up @@ -229,7 +229,7 @@ Finally, this returns a boolean indicating whether the assertion passed.

### `.throws(fn, expectation?, message?)`

Assert that an error is thrown. `fn` must be a function which should throw. The thrown value *must* be an error. It is returned so you can run more assertions against it. If the assertion fails then `null` is returned.
Assert that an error is thrown. `fn` must be a function which should throw. The thrown value *must* be an error. It is returned so you can run more assertions against it. If the assertion fails then `undefined` is returned.

`expectation` can be an object with one or more of the following properties:

Expand Down Expand Up @@ -261,7 +261,7 @@ test('throws', t => {

Assert that an error is thrown. `thrower` can be an async function which should throw, or a promise that should reject. This assertion must be awaited.

The thrown value *must* be an error. It is returned so you can run more assertions against it. If the assertion fails then `null` is returned.
The thrown value *must* be an error. It is returned so you can run more assertions against it. If the assertion fails then `undefined` is returned.

`expectation` can be an object with one or more of the following properties:

Expand Down
20 changes: 9 additions & 11 deletions lib/assert.js
Expand Up @@ -469,7 +469,7 @@ export class Assertions {
let [fn, expectations, message] = args;

if (!checkMessage('throws', message)) {
return null;
return;
}

if (typeof fn !== 'function') {
Expand All @@ -479,14 +479,14 @@ export class Assertions {
message: '`t.throws()` must be called with a function',
values: [formatWithLabel('Called with:', fn)]
}));
return null;
return;
}

try {
expectations = validateExpectations('throws', expectations, args.length, experiments);
} catch (error) {
fail(error);
return null;
return;
}

let retval;
Expand All @@ -501,7 +501,7 @@ export class Assertions {
message,
values: [formatWithLabel('Function returned a promise. Use `t.throwsAsync()` instead:', retval)]
}));
return null;
return;
}
} catch (error) {
actual = error;
Expand All @@ -513,7 +513,7 @@ export class Assertions {
message,
values: [formatWithLabel('Function returned:', retval)]
}));
return null;
return;
}

try {
Expand All @@ -535,7 +535,7 @@ export class Assertions {
let [thrower, expectations, message] = args;

if (!checkMessage('throwsAsync', message)) {
return null;
return;
}

if (typeof thrower !== 'function' && !isPromise(thrower)) {
Expand All @@ -545,14 +545,14 @@ export class Assertions {
message: '`t.throwsAsync()` must be called with a function or promise',
values: [formatWithLabel('Called with:', thrower)]
}));
return null;
return;
}

try {
expectations = validateExpectations('throwsAsync', expectations, args.length, experiments);
} catch (error) {
fail(error);
return null;
return;
}

const handlePromise = async (promise, wasReturned) => {
Expand Down Expand Up @@ -583,7 +583,6 @@ export class Assertions {
return await intermediate;
} catch {
// Don't reject the returned promise, even if the assertion fails.
return null;
}
};

Expand All @@ -606,7 +605,7 @@ export class Assertions {
actualStack: actual.stack,
values: [formatWithLabel('Function threw synchronously. Use `t.throws()` instead:', actual)]
}));
return null;
return;
}

if (isPromise(retval)) {
Expand All @@ -618,7 +617,6 @@ export class Assertions {
message,
values: [formatWithLabel('Function returned:', retval)]
}));
return null;
});

this.notThrows = withSkip((fn, message) => {
Expand Down
16 changes: 8 additions & 8 deletions test-d/throws.ts
Expand Up @@ -12,15 +12,15 @@ class CustomError extends Error {
}

test('throws', t => {
expectType<Error | null>(t.throws(() => {}));
const error2: CustomError | null = t.throws(() => {});
expectType<CustomError | null>(error2);
expectType<CustomError | null>(t.throws<CustomError>(() => {}));
expectType<Error | undefined>(t.throws(() => {}));
const error2: CustomError | undefined = t.throws(() => {});
expectType<CustomError | undefined>(error2);
expectType<CustomError | undefined>(t.throws<CustomError>(() => {}));
});

test('throwsAsync', async t => {
expectType<Error | null>(await t.throwsAsync(async () => {}));
expectType<CustomError | null>(await t.throwsAsync<CustomError>(async () => {}));
expectType<Error | null>(await t.throwsAsync(Promise.reject()));
expectType<CustomError | null>(await t.throwsAsync<CustomError>(Promise.reject()));
expectType<Error | undefined>(await t.throwsAsync(async () => {}));
expectType<CustomError | undefined>(await t.throwsAsync<CustomError>(async () => {}));
expectType<Error | undefined>(await t.throwsAsync(Promise.reject()));
expectType<CustomError | undefined>(await t.throwsAsync<CustomError>(Promise.reject()));
});
2 changes: 1 addition & 1 deletion test-tap/assert.js
Expand Up @@ -115,7 +115,7 @@ function throwsAsyncFails(t, fn, subset) {
return add(() => {
lastFailure = null;
return fn().then(retval => {
t.equal(retval, null);
t.equal(retval, undefined);
assertFailure(t, subset);
});
});
Expand Down
12 changes: 6 additions & 6 deletions types/assertions.d.ts
Expand Up @@ -279,9 +279,9 @@ export interface SnapshotAssertion {
export interface ThrowsAssertion {
/**
* Assert that the function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error value.
* The error must satisfy all expectations. Returns null when the assertion fails.
* The error must satisfy all expectations. Returns undefined when the assertion fails.
*/
<ThrownError extends Error>(fn: () => any, expectations?: ThrowsExpectation, message?: string): ThrownError | null;
<ThrownError extends Error>(fn: () => any, expectations?: ThrowsExpectation, message?: string): ThrownError | undefined;

/** Skip this assertion. */
skip(fn: () => any, expectations?: any, message?: string): void;
Expand All @@ -290,16 +290,16 @@ export interface ThrowsAssertion {
export interface ThrowsAsyncAssertion {
/**
* Assert that the async function throws [an error](https://www.npmjs.com/package/is-error). If so, returns the error
* value. Returns null when the assertion fails. You must await the result. The error must satisfy all expectations.
* value. Returns undefined when the assertion fails. You must await the result. The error must satisfy all expectations.
*/
<ThrownError extends Error>(fn: () => PromiseLike<any>, expectations?: ThrowsExpectation, message?: string): Promise<ThrownError | null>;
<ThrownError extends Error>(fn: () => PromiseLike<any>, expectations?: ThrowsExpectation, message?: string): Promise<ThrownError | undefined>;

/**
* Assert that the promise rejects with [an error](https://www.npmjs.com/package/is-error). If so, returns the
* rejection reason. Returns null when the assertion fails. You must await the result. The error must satisfy all
* rejection reason. Returns undefined when the assertion fails. You must await the result. The error must satisfy all
* expectations.
*/
<ThrownError extends Error>(promise: PromiseLike<any>, expectations?: ThrowsExpectation, message?: string): Promise<ThrownError | null>; // eslint-disable-line @typescript-eslint/unified-signatures
<ThrownError extends Error>(promise: PromiseLike<any>, expectations?: ThrowsExpectation, message?: string): Promise<ThrownError | undefined>; // eslint-disable-line @typescript-eslint/unified-signatures

/** Skip this assertion. */
skip(thrower: any, expectations?: any, message?: string): void;
Expand Down

0 comments on commit dc93f37

Please sign in to comment.