Guest User

Untitled

a guest
Oct 20th, 2018
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.39 KB | None | 0 0
  1. # The second way is recommended, which is flexible, and also work for non jQuery ajax library.
  2.  
  3.  
  4. # Setup sinon sandbox
  5.  
  6. beforeEach ->
  7. @sinon = sinon.sandbox.create()
  8.  
  9. afterEach ->
  10. @sinon.restore()
  11.  
  12. jasmine.Spec::spy = (args...) ->
  13. @sinon.spy args...
  14.  
  15. jasmine.Spec::stub = (args...) ->
  16. @sinon.stub args...
  17.  
  18. # no mock, tests the real code
  19.  
  20. # ==================================================
  21. # 1. Stub out ajax using Deferred #
  22. #
  23. # Use deferred object to trigger callback, so testing is synchronous. The
  24. # resolve or reject are invoked, all requests are executed and returned.
  25. #
  26. # It also can be applied to any other library based on $.Deferred
  27. jasmine.Spec::stubAjax = (object = $) ->
  28. @stub object, 'ajax', (options) ->
  29. # returns a new Deferred object so it supports all deferred methods, also invokes the callbacks in options
  30. dfd = $.Deferred()
  31. dfd.done(options.done) if options.done
  32. dfd.done(options.success) if options.success
  33. dfd.fail(options.fail) if options.fail
  34. dfd.fail(options.error) if options.error
  35. dfd.always(options.always) if options.always
  36. dfd.always(options.complete) if options.complete
  37. dfd.success = dfd.done
  38. dfd.error = dfd.fail
  39. dfd.complete = dfd.always
  40.  
  41. dfd
  42.  
  43. describe 'Stup Ajax', ->
  44. beforeEach ->
  45. @ajaxStub = @stubAjax()
  46. @ajax = $.ajax
  47. url: '/test'
  48. success: @success = @spy()
  49. error: @error = @spy()
  50. complete: @complete = @spy()
  51.  
  52. it 'tests options', ->
  53. # accept options can be checked in stub
  54. expect(@ajaxStub.args[0][0].url).toEqual('/test')
  55.  
  56. it 'tests success', ->
  57. # resolve with success arguments, should match the arguments for ajax success callback
  58. @ajax.resolve(name: 'abc')
  59. expect(@success.callCount).toBe(1)
  60. expect(@success.args[0]).toEqual([name: 'abc'])
  61.  
  62. # or
  63. spy = @spy()
  64. @ajax.done(spy)
  65. expect(spy.callCount).toBe(1)
  66. expect(spy.args[0]).toEqual([name: 'abc'])
  67.  
  68. it 'tests failure', ->
  69. # to test failure, should match the arguments for ajax error callback
  70. @ajax.reject()
  71.  
  72. expect(@error.callCount).toBe(1)
  73. expect(@error.args[0]).toEqual([])
  74.  
  75. # or
  76. spy = @spy()
  77. @ajax.fail(spy)
  78. expect(spy.callCount).toBe(1)
  79. expect(spy.args[0]).toEqual([])
  80.  
  81. it 'tests complete', ->
  82. # both resolve and reject will trigger complete/always
  83. @ajax.resolve()
  84. # or ajax.reject()
  85.  
  86. expect(@complete.callCount).toBe(1)
  87. expect(@complete.args[0]).toEqual([])
  88.  
  89. # ==================================================
  90. # 2. Stub out jqxhr using sinon server (RECOMMENDED)
  91. #
  92. # Use respond to trigger callback, so testing is synchronous.
  93. #
  94. # This way you can get real AJAX response.
  95. #
  96. # It is also works for any ajax libraries.
  97.  
  98. # setup sinon server sandbox
  99. afterEach ->
  100. @server?.restore()
  101.  
  102. jasmine.Spec::fakeServer = ->
  103. @server ?= sinon.fakeServer.create()
  104.  
  105. # ease respondWith
  106. # The matching is processed in FIFO sequence, to add a catch all response, but that can be overrided
  107. # later, set urlOrRegExp to null
  108. jasmine.Spec::respondWith = (urlOrRegExp, options = {}) ->
  109. type = options.type
  110. code = options.code ? 200
  111. headers = options.headers ? {}
  112. data = options.data ? ''
  113.  
  114. contentType = options.contentType ? headers['Content-Type']
  115. contentType = 'application/x-www-form-urlencoded' if contentType is 'form'
  116. headers['Content-Type'] = contentType if contentType
  117.  
  118. unless type of data is 'string'
  119. contentType ?= 'application/json'
  120. headers['Content-Type'] = contentType
  121. if /json$/.test(contentType)
  122. data = JSON.stringify(data)
  123. else if /x-www-form-urlencoded$/.test(contentType)
  124. data = $.param(data)
  125.  
  126. if urlOrRegExp
  127. if type
  128. @fakeServer().respondWith(type, urlOrRegExp, [code, headers, data])
  129. else
  130. @fakeServer().respondWith(urlOrRegExp, [code, headers, data])
  131. else
  132. # if urlOrRegExp is falsy, use as default response, a.k.a, when no response matches, returns this
  133. @fakeServer().respondWith([code, headers, data])
  134.  
  135. # All ajax requests are returned after call respond
  136. jasmine.Spec::respond = -> @server?.respond()
  137.  
  138. describe 'Stup jqxhr', ->
  139. beforeEach ->
  140. @fakeServer()
  141. @ajaxSpy = @spy($, 'ajax')
  142.  
  143. @ajax = $.ajax
  144. url: '/test'
  145. success: @success = @spy()
  146. error: @error = @spy()
  147. complete: @complete = @spy()
  148.  
  149. it 'tests options', ->
  150. @respond()
  151. # accept options can be checked in spy
  152. expect(@ajaxSpy.args[0][0].url).toEqual('/test')
  153.  
  154. it 'tests success', ->
  155. # simulate a server response
  156. @respondWith '/test',
  157. data:
  158. name: 'abc'
  159.  
  160. # use respond to synchronize
  161. @respond()
  162.  
  163. expect(@success.callCount).toBe(1)
  164. expect(@success.args[0][0]).toEqual(name: 'abc')
  165.  
  166. # or
  167. spy = @spy()
  168. @ajax.done(spy)
  169. expect(spy.callCount).toBe(1)
  170. expect(spy.args[0][0]).toEqual(name: 'abc')
  171.  
  172. it 'tests failure', ->
  173. # to test failure, should match the arguments for ajax error callback
  174. @respondWith '/test',
  175. code: 500
  176. data:
  177. error: 'abc'
  178. @respond()
  179.  
  180. expect(@error.callCount).toBe(1)
  181. expect(@error.args[0][0].status).toBe(500)
  182. expect(@error.args[0][0].responseText).toEqual('{"error":"abc"}')
  183.  
  184. # or
  185. spy = @spy()
  186. @ajax.fail(spy)
  187. expect(spy.callCount).toBe(1)
  188. expect(spy.args[0][0].status).toBe(500)
  189.  
  190. it 'tests complete', ->
  191. # both failure and success trigger complete/always
  192. @respondWith '/test',
  193. code: 500
  194. data:
  195. error: 'abc'
  196. @respond()
  197.  
  198. expect(@complete.callCount).toBe(1)
  199.  
  200. # ==================================================
  201. # 3. Really want to test with real server?
  202. #
  203. # Since ajax requests are asynchronuse, use Deferred pipe and runs/waitsFor to
  204. # synchronize testing.
  205. #
  206. # This is also work for any asynchronize library that written based on Deferred.
  207. #
  208. # Setup a resolved deferred as pipe start point
  209. beforeEach ->
  210. @pipePromise = $.Deferred().resolve().promise()
  211.  
  212. # See jQuery Deferred.pipe
  213. #
  214. # Deferred status is filerted.
  215. jasmine.Spec::pipe = (success, error) ->
  216. # wrap callbacks with current context
  217. context = @
  218. if success
  219. successWrapper = -> success.call(context, arguments...)
  220. if error
  221. errorWrapper = -> error.call(context, arguments...)
  222.  
  223. # setup args to ease test
  224. chained = @pipePromise.pipe(successWrapper, errorWrapper)
  225. chained.always (args...) -> chained.args = args
  226. @pipePromise = chained
  227.  
  228. jasmine.Spec::waitsForPipe = (message = 'Waits for Spec pipe', timeout = 5000) ->
  229. waitsFor ->
  230. @pipePromise.state() in ['rejected', 'resolved']
  231. , message, timeout
  232.  
  233. jasmine.Spec::expectPipeResolved = ->
  234. runs ->
  235. expect(@pipePromise.state()).toEqual('resolved')
  236.  
  237. jasmine.Spec::expectPipeResolvedWith = (args...) ->
  238. runs ->
  239. expect(@pipePromise.state()).toEqual('resolved')
  240. expect(@pipePromise.args).toEqual(args)
  241.  
  242. jasmine.Spec::expectPipeRejected = ->
  243. runs ->
  244. expect(@pipePromise.state()).toEqual('rejected')
  245.  
  246. jasmine.Spec::expectPipeRejectedWith = (args...) ->
  247. runs ->
  248. expect(@pipePromise.state()).toEqual('rejected')
  249. expect(@pipePromise.args).toEqual(args)
  250.  
  251. describe 'Synchronize real ajax', ->
  252. it 'tests 404', ->
  253. @pipe -> $.ajax '/not_found_page.html'
  254.  
  255. # must wait for all deferred in pipe finished
  256. @waitsForPipe()
  257.  
  258. @expectPipeRejected()
  259.  
  260. # code that executed after pipe is finished must be contained in runs block
  261. runs ->
  262. expect(@pipePromise.args[0].status).toBe(404)
  263.  
  264. it 'tests success', ->
  265. @pipe -> $.ajax './'
  266.  
  267. @waitsForPipe()
  268.  
  269. @expectPipeResolved()
  270.  
  271. # code that executed after pipe is finished must be contained in runs block
  272. runs ->
  273. expect(@pipePromise.args[2].status).toBe(200)
  274.  
  275. it 'multiple requests', ->
  276. step1 = @pipe -> $.ajax './'
  277. # execute when former request is success
  278. @pipe -> $.ajax '/not_found_page.html'
  279.  
  280. @waitsForPipe()
  281.  
  282. @expectPipeRejected()
  283.  
  284. # code that executed after pipe is finished must be contained in runs block
  285. runs ->
  286. expect(step1.state()).toBe('resolved')
  287. expect(step1.args[0]).toContain('<html')
  288. expect(step1.args[2].status).toBe(200)
  289.  
  290. expect(@pipePromise.args[0].status).toBe(404)
  291.  
  292. it 'pipe error', ->
  293. step1 = @pipe -> $.ajax '/not_found_page.html'
  294. # to pipe when former request is failed, use the second argument
  295. @pipe null, -> $.ajax './'
  296.  
  297. @waitsForPipe()
  298.  
  299. @expectPipeResolved()
  300.  
  301. # code that executed after pipe is finished must be contained in runs block
  302. runs ->
  303. expect(step1.state()).toBe('rejected')
  304. expect(step1.args[0].status).toBe(404)
  305.  
  306. expect(@pipePromise.args[2].status).toBe(200)
Add Comment
Please, Sign In to add comment