exit-usage.test.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. var assert = require('assert');
  2. var _ = require('@sailshq/lodash');
  3. var M = require('../');
  4. describe('Machine fn calling `exits()` (w/ different usages)', function() {
  5. describe('with success exit and error exit defined', function() {
  6. testDifferentUsages({
  7. exits: {
  8. success: {},
  9. error: {}
  10. }
  11. });
  12. }); // </with success exit and error exit defined>
  13. describe('with error exit defined, but no success exit', function() {
  14. testDifferentUsages({
  15. exits: {
  16. error: {}
  17. }
  18. });
  19. }); // </with error exit defined, but no success exit>
  20. describe('with success exit defined, but no error exit', function() {
  21. testDifferentUsages({
  22. exits: {
  23. success: {}
  24. }
  25. });
  26. }); // </with success exit defined, but no error exit>
  27. describe('with some other exit defined, but no success or error exit', function() {
  28. testDifferentUsages({
  29. exits: {
  30. somethingElse: {}
  31. }
  32. });
  33. }); // </with somethingElse exit defined, but no error exit>
  34. describe('with neither error nor success exit defined', function() {
  35. testDifferentUsages({
  36. exits: {}
  37. });
  38. }); // </with neither error nor success exit defined>
  39. describe('with no exits object defined in the machine def at all', function() {
  40. testDifferentUsages({});
  41. }); // </with no exits object defined in the machine def at all>
  42. describe('with success exit defined such that it has both an `example` and an `outputExample`', function() {
  43. testDifferentUsages(
  44. {
  45. exits: {
  46. success: {
  47. outputExample: 'foo',
  48. example: false
  49. }
  50. }
  51. },
  52. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  53. undefined,
  54. // ...then the following runtime value should be received on the OUTSIDE:
  55. ''
  56. );
  57. testDifferentUsages(
  58. {
  59. exits: {
  60. success: {
  61. outputExample: 'foo',
  62. example: undefined
  63. }
  64. }
  65. },
  66. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  67. undefined,
  68. // ...then the following runtime value should be received on the OUTSIDE:
  69. ''
  70. );
  71. }); // </with success exit defined such that it has both an `example` and an `outputExample`>
  72. describe('with an exit defined with an `outputExample`', function() {
  73. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  74. // The following constants are used below:
  75. // =======================================
  76. //
  77. // To test regular expressions:
  78. var SOME_REGEXP = /^Sandwich/gi;
  79. //
  80. // To test functions:
  81. var SOME_ARBITRARY_FUNCTION = function foo (a, b, c){ console.log('stuff'); };
  82. //
  83. // To test circular references:
  84. var ERSTWHILE_PARTICLE = { x: 32, y: 49, z: -101, rgba: {r:255,g:255,b:255,a:100} };
  85. var DIFFUSE_PARTICLE = { x: -500, y: 871.5, z: 4.4, rgba: {r:0,g:0,b:0,a:255} };
  86. // DIFFUSE_PARTICLE.entangling = [ {}, {}, ERSTWHILE_PARTICLE, {}, {} ];
  87. DIFFUSE_PARTICLE.entangling = [ ERSTWHILE_PARTICLE ];
  88. ERSTWHILE_PARTICLE.entangledBy = { particleRef: DIFFUSE_PARTICLE };
  89. var ITERATOR_SAFE_VERSION_OF_ERSTWHILE_PARTICLE = {
  90. x: 32,
  91. y: 49,
  92. z: -101,
  93. rgba: { r:255, g:255, b:255, a:100 },
  94. entangledBy: {
  95. particleRef: {
  96. x: -500,
  97. y: 871.5,
  98. z: 4.4,
  99. rgba: { r:0, g:0, b:0, a:255 },
  100. // entangling: [ {}, {}, '[Circular ~.0]', {}, {} ]
  101. entangling: [ '[Circular ~.0]' ]
  102. }//</.entangledBy.particleRef>
  103. }//</.entangledBy>
  104. };
  105. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  106. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  107. // Start with a few basic sanity checks to be sure that it builds properly:
  108. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  109. testDifferentUsages({
  110. exits: {
  111. success: {
  112. outputExample: 'foo'
  113. }
  114. }
  115. });
  116. testDifferentUsages({
  117. exits: {
  118. success: { outputExample: 'foo' },
  119. somethingElse: { outputExample: true },
  120. somethingElse2: { outputExample: false },
  121. somethingElse3: { outputExample: -329.3 },
  122. somethingElse4: { outputExample: {} },
  123. somethingElse5: { outputExample: '*' },
  124. somethingElse6: { outputExample: '->' },
  125. somethingElse7: { outputExample: '===' },
  126. somethingElse8: { outputExample: [{opts: '*'}] },
  127. somethingElse9: { outputExample: [{fn: '->'}] },
  128. somethingElse10: { outputExample: [{meta: '==='}] },
  129. somethingElse11: { outputExample: [] },
  130. somethingElse12: { example: false },
  131. somethingElse13: { example: -329.3 },
  132. somethingElse14: { example: {} },
  133. somethingElse15: { example: '*' },
  134. somethingElse16: { example: '->' },
  135. somethingElse17: { example: '===' },
  136. somethingElse18: { example: [{opts: '*'}] },
  137. somethingElse19: { example: [{fn: '->'}] },
  138. somethingElse20: { example: [{meta: '==='}] },
  139. somethingElse21: { example: [] },
  140. error: {}
  141. }
  142. });
  143. testDifferentUsages({
  144. exits: {
  145. success: { outputExample: 'foo' },
  146. error: { outputExample: '===' }
  147. }
  148. });
  149. testDifferentUsages({
  150. exits: {
  151. success: { outputExample: 'foo' },
  152. error: { example: '===' }
  153. }
  154. });
  155. testDifferentUsages({
  156. exits: {
  157. success: { example: 'foo' },
  158. error: { outputExample: '===' }
  159. }
  160. });
  161. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  162. // Then finish up with a few more tests to ensure the underlying runtime type
  163. // coercion is working properly and respecting the `outputExample` as the exemplar
  164. // that gets passed in to `rttc.coerce()`:
  165. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  166. describe('when there is runtime output', function() {
  167. testDifferentUsages(
  168. { exits: { success: { outputExample: 'foo' } } },
  169. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  170. 'Butter sandwich',
  171. // ...then the following runtime value should be received on the OUTSIDE:
  172. 'Butter sandwich'
  173. );
  174. testDifferentUsages(
  175. { exits: { success: { outputExample: 123 } } },
  176. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  177. 'Butter sandwich',
  178. // ...then the following runtime value should be received on the OUTSIDE:
  179. 0
  180. );
  181. testDifferentUsages(
  182. { exits: { success: { outputExample: 123 } } },
  183. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  184. undefined,
  185. // ...then the following runtime value should be received on the OUTSIDE:
  186. 0
  187. );
  188. testDifferentUsages(
  189. { exits: { success: { outputExample: 'foo' } } },
  190. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  191. undefined,
  192. // ...then the following runtime value should be received on the OUTSIDE:
  193. ''
  194. );
  195. testDifferentUsages(
  196. { exits: { success: { outputExample: '*' } } },
  197. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  198. undefined,
  199. // ...then the following runtime value should be received on the OUTSIDE:
  200. null
  201. );
  202. testDifferentUsages(
  203. { exits: { success: { outputExample: '===' } } },
  204. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  205. undefined,
  206. // ...then the following runtime value should be received on the OUTSIDE:
  207. null
  208. );
  209. testDifferentUsages(
  210. { exits: { success: { outputExample: '===' } } },
  211. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  212. SOME_REGEXP,
  213. // ...then the following runtime value should be received on the OUTSIDE:
  214. SOME_REGEXP,
  215. true
  216. );
  217. testDifferentUsages(
  218. { exits: { success: { outputExample: ['==='] } } },
  219. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  220. undefined,
  221. // ...then the following runtime value should be received on the OUTSIDE:
  222. []
  223. );
  224. testDifferentUsages(
  225. { exits: { success: { outputExample: ['*'] } } },
  226. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  227. [null],
  228. // ...then the following runtime value should be received on the OUTSIDE:
  229. [null]
  230. );
  231. testDifferentUsages(
  232. { exits: { success: { outputExample: [] } } },
  233. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  234. [null],
  235. // ...then the following runtime value should be received on the OUTSIDE:
  236. [null]
  237. );
  238. testDifferentUsages(
  239. { exits: { success: { outputExample: [] } } },
  240. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  241. undefined,
  242. // ...then the following runtime value should be received on the OUTSIDE:
  243. []
  244. );
  245. testDifferentUsages(
  246. { exits: { success: { outputExample: ['*'] } } },
  247. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  248. SOME_REGEXP,
  249. // ...then the following runtime value should be received on the OUTSIDE:
  250. []
  251. );
  252. testDifferentUsages(
  253. { exits: { success: { outputExample: ['*'] } } },
  254. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  255. [ SOME_REGEXP ],
  256. // ...then the following runtime value should be received on the OUTSIDE:
  257. [ '/^Sandwich/gi' ] // << testing JSON stringification
  258. );
  259. testDifferentUsages(
  260. { exits: { success: { outputExample: [] } } },
  261. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  262. [ SOME_REGEXP ],
  263. // ...then the following runtime value should be received on the OUTSIDE:
  264. [ '/^Sandwich/gi' ] // << testing JSON stringification
  265. );
  266. // testDifferentUsages(
  267. // { exits: { success: { outputExample: [] } } },
  268. // // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  269. // [ ERSTWHILE_PARTICLE ],
  270. // // ...then the following runtime value should be received on the OUTSIDE:
  271. // [ ITERATOR_SAFE_VERSION_OF_ERSTWHILE_PARTICLE ] // << testing JSON stringification
  272. // );
  273. // testDifferentUsages(
  274. // { exits: { success: { outputExample: ['==='] } } },
  275. // // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  276. // [ SOME_REGEXP ],
  277. // // ...then the following runtime value should be received on the OUTSIDE:
  278. // [ SOME_REGEXP ],
  279. // true // .... welll, sort of-- need to do a strict equality check only on the array items...
  280. // );
  281. // testDifferentUsages(
  282. // { exits: { success: { outputExample: ['==='] } } },
  283. // // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  284. // [ ERSTWHILE_PARTICLE ],
  285. // // ...then the following runtime value should be received on the OUTSIDE:
  286. // [ ERSTWHILE_PARTICLE ],
  287. // true // .... welll, sort of-- need to do a strict equality check only on the array items...
  288. // );
  289. testDifferentUsages(
  290. { exits: { success: { outputExample: '===' } } },
  291. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  292. SOME_ARBITRARY_FUNCTION,
  293. // ...then the following runtime value should be received on the OUTSIDE:
  294. SOME_ARBITRARY_FUNCTION,
  295. true
  296. );
  297. testDifferentUsages(
  298. { exits: { success: { outputExample: '===' } } },
  299. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  300. ERSTWHILE_PARTICLE,
  301. // ...then the following runtime value should be received on the OUTSIDE:
  302. ERSTWHILE_PARTICLE,
  303. true
  304. );
  305. // testDifferentUsages(
  306. // { exits: { success: { outputExample: '*' } } },
  307. // // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  308. // ERSTWHILE_PARTICLE,
  309. // // ...then the following runtime value should be received on the OUTSIDE:
  310. // ITERATOR_SAFE_VERSION_OF_ERSTWHILE_PARTICLE
  311. // );
  312. testDifferentUsages(
  313. { exits: { success: { outputExample: [{meta: '==='}] } } },
  314. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  315. SOME_ARBITRARY_FUNCTION,
  316. // ...then the following runtime value should be received on the OUTSIDE:
  317. []
  318. );
  319. testDifferentUsages(
  320. { exits: { success: { outputExample: [{meta: '==='}] } } },
  321. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  322. [{meta: SOME_ARBITRARY_FUNCTION, foo: 12412, bar: 35132}],
  323. // ...then the following runtime value should be received on the OUTSIDE:
  324. [{meta: SOME_ARBITRARY_FUNCTION}]
  325. );
  326. testDifferentUsages(
  327. {
  328. exits: {
  329. success: { outputExample: 'foo' },
  330. somethingElse: { outputExample: true },
  331. somethingElse2: { outputExample: false },
  332. somethingElse3: { outputExample: -329.3 },
  333. somethingElse4: { outputExample: {} },
  334. somethingElse5: { outputExample: '*' },
  335. somethingElse6: { outputExample: '->' },
  336. somethingElse7: { outputExample: '===' },
  337. somethingElse8: { outputExample: [{opts: '*'}] },
  338. somethingElse9: { outputExample: [{fn: '->'}] },
  339. somethingElse10: { outputExample: [{meta: '==='}] },
  340. somethingElse11: { outputExample: [] },
  341. somethingElse12: { example: false },
  342. somethingElse13: { example: -329.3 },
  343. somethingElse14: { example: {} },
  344. somethingElse15: { example: '*' },
  345. somethingElse16: { example: '->' },
  346. somethingElse17: { example: '===' },
  347. somethingElse18: { example: [{opts: '*'}] },
  348. somethingElse19: { example: [{fn: '->'}] },
  349. somethingElse20: { example: [{meta: '==='}] },
  350. somethingElse21: { example: [] },
  351. error: {}
  352. }
  353. },
  354. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  355. 'Butter sandwich',
  356. // ...then the following runtime value should be received on the OUTSIDE:
  357. 'Butter sandwich'
  358. );
  359. testDifferentUsages(
  360. {
  361. exits: {
  362. success: { outputExample: 'foo' },
  363. somethingElse: { outputExample: true },
  364. somethingElse2: { outputExample: false },
  365. somethingElse3: { outputExample: -329.3 },
  366. somethingElse4: { outputExample: {} },
  367. somethingElse5: { outputExample: '*' },
  368. somethingElse6: { outputExample: '->' },
  369. somethingElse7: { outputExample: '===' },
  370. somethingElse8: { outputExample: [{opts: '*'}] },
  371. somethingElse9: { outputExample: [{fn: '->'}] },
  372. somethingElse10: { outputExample: [{meta: '==='}] },
  373. somethingElse11: { outputExample: [] },
  374. somethingElse12: { example: false },
  375. somethingElse13: { example: -329.3 },
  376. somethingElse14: { example: {} },
  377. somethingElse15: { example: '*' },
  378. somethingElse16: { example: '->' },
  379. somethingElse17: { example: '===' },
  380. somethingElse18: { example: [{opts: '*'}] },
  381. somethingElse19: { example: [{fn: '->'}] },
  382. somethingElse20: { example: [{meta: '==='}] },
  383. somethingElse21: { example: [] },
  384. error: {}
  385. }
  386. },
  387. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  388. undefined,
  389. // ...then the following runtime value should be received on the OUTSIDE:
  390. ''
  391. );
  392. testDifferentUsages(
  393. {
  394. exits: {
  395. success: { outputExample: 123 },
  396. error: { outputExample: '===' }
  397. }
  398. },
  399. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  400. undefined,
  401. // ...then the following runtime value should be received on the OUTSIDE:
  402. 0
  403. );
  404. testDifferentUsages(
  405. {
  406. exits: {
  407. success: { outputExample: 123 },
  408. error: { example: 'foo' }
  409. }
  410. },
  411. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  412. 999,
  413. // ...then the following runtime value should be received on the OUTSIDE:
  414. 999
  415. );
  416. testDifferentUsages(
  417. {
  418. exits: {
  419. success: { example: 123 },
  420. error: { outputExample: 'foo' }
  421. }
  422. },
  423. // If the following runtime value is returned through the success exit FROM INSIDE the machine `fn`:
  424. 999,
  425. // ...then the following runtime value should be received on the OUTSIDE:
  426. 999
  427. );
  428. }); // </when there is runtime output>
  429. }); // </with success exit defined, with an `outputExample`>
  430. });
  431. /**
  432. * This helper tests different usages of the specified machine def.
  433. * NOTE: The provided machine def SHOULD NOT specify a `fn` or `inputs`!
  434. *
  435. * Machine def should call its error exit when the `foo` input is set to
  436. * the string: "error"
  437. *
  438. * @param {===} machine - the machine def
  439. * @param {===?} runtimeValueToReturn - the runtime value that the machine's `fn` will return through the success exit.
  440. * @param {===?} expectedOutputIfSuccessExitIsCalled - the expected output if the success exit is called. Will be compared using Node's native `assert.deepEqual()`.
  441. * @param {Boolean} useStrictEq - if set to true, then a strict equality check (`assert.strictEqual()`) will be used instead of `assert.deepEqual()`
  442. */
  443. function testDifferentUsages (machine, runtimeValueToReturn, expectedOutputIfSuccessExitIsCalled, useStrictEq) {
  444. if (machine.fn || machine.inputs) {
  445. throw new Error('Test is invalid-- please do not provide a `fn` or `inputs` to this test helper.');
  446. }
  447. machine.inputs = {
  448. foo: {
  449. example: 'foo bar'
  450. }
  451. };
  452. machine.fn = function (inputs, exits, deps) {
  453. if (inputs.foo === 'error') {
  454. exits('ERROR!');
  455. }
  456. else {
  457. if (!_.isUndefined(runtimeValueToReturn)) {
  458. exits(undefined, runtimeValueToReturn);
  459. }
  460. else {
  461. exits();
  462. }
  463. }
  464. };
  465. ////////////////////////////////////////////////////////////////////
  466. // Trying to `.exec()` a machine with no callbacks
  467. ////////////////////////////////////////////////////////////////////
  468. it('should throw an error when when `fn` calls `exits()` and no callbacks are bound', function(done) {
  469. assert.throws(function (){
  470. M.build(machine)
  471. .configure({
  472. foo: 'hello'
  473. })
  474. .exec();
  475. });
  476. return done();
  477. });
  478. it('should throw an error when when `fn` calls `exits("ERROR!")` and no callbacks are bound', function(done) {
  479. assert.throws(function (){
  480. M.build(machine)
  481. .configure({
  482. foo: 'error'
  483. })
  484. .exec();
  485. });
  486. return done();
  487. });
  488. ////////////////////////////////////////////////////////////////////
  489. // Binding exit callbacks with second argument to .configure()
  490. ////////////////////////////////////////////////////////////////////
  491. it('should call the success exit when `fn` calls `exits()` and callbacks are bound using second argument to `configure()`', function(done) {
  492. M.build(machine)
  493. .configure({
  494. foo: 'hello'
  495. }, {
  496. success: function(resultMaybe) {
  497. // Verify the output, if expected output was provided to this test helper.
  498. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  499. if (useStrictEq) {
  500. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  501. catch (e) { return done(e); }
  502. }
  503. else {
  504. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  505. catch (e) { return done(e); }
  506. }
  507. }
  508. return done();
  509. },
  510. error: function(err) {
  511. return done(new Error('Should NOT have called the error exit!'));
  512. }
  513. })
  514. .exec();
  515. });
  516. it('should call the error exit when `fn` calls `exits("ERROR!")` and callbacks are bound using second argument to `configure()`', function(done) {
  517. M.build(machine)
  518. .configure({
  519. foo: 'error'
  520. }, {
  521. success: function() {
  522. done(new Error('Should NOT have called the success exit!'));
  523. },
  524. error: function(err) {
  525. assert(err, 'expected `'+err+'` to be truthy');
  526. return done();
  527. }
  528. })
  529. .exec();
  530. });
  531. it('should call the error exit when `fn` calls `exits()` and ONLY an `error` callback is bound using second argument to `configure()`', function(done) {
  532. M.build(machine)
  533. .configure({
  534. foo: 'hello'
  535. }, {
  536. error: function(err) { return done(); }
  537. })
  538. .exec();
  539. });
  540. it('should call the error exit when `fn` calls `exits("ERROR!")` and ONLY an `error` callback is bound using second argument to `configure()`', function(done) {
  541. M.build(machine)
  542. .configure({
  543. foo: 'error'
  544. }, {
  545. error: function(err) { return done(); }
  546. })
  547. .exec();
  548. });
  549. it('should throw an error when no `error` callback is bound using second argument to `configure()`', function(done) {
  550. assert.throws(function (){
  551. M.build(machine)
  552. .configure({
  553. foo: 'hello'
  554. }, {
  555. success: function() {
  556. return done(new Error('Should have thrown, and not called any exit!'));
  557. }
  558. })
  559. .exec();
  560. });
  561. done();
  562. });
  563. ////////////////////////////////////////////////////////////////////
  564. // Binding Node callback with second argument to .configure()
  565. ////////////////////////////////////////////////////////////////////
  566. it('should call the success exit when `fn` calls `exits()` and a single Node callback is bound using second argument to `configure()`', function(done) {
  567. M.build(machine)
  568. .configure({
  569. foo: 'hello'
  570. }, function (err, resultMaybe){
  571. if (err) {
  572. return done(new Error('`err` should NOT have been set!'));
  573. }
  574. // Verify the output, if expected output was provided to this test helper.
  575. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  576. // If the expected output cannot be stringified, then use a strict equality check.
  577. var useStrictEq;
  578. try { JSON.stringify(expectedOutputIfSuccessExitIsCalled); }
  579. catch (ignored) { useStrictEq = true; }
  580. if (useStrictEq) {
  581. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  582. catch (e) { return done(e); }
  583. }
  584. else {
  585. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  586. catch (e) { return done(e); }
  587. }
  588. }
  589. return done();
  590. })
  591. .exec();
  592. });
  593. it('should call the error exit when `fn` calls `exits("ERROR!")` and a single Node callback is bound using second argument to `configure()`', function(done) {
  594. M.build(machine)
  595. .configure({
  596. foo: 'error'
  597. },function (err){
  598. if (err) {
  599. return done();
  600. }
  601. return done(new Error('`err` should have been set!'));
  602. })
  603. .exec();
  604. });
  605. ////////////////////////////////////////////////////////////////////
  606. // Binding exit callbacks with .exec()
  607. ////////////////////////////////////////////////////////////////////
  608. it('should call the success exit when `fn` calls `exits()` and callbacks are bound using .exec()', function(done) {
  609. M.build(machine)
  610. .configure({
  611. foo: 'hello'
  612. }).exec({
  613. success: function(resultMaybe) {
  614. // Verify the output, if expected output was provided to this test helper.
  615. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  616. if (useStrictEq) {
  617. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  618. catch (e) { return done(e); }
  619. }
  620. else {
  621. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  622. catch (e) { return done(e); }
  623. }
  624. }
  625. return done();
  626. },
  627. error: function(err) { return done(new Error('Should NOT have called the error exit!'));}
  628. });
  629. });
  630. it('should call the error exit when `fn` calls `exits("ERROR!")` and callbacks are bound using .exec()', function(done) {
  631. M.build(machine)
  632. .configure({
  633. foo: 'error'
  634. }).exec({
  635. success: function() { return done(new Error('Should NOT have called the success exit!'));},
  636. error: function(err) {
  637. assert(err, 'expected `'+err+'` to be truthy');
  638. return done();
  639. }
  640. });
  641. });
  642. it('should call the error exit when `fn` calls `exits()` and ONLY an `error` callback is bound using .exec()', function(done) {
  643. M.build(machine)
  644. .configure({
  645. foo: 'hello'
  646. }).exec({
  647. error: function(err) { return done(); }
  648. });
  649. });
  650. it('should call the error exit when `fn` calls `exits("ERROR!")` and ONLY an `error` callback is bound using .exec()', function(done) {
  651. M.build(machine)
  652. .configure({
  653. foo: 'error'
  654. }).exec({
  655. error: function(err) { return done(); }
  656. });
  657. });
  658. it('should throw an error when no `error` callback is bound using .exec()', function(done) {
  659. assert.throws(function (){
  660. M.build(machine)
  661. .configure({
  662. foo: 'hello'
  663. }).exec({
  664. success: function() {
  665. return done(new Error('Should have thrown, and not called any exit!'));
  666. }
  667. });
  668. });
  669. done();
  670. });
  671. ////////////////////////////////////////////////////////////////////
  672. // Binding Node callback with .exec()
  673. ////////////////////////////////////////////////////////////////////
  674. it('should call the success exit when `fn` calls `exits()` and a single Node callback is bound using .exec()', function(done) {
  675. M.build(machine)
  676. .configure({
  677. foo: 'hello'
  678. })
  679. .exec(function (err, resultMaybe){
  680. if (err) {
  681. return done(new Error('`err` should NOT have been set!'));
  682. }
  683. // Verify the output, if expected output was provided to this test helper.
  684. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  685. // If the expected output cannot be stringified, then use a strict equality check.
  686. var useStrictEq;
  687. try { JSON.stringify(expectedOutputIfSuccessExitIsCalled); }
  688. catch (ignored) { useStrictEq = true; }
  689. if (useStrictEq) {
  690. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  691. catch (e) { return done(e); }
  692. }
  693. else {
  694. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  695. catch (e) { return done(e); }
  696. }
  697. }
  698. return done();
  699. });
  700. });
  701. it('should call the error exit when `fn` calls `exits("ERROR!")` and a single Node callback is bound using .exec()', function(done) {
  702. M.build(machine)
  703. .configure({
  704. foo: 'error'
  705. }).exec(function (err){
  706. if (err) {
  707. return done();
  708. }
  709. return done(new Error('`err` should have been set!'));
  710. });
  711. });
  712. ////////////////////////////////////////////////////////////////////
  713. // Binding exit callbacks with .configure()
  714. ////////////////////////////////////////////////////////////////////
  715. it('should call the success exit when `fn` calls `exits()` and callbacks are bound using .configure()', function(done) {
  716. M.build(machine)
  717. .configure({
  718. foo: 'hello'
  719. }, {
  720. success: function(resultMaybe) {
  721. // Verify the output, if expected output was provided to this test helper.
  722. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  723. if (useStrictEq) {
  724. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  725. catch (e) { return done(e); }
  726. }
  727. else {
  728. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  729. catch (e) { return done(e); }
  730. }
  731. }
  732. return done();
  733. },
  734. error: function(err) { return done(new Error('Should NOT have called the error exit!')); }
  735. })
  736. .exec();
  737. });
  738. it('should call the error exit when `fn` calls `exits("ERROR!")` and callbacks are bound using .configure()', function(done) {
  739. M.build(machine)
  740. .configure({
  741. foo: 'error'
  742. }, {
  743. success: function() { return done(new Error('Should NOT have called the success exit!')); },
  744. error: function(err) {
  745. assert(err, 'expected `'+err+'` to be truthy');
  746. return done();
  747. }
  748. })
  749. .exec();
  750. });
  751. it('should call the error exit when `fn` calls `exits()` and ONLY an `error` callback is bound using .configure()', function(done) {
  752. M.build(machine)
  753. .configure({
  754. foo: 'hello'
  755. }, {
  756. error: function(err) { return done(); }
  757. })
  758. .exec();
  759. });
  760. it('should call the error exit when `fn` calls `exits("ERROR!")` and ONLY an `error` callback is bound using .configure()', function(done) {
  761. M.build(machine)
  762. .configure({
  763. foo: 'error'
  764. }, {
  765. error: function(err) { return done(); }
  766. })
  767. .exec();
  768. });
  769. it('should throw an error when no `error` callback is bound using .configure()', function(done) {
  770. assert.throws(function (){
  771. M.build(machine)
  772. .configure({
  773. foo: 'hello'
  774. }, {
  775. success: function() {
  776. return done(new Error('Should have thrown, and not called any exit!'));
  777. }
  778. })
  779. .exec();
  780. });
  781. return done();
  782. });
  783. ////////////////////////////////////////////////////////////////////
  784. // Binding Node callback with configure()
  785. ////////////////////////////////////////////////////////////////////
  786. it('should call the success exit when `fn` calls `exits()` and a single Node callback is bound using .configure()', function(done) {
  787. M.build(machine)
  788. .configure({
  789. foo: 'hello'
  790. }, function (err, resultMaybe){
  791. if (err) {
  792. return done(new Error('`err` should NOT have been set!'));
  793. }
  794. // Verify the output, if expected output was provided to this test helper.
  795. if (!_.isUndefined(expectedOutputIfSuccessExitIsCalled)) {
  796. // If the expected output cannot be stringified, then use a strict equality check.
  797. var useStrictEq;
  798. try { JSON.stringify(expectedOutputIfSuccessExitIsCalled); }
  799. catch (ignored) { useStrictEq = true; }
  800. if (useStrictEq) {
  801. try { assert.strictEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  802. catch (e) { return done(e); }
  803. }
  804. else {
  805. try { assert.deepEqual(resultMaybe, expectedOutputIfSuccessExitIsCalled); }
  806. catch (e) { return done(e); }
  807. }
  808. }
  809. return done();
  810. })
  811. .exec();
  812. });
  813. it('should call the error exit when `fn` calls `exits("ERROR!")` and a single Node callback is bound using .configure()', function(done) {
  814. M.build(machine)
  815. .configure({
  816. foo: 'error'
  817. }, function (err){
  818. if (err) {
  819. return done();
  820. }
  821. return done(new Error('`err` should have been set!'));
  822. })
  823. .exec();
  824. });
  825. }