From bdd8b6f83c9a23e4e5b91df6f29f35cc893f95bd Mon Sep 17 00:00:00 2001 From: "Aral Balkan (LabTop)" Date: Tue, 10 Aug 2021 15:26:58 +0100 Subject: [PATCH 1/6] Add assert.rejects and assert.not.rejects methods for promises --- src/assert.js | 38 +++++++++++ test/assert.js | 171 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 208 insertions(+), 1 deletion(-) diff --git a/src/assert.js b/src/assert.js index 2a2c015..2b81d45 100644 --- a/src/assert.js +++ b/src/assert.js @@ -97,6 +97,26 @@ export function throws(blk, exp, msg) { } } +export async function rejects(blk, exp, msg) { + if (!msg && typeof exp === 'string') { + msg = exp; exp = null; + } + + try { + await blk(); + assert(false, false, true, 'rejects', false, 'Expected promise to reject', msg); + } catch (err) { + if (err instanceof Assertion) throw err; + + if (typeof exp === 'function') { + assert(exp(err), false, true, 'rejects', false, 'Expected promise to reject matching exception', msg); + } else if (exp instanceof RegExp) { + const errorMessage = err instanceof Error ? err.message : err + assert(exp.test(errorMessage), false, true, 'rejects', false, `Expected promise to reject matching exception \`${String(exp)}\` pattern`, msg); + } + } +} + // --- export function not(val, msg) { @@ -158,3 +178,21 @@ not.throws = function (blk, exp, msg) { } } } + +not.rejects = async function (blk, exp, msg) { + if (!msg && typeof exp === 'string') { + msg = exp; exp = null; + } + + try { + await blk(); + } catch (err) { + if (typeof exp === 'function') { + assert(!exp(err), true, false, 'not.rejects', false, 'Expected function not to reject promise matching exception', msg); + } else if (exp instanceof RegExp) { + assert(!exp.test(err instanceof Error ? err.message : err), true, false, 'not.rejects', false, `Expected function not to reject promise exception matching \`${String(exp)}\` pattern`, msg); + } else if (!exp) { + assert(false, true, false, 'not.rejects', false, 'Expected function not to reject promise', msg); + } + } +} diff --git a/test/assert.js b/test/assert.js index ac0ecac..e3b6592 100644 --- a/test/assert.js +++ b/test/assert.js @@ -366,6 +366,7 @@ throws('should be a function', () => { throws('should throw if function does not throw Error :: generic', () => { try { $.throws(() => 123); + assert.unreachable('Function threw when it shouldn’t have'); } catch (err) { assert.is(err.message, 'Expected function to throw'); isError(err, '', false, true, 'throws', false); // no details (true vs false) @@ -375,6 +376,7 @@ throws('should throw if function does not throw Error :: generic', () => { throws('should throw if function does not throw matching Error :: RegExp', () => { try { $.throws(() => { throw new Error('hello') }, /world/); + assert.unreachable('Function threw correct pattern when it should have thrown incorrect one'); } catch (err) { assert.is(err.message, 'Expected function to throw exception matching `/world/` pattern'); isError(err, '', false, true, 'throws', false); // no details @@ -418,6 +420,91 @@ throws.run(); // --- +const rejects = suite('rejects'); + +rejects('should be a function', () => { + assert.type($.rejects, 'function'); +}); + +rejects('should throw if function does not reject Error :: generic', async () => { + try { + await $.rejects(() => { + return new Promise((resolve, reject) => { + setTimeout(() => resolve(), 1); + }); + }); + assert.unreachable('Promise rejected when it shouldn’t have'); + } catch (err) { + assert.is(err.message, 'Expected promise to reject'); + isError(err, '', false, true, 'rejects', false); // no details (true vs false) + } +}); + +rejects('should throw if function does not reject matching Error :: RegExp', async () => { + try { + await $.rejects(() => { + return new Promise((resolve, reject) => { + setTimeout(() => reject('hello'), 1) + }); + }, /world/); + assert.unreachable('Promise rejected with correct pattern when it should have with incorrect one'); + } catch (err) { + assert.is(err.message, 'Expected promise to reject matching exception `/world/` pattern'); + isError(err, '', false, true, 'rejects', false); // no details + } +}); + +rejects('should throw if function does not reject matching Error :: Function', async () => { + try { + await $.rejects( + () => { + return new Promise((resolve, reject) => { + reject(new Error()) + }) + }, + (err) => err.message.includes('foobar') + ); + assert.unreachable('Promise should have rejected without matching exception'); + } catch (err) { + assert.is(err.message, 'Expected promise to reject matching exception'); + isError(err, '', false, true, 'rejects', false); // no details + } +}); + +rejects('should not reject if promise does reject Error :: generic', async () => { + await assert.not.rejects( + async () => await $.rejects(() => { + return new Promise ((resolve, reject) => setTimeout(() => reject(), 1)); + }) + , 'should not reject if function does reject Error :: generic'); +}); + +rejects('should not reject if promise does reject matching Error :: RegExp', async () => { + await assert.not.rejects( + async () => await $.rejects( + () => { + return new Promise((resolve, reject) => setTimeout(() => reject(new Error('hello')), 1)); + }, + /hello/ + ) + ); +}); + +rejects('should not reject if function does reject matching Error :: Function', async () => { + await assert.not.rejects( + async () => await $.rejects( + () => { + return new Promise((resolve, reject) => setTimeout(() => reject(new Error('foobar')), 1)) + }, + (err) => err.message.includes('foobar') + ) + ); +}) + +rejects.run(); + +// --- + const not = suite('not'); not('should be a function', () => { @@ -793,7 +880,7 @@ notMatch.run(); const notThrows = suite('not.throws'); notThrows('should be a function', () => { - assert.type($.throws, 'function'); + assert.type($.not.throws, 'function'); }); notThrows('should not throw if function does not throw Error :: generic', () => { @@ -848,3 +935,85 @@ notThrows('should throw if function does throw matching Error :: Function', () = }); notThrows.run(); + +// --- + +const notRejects = suite('not.throws'); + +notRejects('should be a function', () => { + assert.type($.not.rejects, 'function'); +}); + +notRejects('should not reject if function does not reject Error :: generic', async () => { + await assert.not.rejects( + async () => await $.not.rejects(() => new Promise((resolve, reject) => setTimeout(() => resolve(123), 1))) + ); +}); + +notRejects('should not reject if function does not reject matching Error :: RegExp', async () => { + await assert.not.rejects( + async () => { + await $.not.rejects(() => { + return new Promise((resolve, reject) => { + setTimeout(() => reject(new Error('hello')), 1); + }) + }, /world/); + } + ); +}); + +notRejects('should not reject if function does not reject matching Error :: Function', async () => { + await assert.not.rejects(async () => { + await $.not.rejects(() => { + return new Promise ((resolve, reject) => { + setTimeout(() => reject(new Error('hello')), 1); + }) + }, (err) => err.message.includes('world')); + }); +}); + +notRejects('should reject if function does reject Error :: generic', async () => { + try { + await $.not.rejects(() => { + return new Promise((resolve, reject) => { + setTimeout(() => reject(new Error()), 1); + }); + }); + assert.unreachable('Function resolved when we were expecting it to reject'); + } catch (err) { + assert.is(err.message, 'Expected function not to reject promise'); + isError(err, '', true, false, 'not.rejects', false); // no details + } +}); + +notRejects('should reject if function does reject matching Error :: RegExp', async () => { + try { + await $.not.rejects(() => { + return new Promise((resolve, reject) => { + setTimeout(() => reject(new Error('hello')), 1) + }) + }, /hello/); + } catch (err) { + assert.is(err.message, 'Expected function not to reject promise exception matching `/hello/` pattern'); + isError(err, '', true, false, 'not.rejects', false); // no details + } +}); + +notRejects('should reject if function does reject matching Error :: Function', async () => { + try { + await $.not.rejects( + () => { + return new Promise((resolve, reject) => { + setTimeout(() => reject(new Error()), 1) + }) + }, + (err) => err instanceof Error + ); + assert.unreachable('Expected the function to reject with Error instance but it rejected with other value') + } catch (err) { + assert.is(err.message, 'Expected function not to reject promise matching exception'); + isError(err, '', true, false, 'not.rejects', false); // no details + } +}); + +notRejects.run(); From f007c7eb3441fac0c17e1a6d86e072b2db03c36b Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Wed, 11 Aug 2021 14:26:44 +0100 Subject: [PATCH 2/6] Update src/assert.js Remove error type fix for now Co-authored-by: Luke Edwards --- src/assert.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/assert.js b/src/assert.js index 2b81d45..1e59547 100644 --- a/src/assert.js +++ b/src/assert.js @@ -111,8 +111,7 @@ export async function rejects(blk, exp, msg) { if (typeof exp === 'function') { assert(exp(err), false, true, 'rejects', false, 'Expected promise to reject matching exception', msg); } else if (exp instanceof RegExp) { - const errorMessage = err instanceof Error ? err.message : err - assert(exp.test(errorMessage), false, true, 'rejects', false, `Expected promise to reject matching exception \`${String(exp)}\` pattern`, msg); + assert(exp.test(err.message), false, true, 'rejects', false, `Expected promise to reject matching exception \`${String(exp)}\` pattern`, msg); } } } From 7a03d8c28584d19a20223583653065ff708a206b Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Wed, 11 Aug 2021 14:27:12 +0100 Subject: [PATCH 3/6] Update src/assert.js Remove error type fix for now Co-authored-by: Luke Edwards --- src/assert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assert.js b/src/assert.js index 1e59547..fd8d150 100644 --- a/src/assert.js +++ b/src/assert.js @@ -189,7 +189,7 @@ not.rejects = async function (blk, exp, msg) { if (typeof exp === 'function') { assert(!exp(err), true, false, 'not.rejects', false, 'Expected function not to reject promise matching exception', msg); } else if (exp instanceof RegExp) { - assert(!exp.test(err instanceof Error ? err.message : err), true, false, 'not.rejects', false, `Expected function not to reject promise exception matching \`${String(exp)}\` pattern`, msg); + assert(!exp.test(err.message), true, false, 'not.rejects', false, `Expected function not to reject promise exception matching \`${String(exp)}\` pattern`, msg); } else if (!exp) { assert(false, true, false, 'not.rejects', false, 'Expected function not to reject promise', msg); } From bbd9ba6eaad1e07961be1e85dd866afc55d8f040 Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Wed, 11 Aug 2021 14:27:31 +0100 Subject: [PATCH 4/6] Update src/assert.js Improve phrasing Co-authored-by: Luke Edwards --- src/assert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assert.js b/src/assert.js index fd8d150..cd54ccb 100644 --- a/src/assert.js +++ b/src/assert.js @@ -187,7 +187,7 @@ not.rejects = async function (blk, exp, msg) { await blk(); } catch (err) { if (typeof exp === 'function') { - assert(!exp(err), true, false, 'not.rejects', false, 'Expected function not to reject promise matching exception', msg); + assert(!exp(err), true, false, 'not.rejects', false, 'Expected promise not to reject matching exception', msg); } else if (exp instanceof RegExp) { assert(!exp.test(err.message), true, false, 'not.rejects', false, `Expected function not to reject promise exception matching \`${String(exp)}\` pattern`, msg); } else if (!exp) { From 74b0d02620070f9512cab27f82588bde79d148f5 Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Wed, 11 Aug 2021 14:32:56 +0100 Subject: [PATCH 5/6] Update src/assert.js Improve phrasing Co-authored-by: Luke Edwards --- src/assert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assert.js b/src/assert.js index cd54ccb..0b14ded 100644 --- a/src/assert.js +++ b/src/assert.js @@ -191,7 +191,7 @@ not.rejects = async function (blk, exp, msg) { } else if (exp instanceof RegExp) { assert(!exp.test(err.message), true, false, 'not.rejects', false, `Expected function not to reject promise exception matching \`${String(exp)}\` pattern`, msg); } else if (!exp) { - assert(false, true, false, 'not.rejects', false, 'Expected function not to reject promise', msg); + assert(false, true, false, 'not.rejects', false, 'Expected promise not to reject', msg); } } } From 009b09c130b079288eba5201d4b37015ed2ff9dc Mon Sep 17 00:00:00 2001 From: "Aral Balkan (LabTop)" Date: Wed, 11 Aug 2021 14:39:02 +0100 Subject: [PATCH 6/6] Update tests based on changes from review --- test/assert.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/assert.js b/test/assert.js index e3b6592..7a95471 100644 --- a/test/assert.js +++ b/test/assert.js @@ -981,7 +981,7 @@ notRejects('should reject if function does reject Error :: generic', async () => }); assert.unreachable('Function resolved when we were expecting it to reject'); } catch (err) { - assert.is(err.message, 'Expected function not to reject promise'); + assert.is(err.message, 'Expected promise not to reject'); isError(err, '', true, false, 'not.rejects', false); // no details } }); @@ -1011,7 +1011,7 @@ notRejects('should reject if function does reject matching Error :: Function', a ); assert.unreachable('Expected the function to reject with Error instance but it rejected with other value') } catch (err) { - assert.is(err.message, 'Expected function not to reject promise matching exception'); + assert.is(err.message, 'Expected promise not to reject matching exception'); isError(err, '', true, false, 'not.rejects', false); // no details } });