diff --git a/msg-test.js b/msg-test.js index 1f09529..11344fe 100644 --- a/msg-test.js +++ b/msg-test.js @@ -36,7 +36,7 @@ const optioner = Optioner({ .default({}), out: Joi.alternatives().try(Joi.object().unknown(), Joi.array()), err: Joi.object().unknown(), - delegate: Joi.string(), + delegate: Joi.alternatives(Joi.string(), Joi.array(), Joi.func()), verify: Joi.func() }) ) @@ -63,7 +63,6 @@ function msg_test(seneca, spec) { await seneca.ready() } - // TODO: make optional var datajson = JSON.stringify(spec.data) await seneca.post('role:mem-store,cmd:import', { @@ -114,138 +113,169 @@ const intern = (module.exports.intern = { }) function next_call(call_index, done) { - if (spec.calls.length <= call_index) { - return done() - } - - var call = spec.calls[call_index] - - if (false === call.run) { - return setImmediate(next_call.bind(null, call_index + 1, done)) - } - - var params = {} - Object.keys(call.params).forEach(function(pk) { - var pv = call.params[pk] - - pk = Inks(pk, callmap) - if ('string' === typeof pv) { - pv = Inks(pv, callmap) + try { + if (spec.calls.length <= call_index) { + return done() } - params[pk] = pv - }) - - var print = spec.print || call.print + var call = spec.calls[call_index] - if (print) { - console.log('\n\nCALL : ', call.pattern, params) - } + if (false === call.run) { + return setImmediate(next_call.bind(null, call_index + 1, done)) + } - if (call.print_context) { - console.dir(callmap, { depth: 3, colors: true }) - } + var params = {} + Object.keys(call.params).forEach(function(pk) { + var pv = call.params[pk] - var msg = Object.assign( - {}, - params, - spec.pattern ? Jsonic(spec.pattern) : {}, - Jsonic(call.pattern) - ) - var msgstr = Jsonic.stringify(msg) + pk = Inks(pk, callmap) + if ('string' === typeof pv) { + pv = Inks(pv, callmap) + } - var instance = seneca + params[pk] = pv + }) - if (call.delegate) { - instance = spec.delegates[call.delegate] + var print = spec.print || call.print - if (null == instance) { - return done(new Error('Delegate not defined: ' + call.delegate)) - } - } - - instance.act(msg, function(err, out, meta) { if (print) { - console.log('ERROR : ', err) - console.log( - 'RESULT : ', - Util.inspect(out, { depth: null, colors: true }) - ) + console.log('\n\nCALL : ', call.pattern, params) } - if (null == call.err) { - if (null != err) { - return done( - new Error('Error not expected for: ' + msgstr + ', err: ' + err) - ) - } - } else { - if (null == err) { - return done( - new Error('Error expected for: ' + msgstr + ', was null') - ) - } - - var result = Optioner(call.err, { must_match_literals: true })(err) - if (result.error) { - return done(result.error) - } + if (call.print_context) { + console.dir(callmap, { depth: 3, colors: true }) } - if (null === call.out) { - if (null != out) { - return done( - new Error('Output not expected for: ' + msgstr + ', out: ' + out) + var msg = Object.assign( + {}, + params, + spec.pattern ? Jsonic(spec.pattern) : {}, + Jsonic(call.pattern) + ) + var msgstr = Jsonic.stringify(msg) + call.msgstr = msgstr + + var instance = intern.handle_delegate(seneca, call, callmap, spec) + + instance.act(msg, function(err, out, meta) { + if (print) { + console.log('ERROR : ', err) + console.log( + 'RESULT : ', + Util.inspect(out, { depth: null, colors: true }) ) } - } else if (null != call.out) { - if (null == out) { - return done( - new Error('Output expected for: ' + msgstr + ', was null') - ) + + if (null == call.err) { + if (null != err) { + return done( + new Error('Error not expected for: ' + msgstr + ', err: ' + err) + ) + } } else { - var result = Optioner(call.out, { must_match_literals: true })(out) + if (null == err) { + return done( + new Error('Error expected for: ' + msgstr + ', was null') + ) + } + + var result = Optioner(call.err, { must_match_literals: true })(err) if (result.error) { + return done(result.error) + } + } + + if (null === call.out) { + if (null != out) { return done( new Error( - 'Output for: ' + - msgstr + - ' was invalid: ' + - result.error.message + 'Output not expected for: ' + msgstr + ', out: ' + out ) ) } + } else if (null != call.out) { + if (null == out) { + return done( + new Error('Output expected for: ' + msgstr + ', was null') + ) + } else { + var result = Optioner(call.out, { must_match_literals: true })( + out + ) + if (result.error) { + return done( + new Error( + 'Output for: ' + + msgstr + + ' was invalid: ' + + result.error.message + ) + ) + } + } } - } - if (null != call.verify) { - var result = call.verify(call, callmap) - if (null != result && true !== result) { - return done( - new Error( - 'Verify of: ' + - msgstr + - ' failed: ' + - (result.message || result) + if (null != call.verify) { + var result = call.verify(call, callmap, spec, instance) + if (null != result && true !== result) { + return done( + new Error( + 'Verify of: ' + + msgstr + + ' failed: ' + + (result.message || result) + ) ) - ) + } } - } - if (call.name) { - callmap[call.name] = { - top_pattern: spec.pattern, - pattern: call.pattern, - params: params, - msg: msg, - err: err, - out: out, - meta: meta + if (call.name) { + callmap[call.name] = { + top_pattern: spec.pattern, + pattern: call.pattern, + params: params, + msg: msg, + err: err, + out: out, + meta: meta + } } - } - setImmediate(next_call.bind(null, call_index + 1, done)) - }) + setImmediate(next_call.bind(null, call_index + 1, done)) + }) + } catch (e) { + return done(e) + } + } + }, + + handle_delegate: function(instance, call, callmap, spec) { + if (call.delegate) { + if ('string' === typeof call.delegate) { + instance = spec.delegates[call.delegate] + + if (null == instance) { + throw new Error( + 'Delegate not defined: ' + + call.delegate + + '. Message was: ' + + call.msgstr + ) + } + } else if (Array.isArray(call.delegate)) { + return instance.delegate.apply(instance, call.delegate) + } else if ('function' === typeof call.delegate) { + return call.delegate.call(instance, call, callmap, spec) + } else { + throw new Error( + 'Unknown delegate reference: ' + + Util.inspect(call.delegate) + + '. Message was: ' + + call.msgstr + ) + } } + + return instance } }) diff --git a/package.json b/package.json index 77647a7..4a67fcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "seneca-msg-test", - "version": "1.1.0", + "version": "1.2.0", "description": "Structured testing of seneca plugin messages.", "main": "msg-test.js", "scripts": { diff --git a/test/msg-test.test.js b/test/msg-test.test.js index 0a1b580..8a74139 100644 --- a/test/msg-test.test.js +++ b/test/msg-test.test.js @@ -93,6 +93,12 @@ lab.test( pattern: 'cmd:qaz', params: { y: 'd' }, out: { x: 1, y: 'd', z: 'B', w: 'BB' } + }, + { + delegate: [{ w: 'CC' }, { custom: { z: 'C' } }], + pattern: 'cmd:qaz', + params: { y: 'e' }, + out: { x: 1, y: 'e', z: 'C', w: 'CC' } } ] } @@ -157,7 +163,69 @@ lab.test( ) ) -// TODO: provide in common-server-test +lab.test('bad-delegate', async () => { + var msgfunc = SenecaMsgTest(seneca_instance({ log: 'silent' }), { + test: true, + pattern: 'a:1', + calls: [ + { + delegate: 'bad', + pattern: 'b:1' + } + ] + })() + + await expect(msgfunc).reject( + Error, + 'Delegate not defined: bad. Message was: {a:1,b:1}' + ) +}) + +lab.test( + 'dynamic-delegate', + SenecaMsgTest( + seneca_instance({ log: 'silent' }, function(seneca) { + return seneca + .use('promisify') + .message('a:1', async function(msg) { + return { b: msg.b + 1 } + }) + .message('c:1', async function(msg) { + return { b: msg.b } + }) + }), + { + test: true, + print: false, + pattern: 'x:1', + calls: [ + { + name: 'a', + pattern: 'a:1', + params: { b: 2 }, + out: { b: 3 }, + verify: function(call, callmap, spec, seneca) { + spec.delegates.d0 = seneca.delegate(call.out) + } + }, + { + delegate: 'd0', + pattern: 'c:1', + out: { b: 3 } + }, + { + delegate: function(call, callmap) { + return this.delegate(callmap.a.out) + }, + pattern: 'c:1', + out: { b: 3 } + } + ] + } + ) +) + function seneca_instance(options, setup) { + setup = setup || (x => x) return setup(Seneca(options).use('entity')) }