From 9e854795e6260133d22d38c5a4247ce51b0f519c Mon Sep 17 00:00:00 2001 From: John Markham Date: Sun, 21 Feb 2021 23:54:58 -0800 Subject: [PATCH 01/11] [draft] feat: assertions return booleans --- index.d.ts | 160 ++++++++++---- lib/assert.js | 269 +++++++++++++----------- test-tap/assert.js | 506 ++++++++++++++++++++++----------------------- 3 files changed, 512 insertions(+), 423 deletions(-) diff --git a/index.d.ts b/index.d.ts index 64efe99f6..84b920e78 100644 --- a/index.d.ts +++ b/index.d.ts @@ -33,40 +33,68 @@ export type CommitDiscardOptions = { }; export interface Assertions { - /** Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). Comes with power-assert. */ + /** + * Assert that `actual` is + * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), + * returning Boolean indicating whether the assertion passes. Comes with + * power-assert. + */ assert: AssertAssertion; - /** Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to `expected`. */ + /** + * Assert that `actual` is [deeply + * equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning Boolean indicating whether the assertion passes. + */ deepEqual: DeepEqualAssertion; - /** Assert that `actual` is like `expected`. */ + /** + * Assert that `value` is like `selector`, returning Boolean indicating + * whether the assertion passes. + */ like: LikeAssertion; - /** Fail the test. */ + /** Fail the test, always returning `false`. */ fail: FailAssertion; - /** Assert that `actual` is strictly false. */ + /** + * Assert that `actual` is strictly false, returning Boolean indicating + * whether the assertion passes. + */ false: FalseAssertion; - /** Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy). */ + /** + * Assert that `actual` is + * [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning + * Boolean whether the assertion passes. + */ falsy: FalsyAssertion; /** * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as `expected`, returning Boolean indicating whether the assertion passes. */ is: IsAssertion; /** * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as `expected`, returning Boolean indicating whether the assertion passes. */ not: NotAssertion; - /** Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to `expected`. */ + /** + * Assert that `actual` is not [deeply + * equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning Boolean indicating whether the assertion passes. + */ notDeepEqual: NotDeepEqualAssertion; - /** Assert that `string` does not match the regular expression. */ + /** + * Assert that `string` does not match the regular expression, returning + * Boolean indicating whether the assertion passes. + */ notRegex: NotRegexAssertion; /** Assert that the function does not throw. */ @@ -75,10 +103,13 @@ export interface Assertions { /** Assert that the async function does not throw, or that the promise does not reject. Must be awaited. */ notThrowsAsync: NotThrowsAsyncAssertion; - /** Count a passing assertion. */ + /** Count a passing assertion, always returning `true`. */ pass: PassAssertion; - /** Assert that `string` matches the regular expression. */ + /** + * Assert that `string` matches the regular expression, returning Boolean + * indicating whether the assertion passes. + */ regex: RegexAssertion; /** @@ -99,56 +130,82 @@ export interface Assertions { */ throwsAsync: ThrowsAsyncAssertion; - /** Assert that `actual` is strictly true. */ + /** + * Assert that `actual` is strictly true, returning Boolean indicating + * whether the assertion passes. + */ true: TrueAssertion; - /** Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). */ + /** + * Assert that `actual` is + * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), + * returning Boolean indicating whether the assertion passes. + */ truthy: TruthyAssertion; } export interface AssertAssertion { - /** Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). Comes with power-assert. */ - (actual: any, message?: string): void; + /** + * Assert that `actual` is + * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), + * returning Boolean indicating whether the assertion passes. Comes with + * power-assert. + */ + (actual: any, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, message?: string): void; } export interface DeepEqualAssertion { - /** Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to `expected`. */ - (actual: ValueType, expected: ValueType, message?: string): void; + /** + * Assert that `actual` is [deeply + * equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning Boolean indicating whether the assertion passes. + */ + (actual: ValueType, expected: ValueType, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, expected: any, message?: string): void; } export interface LikeAssertion { - /** Assert that `value` is like `selector`. */ - (value: any, selector: Record, message?: string): void; + /** + * Assert that `value` is like `selector`, returning Boolean indicating + * whether the assertion passes. + */ + (value: any, selector: Record, message?: string): boolean; /** Skip this assertion. */ skip(value: any, selector: any, message?: string): void; } export interface FailAssertion { - /** Fail the test. */ - (message?: string): void; + /** Fail the test, always returning `false`. */ + (message?: string): boolean; /** Skip this assertion. */ skip(message?: string): void; } export interface FalseAssertion { - /** Assert that `actual` is strictly false. */ - (actual: any, message?: string): void; + /** + * Assert that `actual` is strictly false, returning Boolean indicating + * whether the assertion passes. + */ + (actual: any, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, message?: string): void; } export interface FalsyAssertion { - /** Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy). */ - (actual: any, message?: string): void; + /** + * Assert that `actual` is + * [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning + * Boolean whether the assertion passes. + */ + (actual: any, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, message?: string): void; @@ -157,9 +214,10 @@ export interface FalsyAssertion { export interface IsAssertion { /** * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as `expected`, returning Boolean indicating whether the assertion passes. */ - (actual: ValueType, expected: ValueType, message?: string): void; + (actual: ValueType, expected: ValueType, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, expected: any, message?: string): void; @@ -168,25 +226,33 @@ export interface IsAssertion { export interface NotAssertion { /** * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as `expected`, returning Boolean indicating whether the assertion passes. */ - (actual: ValueType, expected: ValueType, message?: string): void; + (actual: ValueType, expected: ValueType, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, expected: any, message?: string): void; } export interface NotDeepEqualAssertion { - /** Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to `expected`. */ - (actual: ValueType, expected: ValueType, message?: string): void; + /** + * Assert that `actual` is not [deeply + * equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning Boolean indicating whether the assertion passes. + */ + (actual: ValueType, expected: ValueType, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, expected: any, message?: string): void; } export interface NotRegexAssertion { - /** Assert that `string` does not match the regular expression. */ - (string: string, regex: RegExp, message?: string): void; + /** + * Assert that `string` does not match the regular expression, returning + * Boolean indicating whether the assertion passes. + */ + (string: string, regex: RegExp, message?: string): boolean; /** Skip this assertion. */ skip(string: string, regex: RegExp, message?: string): void; @@ -212,16 +278,19 @@ export interface NotThrowsAsyncAssertion { } export interface PassAssertion { - /** Count a passing assertion. */ - (message?: string): void; + /** Count a passing assertion, always returning `true`. */ + (message?: string): boolean; /** Skip this assertion. */ skip(message?: string): void; } export interface RegexAssertion { - /** Assert that `string` matches the regular expression. */ - (string: string, regex: RegExp, message?: string): void; + /** + * Assert that `string` matches the regular expression, returning Boolean + * indicating whether the assertion passes. + */ + (string: string, regex: RegExp, message?: string): boolean; /** Skip this assertion. */ skip(string: string, regex: RegExp, message?: string): void; @@ -280,16 +349,23 @@ export interface ThrowsAsyncAssertion { } export interface TrueAssertion { - /** Assert that `actual` is strictly true. */ - (actual: any, message?: string): void; + /** + * Assert that `actual` is strictly true, returning Boolean indicating + * whether the assertion passes. + */ + (actual: any, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, message?: string): void; } export interface TruthyAssertion { - /** Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). */ - (actual: any, message?: string): void; + /** + * Assert that `actual` is + * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), + * returning Boolean indicating whether the assertion passes. + */ + (actual: any, message?: string): boolean; /** Skip this assertion. */ skip(actual: any, message?: string): void; diff --git a/lib/assert.js b/lib/assert.js index dab44e906..cfdad3dd5 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -283,9 +283,11 @@ class Assertions { } fail(event.error); + return false; }, onSuccess: () => { pass(); + return true; }, bindReceiver: false, patterns: [pattern] @@ -294,7 +296,7 @@ class Assertions { const checkMessage = (assertion, message, powerAssert = false) => { const result = checkAssertionMessage(assertion, message); if (result === true) { - return this.true; + return true; } if (powerAssert) { @@ -307,52 +309,58 @@ class Assertions { this.pass = withSkip(() => { pass(); + return true; }); this.fail = withSkip(message => { if (!checkMessage('fail', message)) { - return; + return false; } fail(new AssertionError({ assertion: 'fail', message: message || 'Test failed via `t.fail()`' })); - }); - - this.is = withSkip((actual, expected, message) => { - if (!checkMessage('is', message)) { - return; - } - if (Object.is(actual, expected)) { - pass(); - } else { - const result = concordance.compare(actual, expected, concordanceOptions); - const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + return false; + }); - if (result.pass) { - fail(new AssertionError({ - assertion: 'is', - message, - raw: {actual, expected}, - values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)] - })); - } else { - fail(new AssertionError({ - assertion: 'is', - message, - raw: {actual, expected}, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - } - } + this.is = withSkip((actual, expected, message) => { + if (!checkMessage('is', message)) { + return false; + } + + if (Object.is(actual, expected)) { + pass(); + return true; + } + + const result = concordance.compare(actual, expected, concordanceOptions); + const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + + if (result.pass) { + fail(new AssertionError({ + assertion: 'is', + message, + raw: {actual, expected}, + values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)] + })); + } else { + fail(new AssertionError({ + assertion: 'is', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + } + + return false; }); this.not = withSkip((actual, expected, message) => { if (!checkMessage('not', message)) { - return; + return false; } if (Object.is(actual, expected)) { @@ -362,34 +370,38 @@ class Assertions { raw: {actual, expected}, values: [formatWithLabel('Value is the same as:', actual)] })); - } else { - pass(); - } + return false; + } + + pass(); + return true; }); this.deepEqual = withSkip((actual, expected, message) => { if (!checkMessage('deepEqual', message)) { - return; + return false; } const result = concordance.compare(actual, expected, concordanceOptions); if (result.pass) { pass(); - } else { - const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); - fail(new AssertionError({ - assertion: 'deepEqual', - message, - raw: {actual, expected}, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - } - }); + return true; + } + + const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + fail(new AssertionError({ + assertion: 'deepEqual', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + return false; + }); this.notDeepEqual = withSkip((actual, expected, message) => { if (!checkMessage('notDeepEqual', message)) { - return; + return false; } const result = concordance.compare(actual, expected, concordanceOptions); @@ -401,14 +413,15 @@ class Assertions { raw: {actual, expected}, values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)] })); - } else { - pass(); - } + } + + pass(); + return true; }); this.like = withSkip((actual, selector, message) => { if (!checkMessage('like', message)) { - return; + return false; } if (!isLikeSelector(selector)) { @@ -418,7 +431,7 @@ class Assertions { message: '`t.like()` selector must be a non-empty object', values: [formatWithLabel('Called with:', selector)] })); - return; + return false; } let comparable; @@ -432,24 +445,27 @@ class Assertions { message: '`t.like()` selector must not contain circular references', values: [formatWithLabel('Called with:', selector)] })); - return; + return false; } throw error; } const result = concordance.compare(comparable, selector, concordanceOptions); - if (result.pass) { - pass(); - } else { - const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions); - fail(new AssertionError({ - assertion: 'like', - message, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - } + if (result.pass) { + pass(); + return true; + } + + const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions); + fail(new AssertionError({ + assertion: 'like', + message, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + + return false; }); this.throws = withSkip((...args) => { @@ -619,7 +635,7 @@ class Assertions { message: '`t.notThrows()` must be called with a function', values: [formatWithLabel('Called with:', fn)] })); - return; + return false; } try { @@ -631,15 +647,16 @@ class Assertions { actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); - return; + return false; } pass(); + return true; }); this.notThrowsAsync = withSkip((nonThrower, message) => { if (!checkMessage('notThrowsAsync', message)) { - return Promise.resolve(); + return Promise.resolve(false); } if (typeof nonThrower !== 'function' && !isPromise(nonThrower)) { @@ -649,14 +666,14 @@ class Assertions { message: '`t.notThrowsAsync()` must be called with a function or promise', values: [formatWithLabel('Called with:', nonThrower)] })); - return Promise.resolve(); + return Promise.resolve(false); } const handlePromise = (promise, wasReturned) => { // Create an error object to record the stack before it gets lost in the promise chain. const savedError = getErrorWithLongStackTrace(); // Handle "promise like" objects by casting to a real Promise. - const intermediate = Promise.resolve(promise).then(noop, error => { // eslint-disable-line promise/prefer-await-to-then + const intermediate = Promise.resolve(promise).then(() => true, error => { // eslint-disable-line promise/prefer-await-to-then throw new AssertionError({ assertion: 'notThrowsAsync', message, @@ -683,7 +700,7 @@ class Assertions { actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); - return Promise.resolve(); + return Promise.resolve(false); } if (!isPromise(retval)) { @@ -692,7 +709,7 @@ class Assertions { message, values: [formatWithLabel('Function did not return a promise. Use `t.notThrows()` instead:', retval)] })); - return Promise.resolve(); + return Promise.resolve(false); } return handlePromise(retval, true); @@ -705,7 +722,7 @@ class Assertions { message: '`t.snapshot()` can only be used in tests', improperUsage: true })); - return; + return false; } if (message && message.id !== undefined) { @@ -715,11 +732,11 @@ class Assertions { improperUsage: true, values: [formatWithLabel('Called with id:', message.id)] })); - return; + return false; } if (!checkMessage('snapshot', message)) { - return; + return false; } if (message === '') { @@ -729,7 +746,7 @@ class Assertions { message: 'The snapshot assertion message must be a non-empty string', values: [formatWithLabel('Called with:', message)] })); - return; + return false; } let result; @@ -751,12 +768,15 @@ class Assertions { message: message || 'Could not compare snapshot', improperUsage })); - return; + return false; } if (result.pass) { pass(); - } else if (result.actual) { + return true; + } + + if (result.actual) { fail(new AssertionError({ assertion: 'snapshot', message: message || 'Did not match snapshot', @@ -769,28 +789,32 @@ class Assertions { message: message || 'No snapshot available — new snapshots are not created in CI environments' })); } + + return false; }); this.truthy = withSkip((actual, message) => { if (!checkMessage('truthy', message)) { - return; + return false; } if (actual) { pass(); - } else { - fail(new AssertionError({ - assertion: 'truthy', - message, - operator: '!!', - values: [formatWithLabel('Value is not truthy:', actual)] - })); - } - }); + return true; + } - this.falsy = withSkip((actual, message) => { - if (!checkMessage('falsy', message)) { - return; + fail(new AssertionError({ + assertion: 'truthy', + message, + operator: '!!', + values: [formatWithLabel('Value is not truthy:', actual)] + })); + return false; + }); + + this.falsy = withSkip((actual, message) => { + if (!checkMessage('falsy', message)) { + return false; } if (actual) { @@ -800,46 +824,52 @@ class Assertions { operator: '!', values: [formatWithLabel('Value is not falsy:', actual)] })); - } else { - pass(); - } + return false; + } + + pass(); + return true; }); this.true = withSkip((actual, message) => { if (!checkMessage('true', message)) { - return; + return false; } if (actual === true) { pass(); - } else { - fail(new AssertionError({ - assertion: 'true', - message, - values: [formatWithLabel('Value is not `true`:', actual)] - })); - } + return true; + } + + fail(new AssertionError({ + assertion: 'true', + message, + values: [formatWithLabel('Value is not `true`:', actual)] + })); + return false; }); this.false = withSkip((actual, message) => { if (!checkMessage('false', message)) { - return; + return false; } if (actual === false) { pass(); - } else { - fail(new AssertionError({ - assertion: 'false', - message, - values: [formatWithLabel('Value is not `false`:', actual)] - })); - } + return true; + } + + fail(new AssertionError({ + assertion: 'false', + message, + values: [formatWithLabel('Value is not `false`:', actual)] + })); + return false; }); this.regex = withSkip((string, regex, message) => { if (!checkMessage('regex', message)) { - return; + return true; } if (typeof string !== 'string') { @@ -849,7 +879,7 @@ class Assertions { message: '`t.regex()` must be called with a string', values: [formatWithLabel('Called with:', string)] })); - return; + return false; } if (!(regex instanceof RegExp)) { @@ -859,7 +889,7 @@ class Assertions { message: '`t.regex()` must be called with a regular expression', values: [formatWithLabel('Called with:', regex)] })); - return; + return false; } if (!regex.test(string)) { @@ -871,15 +901,16 @@ class Assertions { formatWithLabel('Regular expression:', regex) ] })); - return; + return false; } pass(); + return true; }); this.notRegex = withSkip((string, regex, message) => { if (!checkMessage('notRegex', message)) { - return; + return false; } if (typeof string !== 'string') { @@ -889,7 +920,7 @@ class Assertions { message: '`t.notRegex()` must be called with a string', values: [formatWithLabel('Called with:', string)] })); - return; + return false; } if (!(regex instanceof RegExp)) { @@ -899,7 +930,7 @@ class Assertions { message: '`t.notRegex()` must be called with a regular expression', values: [formatWithLabel('Called with:', regex)] })); - return; + return false; } if (regex.test(string)) { @@ -911,16 +942,17 @@ class Assertions { formatWithLabel('Regular expression:', regex) ] })); - return; + return false; } pass(); + return true; }); if (powerAssert === undefined) { this.assert = withSkip((actual, message) => { if (!checkMessage('assert', message)) { - return; + return false; } if (!actual) { @@ -930,7 +962,6 @@ class Assertions { operator: '!!', values: [formatWithLabel('Value is not truthy:', actual)] })); - return; } pass(); diff --git a/test-tap/assert.js b/test-tap/assert.js index 89e5ad681..35bf86eff 100644 --- a/test-tap/assert.js +++ b/test-tap/assert.js @@ -70,6 +70,7 @@ function assertFailure(t, subset) { } else { t.same(lastFailure.values, []); } + } let gathering = false; @@ -102,7 +103,7 @@ function add(fn) { function failsWith(t, fn, subset) { lastFailure = null; - fn(); + subset.returnValue = fn(); assertFailure(t, subset); } @@ -117,9 +118,9 @@ function eventuallyFailsWith(t, fn, subset) { function fails(t, fn) { lastFailure = null; - fn(); + const retval = fn(); if (lastFailure) { - t.pass(); + t.pass(retval); } else { t.fail('Expected assertion to fail'); } @@ -143,9 +144,9 @@ function eventuallyFails(t, fn) { function passes(t, fn) { lastPassed = false; lastFailure = null; - fn(); + const retval = fn(); if (lastPassed) { - t.pass(); + t.pass(retval); } else { t.ifError(lastFailure, 'Expected assertion to pass'); } @@ -167,12 +168,11 @@ function eventuallyPasses(t, fn) { test('.pass()', t => { passes(t, () => { - assertions.pass(); + return assertions.pass(); }); passes(t, () => { - const {pass} = assertions; - pass(); + return assertions.pass(); }); t.end(); @@ -180,29 +180,28 @@ test('.pass()', t => { test('.fail()', t => { failsWith(t, () => { - assertions.fail(); + return assertions.fail(); }, { assertion: 'fail', message: 'Test failed via `t.fail()`' }); failsWith(t, () => { - assertions.fail('my message'); + return assertions.fail('my message'); }, { assertion: 'fail', message: 'my message' }); failsWith(t, () => { - const {fail} = assertions; - fail(); + return assertions.fail(); }, { assertion: 'fail', message: 'Test failed via `t.fail()`' }); failsWith(t, () => { - assertions.fail(null); + return assertions.fail(null); }, { assertion: 'fail', improperUsage: true, @@ -218,119 +217,118 @@ test('.fail()', t => { test('.is()', t => { passes(t, () => { - assertions.is('foo', 'foo'); + return assertions.is('foo', 'foo'); }); passes(t, () => { - const {is} = assertions; - is('foo', 'foo'); + return assertions.is('foo', 'foo'); }); passes(t, () => { - assertions.is('', ''); + return assertions.is('', ''); }); passes(t, () => { - assertions.is(true, true); + return assertions.is(true, true); }); passes(t, () => { - assertions.is(false, false); + return assertions.is(false, false); }); passes(t, () => { - assertions.is(null, null); + return assertions.is(null, null); }); passes(t, () => { - assertions.is(undefined, undefined); + return assertions.is(undefined, undefined); }); passes(t, () => { - assertions.is(1, 1); + return assertions.is(1, 1); }); passes(t, () => { - assertions.is(0, 0); + return assertions.is(0, 0); }); passes(t, () => { - assertions.is(-0, -0); + return assertions.is(-0, -0); }); passes(t, () => { - assertions.is(Number.NaN, Number.NaN); + return assertions.is(Number.NaN, Number.NaN); }); passes(t, () => { - assertions.is(0 / 0, Number.NaN); + return assertions.is(0 / 0, Number.NaN); }); passes(t, () => { const someRef = {foo: 'bar'}; - assertions.is(someRef, someRef); + return assertions.is(someRef, someRef); }); fails(t, () => { - assertions.is(0, -0); + return assertions.is(0, -0); }); fails(t, () => { - assertions.is(0, false); + return assertions.is(0, false); }); fails(t, () => { - assertions.is('', false); + return assertions.is('', false); }); fails(t, () => { - assertions.is('0', 0); + return assertions.is('0', 0); }); fails(t, () => { - assertions.is('17', 17); + return assertions.is('17', 17); }); fails(t, () => { - assertions.is([1, 2], '1,2'); + return assertions.is([1, 2], '1,2'); }); fails(t, () => { // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins - assertions.is(new String('foo'), 'foo'); + return assertions.is(new String('foo'), 'foo'); }); fails(t, () => { - assertions.is(null, undefined); + return assertions.is(null, undefined); }); fails(t, () => { - assertions.is(null, false); + return assertions.is(null, false); }); fails(t, () => { - assertions.is(undefined, false); + return assertions.is(undefined, false); }); fails(t, () => { // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins - assertions.is(new String('foo'), new String('foo')); + return assertions.is(new String('foo'), new String('foo')); }); fails(t, () => { - assertions.is(0, null); + return assertions.is(0, null); }); fails(t, () => { - assertions.is(0, Number.NaN); + return assertions.is(0, Number.NaN); }); fails(t, () => { - assertions.is('foo', Number.NaN); + return assertions.is('foo', Number.NaN); }); failsWith(t, () => { - assertions.is({foo: 'bar'}, {foo: 'bar'}); + return assertions.is({foo: 'bar'}, {foo: 'bar'}); }, { assertion: 'is', message: '', @@ -343,7 +341,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is('foo', 'bar'); + return assertions.is('foo', 'bar'); }, { assertion: 'is', message: '', @@ -354,7 +352,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is('foo', 42); + return assertions.is('foo', 42); }, { actual: 'foo', assertion: 'is', @@ -366,7 +364,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is('foo', 42, 'my message'); + return assertions.is('foo', 42, 'my message'); }, { assertion: 'is', message: 'my message', @@ -376,7 +374,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is(0, -0, 'my message'); + return assertions.is(0, -0, 'my message'); }, { assertion: 'is', message: 'my message', @@ -386,7 +384,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is(-0, 0, 'my message'); + return assertions.is(-0, 0, 'my message'); }, { assertion: 'is', message: 'my message', @@ -396,7 +394,7 @@ test('.is()', t => { }); failsWith(t, () => { - assertions.is(0, 0, null); + return assertions.is(0, 0, null); }, { assertion: 'is', improperUsage: true, @@ -412,24 +410,23 @@ test('.is()', t => { test('.not()', t => { passes(t, () => { - assertions.not('foo', 'bar'); + return assertions.not('foo', 'bar'); }); passes(t, () => { - const {not} = assertions; - not('foo', 'bar'); + return assertions.not('foo', 'bar'); }); fails(t, () => { - assertions.not(Number.NaN, Number.NaN); + return assertions.not(Number.NaN, Number.NaN); }); fails(t, () => { - assertions.not(0 / 0, Number.NaN); + return assertions.not(0 / 0, Number.NaN); }); failsWith(t, () => { - assertions.not('foo', 'foo'); + return assertions.not('foo', 'foo'); }, { assertion: 'not', message: '', @@ -438,7 +435,7 @@ test('.not()', t => { }); failsWith(t, () => { - assertions.not('foo', 'foo', 'my message'); + return assertions.not('foo', 'foo', 'my message'); }, { assertion: 'not', message: 'my message', @@ -446,7 +443,7 @@ test('.not()', t => { }); failsWith(t, () => { - assertions.not(0, 1, null); + return assertions.not(0, 1, null); }, { assertion: 'not', improperUsage: true, @@ -465,11 +462,11 @@ test('.deepEqual()', t => { // used to test deep object equality fails(t, () => { - assertions.deepEqual({a: false}, {a: 0}); + return assertions.deepEqual({a: false}, {a: 0}); }); passes(t, () => { - assertions.deepEqual({ + return assertions.deepEqual({ a: 'a', b: 'b' }, { @@ -479,12 +476,11 @@ test('.deepEqual()', t => { }); passes(t, () => { - const {deepEqual} = assertions; - deepEqual({a: 'a', b: 'b'}, {b: 'b', a: 'a'}); + return assertions.deepEqual({a: 'a', b: 'b'}, {b: 'b', a: 'a'}); }); passes(t, () => { - assertions.deepEqual({ + return assertions.deepEqual({ a: 'a', b: 'b', c: { @@ -500,17 +496,17 @@ test('.deepEqual()', t => { }); fails(t, () => { - assertions.deepEqual([1, 2, 3], [1, 2, 3, 4]); + return assertions.deepEqual([1, 2, 3], [1, 2, 3, 4]); }); passes(t, () => { - assertions.deepEqual([1, 2, 3], [1, 2, 3]); + return assertions.deepEqual([1, 2, 3], [1, 2, 3]); }); fails(t, () => { const fnA = a => a; const fnB = a => a; - assertions.deepEqual(fnA, fnB); + return assertions.deepEqual(fnA, fnB); }); passes(t, () => { @@ -522,7 +518,7 @@ test('.deepEqual()', t => { const y2 = {x: x2}; x2.y = y2; - assertions.deepEqual(x1, x2); + return assertions.deepEqual(x1, x2); }); passes(t, () => { @@ -533,7 +529,7 @@ test('.deepEqual()', t => { const x = new Foo(1); const y = new Foo(1); - assertions.deepEqual(x, y); + return assertions.deepEqual(x, y); }); fails(t, () => { @@ -548,11 +544,11 @@ test('.deepEqual()', t => { const x = new Foo(1); const y = new Bar(1); - assertions.deepEqual(x, y); + return assertions.deepEqual(x, y); }); fails(t, () => { - assertions.deepEqual({ + return assertions.deepEqual({ a: 'a', b: 'b', c: { @@ -568,73 +564,73 @@ test('.deepEqual()', t => { }); fails(t, () => { - assertions.deepEqual({}, []); + return assertions.deepEqual({}, []); }); fails(t, () => { - assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']); + return assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']); }); fails(t, () => { - assertions.deepEqual({a: 1}, {a: 1, b: undefined}); + return assertions.deepEqual({a: 1}, {a: 1, b: undefined}); }); fails(t, () => { - assertions.deepEqual(new Date('1972-08-01'), null); + return assertions.deepEqual(new Date('1972-08-01'), null); }); fails(t, () => { - assertions.deepEqual(new Date('1972-08-01'), undefined); + return assertions.deepEqual(new Date('1972-08-01'), undefined); }); passes(t, () => { - assertions.deepEqual(new Date('1972-08-01'), new Date('1972-08-01')); + return assertions.deepEqual(new Date('1972-08-01'), new Date('1972-08-01')); }); passes(t, () => { - assertions.deepEqual({x: new Date('1972-08-01')}, {x: new Date('1972-08-01')}); + return assertions.deepEqual({x: new Date('1972-08-01')}, {x: new Date('1972-08-01')}); }); fails(t, () => { - assertions.deepEqual(() => {}, () => {}); + return assertions.deepEqual(() => {}, () => {}); }); passes(t, () => { - assertions.deepEqual(undefined, undefined); - assertions.deepEqual({x: undefined}, {x: undefined}); - assertions.deepEqual({x: [undefined]}, {x: [undefined]}); - }); + return assertions.deepEqual(undefined, undefined) && + assertions.deepEqual({x: undefined}, {x: undefined}) && + assertions.deepEqual({x: [undefined]}, {x: [undefined]}); + }); - passes(t, () => { - assertions.deepEqual(null, null); - assertions.deepEqual({x: null}, {x: null}); - assertions.deepEqual({x: [null]}, {x: [null]}); + passes(t, () => { + return assertions.deepEqual(null, null) && + assertions.deepEqual({x: null}, {x: null}) && + assertions.deepEqual({x: [null]}, {x: [null]}); }); passes(t, () => { - assertions.deepEqual(0, 0); - assertions.deepEqual(1, 1); - assertions.deepEqual(3.14, 3.14); + return assertions.deepEqual(0, 0) && + assertions.deepEqual(1, 1) && + assertions.deepEqual(3.14, 3.14); }); fails(t, () => { - assertions.deepEqual(0, 1); + return assertions.deepEqual(0, 1); }); fails(t, () => { - assertions.deepEqual(1, -1); + return assertions.deepEqual(1, -1); }); fails(t, () => { - assertions.deepEqual(3.14, 2.72); + return assertions.deepEqual(3.14, 2.72); }); fails(t, () => { - assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']); + return assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']); }); passes(t, () => { - assertions.deepEqual( + return assertions.deepEqual( [ {foo: {z: 100, y: 200, x: 300}}, 'bar', @@ -651,7 +647,7 @@ test('.deepEqual()', t => { }); passes(t, () => { - assertions.deepEqual( + return assertions.deepEqual( {x: {a: 1, b: 2}, y: {c: 3, d: 4}}, {y: {d: 4, c: 3}, x: {b: 2, a: 1}} ); @@ -660,33 +656,33 @@ test('.deepEqual()', t => { // Regression test end here passes(t, () => { - assertions.deepEqual({a: 'a'}, {a: 'a'}); + return assertions.deepEqual({a: 'a'}, {a: 'a'}); }); passes(t, () => { - assertions.deepEqual(['a', 'b'], ['a', 'b']); + return assertions.deepEqual(['a', 'b'], ['a', 'b']); }); fails(t, () => { - assertions.deepEqual({a: 'a'}, {a: 'b'}); + return assertions.deepEqual({a: 'a'}, {a: 'b'}); }); fails(t, () => { - assertions.deepEqual(['a', 'b'], ['a', 'a']); + return assertions.deepEqual(['a', 'b'], ['a', 'a']); }); fails(t, () => { - assertions.deepEqual([['a', 'b'], 'c'], [['a', 'b'], 'd']); + return assertions.deepEqual([['a', 'b'], 'c'], [['a', 'b'], 'd']); }); fails(t, () => { const circular = ['a', 'b']; circular.push(circular); - assertions.deepEqual([circular, 'c'], [circular, 'd']); + return assertions.deepEqual([circular, 'c'], [circular, 'd']); }); failsWith(t, () => { - assertions.deepEqual('foo', 'bar'); + return assertions.deepEqual('foo', 'bar'); }, { assertion: 'deepEqual', message: '', @@ -695,7 +691,7 @@ test('.deepEqual()', t => { }); failsWith(t, () => { - assertions.deepEqual('foo', 42); + return assertions.deepEqual('foo', 42); }, { assertion: 'deepEqual', message: '', @@ -704,7 +700,7 @@ test('.deepEqual()', t => { }); failsWith(t, () => { - assertions.deepEqual('foo', 42, 'my message'); + return assertions.deepEqual('foo', 42, 'my message'); }, { assertion: 'deepEqual', message: 'my message', @@ -712,7 +708,7 @@ test('.deepEqual()', t => { }); failsWith(t, () => { - assertions.deepEqual({}, {}, null); + return assertions.deepEqual({}, {}, null); }, { assertion: 'deepEqual', improperUsage: true, @@ -728,22 +724,21 @@ test('.deepEqual()', t => { test('.notDeepEqual()', t => { passes(t, () => { - assertions.notDeepEqual({a: 'a'}, {a: 'b'}); + return assertions.notDeepEqual({a: 'a'}, {a: 'b'}); }); passes(t, () => { - const {notDeepEqual} = assertions; - notDeepEqual({a: 'a'}, {a: 'b'}); + return assertions.notDeepEqual({a: 'a'}, {a: 'b'}); }); passes(t, () => { - assertions.notDeepEqual(['a', 'b'], ['c', 'd']); + return assertions.notDeepEqual(['a', 'b'], ['c', 'd']); }); const actual = {a: 'a'}; const expected = {a: 'a'}; failsWith(t, () => { - assertions.notDeepEqual(actual, expected); + return assertions.notDeepEqual(actual, expected); }, { actual, assertion: 'notDeepEqual', @@ -754,7 +749,7 @@ test('.notDeepEqual()', t => { }); failsWith(t, () => { - assertions.notDeepEqual(['a', 'b'], ['a', 'b'], 'my message'); + return assertions.notDeepEqual(['a', 'b'], ['a', 'b'], 'my message'); }, { assertion: 'notDeepEqual', message: 'my message', @@ -762,7 +757,7 @@ test('.notDeepEqual()', t => { }); failsWith(t, () => { - assertions.notDeepEqual({}, [], null); + return assertions.notDeepEqual({}, [], null); }, { assertion: 'notDeepEqual', improperUsage: true, @@ -778,11 +773,11 @@ test('.notDeepEqual()', t => { test('.like()', t => { fails(t, () => { - assertions.like({a: false}, {a: 0}); + return assertions.like({a: false}, {a: 0}); }); passes(t, () => { - assertions.like({ + return assertions.like({ a: 'a', b: 'b' }, { @@ -792,12 +787,11 @@ test('.like()', t => { }); passes(t, () => { - const {like} = assertions; - like({a: 'a', b: 'b'}, {b: 'b', a: 'a'}); + return assertions.like({a: 'a', b: 'b'}, {b: 'b', a: 'a'}); }); passes(t, () => { - assertions.like({ + return assertions.like({ a: 'a', b: 'b', c: { @@ -815,11 +809,11 @@ test('.like()', t => { }); fails(t, () => { - assertions.like([1, 2, 3], [1, 2, 3, 4]); + return assertions.like([1, 2, 3], [1, 2, 3, 4]); }); fails(t, () => { - assertions.like({ + return assertions.like({ a: [1, 2, 3] }, { a: [1, 2, 3, 4] @@ -827,7 +821,7 @@ test('.like()', t => { }); passes(t, () => { - assertions.like({ + return assertions.like({ a: [1, 2, 3], x: 'x' }, { @@ -846,19 +840,19 @@ test('.like()', t => { a: 'a' }; - assertions.like(actual, likePattern); + return assertions.like(actual, likePattern); }); fails(t, () => { const fnA = a => a; const fnB = a => a; - assertions.like(fnA, fnB); + return assertions.like(fnA, fnB); }); fails(t, () => { const fnA = a => a; const fnB = a => a; - assertions.like({ + return assertions.like({ fn: fnA }, { fn: fnB @@ -877,59 +871,59 @@ test('.like()', t => { const x = new Foo(1); const y = new Bar(1); - assertions.like(x, y); + return assertions.like(x, y); }); passes(t, () => { - assertions.like({a: 'a'}, {a: 'a'}); + return assertions.like({a: 'a'}, {a: 'a'}); }); passes(t, () => { - assertions.like({a: 'a', b: 'b'}, {a: 'a'}); + return assertions.like({a: 'a', b: 'b'}, {a: 'a'}); }); passes(t, () => { - assertions.like({ab: ['a', 'b']}, {ab: ['a', 'b']}); + return assertions.like({ab: ['a', 'b']}, {ab: ['a', 'b']}); }); passes(t, () => { - assertions.like({ab: ['a', 'b'], c: 'c'}, {ab: ['a', 'b']}); + return assertions.like({ab: ['a', 'b'], c: 'c'}, {ab: ['a', 'b']}); }); fails(t, () => { - assertions.like({a: 'a'}, {a: 'b'}); + return assertions.like({a: 'a'}, {a: 'b'}); }); fails(t, () => { - assertions.like({a: 'a', b: 'b'}, {a: 'b'}); + return assertions.like({a: 'a', b: 'b'}, {a: 'b'}); }); fails(t, () => { - assertions.like({ab: ['a', 'b']}, {ab: ['a', 'a']}); + return assertions.like({ab: ['a', 'b']}, {ab: ['a', 'a']}); }); fails(t, () => { - assertions.like({ab: ['a', 'b'], c: 'c'}, {ab: ['a', 'a']}); + return assertions.like({ab: ['a', 'b'], c: 'c'}, {ab: ['a', 'a']}); }); fails(t, () => { - assertions.like([['a', 'b'], 'c'], [['a', 'b'], 'd']); + return assertions.like([['a', 'b'], 'c'], [['a', 'b'], 'd']); }); fails(t, () => { const circular = ['a', 'b']; circular.push(circular); - assertions.like([circular, 'c'], [circular, 'd']); + return assertions.like([circular, 'c'], [circular, 'd']); }); fails(t, () => { const circular = ['a', 'b']; circular.push(circular); - assertions.like({xc: [circular, 'c']}, {xc: [circular, 'd']}); + return assertions.like({xc: [circular, 'c']}, {xc: [circular, 'd']}); }); failsWith(t, () => { - assertions.like({a: 'a'}, {}); + return assertions.like({a: 'a'}, {}); }, { assertion: 'like', message: '`t.like()` selector must be a non-empty object', @@ -937,7 +931,7 @@ test('.like()', t => { }); failsWith(t, () => { - assertions.like('foo', 'bar'); + return assertions.like('foo', 'bar'); }, { assertion: 'like', message: '`t.like()` selector must be a non-empty object', @@ -950,7 +944,7 @@ test('.like()', t => { }; likePattern.circular = likePattern; - assertions.like({}, likePattern); + return assertions.like({}, likePattern); }, { assertion: 'like', message: '`t.like()` selector must not contain circular references', @@ -958,7 +952,7 @@ test('.like()', t => { }); failsWith(t, () => { - assertions.like({}, {}, null); + return assertions.like({}, {}, null); }, { assertion: 'like', improperUsage: true, @@ -970,7 +964,7 @@ test('.like()', t => { }); failsWith(t, () => { - assertions.like({a: 'foo', b: 'irrelevant'}, {a: 'bar'}); + return assertions.like({a: 'foo', b: 'irrelevant'}, {a: 'bar'}); }, { assertion: 'like', message: '', @@ -983,7 +977,7 @@ test('.like()', t => { test('.throws()', gather(t => { // Fails because function doesn't throw. failsWith(t, () => { - assertions.throws(() => {}); + return assertions.throws(() => {}); }, { assertion: 'throws', message: '', @@ -991,8 +985,7 @@ test('.throws()', gather(t => { }); failsWith(t, () => { - const {throws} = assertions; - throws(() => {}); + return assertions.throws(() => {}); }, { assertion: 'throws', message: '', @@ -1002,7 +995,7 @@ test('.throws()', gather(t => { // Fails because function doesn't throw. Asserts that 'my message' is used // as the assertion message (*not* compared against the error). failsWith(t, () => { - assertions.throws(() => {}, undefined, 'my message'); + return assertions.throws(() => {}, undefined, 'my message'); }, { assertion: 'throws', message: 'my message', @@ -1011,7 +1004,7 @@ test('.throws()', gather(t => { // Fails because the function returned a promise. failsWith(t, () => { - assertions.throws(() => Promise.resolve()); + return assertions.throws(() => Promise.resolve()); }, { assertion: 'throws', message: '', @@ -1020,7 +1013,7 @@ test('.throws()', gather(t => { // Fails because thrown exception is not an error failsWith(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = 'foo'; throw err; }); @@ -1034,7 +1027,7 @@ test('.throws()', gather(t => { // Passes because an error is thrown. passes(t, () => { - assertions.throws(() => { + return assertions.throws(() => { throw new Error('foo'); }); }); @@ -1042,7 +1035,7 @@ test('.throws()', gather(t => { // Passes because the correct error is thrown. passes(t, () => { const err = new Error('foo'); - assertions.throws(() => { + return assertions.throws(() => { throw err; }, {is: err}); }); @@ -1050,7 +1043,7 @@ test('.throws()', gather(t => { // Fails because the thrown value is not an error fails(t, () => { const object = {}; - assertions.throws(() => { + return assertions.throws(() => { throw object; }, {is: object}); }); @@ -1058,21 +1051,21 @@ test('.throws()', gather(t => { // Fails because the thrown value is not the right one fails(t, () => { const err = new Error('foo'); - assertions.throws(() => { + return assertions.throws(() => { throw err; }, {is: {}}); }); // Passes because the correct error is thrown. passes(t, () => { - assertions.throws(() => { + return assertions.throws(() => { throw new TypeError(); }, {name: 'TypeError'}); }); // Fails because the thrown value is not an error fails(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = {name: 'Bob'}; throw err; }, {name: 'Bob'}); @@ -1080,14 +1073,14 @@ test('.throws()', gather(t => { // Fails because the thrown value is not the right one fails(t, () => { - assertions.throws(() => { + return assertions.throws(() => { throw new Error('foo'); }, {name: 'TypeError'}); }); // Passes because the correct error is thrown. passes(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = new TypeError(); err.code = 'ERR_TEST'; throw err; @@ -1096,7 +1089,7 @@ test('.throws()', gather(t => { // Passes because the correct error is thrown. passes(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = new TypeError(); err.code = 42; throw err; @@ -1105,7 +1098,7 @@ test('.throws()', gather(t => { // Fails because the thrown value is not the right one fails(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = new TypeError(); err.code = 'ERR_NOPE'; throw err; @@ -1113,7 +1106,7 @@ test('.throws()', gather(t => { }); fails(t, () => { - assertions.throws(() => { + return assertions.throws(() => { const err = new TypeError(); err.code = 1; throw err; @@ -1122,13 +1115,13 @@ test('.throws()', gather(t => { // Regression test for https://github.com/avajs/ava/issues/1676 fails(t, () => { - assertions.throws(() => { + return assertions.throws(() => { throw new Error('foo'); }, false); }); passes(t, () => { - assertions.throws(() => { + return assertions.throws(() => { throw new Error('foo'); }, undefined); }); @@ -1140,7 +1133,7 @@ test('.throws()', gather(t => { }); failsWith(t, () => { - assertions.throws(() => {}, undefined, null); + return assertions.throws(() => {}, undefined, null); }, { assertion: 'throws', improperUsage: true, @@ -1172,8 +1165,7 @@ test('.throwsAsync()', gather(t => { }); eventuallyFailsWith(t, () => { - const {throwsAsync} = assertions; - return throwsAsync(Promise.resolve('foo')); + return assertions.throwsAsync(Promise.resolve('foo')); }, { assertion: 'throwsAsync', message: '', @@ -1253,7 +1245,7 @@ test('.throwsAsync() returns the rejection reason of a promise returned by the f test('.throws() fails if passed a bad value', t => { failsWith(t, () => { - assertions.throws('not a function'); + return assertions.throws('not a function'); }, { assertion: 'throws', message: '`t.throws()` must be called with a function', @@ -1265,7 +1257,7 @@ test('.throws() fails if passed a bad value', t => { test('.throwsAsync() fails if passed a bad value', t => { failsWith(t, () => { - assertions.throwsAsync('not a function'); + return assertions.throwsAsync('not a function'); }, { assertion: 'throwsAsync', message: '`t.throwsAsync()` must be called with a function or promise', @@ -1277,7 +1269,7 @@ test('.throwsAsync() fails if passed a bad value', t => { test('.throws() fails if passed a bad expectation', t => { failsWith(t, () => { - assertions.throws(() => {}, true); + return assertions.throws(() => {}, true); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1285,7 +1277,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, 'foo'); + return assertions.throws(() => {}, 'foo'); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1293,7 +1285,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, /baz/); + return assertions.throws(() => {}, /baz/); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1301,7 +1293,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, class Bar {}); + return assertions.throws(() => {}, class Bar {}); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1309,7 +1301,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {}); + return assertions.throws(() => {}, {}); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1317,7 +1309,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, []); + return assertions.throws(() => {}, []); }, { assertion: 'throws', message: 'The second argument to `t.throws()` must be an expectation object, `null` or `undefined`', @@ -1325,7 +1317,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {code: {}}); + return assertions.throws(() => {}, {code: {}}); }, { assertion: 'throws', message: 'The `code` property of the second argument to `t.throws()` must be a string or number', @@ -1333,7 +1325,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {instanceOf: null}); + return assertions.throws(() => {}, {instanceOf: null}); }, { assertion: 'throws', message: 'The `instanceOf` property of the second argument to `t.throws()` must be a function', @@ -1341,7 +1333,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {message: null}); + return assertions.throws(() => {}, {message: null}); }, { assertion: 'throws', message: 'The `message` property of the second argument to `t.throws()` must be a string or regular expression', @@ -1349,7 +1341,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {name: null}); + return assertions.throws(() => {}, {name: null}); }, { assertion: 'throws', message: 'The `name` property of the second argument to `t.throws()` must be a string', @@ -1357,7 +1349,7 @@ test('.throws() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throws(() => {}, {is: {}, message: '', name: '', of() {}, foo: null}); + return assertions.throws(() => {}, {is: {}, message: '', name: '', of() {}, foo: null}); }, { assertion: 'throws', message: 'The second argument to `t.throws()` contains unexpected properties', @@ -1369,7 +1361,7 @@ test('.throws() fails if passed a bad expectation', t => { test('.throwsAsync() fails if passed a bad expectation', t => { failsWith(t, () => { - assertions.throwsAsync(() => {}, true); + return assertions.throwsAsync(() => {}, true); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1377,7 +1369,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, 'foo'); + return assertions.throwsAsync(() => {}, 'foo'); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1385,7 +1377,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, /baz/); + return assertions.throwsAsync(() => {}, /baz/); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1393,7 +1385,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, class Bar {}); + return assertions.throwsAsync(() => {}, class Bar {}); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1401,7 +1393,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {}); + return assertions.throwsAsync(() => {}, {}); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1409,7 +1401,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, []); + return assertions.throwsAsync(() => {}, []); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', @@ -1417,7 +1409,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {code: {}}); + return assertions.throwsAsync(() => {}, {code: {}}); }, { assertion: 'throwsAsync', message: 'The `code` property of the second argument to `t.throwsAsync()` must be a string or number', @@ -1425,7 +1417,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {instanceOf: null}); + return assertions.throwsAsync(() => {}, {instanceOf: null}); }, { assertion: 'throwsAsync', message: 'The `instanceOf` property of the second argument to `t.throwsAsync()` must be a function', @@ -1433,7 +1425,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {message: null}); + return assertions.throwsAsync(() => {}, {message: null}); }, { assertion: 'throwsAsync', message: 'The `message` property of the second argument to `t.throwsAsync()` must be a string or regular expression', @@ -1441,7 +1433,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {name: null}); + return assertions.throwsAsync(() => {}, {name: null}); }, { assertion: 'throwsAsync', message: 'The `name` property of the second argument to `t.throwsAsync()` must be a string', @@ -1449,7 +1441,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { }); failsWith(t, () => { - assertions.throwsAsync(() => {}, {is: {}, message: '', name: '', of() {}, foo: null}); + return assertions.throwsAsync(() => {}, {is: {}, message: '', name: '', of() {}, foo: null}); }, { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` contains unexpected properties', @@ -1490,17 +1482,16 @@ test('.throwsAsync() fails if passed null', t => { test('.notThrows()', gather(t => { // Passes because the function doesn't throw passes(t, () => { - assertions.notThrows(() => {}); + return assertions.notThrows(() => {}); }); passes(t, () => { - const {notThrows} = assertions; - notThrows(() => {}); + return assertions.notThrows(() => {}); }); // Fails because the function throws. failsWith(t, () => { - assertions.notThrows(() => { + return assertions.notThrows(() => { throw new Error('foo'); }); }, { @@ -1512,7 +1503,7 @@ test('.notThrows()', gather(t => { // Fails because the function throws. Asserts that message is used for the // assertion, not to validate the thrown error. failsWith(t, () => { - assertions.notThrows(() => { + return assertions.notThrows(() => { throw new Error('foo'); }, 'my message'); }, { @@ -1522,7 +1513,7 @@ test('.notThrows()', gather(t => { }); failsWith(t, () => { - assertions.notThrows(() => {}, null); + return assertions.notThrows(() => {}, null); }, { assertion: 'notThrows', improperUsage: true, @@ -1539,8 +1530,7 @@ test('.notThrowsAsync()', gather(t => { eventuallyPasses(t, () => assertions.notThrowsAsync(Promise.resolve())); eventuallyPasses(t, () => { - const {notThrowsAsync} = assertions; - return notThrowsAsync(Promise.resolve()); + return assertions.notThrowsAsync(Promise.resolve()); }); // Fails because the promise is rejected @@ -1593,7 +1583,7 @@ test('.notThrowsAsync()', gather(t => { test('.notThrowsAsync() returns undefined for a fulfilled promise', t => { return assertions.notThrowsAsync(Promise.resolve(Symbol(''))).then(actual => { - t.is(actual, undefined); + t.is(actual, true); }); }); @@ -1601,13 +1591,13 @@ test('.notThrowsAsync() returns undefined for a fulfilled promise returned by th return assertions.notThrowsAsync(() => { return Promise.resolve(Symbol('')); }).then(actual => { - t.is(actual, undefined); + t.is(actual, true); }); }); test('.notThrows() fails if passed a bad value', t => { failsWith(t, () => { - assertions.notThrows('not a function'); + return assertions.notThrows('not a function'); }, { assertion: 'notThrows', message: '`t.notThrows()` must be called with a function', @@ -1619,7 +1609,7 @@ test('.notThrows() fails if passed a bad value', t => { test('.notThrowsAsync() fails if passed a bad value', t => { failsWith(t, () => { - assertions.notThrowsAsync('not a function'); + return assertions.notThrowsAsync('not a function'); }, { assertion: 'notThrowsAsync', message: '`t.notThrowsAsync()` must be called with a function or promise', @@ -1672,22 +1662,21 @@ test('.snapshot()', t => { const assertions = setup('passes'); passes(t, () => { - assertions.snapshot({foo: 'bar'}); + return assertions.snapshot({foo: 'bar'}); }); passes(t, () => { - const {snapshot} = assertions; - snapshot({foo: 'bar'}); + return assertions.snapshot({foo: 'bar'}); }); } { const assertions = setup('fails'); if (updating) { - assertions.snapshot({foo: 'bar'}); + return assertions.snapshot({foo: 'bar'}); } else { failsWith(t, () => { - assertions.snapshot({foo: 'not bar'}); + return assertions.snapshot({foo: 'not bar'}); }, { assertion: 'snapshot', message: 'Did not match snapshot', @@ -1699,10 +1688,10 @@ test('.snapshot()', t => { { const assertions = setup('fails'); if (updating) { - assertions.snapshot({foo: 'bar'}, 'my message'); + return assertions.snapshot({foo: 'bar'}, 'my message'); } else { failsWith(t, () => { - assertions.snapshot({foo: 'not bar'}, 'my message'); + return assertions.snapshot({foo: 'not bar'}, 'my message'); }, { assertion: 'snapshot', message: 'my message', @@ -1714,7 +1703,7 @@ test('.snapshot()', t => { { const assertions = setup('bad message'); failsWith(t, () => { - assertions.snapshot(null, null); + return assertions.snapshot(null, null); }, { assertion: 'snapshot', improperUsage: true, @@ -1726,7 +1715,7 @@ test('.snapshot()', t => { }); failsWith(t, () => { - assertions.snapshot(null, ''); + return assertions.snapshot(null, ''); }, { assertion: 'snapshot', improperUsage: true, @@ -1742,7 +1731,7 @@ test('.snapshot()', t => { // See https://github.com/avajs/ava/issues/2669 const assertions = setup('id'); failsWith(t, () => { - assertions.snapshot({foo: 'bar'}, {id: 'an id'}); + return assertions.snapshot({foo: 'bar'}, {id: 'an id'}); }, { assertion: 'snapshot', improperUsage: true, @@ -1760,7 +1749,7 @@ test('.snapshot()', t => { test('.truthy()', t => { failsWith(t, () => { - assertions.truthy(0); + return assertions.truthy(0); }, { assertion: 'truthy', message: '', @@ -1769,7 +1758,7 @@ test('.truthy()', t => { }); failsWith(t, () => { - assertions.truthy(false, 'my message'); + return assertions.truthy(false, 'my message'); }, { assertion: 'truthy', message: 'my message', @@ -1778,18 +1767,16 @@ test('.truthy()', t => { }); passes(t, () => { - assertions.truthy(1); - assertions.truthy(true); + return assertions.truthy(1) && + assertions.truthy(true); }); passes(t, () => { - const {truthy} = assertions; - truthy(1); - truthy(true); + return assertions.truthy(1) && assertions.truthy(true); }); failsWith(t, () => { - assertions.truthy(true, null); + return assertions.truthy(true, null); }, { assertion: 'truthy', improperUsage: true, @@ -1805,7 +1792,7 @@ test('.truthy()', t => { test('.falsy()', t => { failsWith(t, () => { - assertions.falsy(1); + return assertions.falsy(1); }, { assertion: 'falsy', message: '', @@ -1814,7 +1801,7 @@ test('.falsy()', t => { }); failsWith(t, () => { - assertions.falsy(true, 'my message'); + return assertions.falsy(true, 'my message'); }, { assertion: 'falsy', message: 'my message', @@ -1823,18 +1810,17 @@ test('.falsy()', t => { }); passes(t, () => { - assertions.falsy(0); - assertions.falsy(false); + return assertions.falsy(0) && + assertions.falsy(false); }); passes(t, () => { - const {falsy} = assertions; - falsy(0); - falsy(false); + return assertions.falsy(0) && + assertions.falsy(false); }); failsWith(t, () => { - assertions.falsy(false, null); + return assertions.falsy(false, null); }, { assertion: 'falsy', improperUsage: true, @@ -1850,7 +1836,7 @@ test('.falsy()', t => { test('.true()', t => { failsWith(t, () => { - assertions.true(1); + return assertions.true(1); }, { assertion: 'true', message: '', @@ -1858,7 +1844,7 @@ test('.true()', t => { }); failsWith(t, () => { - assertions.true(0); + return assertions.true(0); }, { assertion: 'true', message: '', @@ -1866,7 +1852,7 @@ test('.true()', t => { }); failsWith(t, () => { - assertions.true(false); + return assertions.true(false); }, { assertion: 'true', message: '', @@ -1874,7 +1860,7 @@ test('.true()', t => { }); failsWith(t, () => { - assertions.true('foo', 'my message'); + return assertions.true('foo', 'my message'); }, { assertion: 'true', message: 'my message', @@ -1882,16 +1868,16 @@ test('.true()', t => { }); passes(t, () => { - assertions.true(true); + return assertions.true(true); }); passes(t, () => { - const {true: trueFn} = assertions; - trueFn(true); + const {true: trueFn} = assertions + return trueFn(true); }); failsWith(t, () => { - assertions.true(true, null); + return assertions.true(true, null); }, { assertion: 'true', improperUsage: true, @@ -1907,7 +1893,7 @@ test('.true()', t => { test('.false()', t => { failsWith(t, () => { - assertions.false(0); + return assertions.false(0); }, { assertion: 'false', message: '', @@ -1915,7 +1901,7 @@ test('.false()', t => { }); failsWith(t, () => { - assertions.false(1); + return assertions.false(1); }, { assertion: 'false', message: '', @@ -1923,7 +1909,7 @@ test('.false()', t => { }); failsWith(t, () => { - assertions.false(true); + return assertions.false(true); }, { assertion: 'false', message: '', @@ -1931,7 +1917,7 @@ test('.false()', t => { }); failsWith(t, () => { - assertions.false('foo', 'my message'); + return assertions.false('foo', 'my message'); }, { assertion: 'false', message: 'my message', @@ -1939,16 +1925,16 @@ test('.false()', t => { }); passes(t, () => { - assertions.false(false); + return assertions.false(false); }); passes(t, () => { - const {false: falseFn} = assertions; - falseFn(false); + const {false: falseFn} = assertions; + return falseFn(false); }); failsWith(t, () => { - assertions.false(false, null); + return assertions.false(false, null); }, { assertion: 'false', improperUsage: true, @@ -1964,16 +1950,15 @@ test('.false()', t => { test('.regex()', t => { passes(t, () => { - assertions.regex('abc', /^abc$/); + return assertions.regex('abc', /^abc$/); }); passes(t, () => { - const {regex} = assertions; - regex('abc', /^abc$/); + return assertions.regex('abc', /^abc$/); }); failsWith(t, () => { - assertions.regex('foo', /^abc$/); + return assertions.regex('foo', /^abc$/); }, { assertion: 'regex', message: '', @@ -1984,7 +1969,7 @@ test('.regex()', t => { }); failsWith(t, () => { - assertions.regex('foo', /^abc$/, 'my message'); + return assertions.regex('foo', /^abc$/, 'my message'); }, { assertion: 'regex', message: 'my message', @@ -1995,7 +1980,7 @@ test('.regex()', t => { }); failsWith(t, () => { - assertions.regex('foo', /^abc$/, null); + return assertions.regex('foo', /^abc$/, null); }, { assertion: 'regex', improperUsage: true, @@ -2011,7 +1996,7 @@ test('.regex()', t => { test('.regex() fails if passed a bad value', t => { failsWith(t, () => { - assertions.regex(42, /foo/); + return assertions.regex(42, /foo/); }, { assertion: 'regex', improperUsage: true, @@ -2020,7 +2005,7 @@ test('.regex() fails if passed a bad value', t => { }); failsWith(t, () => { - assertions.regex('42', {}); + return assertions.regex('42', {}); }, { assertion: 'regex', message: '`t.regex()` must be called with a regular expression', @@ -2032,16 +2017,15 @@ test('.regex() fails if passed a bad value', t => { test('.notRegex()', t => { passes(t, () => { - assertions.notRegex('abc', /def/); + return assertions.notRegex('abc', /def/); }); passes(t, () => { - const {notRegex} = assertions; - notRegex('abc', /def/); + return assertions.notRegex('abc', /def/); }); failsWith(t, () => { - assertions.notRegex('abc', /abc/); + return assertions.notRegex('abc', /abc/); }, { assertion: 'notRegex', message: '', @@ -2052,7 +2036,7 @@ test('.notRegex()', t => { }); failsWith(t, () => { - assertions.notRegex('abc', /abc/, 'my message'); + return assertions.notRegex('abc', /abc/, 'my message'); }, { assertion: 'notRegex', message: 'my message', @@ -2063,7 +2047,7 @@ test('.notRegex()', t => { }); failsWith(t, () => { - assertions.notRegex('abc', /abc/, null); + return assertions.notRegex('abc', /abc/, null); }, { assertion: 'notRegex', improperUsage: true, @@ -2079,7 +2063,7 @@ test('.notRegex()', t => { test('.notRegex() fails if passed a bad value', t => { failsWith(t, () => { - assertions.notRegex(42, /foo/); + return assertions.notRegex(42, /foo/); }, { assertion: 'notRegex', message: '`t.notRegex()` must be called with a string', @@ -2087,7 +2071,7 @@ test('.notRegex() fails if passed a bad value', t => { }); failsWith(t, () => { - assertions.notRegex('42', {}); + return assertions.notRegex('42', {}); }, { assertion: 'notRegex', message: '`t.notRegex()` must be called with a regular expression', @@ -2099,7 +2083,7 @@ test('.notRegex() fails if passed a bad value', t => { test('.assert()', t => { failsWith(t, () => { - assertions.assert(0); + return assertions.assert(0); }, { assertion: 'assert', message: '', @@ -2108,7 +2092,7 @@ test('.assert()', t => { }); failsWith(t, () => { - assertions.assert(false, 'my message'); + return assertions.assert(false, 'my message'); }, { assertion: 'assert', message: 'my message', @@ -2117,18 +2101,16 @@ test('.assert()', t => { }); passes(t, () => { - assertions.assert(1); - assertions.assert(true); + return assertions.assert(1) && + assertions.assert(true); }); passes(t, () => { - const {assert} = assertions; - assert(1); - assert(true); + return assertions.assert(1) && assertions.assert(true); }); failsWith(t, () => { - assertions.assert(null, null); + return assertions.assert(null, null); }, { assertion: 'assert', improperUsage: true, From 848d46cf8c9dbdb557ba37bf9d634dcb264d09ca Mon Sep 17 00:00:00 2001 From: John Markham Date: Wed, 24 Feb 2021 14:47:43 -0800 Subject: [PATCH 02/11] Type bandaid to appease tsd --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 84b920e78..47e146bb0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -493,7 +493,7 @@ export interface CbExecutionContext extends ExecutionContext< end(error?: any): void; } -export type ImplementationResult = PromiseLike | Subscribable | void; +export type ImplementationResult = PromiseLike | Subscribable | boolean | void; export type Implementation = (t: ExecutionContext) => ImplementationResult; export type CbImplementation = (t: CbExecutionContext) => ImplementationResult; From 350d75ffcaf24bcb7fdd2cab0175c852247f4339 Mon Sep 17 00:00:00 2001 From: John Markham Date: Wed, 24 Feb 2021 22:03:58 -0800 Subject: [PATCH 03/11] Potentially fix linting errors with xo --- lib/assert.js | 224 ++++++++++++++++++++++----------------------- test-tap/assert.js | 61 ++++++------ 2 files changed, 142 insertions(+), 143 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index cfdad3dd5..ccc8fcd09 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -283,11 +283,11 @@ class Assertions { } fail(event.error); - return false; + return false; }, onSuccess: () => { pass(); - return true; + return true; }, bindReceiver: false, patterns: [pattern] @@ -309,7 +309,7 @@ class Assertions { this.pass = withSkip(() => { pass(); - return true; + return true; }); this.fail = withSkip(message => { @@ -322,40 +322,40 @@ class Assertions { message: message || 'Test failed via `t.fail()`' })); - return false; + return false; }); - this.is = withSkip((actual, expected, message) => { - if (!checkMessage('is', message)) { - return false; - } - - if (Object.is(actual, expected)) { - pass(); - return true; - } - - const result = concordance.compare(actual, expected, concordanceOptions); - const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); - - if (result.pass) { - fail(new AssertionError({ - assertion: 'is', - message, - raw: {actual, expected}, - values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)] - })); - } else { - fail(new AssertionError({ - assertion: 'is', - message, - raw: {actual, expected}, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - } - - return false; + this.is = withSkip((actual, expected, message) => { + if (!checkMessage('is', message)) { + return false; + } + + if (Object.is(actual, expected)) { + pass(); + return true; + } + + const result = concordance.compare(actual, expected, concordanceOptions); + const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + + if (result.pass) { + fail(new AssertionError({ + assertion: 'is', + message, + raw: {actual, expected}, + values: [formatDescriptorWithLabel('Values are deeply equal to each other, but they are not the same:', actualDescriptor)] + })); + } else { + fail(new AssertionError({ + assertion: 'is', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + } + + return false; }); this.not = withSkip((actual, expected, message) => { @@ -370,11 +370,11 @@ class Assertions { raw: {actual, expected}, values: [formatWithLabel('Value is the same as:', actual)] })); - return false; - } + return false; + } - pass(); - return true; + pass(); + return true; }); this.deepEqual = withSkip((actual, expected, message) => { @@ -385,19 +385,19 @@ class Assertions { const result = concordance.compare(actual, expected, concordanceOptions); if (result.pass) { pass(); - return true; - } - - const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); - fail(new AssertionError({ - assertion: 'deepEqual', - message, - raw: {actual, expected}, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - return false; - }); + return true; + } + + const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + fail(new AssertionError({ + assertion: 'deepEqual', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + return false; + }); this.notDeepEqual = withSkip((actual, expected, message) => { if (!checkMessage('notDeepEqual', message)) { @@ -413,10 +413,10 @@ class Assertions { raw: {actual, expected}, values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)] })); - } + } - pass(); - return true; + pass(); + return true; }); this.like = withSkip((actual, selector, message) => { @@ -452,20 +452,20 @@ class Assertions { } const result = concordance.compare(comparable, selector, concordanceOptions); - if (result.pass) { - pass(); - return true; - } - - const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions); - const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions); - fail(new AssertionError({ - assertion: 'like', - message, - values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] - })); - - return false; + if (result.pass) { + pass(); + return true; + } + + const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions); + fail(new AssertionError({ + assertion: 'like', + message, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); + + return false; }); this.throws = withSkip((...args) => { @@ -651,7 +651,7 @@ class Assertions { } pass(); - return true; + return true; }); this.notThrowsAsync = withSkip((nonThrower, message) => { @@ -773,10 +773,10 @@ class Assertions { if (result.pass) { pass(); - return true; - } + return true; + } - if (result.actual) { + if (result.actual) { fail(new AssertionError({ assertion: 'snapshot', message: message || 'Did not match snapshot', @@ -790,7 +790,7 @@ class Assertions { })); } - return false; + return false; }); this.truthy = withSkip((actual, message) => { @@ -800,20 +800,20 @@ class Assertions { if (actual) { pass(); - return true; - } - - fail(new AssertionError({ - assertion: 'truthy', - message, - operator: '!!', - values: [formatWithLabel('Value is not truthy:', actual)] - })); - return false; - }); - - this.falsy = withSkip((actual, message) => { - if (!checkMessage('falsy', message)) { + return true; + } + + fail(new AssertionError({ + assertion: 'truthy', + message, + operator: '!!', + values: [formatWithLabel('Value is not truthy:', actual)] + })); + return false; + }); + + this.falsy = withSkip((actual, message) => { + if (!checkMessage('falsy', message)) { return false; } @@ -824,11 +824,11 @@ class Assertions { operator: '!', values: [formatWithLabel('Value is not falsy:', actual)] })); - return false; - } + return false; + } - pass(); - return true; + pass(); + return true; }); this.true = withSkip((actual, message) => { @@ -838,15 +838,15 @@ class Assertions { if (actual === true) { pass(); - return true; - } - - fail(new AssertionError({ - assertion: 'true', - message, - values: [formatWithLabel('Value is not `true`:', actual)] - })); - return false; + return true; + } + + fail(new AssertionError({ + assertion: 'true', + message, + values: [formatWithLabel('Value is not `true`:', actual)] + })); + return false; }); this.false = withSkip((actual, message) => { @@ -856,15 +856,15 @@ class Assertions { if (actual === false) { pass(); - return true; - } - - fail(new AssertionError({ - assertion: 'false', - message, - values: [formatWithLabel('Value is not `false`:', actual)] - })); - return false; + return true; + } + + fail(new AssertionError({ + assertion: 'false', + message, + values: [formatWithLabel('Value is not `false`:', actual)] + })); + return false; }); this.regex = withSkip((string, regex, message) => { @@ -905,7 +905,7 @@ class Assertions { } pass(); - return true; + return true; }); this.notRegex = withSkip((string, regex, message) => { @@ -946,7 +946,7 @@ class Assertions { } pass(); - return true; + return true; }); if (powerAssert === undefined) { diff --git a/test-tap/assert.js b/test-tap/assert.js index 35bf86eff..360c05d3b 100644 --- a/test-tap/assert.js +++ b/test-tap/assert.js @@ -70,7 +70,6 @@ function assertFailure(t, subset) { } else { t.same(lastFailure.values, []); } - } let gathering = false; @@ -103,7 +102,7 @@ function add(fn) { function failsWith(t, fn, subset) { lastFailure = null; - subset.returnValue = fn(); + subset.returnValue = fn(); assertFailure(t, subset); } @@ -596,19 +595,19 @@ test('.deepEqual()', t => { }); passes(t, () => { - return assertions.deepEqual(undefined, undefined) && - assertions.deepEqual({x: undefined}, {x: undefined}) && + return assertions.deepEqual(undefined, undefined) && + assertions.deepEqual({x: undefined}, {x: undefined}) && assertions.deepEqual({x: [undefined]}, {x: [undefined]}); - }); + }); - passes(t, () => { - return assertions.deepEqual(null, null) && - assertions.deepEqual({x: null}, {x: null}) && + passes(t, () => { + return assertions.deepEqual(null, null) && + assertions.deepEqual({x: null}, {x: null}) && assertions.deepEqual({x: [null]}, {x: [null]}); }); passes(t, () => { - return assertions.deepEqual(0, 0) && + return assertions.deepEqual(0, 0) && assertions.deepEqual(1, 1) && assertions.deepEqual(3.14, 3.14); }); @@ -1674,30 +1673,30 @@ test('.snapshot()', t => { const assertions = setup('fails'); if (updating) { return assertions.snapshot({foo: 'bar'}); - } else { - failsWith(t, () => { - return assertions.snapshot({foo: 'not bar'}); - }, { - assertion: 'snapshot', - message: 'Did not match snapshot', - values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}] - }); } + + failsWith(t, () => { + return assertions.snapshot({foo: 'not bar'}); + }, { + assertion: 'snapshot', + message: 'Did not match snapshot', + values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}] + }); } { const assertions = setup('fails'); if (updating) { return assertions.snapshot({foo: 'bar'}, 'my message'); - } else { - failsWith(t, () => { - return assertions.snapshot({foo: 'not bar'}, 'my message'); - }, { - assertion: 'snapshot', - message: 'my message', - values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}] - }); } + + failsWith(t, () => { + return assertions.snapshot({foo: 'not bar'}, 'my message'); + }, { + assertion: 'snapshot', + message: 'my message', + values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}] + }); } { @@ -1767,7 +1766,7 @@ test('.truthy()', t => { }); passes(t, () => { - return assertions.truthy(1) && + return assertions.truthy(1) && assertions.truthy(true); }); @@ -1810,12 +1809,12 @@ test('.falsy()', t => { }); passes(t, () => { - return assertions.falsy(0) && + return assertions.falsy(0) && assertions.falsy(false); }); passes(t, () => { - return assertions.falsy(0) && + return assertions.falsy(0) && assertions.falsy(false); }); @@ -1872,7 +1871,7 @@ test('.true()', t => { }); passes(t, () => { - const {true: trueFn} = assertions + const {true: trueFn} = assertions; return trueFn(true); }); @@ -1929,7 +1928,7 @@ test('.false()', t => { }); passes(t, () => { - const {false: falseFn} = assertions; + const {false: falseFn} = assertions; return falseFn(false); }); @@ -2101,7 +2100,7 @@ test('.assert()', t => { }); passes(t, () => { - return assertions.assert(1) && + return assertions.assert(1) && assertions.assert(true); }); From 68db1e67c78ce1ef4118f937a4b2e0b30db8818c Mon Sep 17 00:00:00 2001 From: John Markham Date: Wed, 24 Feb 2021 22:22:07 -0800 Subject: [PATCH 04/11] Remove unnecessary returnValue assignment --- test-tap/assert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-tap/assert.js b/test-tap/assert.js index 360c05d3b..cbd8f9031 100644 --- a/test-tap/assert.js +++ b/test-tap/assert.js @@ -102,7 +102,7 @@ function add(fn) { function failsWith(t, fn, subset) { lastFailure = null; - subset.returnValue = fn(); + fn(); assertFailure(t, subset); } From 1d51bae0da48eb7998699e1c02a0cd079677fc7f Mon Sep 17 00:00:00 2001 From: John Markham Date: Wed, 24 Feb 2021 22:28:38 -0800 Subject: [PATCH 05/11] Add in missing returns --- lib/assert.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/assert.js b/lib/assert.js index ccc8fcd09..3879f5e15 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -413,6 +413,7 @@ class Assertions { raw: {actual, expected}, values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)] })); + return false; } pass(); @@ -962,9 +963,11 @@ class Assertions { operator: '!!', values: [formatWithLabel('Value is not truthy:', actual)] })); + return false; } pass(); + return true; }); } else { this.assert = withSkip(withPowerAssert( From e4115fb5b4ae7c75901457eaa5d1512d35dedd4d Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 1 Mar 2021 17:01:53 +0100 Subject: [PATCH 06/11] Reword and reflow TypeScript documentation --- index.d.ts | 100 +++++++++++++++++++++-------------------------------- 1 file changed, 40 insertions(+), 60 deletions(-) diff --git a/index.d.ts b/index.d.ts index 47e146bb0..a0c92515c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -34,23 +34,19 @@ export type CommitDiscardOptions = { export interface Assertions { /** - * Assert that `actual` is - * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), - * returning Boolean indicating whether the assertion passes. Comes with - * power-assert. + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. Comes with power-assert. */ assert: AssertAssertion; /** - * Assert that `actual` is [deeply - * equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning Boolean indicating whether the assertion passes. + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. */ deepEqual: DeepEqualAssertion; /** - * Assert that `value` is like `selector`, returning Boolean indicating - * whether the assertion passes. + * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. */ like: LikeAssertion; @@ -58,42 +54,39 @@ export interface Assertions { fail: FailAssertion; /** - * Assert that `actual` is strictly false, returning Boolean indicating - * whether the assertion passes. + * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. */ false: FalseAssertion; /** - * Assert that `actual` is - * [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning - * Boolean whether the assertion passes. + * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean + * indicating whether the assertion passed. */ falsy: FalsyAssertion; /** * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) - * as `expected`, returning Boolean indicating whether the assertion passes. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. */ is: IsAssertion; /** * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) - * as `expected`, returning Boolean indicating whether the assertion passes. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. */ not: NotAssertion; /** - * Assert that `actual` is not [deeply - * equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning Boolean indicating whether the assertion passes. + * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. */ notDeepEqual: NotDeepEqualAssertion; /** - * Assert that `string` does not match the regular expression, returning - * Boolean indicating whether the assertion passes. + * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion + * passed. */ notRegex: NotRegexAssertion; @@ -107,8 +100,7 @@ export interface Assertions { pass: PassAssertion; /** - * Assert that `string` matches the regular expression, returning Boolean - * indicating whether the assertion passes. + * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. */ regex: RegexAssertion; @@ -131,25 +123,21 @@ export interface Assertions { throwsAsync: ThrowsAsyncAssertion; /** - * Assert that `actual` is strictly true, returning Boolean indicating - * whether the assertion passes. + * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. */ true: TrueAssertion; /** - * Assert that `actual` is - * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), - * returning Boolean indicating whether the assertion passes. + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. */ truthy: TruthyAssertion; } export interface AssertAssertion { /** - * Assert that `actual` is - * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), - * returning Boolean indicating whether the assertion passes. Comes with - * power-assert. + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. Comes with power-assert. */ (actual: any, message?: string): boolean; @@ -159,9 +147,8 @@ export interface AssertAssertion { export interface DeepEqualAssertion { /** - * Assert that `actual` is [deeply - * equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning Boolean indicating whether the assertion passes. + * Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. */ (actual: ValueType, expected: ValueType, message?: string): boolean; @@ -171,8 +158,7 @@ export interface DeepEqualAssertion { export interface LikeAssertion { /** - * Assert that `value` is like `selector`, returning Boolean indicating - * whether the assertion passes. + * Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed. */ (value: any, selector: Record, message?: string): boolean; @@ -190,8 +176,7 @@ export interface FailAssertion { export interface FalseAssertion { /** - * Assert that `actual` is strictly false, returning Boolean indicating - * whether the assertion passes. + * Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed. */ (actual: any, message?: string): boolean; @@ -201,9 +186,8 @@ export interface FalseAssertion { export interface FalsyAssertion { /** - * Assert that `actual` is - * [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning - * Boolean whether the assertion passes. + * Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean + * indicating whether the assertion passed. */ (actual: any, message?: string): boolean; @@ -214,8 +198,8 @@ export interface FalsyAssertion { export interface IsAssertion { /** * Assert that `actual` is [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) - * as `expected`, returning Boolean indicating whether the assertion passes. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. */ (actual: ValueType, expected: ValueType, message?: string): boolean; @@ -226,8 +210,8 @@ export interface IsAssertion { export interface NotAssertion { /** * Assert that `actual` is not [the same - * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) - * as `expected`, returning Boolean indicating whether the assertion passes. + * value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`, + * returning a boolean indicating whether the assertion passed. */ (actual: ValueType, expected: ValueType, message?: string): boolean; @@ -237,9 +221,8 @@ export interface NotAssertion { export interface NotDeepEqualAssertion { /** - * Assert that `actual` is not [deeply - * equal](https://github.com/concordancejs/concordance#comparison-details) to - * `expected`, returning Boolean indicating whether the assertion passes. + * Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to + * `expected`, returning a boolean indicating whether the assertion passed. */ (actual: ValueType, expected: ValueType, message?: string): boolean; @@ -249,8 +232,8 @@ export interface NotDeepEqualAssertion { export interface NotRegexAssertion { /** - * Assert that `string` does not match the regular expression, returning - * Boolean indicating whether the assertion passes. + * Assert that `string` does not match the regular expression, returning a boolean indicating whether the assertion + * passed. */ (string: string, regex: RegExp, message?: string): boolean; @@ -287,8 +270,7 @@ export interface PassAssertion { export interface RegexAssertion { /** - * Assert that `string` matches the regular expression, returning Boolean - * indicating whether the assertion passes. + * Assert that `string` matches the regular expression, returning a boolean indicating whether the assertion passed. */ (string: string, regex: RegExp, message?: string): boolean; @@ -350,8 +332,7 @@ export interface ThrowsAsyncAssertion { export interface TrueAssertion { /** - * Assert that `actual` is strictly true, returning Boolean indicating - * whether the assertion passes. + * Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed. */ (actual: any, message?: string): boolean; @@ -361,9 +342,8 @@ export interface TrueAssertion { export interface TruthyAssertion { /** - * Assert that `actual` is - * [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), - * returning Boolean indicating whether the assertion passes. + * Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean + * indicating whether the assertion passed. */ (actual: any, message?: string): boolean; From a6ad5c7f009f1ba2e4eb84e921400e6b20cf0488 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 1 Mar 2021 17:04:10 +0100 Subject: [PATCH 07/11] Add FIXME for ImplementationResult type --- index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.d.ts b/index.d.ts index a0c92515c..7641ba2ef 100644 --- a/index.d.ts +++ b/index.d.ts @@ -473,6 +473,8 @@ export interface CbExecutionContext extends ExecutionContext< end(error?: any): void; } +// FIXME(novemberborn) Refactor implementations to be different types returning a promise,, subscribable, or void, not a +// single type returning a union. A union with void as a return type doesn't make sense. export type ImplementationResult = PromiseLike | Subscribable | boolean | void; export type Implementation = (t: ExecutionContext) => ImplementationResult; export type CbImplementation = (t: CbExecutionContext) => ImplementationResult; From cc361ccac913ddd76858eb23492df89c380af230 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 1 Mar 2021 17:38:16 +0100 Subject: [PATCH 08/11] throw assertions must not return booleans Normally throws() returns the error when it passes. Let's not change that. --- lib/assert.js | 15 +++--- test-tap/assert.js | 113 ++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index 3879f5e15..7f1d45f08 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -636,7 +636,7 @@ class Assertions { message: '`t.notThrows()` must be called with a function', values: [formatWithLabel('Called with:', fn)] })); - return false; + return; } try { @@ -648,16 +648,15 @@ class Assertions { actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); - return false; + return; } pass(); - return true; }); this.notThrowsAsync = withSkip((nonThrower, message) => { if (!checkMessage('notThrowsAsync', message)) { - return Promise.resolve(false); + return Promise.resolve(); } if (typeof nonThrower !== 'function' && !isPromise(nonThrower)) { @@ -667,14 +666,14 @@ class Assertions { message: '`t.notThrowsAsync()` must be called with a function or promise', values: [formatWithLabel('Called with:', nonThrower)] })); - return Promise.resolve(false); + return Promise.resolve(); } const handlePromise = (promise, wasReturned) => { // Create an error object to record the stack before it gets lost in the promise chain. const savedError = getErrorWithLongStackTrace(); // Handle "promise like" objects by casting to a real Promise. - const intermediate = Promise.resolve(promise).then(() => true, error => { // eslint-disable-line promise/prefer-await-to-then + const intermediate = Promise.resolve(promise).then(noop, error => { // eslint-disable-line promise/prefer-await-to-then throw new AssertionError({ assertion: 'notThrowsAsync', message, @@ -701,7 +700,7 @@ class Assertions { actualStack: error.stack, values: [formatWithLabel('Function threw:', error)] })); - return Promise.resolve(false); + return Promise.resolve(); } if (!isPromise(retval)) { @@ -710,7 +709,7 @@ class Assertions { message, values: [formatWithLabel('Function did not return a promise. Use `t.notThrows()` instead:', retval)] })); - return Promise.resolve(false); + return Promise.resolve(); } return handlePromise(retval, true); diff --git a/test-tap/assert.js b/test-tap/assert.js index cbd8f9031..a152409a8 100644 --- a/test-tap/assert.js +++ b/test-tap/assert.js @@ -100,16 +100,20 @@ function add(fn) { return gatheringPromise; } -function failsWith(t, fn, subset) { +function failsWith(t, fn, subset, {expectBoolean = true} = {}) { lastFailure = null; - fn(); + const retval = fn(); assertFailure(t, subset); + if (expectBoolean) { + t.false(retval); + } } -function eventuallyFailsWith(t, fn, subset) { +function throwsAsyncFails(t, fn, subset) { return add(() => { lastFailure = null; - return fn().then(() => { + return fn().then(retval => { + t.is(retval, undefined); assertFailure(t, subset); }); }); @@ -119,39 +123,28 @@ function fails(t, fn) { lastFailure = null; const retval = fn(); if (lastFailure) { - t.pass(retval); + t.false(retval); } else { t.fail('Expected assertion to fail'); } } -/* Might be useful -function eventuallyFails(t, fn) { - return add(() => { - lastFailure = null; - return fn().then(() => { - if (lastFailure) { - t.pass(); - } else { - t.fail('Expected assertion to fail'); - } - }); - }); -} -*/ - -function passes(t, fn) { +function passes(t, fn, {expectBoolean = true} = {}) { lastPassed = false; lastFailure = null; const retval = fn(); if (lastPassed) { - t.pass(retval); + if (expectBoolean) { + t.true(retval); + } else { + t.pass(); + } } else { t.ifError(lastFailure, 'Expected assertion to pass'); } } -function eventuallyPasses(t, fn) { +function throwsAsyncPasses(t, fn) { return add(() => { lastPassed = false; lastFailure = null; @@ -1157,13 +1150,13 @@ test('.throws() returns the thrown error', t => { test('.throwsAsync()', gather(t => { // Fails because the promise is resolved, not rejected. - eventuallyFailsWith(t, () => assertions.throwsAsync(Promise.resolve('foo')), { + throwsAsyncFails(t, () => assertions.throwsAsync(Promise.resolve('foo')), { assertion: 'throwsAsync', message: '', values: [{label: 'Promise resolved with:', formatted: /'foo'/}] }); - eventuallyFailsWith(t, () => { + throwsAsyncFails(t, () => { return assertions.throwsAsync(Promise.resolve('foo')); }, { assertion: 'throwsAsync', @@ -1172,27 +1165,27 @@ test('.throwsAsync()', gather(t => { }); // Fails because the promise is resolved with an Error - eventuallyFailsWith(t, () => assertions.throwsAsync(Promise.resolve(new Error())), { + throwsAsyncFails(t, () => assertions.throwsAsync(Promise.resolve(new Error())), { assertion: 'throwsAsync', message: '', values: [{label: 'Promise resolved with:', formatted: /Error/}] }); // Fails because the function returned a promise that resolved, not rejected. - eventuallyFailsWith(t, () => assertions.throwsAsync(() => Promise.resolve('foo')), { + throwsAsyncFails(t, () => assertions.throwsAsync(() => Promise.resolve('foo')), { assertion: 'throwsAsync', message: '', values: [{label: 'Returned promise resolved with:', formatted: /'foo'/}] }); // Passes because the promise was rejected with an error. - eventuallyPasses(t, () => assertions.throwsAsync(Promise.reject(new Error()))); + throwsAsyncPasses(t, () => assertions.throwsAsync(Promise.reject(new Error()))); // Passes because the function returned a promise rejected with an error. - eventuallyPasses(t, () => assertions.throwsAsync(() => Promise.reject(new Error()))); + throwsAsyncPasses(t, () => assertions.throwsAsync(() => Promise.reject(new Error()))); // Fails because the function throws synchronously - eventuallyFailsWith(t, () => assertions.throwsAsync(() => { + throwsAsyncFails(t, () => assertions.throwsAsync(() => { throw new Error('sync'); }, undefined, 'message'), { assertion: 'throwsAsync', @@ -1203,7 +1196,7 @@ test('.throwsAsync()', gather(t => { }); // Fails because the function did not return a promise - eventuallyFailsWith(t, () => assertions.throwsAsync(() => {}, undefined, 'message'), { + throwsAsyncFails(t, () => assertions.throwsAsync(() => {}, undefined, 'message'), { assertion: 'throwsAsync', message: 'message', values: [ @@ -1211,7 +1204,7 @@ test('.throwsAsync()', gather(t => { ] }); - eventuallyFailsWith(t, () => assertions.throwsAsync(Promise.resolve(), undefined, null), { + throwsAsyncFails(t, () => assertions.throwsAsync(Promise.resolve(), undefined, null), { assertion: 'throwsAsync', improperUsage: true, message: 'The assertion message must be a string', @@ -1261,7 +1254,7 @@ test('.throwsAsync() fails if passed a bad value', t => { assertion: 'throwsAsync', message: '`t.throwsAsync()` must be called with a function or promise', values: [{label: 'Called with:', formatted: /not a function/}] - }); + }, {expectBoolean: false}); t.end(); }); @@ -1365,7 +1358,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /true/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, 'foo'); @@ -1373,7 +1366,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /foo/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, /baz/); @@ -1381,7 +1374,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /baz/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, class Bar {}); @@ -1389,7 +1382,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /Bar/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {}); @@ -1397,7 +1390,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /{}/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, []); @@ -1405,7 +1398,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` must be an expectation object, `null` or `undefined`', values: [{label: 'Called with:', formatted: /\[]/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {code: {}}); @@ -1413,7 +1406,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The `code` property of the second argument to `t.throwsAsync()` must be a string or number', values: [{label: 'Called with:', formatted: /code: {}/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {instanceOf: null}); @@ -1421,7 +1414,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The `instanceOf` property of the second argument to `t.throwsAsync()` must be a function', values: [{label: 'Called with:', formatted: /instanceOf: null/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {message: null}); @@ -1429,7 +1422,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The `message` property of the second argument to `t.throwsAsync()` must be a string or regular expression', values: [{label: 'Called with:', formatted: /message: null/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {name: null}); @@ -1437,7 +1430,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The `name` property of the second argument to `t.throwsAsync()` must be a string', values: [{label: 'Called with:', formatted: /name: null/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.throwsAsync(() => {}, {is: {}, message: '', name: '', of() {}, foo: null}); @@ -1445,7 +1438,7 @@ test('.throwsAsync() fails if passed a bad expectation', t => { assertion: 'throwsAsync', message: 'The second argument to `t.throwsAsync()` contains unexpected properties', values: [{label: 'Called with:', formatted: /foo: null/}] - }); + }, {expectBoolean: false}); t.end(); }); @@ -1482,11 +1475,11 @@ test('.notThrows()', gather(t => { // Passes because the function doesn't throw passes(t, () => { return assertions.notThrows(() => {}); - }); + }, {expectBoolean: false}); passes(t, () => { return assertions.notThrows(() => {}); - }); + }, {expectBoolean: false}); // Fails because the function throws. failsWith(t, () => { @@ -1497,7 +1490,7 @@ test('.notThrows()', gather(t => { assertion: 'notThrows', message: '', values: [{label: 'Function threw:', formatted: /foo/}] - }); + }, {expectBoolean: false}); // Fails because the function throws. Asserts that message is used for the // assertion, not to validate the thrown error. @@ -1509,7 +1502,7 @@ test('.notThrows()', gather(t => { assertion: 'notThrows', message: 'my message', values: [{label: 'Function threw:', formatted: /foo/}] - }); + }, {expectBoolean: false}); failsWith(t, () => { return assertions.notThrows(() => {}, null); @@ -1521,36 +1514,36 @@ test('.notThrows()', gather(t => { label: 'Called with:', formatted: /null/ }] - }); + }, {expectBoolean: false}); })); test('.notThrowsAsync()', gather(t => { // Passes because the promise is resolved - eventuallyPasses(t, () => assertions.notThrowsAsync(Promise.resolve())); + throwsAsyncPasses(t, () => assertions.notThrowsAsync(Promise.resolve())); - eventuallyPasses(t, () => { + throwsAsyncPasses(t, () => { return assertions.notThrowsAsync(Promise.resolve()); }); // Fails because the promise is rejected - eventuallyFailsWith(t, () => assertions.notThrowsAsync(Promise.reject(new Error())), { + throwsAsyncFails(t, () => assertions.notThrowsAsync(Promise.reject(new Error())), { assertion: 'notThrowsAsync', message: '', values: [{label: 'Promise rejected with:', formatted: /Error/}] }); // Passes because the function returned a resolved promise - eventuallyPasses(t, () => assertions.notThrowsAsync(() => Promise.resolve())); + throwsAsyncPasses(t, () => assertions.notThrowsAsync(() => Promise.resolve())); // Fails because the function returned a rejected promise - eventuallyFailsWith(t, () => assertions.notThrowsAsync(() => Promise.reject(new Error())), { + throwsAsyncFails(t, () => assertions.notThrowsAsync(() => Promise.reject(new Error())), { assertion: 'notThrowsAsync', message: '', values: [{label: 'Returned promise rejected with:', formatted: /Error/}] }); // Fails because the function throws synchronously - eventuallyFailsWith(t, () => assertions.notThrowsAsync(() => { + throwsAsyncFails(t, () => assertions.notThrowsAsync(() => { throw new Error('sync'); }, 'message'), { assertion: 'notThrowsAsync', @@ -1561,7 +1554,7 @@ test('.notThrowsAsync()', gather(t => { }); // Fails because the function did not return a promise - eventuallyFailsWith(t, () => assertions.notThrowsAsync(() => {}, 'message'), { + throwsAsyncFails(t, () => assertions.notThrowsAsync(() => {}, 'message'), { assertion: 'notThrowsAsync', message: 'message', values: [ @@ -1569,7 +1562,7 @@ test('.notThrowsAsync()', gather(t => { ] }); - eventuallyFailsWith(t, () => assertions.notThrowsAsync(Promise.resolve(), null), { + throwsAsyncFails(t, () => assertions.notThrowsAsync(Promise.resolve(), null), { assertion: 'notThrowsAsync', improperUsage: true, message: 'The assertion message must be a string', @@ -1582,7 +1575,7 @@ test('.notThrowsAsync()', gather(t => { test('.notThrowsAsync() returns undefined for a fulfilled promise', t => { return assertions.notThrowsAsync(Promise.resolve(Symbol(''))).then(actual => { - t.is(actual, true); + t.is(actual, undefined); }); }); @@ -1590,7 +1583,7 @@ test('.notThrowsAsync() returns undefined for a fulfilled promise returned by th return assertions.notThrowsAsync(() => { return Promise.resolve(Symbol('')); }).then(actual => { - t.is(actual, true); + t.is(actual, undefined); }); }); @@ -1613,6 +1606,8 @@ test('.notThrowsAsync() fails if passed a bad value', t => { assertion: 'notThrowsAsync', message: '`t.notThrowsAsync()` must be called with a function or promise', values: [{label: 'Called with:', formatted: /not a function/}] + }, { + expectBoolean: false }); t.end(); From d8eba21e20f62552bfda72079d115c5dd1acad39 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Mon, 1 Mar 2021 17:38:56 +0100 Subject: [PATCH 09/11] Fix t.regex() returning false The previous commit fixed the return-value assertions, catching this one. --- lib/assert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/assert.js b/lib/assert.js index 7f1d45f08..119b247e3 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -869,7 +869,7 @@ class Assertions { this.regex = withSkip((string, regex, message) => { if (!checkMessage('regex', message)) { - return true; + return false; } if (typeof string !== 'string') { From 64ad93e8a0270c58b9fe6df22f12626b8211bb1e Mon Sep 17 00:00:00 2001 From: John Markham Date: Sat, 6 Mar 2021 13:39:29 -0800 Subject: [PATCH 10/11] Update Assertions documentation to mention their new return type 8) --- docs/03-assertions.md | 48 ++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/03-assertions.md b/docs/03-assertions.md index fe00df6de..ef1b69214 100644 --- a/docs/03-assertions.md +++ b/docs/03-assertions.md @@ -21,6 +21,16 @@ test('unicorns are truthy', t => { If multiple assertion failures are encountered within a single test, AVA will only display the *first* one. +All assertions return a boolean indicating whether the assertion was successful, except for the following: +```js +.throws(fn, expectation?, message?) +.throwsAsync(thrower, expectation?, message?) +.notThrows(fn, message?) +.notThrowsAsync(nonThrower, message?) +``` + +This allows for tests to be written to fail immediately when an assertion fails, if desired. + ## Assertion planning Assertion plans ensure tests only pass when a specific number of assertions have been executed. They'll help you catch cases where tests exit too early. They'll also cause tests to fail if too many assertions are executed, which can be useful if you have assertions inside callbacks or loops. @@ -165,39 +175,39 @@ test('custom assertion', t => { ### `.pass(message?)` -Passing assertion. +Passing assertion. Returns a boolean indicating whether the assertion passed. ### `.fail(message?)` -Failing assertion. +Failing assertion. Returns a boolean indicating whether the assertion passed. ### `.assert(value, message?)` -Asserts that `value` is truthy. This is [`power-assert`](#enhanced-assertion-messages) enabled. +Asserts that `value` is truthy. This is [`power-assert`](#enhanced-assertion-messages) enabled. Returns a boolean indicating whether the assertion passed. ### `.truthy(value, message?)` -Assert that `value` is truthy. +Assert that `value` is truthy. Returns a boolean indicating whether the assertion passed. ### `.falsy(value, message?)` -Assert that `value` is falsy. +Assert that `value` is falsy. Returns a boolean indicating whether the assertion passed. ### `.true(value, message?)` -Assert that `value` is `true`. +Assert that `value` is `true`. Returns a boolean indicating whether the assertion passed. ### `.false(value, message?)` -Assert that `value` is `false`. +Assert that `value` is `false`. Returns a boolean indicating whether the assertion passed. ### `.is(value, expected, message?)` -Assert that `value` is the same as `expected`. This is based on [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). +Assert that `value` is the same as `expected`. This is based on [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). Returns a boolean indicating whether the assertion passed. ### `.not(value, expected, message?)` -Assert that `value` is not the same as `expected`. This is based on [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). +Assert that `value` is not the same as `expected`. This is based on [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). Returns a boolean indicating whether the assertion passed. ### `.deepEqual(value, expected, message?)` @@ -205,7 +215,7 @@ Assert that `value` is deeply equal to `expected`. See [Concordance](https://git ### `.notDeepEqual(value, expected, message?)` -Assert that `value` is not deeply equal to `expected`. The inverse of `.deepEqual()`. +Assert that `value` is not deeply equal to `expected`. The inverse of `.deepEqual()`. Returns a boolean indicating whether the assertion passed. ### `.like(value, selector, message?)` @@ -232,6 +242,8 @@ t.like({ }) ``` +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. @@ -262,6 +274,8 @@ test('throws', t => { }); ``` +Does not return anything. + ### `.throwsAsync(thrower, expectation?, message?)` 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. @@ -297,9 +311,11 @@ test('rejects', async t => { }); ``` +Does not return anything. + ### `.notThrows(fn, message?)` -Assert that no error is thrown. `fn` must be a function which shouldn't throw. +Assert that no error is thrown. `fn` must be a function which shouldn't throw. Does not return anything. ### `.notThrowsAsync(nonThrower, message?)` @@ -313,13 +329,15 @@ test('resolves', async t => { }); ``` +Does not return anything. + ### `.regex(contents, regex, message?)` -Assert that `contents` matches `regex`. +Assert that `contents` matches `regex`. Returns a boolean indicating whether the assertion passed. ### `.notRegex(contents, regex, message?)` -Assert that `contents` does not match `regex`. +Assert that `contents` does not match `regex`. Returns a boolean indicating whether the assertion passed. ### `.snapshot(expected, message?)` @@ -327,7 +345,7 @@ Compares the `expected` value with a previously recorded snapshot. Snapshots are AVA 3 supports an `options` object that lets you select a specific snapshot, for instance `{id: 'my snapshot'}`. This is buggy and will be removed in AVA 4. -Snapshot assertions cannot be skipped when snapshots are being updated. +Snapshot assertions cannot be skipped when snapshots are being updated. Returns a boolean indicating whether the assertion passed. ### `.try(title?, implementation | macro | macro[], ...args?)` @@ -374,3 +392,5 @@ test('flaky macro', async t => { secondTry.commit(); }); ``` + +Returns a boolean indicating whether the assertion passed. From 8b5a9ab58aa09a52387f12d0c11f76df3b6348d7 Mon Sep 17 00:00:00 2001 From: Mark Wubben Date: Sun, 7 Mar 2021 16:16:09 +0100 Subject: [PATCH 11/11] Tweak docs --- docs/03-assertions.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/03-assertions.md b/docs/03-assertions.md index ef1b69214..a0c2d5501 100644 --- a/docs/03-assertions.md +++ b/docs/03-assertions.md @@ -21,15 +21,7 @@ test('unicorns are truthy', t => { If multiple assertion failures are encountered within a single test, AVA will only display the *first* one. -All assertions return a boolean indicating whether the assertion was successful, except for the following: -```js -.throws(fn, expectation?, message?) -.throwsAsync(thrower, expectation?, message?) -.notThrows(fn, message?) -.notThrowsAsync(nonThrower, message?) -``` - -This allows for tests to be written to fail immediately when an assertion fails, if desired. +Assertions return a boolean indicating whether they passed. You can use this to return early from a test. Note that this does not apply to the "throws" assertions. ## Assertion planning