diff --git a/lib/assert.js b/lib/assert.js index fe8f1bfa3..2cb2ac340 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -299,6 +299,7 @@ class Assertions { this.pass = withSkip(() => { pass(); + return true; }); this.fail = withSkip(message => { @@ -310,6 +311,7 @@ class Assertions { assertion: 'fail', message: message || 'Test failed via `t.fail()`' })); + return false; }); this.is = withSkip((actual, expected, message) => { @@ -318,28 +320,28 @@ class Assertions { } 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 pass(); + } - 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)] - })); - } + 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) { + return 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)] + })); } + + return fail(new AssertionError({ + assertion: 'is', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); }); this.not = withSkip((actual, expected, message) => { @@ -348,15 +350,15 @@ class Assertions { } if (Object.is(actual, expected)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'not', message, raw: {actual, expected}, values: [formatWithLabel('Value is the same as:', actual)] })); - } else { - pass(); } + + return pass(); }); this.deepEqual = withSkip((actual, expected, message) => { @@ -366,17 +368,18 @@ class Assertions { 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 pass(); } + + const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions); + + return fail(new AssertionError({ + assertion: 'deepEqual', + message, + raw: {actual, expected}, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); }); this.notDeepEqual = withSkip((actual, expected, message) => { @@ -387,30 +390,37 @@ class Assertions { const result = concordance.compare(actual, expected, concordanceOptions); if (result.pass) { const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions); - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'notDeepEqual', message, raw: {actual, expected}, values: [formatDescriptorWithLabel('Value is deeply equal:', actualDescriptor)] })); - } else { - pass(); } + + return pass(); }); this.like = withSkip((actual, selector, message) => { + if (!experiments.likeAssertion) { + return fail(new AssertionError({ + assertion: 'like', + improperUsage: true, + message: 'You must enable the `likeAssertion` experiment in order to use `t.like()`' + })); + } + if (!checkMessage('like', message)) { return; } if (!isLikeSelector(selector)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'like', improperUsage: true, message: '`t.like()` selector must be a non-empty object', values: [formatWithLabel('Called with:', selector)] })); - return; } let comparable; @@ -418,13 +428,12 @@ class Assertions { comparable = selectComparable(actual, selector); } catch (error) { if (error === CIRCULAR_SELECTOR) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'like', improperUsage: true, message: '`t.like()` selector must not contain circular references', values: [formatWithLabel('Called with:', selector)] })); - return; } throw error; @@ -432,16 +441,16 @@ class Assertions { 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)] - })); + return pass(); } + + const actualDescriptor = result.actual || concordance.describe(comparable, concordanceOptions); + const expectedDescriptor = result.expected || concordance.describe(selector, concordanceOptions); + return fail(new AssertionError({ + assertion: 'like', + message, + values: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)] + })); }); this.throws = withSkip((...args) => { @@ -735,29 +744,30 @@ class Assertions { improperUsage.expectedVersion = error.expectedVersion; } - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'snapshot', message: message || 'Could not compare snapshot', improperUsage })); - return; } if (result.pass) { - pass(); - } else if (result.actual) { - fail(new AssertionError({ + return pass(); + } + + if (result.actual) { + return fail(new AssertionError({ assertion: 'snapshot', message: message || 'Did not match snapshot', values: [formatDescriptorDiff(result.actual, result.expected, {invert: true})] })); - } else { - // This can only occur in CI environments. - fail(new AssertionError({ - assertion: 'snapshot', - message: message || 'No snapshot available — new snapshots are not created in CI environments' - })); } + + // This can only occur in CI environments. + return fail(new AssertionError({ + assertion: 'snapshot', + message: message || 'No snapshot available — new snapshots are not created in CI environments' + })); }); this.truthy = withSkip((actual, message) => { @@ -766,15 +776,15 @@ class Assertions { } if (actual) { - pass(); - } else { - fail(new AssertionError({ - assertion: 'truthy', - message, - operator: '!!', - values: [formatWithLabel('Value is not truthy:', actual)] - })); + return pass(); } + + return fail(new AssertionError({ + assertion: 'truthy', + message, + operator: '!!', + values: [formatWithLabel('Value is not truthy:', actual)] + })); }); this.falsy = withSkip((actual, message) => { @@ -783,15 +793,15 @@ class Assertions { } if (actual) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'falsy', message, operator: '!', values: [formatWithLabel('Value is not falsy:', actual)] })); - } else { - pass(); } + + return pass(); }); this.true = withSkip((actual, message) => { @@ -800,14 +810,14 @@ class Assertions { } if (actual === true) { - pass(); - } else { - fail(new AssertionError({ - assertion: 'true', - message, - values: [formatWithLabel('Value is not `true`:', actual)] - })); + return pass(); } + + return fail(new AssertionError({ + assertion: 'true', + message, + values: [formatWithLabel('Value is not `true`:', actual)] + })); }); this.false = withSkip((actual, message) => { @@ -816,14 +826,14 @@ class Assertions { } if (actual === false) { - pass(); - } else { - fail(new AssertionError({ - assertion: 'false', - message, - values: [formatWithLabel('Value is not `false`:', actual)] - })); + return pass(); } + + return fail(new AssertionError({ + assertion: 'false', + message, + values: [formatWithLabel('Value is not `false`:', actual)] + })); }); this.regex = withSkip((string, regex, message) => { @@ -832,27 +842,25 @@ class Assertions { } if (typeof string !== 'string') { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'regex', improperUsage: true, message: '`t.regex()` must be called with a string', values: [formatWithLabel('Called with:', string)] })); - return; } if (!(regex instanceof RegExp)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'regex', improperUsage: true, message: '`t.regex()` must be called with a regular expression', values: [formatWithLabel('Called with:', regex)] })); - return; } if (!regex.test(string)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'regex', message, values: [ @@ -860,10 +868,9 @@ class Assertions { formatWithLabel('Regular expression:', regex) ] })); - return; } - pass(); + return pass(); }); this.notRegex = withSkip((string, regex, message) => { @@ -872,27 +879,25 @@ class Assertions { } if (typeof string !== 'string') { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'notRegex', improperUsage: true, message: '`t.notRegex()` must be called with a string', values: [formatWithLabel('Called with:', string)] })); - return; } if (!(regex instanceof RegExp)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'notRegex', improperUsage: true, message: '`t.notRegex()` must be called with a regular expression', values: [formatWithLabel('Called with:', regex)] })); - return; } if (regex.test(string)) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'notRegex', message, values: [ @@ -900,10 +905,9 @@ class Assertions { formatWithLabel('Regular expression:', regex) ] })); - return; } - pass(); + return pass(); }); if (powerAssert === undefined) { @@ -913,16 +917,15 @@ class Assertions { } if (!actual) { - fail(new AssertionError({ + return fail(new AssertionError({ assertion: 'assert', message, operator: '!!', values: [formatWithLabel('Value is not truthy:', actual)] })); - return; } - pass(); + return pass(); }); } else { this.assert = withSkip(withPowerAssert( diff --git a/test-tap/assert.js b/test-tap/assert.js index f5b38cbdf..3d8fbc9f4 100644 --- a/test-tap/assert.js +++ b/test-tap/assert.js @@ -12,26 +12,26 @@ const snapshotManager = require('../lib/snapshot-manager'); const HelloMessage = require('./fixture/hello-message'); let lastFailure = null; -let lastPassed = false; const assertions = new class extends assert.Assertions { constructor(overwrites = {}) { super({ - pass: () => { - lastPassed = true; - }, + pass: () => true, pending: promise => { - promise.then(() => { - lastPassed = true; - }, error => { + return promise.then(() => + true + , error => { lastFailure = error; }); }, fail: error => { lastFailure = error; + return false; }, skip: () => {}, - experiments: {}, + experiments: { + likeAssertion: true + }, ...overwrites }); } @@ -142,10 +142,8 @@ function eventuallyFails(t, fn) { */ function passes(t, fn) { - lastPassed = false; lastFailure = null; - fn(); - if (lastPassed) { + if (fn()) { t.pass(); } else { t.ifError(lastFailure, 'Expected assertion to pass'); @@ -154,10 +152,9 @@ function passes(t, fn) { function eventuallyPasses(t, fn) { return add(() => { - lastPassed = false; lastFailure = null; - return fn().then(() => { - if (lastPassed) { + return fn().then(passed => { + if (passed) { t.pass(); } else { t.ifError(lastFailure, 'Expected assertion to pass'); @@ -168,12 +165,12 @@ function eventuallyPasses(t, fn) { test('.pass()', t => { passes(t, () => { - assertions.pass(); + return assertions.pass(); }); passes(t, () => { const {pass} = assertions; - pass(); + return pass(); }); t.end(); @@ -181,14 +178,14 @@ 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' @@ -196,14 +193,14 @@ test('.fail()', t => { failsWith(t, () => { const {fail} = assertions; - fail(); + return fail(); }, { assertion: 'fail', message: 'Test failed via `t.fail()`' }); failsWith(t, () => { - assertions.fail(null); + return assertions.fail(null); }, { assertion: 'fail', improperUsage: true, @@ -219,73 +216,73 @@ 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 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, () => { @@ -2156,3 +2153,4 @@ test('.assert()', t => { t.end(); }); +