deferred.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  6. <link rel="stylesheet" href="test.css">
  7. <title>Zepto Deferred unit tests</title>
  8. <script src="../vendor/evidence.js"></script>
  9. <script src="evidence_runner.js"></script>
  10. <script>
  11. // avoid caching
  12. (function(){
  13. function load(scripts){
  14. scripts.split(' ').forEach(function(script){
  15. document.write('<script src="../src/'+script+'.js?'+(+new Date)+'"></scr'+'ipt>')
  16. })
  17. }
  18. load('zepto callbacks deferred')
  19. })()
  20. </script>
  21. </head>
  22. <body>
  23. <h1>Zepto Deferred unit tests</h1>
  24. <p id="results">
  25. Running… see browser console for results
  26. </p>
  27. <script>
  28. (function(){
  29. var promiseFns = "resolve reject notify resolveWith rejectWith notifyWith done fail progress always".split(/\s+/),
  30. deferredFns = "state always then promise done fail progress".split(/\s+/)
  31. $.each(['', 'WithNew'], function(_, withNew) {
  32. var createDeferred = function(fn) {
  33. return withNew ? new $.Deferred(fn) : $.Deferred(fn)
  34. }
  35. Evidence('ZeptoDeferredTest' + withNew, {
  36. testSuccessOnResolve: function(t) {
  37. var called = 0
  38. createDeferred().resolve().done(function() {
  39. t.assertEqual(0, called++)
  40. t.assertEqual("resolved", this.state(), "Deferred is resolved (state)")
  41. }).fail(function() {
  42. t.fail("Error on resolve")
  43. }).always(function() {
  44. t.assertEqual(1, called++)
  45. })
  46. t.assertEqual(2, called, "Success and Always handlers called")
  47. },
  48. testErrorOnReject: function(t) {
  49. var called = 0
  50. createDeferred().reject().done(function() {
  51. t.fail("Success on reject")
  52. }).fail(function() {
  53. t.assertEqual(0, called++)
  54. t.assertEqual( "rejected", this.state(), "Deferred is rejected (state)" )
  55. }).always(function() {
  56. t.assertEqual(1, called++)
  57. })
  58. t.assertEqual(2, called, "Error and Always handlers called")
  59. },
  60. testDeferredFnContextIsArg1: function(t) {
  61. var called
  62. createDeferred(function(defer) {
  63. called = true
  64. t.assertEqual(defer, this, "Defer passed as this & first argument")
  65. })
  66. t.assertTrue(called, "Deferred function was called")
  67. },
  68. testDoneWithResolvedValue: function(t) {
  69. var called
  70. createDeferred(function(defer) {
  71. defer.resolve("done")
  72. }).done(function(value) {
  73. called = true
  74. t.assertEqual("done", value, "Done() received resolved value")
  75. })
  76. t.assertTrue(called, "Deferred function was called")
  77. },
  78. testNoDoneOnReject: function(t) {
  79. var called = false
  80. createDeferred(function(defer) {
  81. defer.reject("done")
  82. }).done(function(value) {
  83. called = true
  84. t.fail("done() should not be called on error")
  85. })
  86. t.assertFalse(called, "Deferred function was called")
  87. },
  88. testIsChainable: function(t) {
  89. var deferred = createDeferred(), each = $.each
  90. // Ensure that each of the following methods are chainable
  91. each(promiseFns, function(_, method) {
  92. var object = {
  93. m: deferred[method]
  94. }
  95. t.assertEqual(object, object.m(), method + " is chainable" )
  96. })
  97. },
  98. testFilteringDone: function(t) {
  99. var value1, value2, value3,
  100. defer = createDeferred(),
  101. piped = defer.then(function(a, b) {
  102. return a * b
  103. })
  104. piped.done(function(result) { value3 = result })
  105. defer.done(function(a, b) { value1 = a, value2 = b }).resolve(2, 3)
  106. t.assertEqual(2, value1, "first resolve value ok")
  107. t.assertEqual(3, value2, "second resolve value ok")
  108. t.assertEqual(6, value3, "result of filter ok")
  109. createDeferred().reject().then(function() { t.fail("then should not be called on reject") })
  110. createDeferred().resolve().then($.noop).done(function(value) {
  111. t.assertEqual(undefined, value, "then done callback can return undefined/null")
  112. })
  113. },
  114. testSamePromise: function(t) {
  115. createDeferred(function(defer) {
  116. var promise = defer.promise()
  117. t.assertEqual(promise, defer.promise(), "promise is always the same")
  118. })
  119. },
  120. testExtendNonObject: function(t) {
  121. createDeferred(function(defer) {
  122. var func = function() {},
  123. funcPromise = defer.promise(func)
  124. t.assertEqual(func, funcPromise, "non objects get extended")
  125. })
  126. },
  127. testPromiseOnlyFns: function(t) {
  128. createDeferred(function(defer) {
  129. var promise = defer.promise()
  130. $.each(promise, function(key) {
  131. var type = typeof promise[key]
  132. t.assertEqual("function", type, key + " is a function (" + type + ")")
  133. t.assertTrue(deferredFns.indexOf(key) > -1, key + "() is a promise function")
  134. })
  135. })
  136. },
  137. testExtendObjectWithPromiseFns: function(t) {
  138. createDeferred(function(defer) {
  139. var promise = defer.promise(),
  140. func = function() {},
  141. funcPromise = defer.promise(func),
  142. fns = 0
  143. $.each(promise, function(key) {
  144. ++fns
  145. t.assertEqual(promise[key], func[key], key + " is the same")
  146. })
  147. t.assertEqual(deferredFns.length, fns, "should have all of the Deferred functions")
  148. })
  149. },
  150. testFilteringReject: function(t) {
  151. var value1, value2, value3,
  152. defer = createDeferred(),
  153. piped = defer.then(null, function(a, b) {
  154. return a * b
  155. })
  156. piped.fail(function(result) { value3 = result })
  157. defer.fail(function( a, b ) { value1 = a, value2 = b })
  158. defer.reject( 2, 3 )
  159. t.assertEqual(2, value1, "first reject value ok")
  160. t.assertEqual(3, value2, "second reject value ok")
  161. t.assertEqual(6, value3, "result of filter ok")
  162. createDeferred().resolve().then(null, function() {
  163. t.fail("then should not be called on resolve")
  164. })
  165. createDeferred().reject().then(null, $.noop).fail(function(value) {
  166. t.assertEqual(undefined, value, "then fail callback can return undefined/null")
  167. })
  168. },
  169. testFilteringProgress: function(t) {
  170. var value1, value2, value3,
  171. defer = createDeferred(),
  172. piped = defer.then(null, null, function(a, b) {
  173. return a * b
  174. })
  175. piped.progress(function(result) { value3 = result })
  176. defer.progress(function(a, b) { value1 = a, value2 = b })
  177. defer.notify( 2, 3 )
  178. t.assertEqual(2, value1, "first progress value ok")
  179. t.assertEqual(3, value2, "second progress value ok")
  180. t.assertEqual(6, value3, "result of filter ok")
  181. },
  182. testThenDeferredDone: function(t) {
  183. var value1, value2, value3,
  184. defer = createDeferred(),
  185. piped = defer.then(function(a, b) {
  186. return createDeferred(function(defer) {
  187. defer.reject(a * b)
  188. })
  189. })
  190. piped.fail(function(result) { value3 = result })
  191. defer.done(function(a, b) { value1 = a, value2 = b })
  192. defer.resolve(2, 3)
  193. t.assertEqual(2, value1, "first resolve value ok")
  194. t.assertEqual(3, value2, "second resolve value ok")
  195. t.assertEqual(6, value3, "result of filter ok")
  196. },
  197. testThenDeferredFail: function(t) {
  198. var value1, value2, value3,
  199. defer = createDeferred(),
  200. piped = defer.then(null, function(a, b) {
  201. return createDeferred(function(defer) {
  202. defer.resolve(a * b)
  203. })
  204. })
  205. piped.done(function(result) { value3 = result })
  206. defer.fail(function(a, b) { value1 = a, value2 = b })
  207. defer.reject(2, 3)
  208. t.assertEqual(2, value1, "first reject value ok")
  209. t.assertEqual(3, value2, "second reject value ok")
  210. t.assertEqual(6, value3, "result of filter ok")
  211. },
  212. testThenDeferredProgress: function(t) {
  213. var value1, value2, value3,
  214. defer = createDeferred(),
  215. piped = defer.then(null, null, function(a, b) {
  216. return createDeferred(function(defer) {
  217. defer.resolve( a * b )
  218. })
  219. })
  220. piped.done(function(result) { value3 = result })
  221. defer.progress(function(a, b) { value1 = a, value2 = b })
  222. defer.notify(2, 3)
  223. t.assertEqual(2, value1, "first progress value ok")
  224. t.assertEqual(3, value2, "second progress value ok")
  225. t.assertEqual(6, value3, "result of filter ok")
  226. },
  227. testThenWithContext: function(t) {
  228. var defer, piped, defer2, piped2, context = {}
  229. createDeferred().resolveWith(context, [2]).then(function(value) {
  230. return value * 3
  231. }).done(function(value) {
  232. t.assertEqual(context, this, "custom context correctly propagated")
  233. t.assertEqual(6, value, "proper value received")
  234. })
  235. createDeferred().resolve().then(function() {
  236. return createDeferred().resolveWith(context)
  237. }).done(function() {
  238. t.assertEqual(context, this, "custom context of returned deferred correctly propagated")
  239. })
  240. defer = createDeferred()
  241. piped = defer.then(function(value) {
  242. return value * 3
  243. })
  244. defer.resolve( 2 )
  245. piped.done(function(value) {
  246. t.assertEqual(piped, this, "default context gets updated to latest promise in the chain")
  247. t.assertEqual(6, value, "proper value received")
  248. })
  249. defer2 = createDeferred()
  250. piped2 = defer2.then()
  251. defer2.resolve(2)
  252. piped2.done(function(value) {
  253. t.assertEqual(piped2, this, "default context gets updated to latest promise in the chain (without passing function)")
  254. t.assertEqual(2, value, "proper value received (without passing function)")
  255. })
  256. },
  257. testWhenValueCreatesPromise: function(t) {
  258. $.each({
  259. "an empty string": "",
  260. "a non-empty string": "some string",
  261. "zero": 0,
  262. "a number other than zero": 1,
  263. "true": true,
  264. "false": false,
  265. "null": null,
  266. "undefined": undefined,
  267. "a plain object": {},
  268. "an array": [ 1, 2, 3 ]
  269. }, function(message, value) {
  270. t.assertTrue(
  271. $.isFunction($.when(value).done(function(resolveValue) {
  272. t.assertEqual(window, this, "Context is the global object with " + message)
  273. t.assertEqual(value, resolveValue, "Test the promise was resolved with " + message)
  274. }).promise), "Test " + message + " triggers the creation of a new Promise")
  275. })
  276. },
  277. testWhenNoValueCreatesPromise: function(t) {
  278. t.assertTrue(
  279. $.isFunction($.when().done(function(resolveValue) {
  280. t.assertEqual(window, this, "Context is the global object")
  281. t.assertEqual(undefined, resolveValue, "Test the promise was resolved with no parameter")
  282. }).promise), "Test calling when with no parameter triggers the creation of a new Promise")
  283. },
  284. testWhenPropagatesContext: function(t) {
  285. var context = {}, called = false
  286. $.when(createDeferred().resolveWith(context)).done(function() {
  287. called = true
  288. t.assertEqual(context, this, "when( promise ) propagates context")
  289. })
  290. t.assertTrue(called, "called done() after resolveWith")
  291. },
  292. testWhenDoneOnlyPromise: function(t) {
  293. var cache
  294. $.each([1,2,3], function(_, i) {
  295. $.when(cache || createDeferred(function() {
  296. this.resolve(i)
  297. })).done(function(value) {
  298. t.assertEqual(1, value, "Function executed" + (i > 1 ? " only once" : ""))
  299. cache = value
  300. })
  301. })
  302. },
  303. testWhenJoined: function(t) {
  304. var deferreds = {
  305. value: 1,
  306. success: createDeferred().resolve(1),
  307. error: createDeferred().reject(0),
  308. futureSuccess: createDeferred().notify(true),
  309. futureError: createDeferred().notify(true),
  310. notify: createDeferred().notify(true)
  311. },
  312. willSucceed = {
  313. value: true,
  314. success: true,
  315. futureSuccess: true
  316. },
  317. willError = {
  318. error: true,
  319. futureError: true
  320. },
  321. willNotify = {
  322. futureSuccess: true,
  323. futureError: true,
  324. notify: true
  325. }
  326. $.each(deferreds, function(id1, defer1) {
  327. $.each(deferreds, function(id2, defer2) {
  328. var shouldResolve = willSucceed[id1] && willSucceed[id2],
  329. shouldError = willError[id1] || willError[id2],
  330. shouldNotify = willNotify[id1] || willNotify[id2],
  331. expected = shouldResolve ? [1, 1] : [0, undefined],
  332. expectedNotify = shouldNotify && [willNotify[id1], willNotify[id2]],
  333. code = id1 + '/' + id2,
  334. context1 = defer1 && $.isFunction(defer1.promise) ? defer1.promise() : undefined,
  335. context2 = defer2 && $.isFunction(defer2.promise) ? defer2.promise() : undefined
  336. $.when(defer1, defer2).done(function(a, b) {
  337. if (shouldResolve) {
  338. t.assertEqual(expected[0], a, code + " => resolve" )
  339. t.assertEqual(expected[1], b, code + " => resolve" )
  340. t.assertIdentical(context1, this[0], code + " => first context OK")
  341. t.assertIdentical(context2, this[1], code + " => second context OK")
  342. } else {
  343. t.fail(code + " => resolve")
  344. }
  345. }).fail(function(a, b) {
  346. if (shouldError) {
  347. t.assertIdentical(expected[0], a, code + " => reject")
  348. t.assertIdentical(expected[1], b, code + " => reject")
  349. } else {
  350. t.fail(code + " => reject")
  351. }
  352. }).progress(function(a, b) {
  353. t.assertIdentical( expectedNotify[0], a, code + " => progress")
  354. t.assertIdentical( expectedNotify[1], b, code + " => progress")
  355. t.assertIdentical(expectedNotify[0] ? context1 : undefined, this[0], code + " => first context OK")
  356. t.assertIdentical(expectedNotify[1] ? context2 : undefined, this[1], code + " => second context OK")
  357. })
  358. })
  359. })
  360. deferreds.futureSuccess.resolve(1)
  361. deferreds.futureError.reject(0)
  362. }
  363. })
  364. })
  365. })()
  366. </script>
  367. </body>
  368. </html>