promise.test.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*global describe,it */
  2. /**
  3. * Module dependencies.
  4. */
  5. var assert = require('assert');
  6. var MPromise = require('../');
  7. /**
  8. * Test.
  9. */
  10. describe('promise', function () {
  11. it('events fire right after fulfill()', function (done) {
  12. var promise = new MPromise()
  13. , called = 0;
  14. promise.on('fulfill', function (a, b) {
  15. assert.equal(a, '1');
  16. assert.equal(b, '2');
  17. called++;
  18. });
  19. promise.fulfill('1', '2');
  20. promise.on('fulfill', function (a, b) {
  21. assert.equal(a, '1');
  22. assert.equal(b, '2');
  23. called++;
  24. });
  25. assert.equal(2, called);
  26. done();
  27. });
  28. it('events fire right after reject()', function (done) {
  29. var promise = new MPromise()
  30. , called = 0;
  31. promise.on('reject', function (err) {
  32. assert.ok(err instanceof Error);
  33. called++;
  34. });
  35. promise.reject(new Error('booyah'));
  36. promise.on('reject', function (err) {
  37. assert.ok(err instanceof Error);
  38. called++;
  39. });
  40. assert.equal(2, called);
  41. done()
  42. });
  43. describe('onResolve()', function () {
  44. it('from constructor works', function (done) {
  45. var called = 0;
  46. var promise = new MPromise(function (err) {
  47. assert.ok(err instanceof Error);
  48. called++;
  49. });
  50. promise.reject(new Error('dawg'));
  51. assert.equal(1, called);
  52. done();
  53. });
  54. it('after fulfill()', function (done) {
  55. var promise = new MPromise()
  56. , called = 0;
  57. promise.fulfill('woot');
  58. promise.onResolve(function (err, data) {
  59. assert.equal(data, 'woot');
  60. called++;
  61. });
  62. promise.onResolve(function (err) {
  63. assert.strictEqual(err, null);
  64. called++;
  65. });
  66. assert.equal(2, called);
  67. done();
  68. })
  69. });
  70. describe('onFulfill shortcut', function () {
  71. it('works', function (done) {
  72. var promise = new MPromise()
  73. , called = 0;
  74. promise.onFulfill(function (woot) {
  75. assert.strictEqual(woot, undefined);
  76. called++;
  77. });
  78. promise.fulfill();
  79. assert.equal(1, called);
  80. done();
  81. });
  82. });
  83. describe('onReject shortcut', function () {
  84. it('works', function (done) {
  85. var promise = new MPromise()
  86. , called = 0;
  87. promise.onReject(function (err) {
  88. assert.ok(err instanceof Error);
  89. called++;
  90. });
  91. promise.reject(new Error);
  92. assert.equal(1, called);
  93. done();
  94. })
  95. });
  96. describe('return values', function () {
  97. it('on()', function (done) {
  98. var promise = new MPromise();
  99. assert.ok(promise.on('jump', function () {}) instanceof MPromise);
  100. done()
  101. });
  102. it('onFulfill()', function (done) {
  103. var promise = new MPromise();
  104. assert.ok(promise.onFulfill(function () {}) instanceof MPromise);
  105. done();
  106. });
  107. it('onReject()', function (done) {
  108. var promise = new MPromise();
  109. assert.ok(promise.onReject(function () {}) instanceof MPromise);
  110. done();
  111. });
  112. it('onResolve()', function (done) {
  113. var promise = new MPromise();
  114. assert.ok(promise.onResolve(function () {}) instanceof MPromise);
  115. done();
  116. })
  117. });
  118. describe('casting errors', function () {
  119. describe('reject()', function () {
  120. it('does not cast arguments to Error', function (done) {
  121. var p = new MPromise(function (err) {
  122. assert.equal(3, err);
  123. done();
  124. });
  125. p.reject(3);
  126. })
  127. })
  128. });
  129. describe('then', function () {
  130. describe('catching', function () {
  131. it('should not catch returned promise fulfillments', function (done) {
  132. var errorSentinal
  133. , p = new MPromise;
  134. p.then(function () { throw errorSentinal = new Error("boo!") });
  135. p.fulfill();
  136. done();
  137. });
  138. it('should not catch returned promise fulfillments even async', function (done) {
  139. var errorSentinal
  140. , p = new MPromise;
  141. p.then(function () { throw errorSentinal = new Error("boo!") });
  142. setTimeout(function () {
  143. p.fulfill();
  144. done();
  145. }, 10);
  146. });
  147. it('can be disabled using .end()', function (done) {
  148. if (process.version.indexOf('v0.8') == 0) return done();
  149. var errorSentinal
  150. , overTimeout
  151. , domain = require('domain').create();
  152. domain.once('error', function (err) {
  153. assert(err, errorSentinal);
  154. clearTimeout(overTimeout);
  155. done()
  156. });
  157. domain.run(function () {
  158. var p = new MPromise;
  159. var p2 = p.then(function () {
  160. throw errorSentinal = new Error('shucks')
  161. });
  162. p2.end();
  163. p.fulfill();
  164. });
  165. overTimeout = setTimeout(function () { done(new Error('error was swallowed')); }, 10);
  166. });
  167. it('can be disabled using .end() even when async', function (done) {
  168. if (process.version.indexOf('v0.10') != 0) return done();
  169. var errorSentinal
  170. , overTimeout
  171. , domain = require('domain').create();
  172. domain.on('error', function (err) {
  173. assert(err, errorSentinal);
  174. clearTimeout(overTimeout);
  175. done()
  176. });
  177. domain.run(function () {
  178. var p = new MPromise;
  179. var p2 = p.then(function () {
  180. throw errorSentinal = new Error("boo!")
  181. });
  182. p2.end();
  183. setTimeout(function () {p.fulfill();}, 10);
  184. });
  185. overTimeout = setTimeout(function () { done(new Error('error was swallowed')); }, 20);
  186. });
  187. it('can be handled using .end() so no throwing', function (done) {
  188. var errorSentinal
  189. , overTimeout
  190. , domain = require('domain').create();
  191. domain.run(function () {
  192. var p = new MPromise;
  193. var p2 = p.then(function () {
  194. throw errorSentinal = new Error("boo!")
  195. });
  196. p2.end(function (err) {
  197. assert.equal(err, errorSentinal);
  198. clearTimeout(overTimeout);
  199. done()
  200. });
  201. setTimeout(function () {p.fulfill();}, 10);
  202. });
  203. overTimeout = setTimeout(function () { done(new Error('error was swallowed')); }, 20);
  204. });
  205. });
  206. it('persistent', function (done) {
  207. var p = new MPromise;
  208. v = null;
  209. function ensure(val) {
  210. v = v || val;
  211. assert.equal(v, val);
  212. }
  213. function guard() {
  214. throw new Error('onReject should not be called');
  215. }
  216. p.then(ensure, guard).end();
  217. p.fulfill('foo');
  218. p.fulfill('bar');
  219. p.reject(new Error('baz'));
  220. p.then(ensure, guard).end();
  221. setTimeout(done, 0);
  222. });
  223. it('accepts multiple completion values', function (done) {
  224. var p = new MPromise;
  225. p.then(function (a, b) {
  226. assert.equal(2, arguments.length);
  227. assert.equal('hi', a);
  228. assert.equal(4, b);
  229. done();
  230. }, done).end();
  231. p.fulfill('hi', 4);
  232. })
  233. });
  234. describe('fulfill values and splats', function () {
  235. it('should handle multiple values', function (done) {
  236. var p = new MPromise;
  237. p.onFulfill(function (a, b, c) {
  238. assert.equal('a', a);
  239. assert.equal('b', b);
  240. assert.equal('c', c);
  241. done();
  242. });
  243. p.fulfill('a', 'b', 'c');
  244. });
  245. it('should handle multiple values from a then', function (done) {
  246. MPromise.fulfilled().then(
  247. function () {
  248. return MPromise.fulfilled().then(
  249. function () {
  250. var p = new MPromise;
  251. p.fulfill('a', 'b', 'c');
  252. return p;
  253. }
  254. );
  255. }
  256. ).onFulfill(
  257. function (a, b, c) {
  258. assert.equal('a', a);
  259. assert.equal('b', b);
  260. assert.equal('c', c);
  261. done();
  262. }
  263. ).end()
  264. });
  265. it('should work with `fulfilled` convenience method', function (done) {
  266. MPromise.fulfilled('a', 'b', 'c').then(function (a, b, c) {
  267. assert.equal('a', a);
  268. assert.equal('b', b);
  269. assert.equal('c', c);
  270. done();
  271. })
  272. });
  273. });
  274. describe('end', function () {
  275. it("should return the promise", function (done) {
  276. var p = new MPromise;
  277. var p1 = p.end();
  278. assert.equal(p, p1);
  279. done();
  280. });
  281. it("should throw for chain", function (done) {
  282. var p = new MPromise;
  283. p.then().then().then().then().end();
  284. try {
  285. p.reject('bad');
  286. } catch (e) {
  287. done();
  288. }
  289. });
  290. it("should not throw for chain with reject handler", function (done) {
  291. var p = new MPromise;
  292. p.then().then().then().then().end(function () {
  293. done();
  294. });
  295. try {
  296. p.reject('bad');
  297. } catch (e) {
  298. done(e);
  299. }
  300. });
  301. });
  302. describe('chain', function () {
  303. it('should propagate fulfillment', function (done) {
  304. var varSentinel = {a: 'a'};
  305. var p1 = new MPromise;
  306. p1.chain(new MPromise(function (err, doc) {
  307. assert.equal(doc, varSentinel);
  308. done();
  309. }));
  310. p1.fulfill(varSentinel);
  311. });
  312. it('should propagate rejection', function (done) {
  313. var e = new Error("gaga");
  314. var p1 = new MPromise;
  315. p1.chain(new MPromise(function (err) {
  316. assert.equal(err, e);
  317. done();
  318. }));
  319. p1.reject(e);
  320. });
  321. it('should propagate resolution err', function (done) {
  322. var e = new Error("gaga");
  323. var p1 = new MPromise;
  324. p1.chain(new MPromise(function (err) {
  325. assert.equal(err, e);
  326. done();
  327. }));
  328. p1.resolve(e);
  329. });
  330. it('should propagate resolution val', function (done) {
  331. var varSentinel = {a: 'a'};
  332. var p1 = new MPromise;
  333. p1.chain(new MPromise(function (err, val) {
  334. assert.equal(val, varSentinel);
  335. done();
  336. }));
  337. p1.resolve(null, varSentinel);
  338. })
  339. });
  340. describe("all", function () {
  341. it("works", function (done) {
  342. var count = 0;
  343. var p = new MPromise;
  344. var p2 = p.all(function () {
  345. return [
  346. (function () {
  347. var p = new MPromise();
  348. count++;
  349. p.resolve();
  350. return p;
  351. })()
  352. , (function () {
  353. var p = new MPromise();
  354. count++;
  355. p.resolve();
  356. return p;
  357. })()
  358. ];
  359. });
  360. p2.then(function () {
  361. assert.equal(count, 2);
  362. done();
  363. });
  364. p.resolve();
  365. });
  366. it("handles rejects", function (done) {
  367. var count = 0;
  368. var p = new MPromise;
  369. var p2 = p.all(function () {
  370. return [
  371. (function () {
  372. var p = new MPromise();
  373. count++;
  374. p.resolve();
  375. return p;
  376. })()
  377. , (function () {
  378. count++;
  379. throw new Error("gaga");
  380. })()
  381. ];
  382. });
  383. p2.onReject(function (err) {
  384. assert(err.message, "gaga");
  385. assert.equal(count, 2);
  386. done();
  387. });
  388. p.resolve();
  389. });
  390. });
  391. describe("deferred", function () {
  392. it("works", function (done) {
  393. var d = MPromise.deferred();
  394. assert.ok(d.promise instanceof MPromise);
  395. assert.ok(d.reject instanceof Function);
  396. assert.ok(d.resolve instanceof Function);
  397. assert.ok(d.callback instanceof Function);
  398. done();
  399. });
  400. });
  401. describe("hook", function () {
  402. it("works", function (done) {
  403. var run = 0;
  404. var l1 = function (ser, par) {
  405. run++;
  406. ser();
  407. par();
  408. };
  409. MPromise.hook([l1, l1, l1]).then(function () {
  410. assert(run, 3);
  411. done();
  412. })
  413. });
  414. it("works with async serial hooks", function (done) {
  415. this.timeout(800);
  416. var run = 0;
  417. var l1 = function (ser, par) {
  418. run++;
  419. setTimeout(function () {ser();}, 200);
  420. par();
  421. };
  422. MPromise.hook([l1, l1, l1]).then(function () {
  423. assert(run, 3);
  424. done();
  425. })
  426. });
  427. it("works with async parallel hooks", function (done) {
  428. this.timeout(400);
  429. var run = 0;
  430. var l1 = function (ser, par) {
  431. run++;
  432. ser();
  433. setTimeout(function () {par();}, 200);
  434. };
  435. MPromise.hook([l1, l1, l1]).then(function () {
  436. assert(run, 3);
  437. done();
  438. })
  439. });
  440. it("catches errors in hook logic", function (done) {
  441. var run = 0;
  442. var l1 = function (ser, par) {
  443. run++;
  444. ser();
  445. par();
  446. };
  447. var l2 = function (ser, par) {
  448. run++;
  449. ser();
  450. par();
  451. throw new Error("err")
  452. };
  453. MPromise.hook([l1, l2, l1]).end(function (err) {
  454. assert(run, 2);
  455. done();
  456. });
  457. });
  458. });
  459. });