test-promise.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. 'use strict';
  5. var core = require('sdk/core/promise'),
  6. defer = core.defer, resolve = core.resolve, reject = core.reject, all = core.all,
  7. promised = core.promised;
  8. var { setTimeout } = require('sdk/timers');
  9. exports['test all observers are notified'] = function(assert, done) {
  10. var expected = 'Taram pam param!'
  11. var deferred = defer()
  12. var pending = 10, i = 0
  13. function resolved(value) {
  14. assert.equal(value, expected, 'value resolved as expected: #' + pending)
  15. if (!--pending) done()
  16. }
  17. while (i++ < pending) deferred.promise.then(resolved)
  18. deferred.resolve(expected)
  19. }
  20. exports['test exceptions dont stop notifications'] = function(assert, done) {
  21. var threw = false, boom = Error('Boom!')
  22. var deferred = defer()
  23. var promise2 = deferred.promise.then(function() {
  24. threw = true
  25. throw boom
  26. })
  27. deferred.promise.then(function() {
  28. assert.ok(threw, 'observer is called even though previos one threw')
  29. promise2.then(function() {
  30. assert.fail('should not resolve')
  31. }, function(reason) {
  32. assert.equal(reason, boom, 'rejects to thrown error')
  33. done()
  34. })
  35. })
  36. deferred.resolve('go!')
  37. }
  38. exports['test subsequent resolves are ignored'] = function(assert, done) {
  39. var deferred = defer()
  40. deferred.resolve(1)
  41. deferred.resolve(2)
  42. deferred.reject(3)
  43. deferred.promise.then(function(actual) {
  44. assert.equal(actual, 1, 'resolves to first value')
  45. }, function() {
  46. assert.fail('must not reject')
  47. })
  48. deferred.promise.then(function(actual) {
  49. assert.equal(actual, 1, 'subsequent resolutions are ignored')
  50. done()
  51. }, function() {
  52. assert.fail('must not reject')
  53. })
  54. }
  55. exports['test subsequent rejections are ignored'] = function(assert, done) {
  56. var deferred = defer()
  57. deferred.reject(1)
  58. deferred.resolve(2)
  59. deferred.reject(3)
  60. deferred.promise.then(function(actual) {
  61. assert.fail('must not resolve')
  62. }, function(actual) {
  63. assert.equal(actual, 1, 'must reject to first')
  64. })
  65. deferred.promise.then(function(actual) {
  66. assert.fail('must not resolve')
  67. }, function(actual) {
  68. assert.equal(actual, 1, 'must reject to first')
  69. done()
  70. })
  71. }
  72. exports['test error recovery'] = function(assert, done) {
  73. var boom = Error('Boom!')
  74. var deferred = defer()
  75. deferred.promise.then(function() {
  76. assert.fail('rejected promise should not resolve')
  77. }, function(reason) {
  78. assert.equal(reason, boom, 'rejection reason delivered')
  79. return 'recovery'
  80. }).then(function(value) {
  81. assert.equal(value, 'recovery', 'error handled by a handler')
  82. done()
  83. })
  84. deferred.reject(boom)
  85. }
  86. exports['test error recovery with promise'] = function(assert, done) {
  87. var deferred = defer()
  88. deferred.promise.then(function() {
  89. assert.fail('must reject')
  90. }, function(actual) {
  91. assert.equal(actual, 'reason', 'rejected')
  92. var deferred = defer()
  93. deferred.resolve('recovery')
  94. return deferred.promise
  95. }).then(function(actual) {
  96. assert.equal(actual, 'recovery', 'recorvered via promise')
  97. var deferred = defer()
  98. deferred.reject('error')
  99. return deferred.promise
  100. }).then(null, function(actual) {
  101. assert.equal(actual, 'error', 'rejected via promise')
  102. var deferred = defer()
  103. deferred.reject('end')
  104. return deferred.promise
  105. }).then(null, function(actual) {
  106. assert.equal(actual, 'end', 'rejeced via promise')
  107. done()
  108. })
  109. deferred.reject('reason')
  110. }
  111. exports['test propagation'] = function(assert, done) {
  112. var d1 = defer(), d2 = defer(), d3 = defer()
  113. d1.promise.then(function(actual) {
  114. assert.equal(actual, 'expected', 'resolves to expected value')
  115. done()
  116. })
  117. d1.resolve(d2.promise)
  118. d2.resolve(d3.promise)
  119. d3.resolve('expected')
  120. }
  121. exports['test chaining'] = function(assert, done) {
  122. var boom = Error('boom'), brax = Error('braxXXx')
  123. var deferred = defer()
  124. deferred.promise.then().then().then(function(actual) {
  125. assert.equal(actual, 2, 'value propagates unchanged')
  126. return actual + 2
  127. }).then(null, function(reason) {
  128. assert.fail('should not reject')
  129. }).then(function(actual) {
  130. assert.equal(actual, 4, 'value propagates through if not handled')
  131. throw boom
  132. }).then(function(actual) {
  133. assert.fail('exception must reject promise')
  134. }).then().then(null, function(actual) {
  135. assert.equal(actual, boom, 'reason propagates unchanged')
  136. throw brax
  137. }).then().then(null, function(actual) {
  138. assert.equal(actual, brax, 'reason changed becase of exception')
  139. return 'recovery'
  140. }).then(function(actual) {
  141. assert.equal(actual, 'recovery', 'recovered from error')
  142. done()
  143. })
  144. deferred.resolve(2)
  145. }
  146. exports['test reject'] = function(assert, done) {
  147. var expected = Error('boom')
  148. reject(expected).then(function() {
  149. assert.fail('should reject')
  150. }, function(actual) {
  151. assert.equal(actual, expected, 'rejected with expected reason')
  152. }).then(function() {
  153. done()
  154. })
  155. }
  156. exports['test resolve to rejected'] = function(assert, done) {
  157. var expected = Error('boom')
  158. var deferred = defer()
  159. deferred.promise.then(function() {
  160. assert.fail('should reject')
  161. }, function(actual) {
  162. assert.equal(actual, expected, 'rejected with expected failure')
  163. }).then(function() {
  164. done()
  165. })
  166. deferred.resolve(reject(expected))
  167. }
  168. exports['test resolve'] = function(assert, done) {
  169. var expected = 'value'
  170. resolve(expected).then(function(actual) {
  171. assert.equal(actual, expected, 'resolved as expected')
  172. }).then(function() {
  173. done()
  174. })
  175. }
  176. exports['test resolve with prototype'] = function(assert, done) {
  177. var seventy = resolve(70, {
  178. subtract: function subtract(y) {
  179. return this.then(function(x) { return x - y })
  180. }
  181. })
  182. seventy.subtract(17).then(function(actual) {
  183. assert.equal(actual, 70 - 17, 'resolves to expected')
  184. done()
  185. })
  186. }
  187. exports['test promised with normal args'] = function(assert, done) {
  188. var sum = promised(function(x, y) { return x + y })
  189. sum(7, 8).then(function(actual) {
  190. assert.equal(actual, 7 + 8, 'resolves as expected')
  191. done()
  192. })
  193. }
  194. exports['test promised with promise args'] = function(assert, done) {
  195. var sum = promised(function(x, y) { return x + y })
  196. var deferred = defer()
  197. sum(11, deferred.promise).then(function(actual) {
  198. assert.equal(actual, 11 + 24, 'resolved as expected')
  199. done()
  200. })
  201. deferred.resolve(24)
  202. }
  203. exports['test promised with prototype'] = function(assert, done) {
  204. var deferred = defer()
  205. var numeric = {}
  206. numeric.subtract = promised(function(y) { return this - y }, numeric)
  207. var sum = promised(function(x, y) { return x + y }, numeric)
  208. sum(7, 70).
  209. subtract(14).
  210. subtract(deferred.promise).
  211. subtract(5).
  212. then(function(actual) {
  213. assert.equal(actual, 7 + 70 - 14 - 23 - 5, 'resolved as expected')
  214. done()
  215. })
  216. deferred.resolve(23)
  217. }
  218. exports['test promised error handleing'] = function(assert, done) {
  219. var expected = Error('boom')
  220. var f = promised(function() {
  221. throw expected
  222. })
  223. f().then(function() {
  224. assert.fail('should reject')
  225. }, function(actual) {
  226. assert.equal(actual, expected, 'rejected as expected')
  227. done()
  228. })
  229. }
  230. exports['test errors in promise resolution handlers are propagated'] = function(assert, done) {
  231. var expected = Error('Boom');
  232. var { promise, resolve } = defer();
  233. promise.then(function() {
  234. throw expected;
  235. }).then(function() {
  236. return undefined;
  237. }).then(null, function(actual) {
  238. assert.equal(actual, expected, 'rejected as expected');
  239. }).then(done, assert.fail);
  240. resolve({});
  241. }
  242. exports['test return promise form promised'] = function(assert, done) {
  243. var f = promised(function() {
  244. return resolve(17)
  245. })
  246. f().then(function(actual) {
  247. assert.equal(actual, 17, 'resolves to a promise resolution')
  248. done()
  249. })
  250. }
  251. exports['test promised returning failure'] = function(assert, done) {
  252. var expected = Error('boom')
  253. var f = promised(function() {
  254. return reject(expected)
  255. })
  256. f().then(function() {
  257. assert.fail('must reject')
  258. }, function(actual) {
  259. assert.equal(actual, expected, 'rejects with expected reason')
  260. done()
  261. })
  262. }
  263. exports['test promised are greedy'] = function(assert, done) {
  264. var runs = 0
  265. var f = promised(function() { ++runs })
  266. var promise = f()
  267. assert.equal(runs, 1, 'promised runs task right away')
  268. done()
  269. }
  270. exports['test arrays should not flatten'] = function(assert, done) {
  271. var a = defer()
  272. var b = defer()
  273. var combine = promised(function(str, arr) {
  274. assert.equal(str, 'Hello', 'Array was not flattened')
  275. assert.deepEqual(arr, [ 'my', 'friend' ])
  276. })
  277. combine(a.promise, b.promise).then(done)
  278. a.resolve('Hello')
  279. b.resolve([ 'my', 'friend' ])
  280. }
  281. exports['test `all` for all promises'] = function (assert, done) {
  282. all([
  283. resolve(5), resolve(7), resolve(10)
  284. ]).then(function (val) {
  285. assert.equal(
  286. val[0] === 5 &&
  287. val[1] === 7 &&
  288. val[2] === 10
  289. , true, 'return value contains resolved promises values');
  290. done();
  291. }, function () {
  292. assert.fail('should not call reject function');
  293. });
  294. };
  295. exports['test `all` aborts upon first reject'] = function (assert, done) {
  296. all([
  297. resolve(5), reject('error'), delayedResolve()
  298. ]).then(function (val) {
  299. assert.fail('Successful resolve function should not be called');
  300. }, function (reason) {
  301. assert.equal(reason, 'error', 'should reject the `all` promise');
  302. done();
  303. });
  304. function delayedResolve () {
  305. var deferred = defer();
  306. setTimeout(deferred.resolve, 50);
  307. return deferred.promise;
  308. }
  309. };
  310. exports['test `all` with array containing non-promise'] = function (assert, done) {
  311. all([
  312. resolve(5), resolve(10), 925
  313. ]).then(function (val) {
  314. assert.equal(val[2], 925, 'non-promises should pass-through value');
  315. done();
  316. }, function () {
  317. assert.fail('should not be rejected');
  318. });
  319. };
  320. exports['test `all` should resolve with an empty array'] = function (assert, done) {
  321. all([]).then(function (val) {
  322. assert.equal(Array.isArray(val), true, 'should return array in resolved');
  323. assert.equal(val.length, 0, 'array should be empty in resolved');
  324. done();
  325. }, function () {
  326. assert.fail('should not be rejected');
  327. });
  328. };
  329. exports['test `all` with multiple rejected'] = function (assert, done) {
  330. all([
  331. reject('error1'), reject('error2'), reject('error3')
  332. ]).then(function (value) {
  333. assert.fail('should not be successful');
  334. }, function (reason) {
  335. assert.equal(reason, 'error1', 'should reject on first promise reject');
  336. done();
  337. });
  338. };
  339. require("test").run(exports)