diff --git a/lib/assertion.js b/lib/assertion.js index bf6e286e..1b729b30 100644 --- a/lib/assertion.js +++ b/lib/assertion.js @@ -20,12 +20,14 @@ import Context from './context.js'; */ /** - * @param {AssertSubject} assertion + * @param {(AssertObject | AssertSubject)} assertion * @param {AssertMessage} [failureMessage] * @param {AssertMessage} [negatedMessage] * @returns {import('./context').ContextGenerator<{ assert?: boolean }>} */ export function* assert(assertion, failureMessage, negatedMessage) { + if (typeof assertion === 'object' && Object.getPrototypeOf(assertion) === Object.prototype) + ({ assertion, failureMessage = failureMessage, negatedMessage = negatedMessage } = assertion); let expected = yield ({ assert }) => assert?.expected; let error, pass; @@ -37,6 +39,10 @@ export function* assert(assertion, failureMessage, negatedMessage) { pass = false; } + if (typeof pass === 'object' && + Object.getPrototypeOf(pass) === Object.prototype && 'assertion' in pass + ) pass = yield assert(pass, failureMessage, negatedMessage); + if (!!pass !== expected) { throw (error ?? new Error((expected ? (yield failureMessage) || 'Assertion failed' @@ -68,10 +74,6 @@ export class Assertion { * @param {AssertMessage} [negatedMessage] */ constructor(assertion, failureMessage, negatedMessage) { - if (typeof assertion === 'object' && - Object.getPrototypeOf(assertion) === Object.prototype) - ({ assertion, failureMessage, negatedMessage } = assertion); - Object.defineProperty(this, Assertion.Symbol, { // @ts-ignore value: () => assert(assertion, failureMessage, negatedMessage), diff --git a/tests/interactor.test.js b/tests/interactor.test.js index 738145fd..a4453f0e 100644 --- a/tests/interactor.test.js +++ b/tests/interactor.test.js @@ -571,6 +571,23 @@ describe('Assert', () => { 'Negated message'); }); + it('accepts an assertion that returns an assertion object', async () => { + TestAssert.defineAssertion('test', (expected, msg) => ({ + assertion: expected === true, + failureMessage: `Failure message (${msg})`, + negatedMessage: `Negated message (${msg})` + })); + + await assert(typeof T.assert.test === 'function', + 'Expected test to be a function'); + await assert(T.assert.test(true) instanceof Assertion, + 'Expected test to return an Interaction instance'); + await assert.throws(T.assert.test(false, 'foo'), + 'Failure message (foo)'); + await assert.throws(T.assert.not.test(true, 'bar'), + 'Negated message (bar)'); + }); + it('accepts an assertion class', async () => { let pass = false;