From b9cf30612a5e0f822a72373c177c5b4e44f20f70 Mon Sep 17 00:00:00 2001 From: Wil Wilsman Date: Fri, 7 Jul 2023 11:58:41 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Allow=20returning=20booleans=20and?= =?UTF-8?q?=20matchers=20from=20anonymous=20assertions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/assert.js | 17 ++++++++++---- tests/assert.test.js | 56 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index 8e0fb2de..d624ab2c 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -22,8 +22,8 @@ export function assertion(get, matcher = get) { args = [value].concat(args); } - let { message, result } = matcher.apply(this, args); - + let { message, result } = + matcher.apply(this, args); if (result !== expected) throw error(message); }; @@ -158,16 +158,23 @@ export default function InteractorAssert(i, expected = true) { // assertions are called with an assert context and can be negated on error return passert.call(i, defineProperties(function() { + let message; + try { - f.apply(context(this, expected), arguments); - if (expected) return; + let res = f.apply(context(this, expected), arguments); + if (typeof res === 'object' && 'message' in res) message = res.message; + if (typeof res === 'object' && 'result' in res) res = !!res.result; + if (expected === !!(res ?? true)) return; } catch (err) { if (err.name === 'InteractorError') err.bind(this, expected); if (expected) throw err; return; } - throw error('expected assertion to fail but it passed'); + throw error(message ?? [ + 'expected assertion to', expected ? 'pass' : 'fail', + 'but it', expected ? 'failed' : 'passed' + ].join(' ')); }, { name: { value: f.name }, // used to determine invoking the interactor element diff --git a/tests/assert.test.js b/tests/assert.test.js index 9b302be1..5f1e5fdf 100644 --- a/tests/assert.test.js +++ b/tests/assert.test.js @@ -8,6 +8,33 @@ describe('InteractorAssert', () => { assert.notEqual(I().assert, I().assert); }); + it('handles boolean return values', async () => { + await assert.doesNotReject( + Test().assert(() => true) + ); + + await assert.rejects( + Test().assert(() => false), + e('InteractorError', 'expected assertion to pass but it failed') + ); + }); + + it('handles matcher return values', async () => { + await assert.doesNotReject( + Test().assert(() => ({ result: true })) + ); + + await assert.rejects( + Test().assert(() => ({ result: false })), + e('InteractorError', 'expected assertion to pass but it failed') + ); + + await assert.rejects( + Test().assert(() => ({ result: false, message: 'epic fail' })), + e('InteractorError', 'epic fail') + ); + }); + it('can be negated with .not', async () => { let T = Test.extend({ assert: { @@ -33,6 +60,29 @@ describe('InteractorAssert', () => { e('InteractorError', 'expected assertion to fail but it passed') ); + await assert.doesNotReject( + T().assert.not(() => false) + ); + + await assert.rejects( + T().assert.not(() => true), + e('InteractorError', 'expected assertion to fail but it passed') + ); + + await assert.doesNotReject( + Test().assert.not(() => ({ result: false })) + ); + + await assert.rejects( + Test().assert.not(() => ({ result: true })), + e('InteractorError', 'expected assertion to fail but it passed') + ); + + await assert.rejects( + Test().assert.not(() => ({ result: true, message: 'nega fail' })), + e('InteractorError', 'nega fail') + ); + await assert.doesNotReject( T().assert.not(() => { throw Error('failed successfully'); @@ -46,9 +96,9 @@ describe('InteractorAssert', () => { await assert.doesNotReject( Test() - .assert(() => (delta == null && (delta = 10))) - .assert(() => (delta += Date.now() - time)) - .assert(() => (time = Date.now())) + .assert(() => void (delta == null && (delta = 10))) + .assert(() => void (delta += Date.now() - time)) + .assert(() => void (time = Date.now())) .assert.remains() );