unpoly-rails 0.37.0 → 0.50.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -25
  3. data/LICENSE +1 -1
  4. data/README_RAILS.md +4 -2
  5. data/Rakefile +6 -1
  6. data/dist/unpoly.js +3192 -2198
  7. data/dist/unpoly.min.js +4 -3
  8. data/lib/assets/javascripts/unpoly/browser.coffee +51 -63
  9. data/lib/assets/javascripts/unpoly/bus.coffee +58 -33
  10. data/lib/assets/javascripts/unpoly/classes/cache.coffee +117 -0
  11. data/lib/assets/javascripts/unpoly/{dom → classes}/extract_cascade.coffee +3 -3
  12. data/lib/assets/javascripts/unpoly/{dom → classes}/extract_plan.coffee +1 -1
  13. data/lib/assets/javascripts/unpoly/classes/field_observer.coffee +57 -0
  14. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +52 -0
  15. data/lib/assets/javascripts/unpoly/classes/motion_tracker.coffee +95 -0
  16. data/lib/assets/javascripts/unpoly/classes/record.coffee +16 -0
  17. data/lib/assets/javascripts/unpoly/classes/request.coffee +228 -0
  18. data/lib/assets/javascripts/unpoly/classes/response.coffee +138 -0
  19. data/lib/assets/javascripts/unpoly/dom.coffee +151 -142
  20. data/lib/assets/javascripts/unpoly/feedback.coffee +67 -38
  21. data/lib/assets/javascripts/unpoly/form.coffee +156 -139
  22. data/lib/assets/javascripts/unpoly/history.coffee +22 -19
  23. data/lib/assets/javascripts/unpoly/layout.coffee +108 -90
  24. data/lib/assets/javascripts/unpoly/link.coffee +159 -158
  25. data/lib/assets/javascripts/unpoly/log.coffee +5 -5
  26. data/lib/assets/javascripts/unpoly/modal.coffee +93 -81
  27. data/lib/assets/javascripts/unpoly/motion.coffee +291 -250
  28. data/lib/assets/javascripts/unpoly/popup.coffee +67 -53
  29. data/lib/assets/javascripts/unpoly/protocol.coffee +67 -16
  30. data/lib/assets/javascripts/unpoly/proxy.coffee +282 -211
  31. data/lib/assets/javascripts/unpoly/rails.coffee +3 -14
  32. data/lib/assets/javascripts/unpoly/syntax.coffee +54 -49
  33. data/lib/assets/javascripts/unpoly/tooltip.coffee +18 -25
  34. data/lib/assets/javascripts/unpoly/util.coffee +236 -477
  35. data/lib/assets/javascripts/unpoly.coffee +1 -1
  36. data/lib/unpoly/rails/inspector.rb +67 -22
  37. data/lib/unpoly/rails/version.rb +1 -1
  38. data/package.json +1 -1
  39. data/spec_app/Gemfile.lock +13 -13
  40. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  41. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -1
  42. data/spec_app/app/assets/stylesheets/jasmine_specs.sass +10 -0
  43. data/spec_app/app/controllers/binding_test_controller.rb +19 -2
  44. data/spec_app/app/controllers/method_test_controller.rb +16 -0
  45. data/spec_app/app/views/layouts/jasmine_rails/spec_runner.html.erb +20 -0
  46. data/spec_app/app/views/method_test/form_target.erb +17 -0
  47. data/spec_app/app/views/method_test/page1.erb +11 -0
  48. data/spec_app/app/views/method_test/page2.erb +6 -0
  49. data/spec_app/app/views/pages/start.erb +33 -19
  50. data/spec_app/config/initializers/assets.rb +5 -0
  51. data/spec_app/config/routes.rb +3 -0
  52. data/spec_app/spec/controllers/binding_test_controller_spec.rb +82 -27
  53. data/spec_app/spec/javascripts/helpers/agent_detector.coffee +17 -0
  54. data/spec_app/spec/javascripts/helpers/async_sequence.js.coffee +102 -0
  55. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -1
  56. data/spec_app/spec/javascripts/helpers/mock_ajax.js.coffee +5 -2
  57. data/spec_app/spec/javascripts/helpers/promise_state.js +18 -0
  58. data/spec_app/spec/javascripts/helpers/protect_jasmine_runner.coffee +9 -0
  59. data/spec_app/spec/javascripts/helpers/reset_history.js.coffee +22 -0
  60. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +11 -3
  61. data/spec_app/spec/javascripts/helpers/show_lib_versions.coffee +10 -0
  62. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +5 -0
  63. data/spec_app/spec/javascripts/helpers/to_match_url.coffee +13 -0
  64. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +13 -6
  65. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +92 -33
  66. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +64 -15
  67. data/spec_app/spec/javascripts/up/classes/.keep +0 -0
  68. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +1 -0
  69. data/spec_app/spec/javascripts/up/dom_spec.js.coffee +759 -551
  70. data/spec_app/spec/javascripts/up/feedback_spec.js.coffee +155 -82
  71. data/spec_app/spec/javascripts/up/form_spec.js.coffee +490 -349
  72. data/spec_app/spec/javascripts/up/history_spec.js.coffee +226 -179
  73. data/spec_app/spec/javascripts/up/layout_spec.js.coffee +253 -185
  74. data/spec_app/spec/javascripts/up/link_spec.js.coffee +416 -270
  75. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +459 -330
  76. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +198 -153
  77. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +9 -0
  78. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +240 -175
  79. data/spec_app/spec/javascripts/up/protocol_spec.js.coffee +38 -0
  80. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +777 -303
  81. data/spec_app/spec/javascripts/up/rails_spec.js.coffee +24 -8
  82. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +40 -23
  83. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +80 -66
  84. data/spec_app/spec/javascripts/up/util_spec.js.coffee +227 -201
  85. data/spec_app/vendor/asset-libs/es6-promise-4.1.6/es6-promise.auto.js +1159 -0
  86. metadata +30 -7
  87. data/spec_app/spec/javascripts/helpers/reset_path.js.coffee +0 -7
  88. data/spec_app/spec/javascripts/helpers/to_equal_url.coffee +0 -11
@@ -8,41 +8,45 @@ describe 'up.link', ->
8
8
 
9
9
  describeCapability 'canPushState', ->
10
10
 
11
- it 'loads the given link via AJAX and replaces the response in the given target', (done) ->
11
+ it 'loads the given link via AJAX and replaces the response in the given target', asyncSpec (next) ->
12
12
  affix('.before').text('old-before')
13
13
  affix('.middle').text('old-middle')
14
14
  affix('.after').text('old-after')
15
15
  $link = affix('a[href="/path"][up-target=".middle"]')
16
16
 
17
- promise = up.follow($link)
18
-
19
- @respondWith """
20
- <div class="before">new-before</div>
21
- <div class="middle">new-middle</div>
22
- <div class="after">new-after</div>
23
- """
24
-
25
- promise.then ->
17
+ up.follow($link)
18
+
19
+ next =>
20
+ @respondWith """
21
+ <div class="before">new-before</div>
22
+ <div class="middle">new-middle</div>
23
+ <div class="after">new-after</div>
24
+ """
25
+
26
+ next =>
26
27
  expect($('.before')).toHaveText('old-before')
27
28
  expect($('.middle')).toHaveText('new-middle')
28
29
  expect($('.after')).toHaveText('old-after')
29
- done()
30
30
 
31
- it 'uses the method from a data-method attribute', ->
31
+ it 'uses the method from a data-method attribute', asyncSpec (next) ->
32
32
  $link = affix('a[href="/path"][data-method="PUT"]')
33
33
  up.follow($link)
34
- request = @lastRequest()
35
- expect(request).toHaveRequestMethod('PUT')
36
34
 
37
- it 'allows to refer to the link itself as "&" in the CSS selector', ->
35
+ next =>
36
+ request = @lastRequest()
37
+ expect(request).toHaveRequestMethod('PUT')
38
+
39
+ it 'allows to refer to the link itself as "&" in the CSS selector', asyncSpec (next) ->
38
40
  $container = affix('div')
39
41
  $link1 = $('<a id="first" href="/path" up-target="&">first-link</a>').appendTo($container)
40
42
  $link2 = $('<a id="second" href="/path" up-target="&">second-link</a>').appendTo($container)
41
43
  up.follow($link2)
42
- @respondWith '<div id="second">second-div</div>'
43
- expect($container.text()).toBe('first-linksecond-div')
44
44
 
45
- it 'adds history entries and allows the user to use the back- and forward-buttons', (done) ->
45
+ next => @respondWith '<div id="second">second-div</div>'
46
+ next => expect($container.text()).toBe('first-linksecond-div')
47
+
48
+ it 'adds history entries and allows the user to use the back- and forward-buttons', asyncSpec (next) ->
49
+ up.history.config.enabled = true
46
50
 
47
51
  waitForBrowser = 70
48
52
 
@@ -58,10 +62,10 @@ describe 'up.link', ->
58
62
  responseText: "<div class='container'><div class='target'>#{html}</div></div>"
59
63
  responseHeaders: { 'X-Up-Title': title }
60
64
 
61
- followAndRespond = ($link, html, title) ->
62
- promise = up.follow($link)
63
- respondWith(html, title)
64
- promise
65
+ # followAndRespond = ($link, html, title) ->
66
+ # promise = up.follow($link)
67
+ # respondWith(html, title)
68
+ # promise
65
69
 
66
70
  $link1 = affix('a[href="/one"][up-target=".target"]')
67
71
  $link2 = affix('a[href="/two"][up-target=".target"]')
@@ -69,45 +73,66 @@ describe 'up.link', ->
69
73
  $container = affix('.container')
70
74
  $target = affix('.target').appendTo($container).text('original text')
71
75
 
72
- followAndRespond($link1, 'text from one', 'title from one').then =>
76
+ up.follow($link1)
77
+
78
+ next =>
79
+ respondWith('text from one', 'title from one')
80
+
81
+ next =>
73
82
  expect($('.target')).toHaveText('text from one')
74
83
  expect(location.pathname).toEqual('/one')
75
84
  expect(document.title).toEqual('title from one')
76
85
 
77
- followAndRespond($link2, 'text from two', 'title from two').then =>
78
- expect($('.target')).toHaveText('text from two')
79
- expect(location.pathname).toEqual('/two')
80
- expect(document.title).toEqual('title from two')
81
-
82
- followAndRespond($link3, 'text from three', 'title from three').then =>
83
- expect($('.target')).toHaveText('text from three')
84
- expect(location.pathname).toEqual('/three')
85
- expect(document.title).toEqual('title from three')
86
-
87
- history.back()
88
- u.setTimer waitForBrowser, ->
89
- respondWith('restored text from two', 'restored title from two')
90
- expect($('.target')).toHaveText('restored text from two')
91
- expect(location.pathname).toEqual('/two')
92
- expect(document.title).toEqual('restored title from two')
93
-
94
- history.back()
95
- u.setTimer waitForBrowser, ->
96
- respondWith('restored text from one', 'restored title from one')
97
- expect($('.target')).toHaveText('restored text from one')
98
- expect(location.pathname).toEqual('/one')
99
- expect(document.title).toEqual('restored title from one')
100
-
101
- history.forward()
102
- u.setTimer waitForBrowser, ->
103
- # Since the response is cached, we don't have to respond
104
- expect($('.target')).toHaveText('restored text from two', 'restored title from two')
105
- expect(location.pathname).toEqual('/two')
106
- expect(document.title).toEqual('restored title from two')
107
-
108
- done()
109
-
110
- it 'does not add additional history entries when linking to the current URL', (done) ->
86
+ up.follow($link2)
87
+
88
+ next =>
89
+ respondWith('text from two', 'title from two')
90
+
91
+ next =>
92
+ expect($('.target')).toHaveText('text from two')
93
+ expect(location.pathname).toEqual('/two')
94
+ expect(document.title).toEqual('title from two')
95
+
96
+ up.follow($link3)
97
+
98
+ next =>
99
+ respondWith('text from three', 'title from three')
100
+
101
+ next =>
102
+ expect($('.target')).toHaveText('text from three')
103
+ expect(location.pathname).toEqual('/three')
104
+ expect(document.title).toEqual('title from three')
105
+
106
+ history.back()
107
+
108
+ next.after waitForBrowser, =>
109
+ respondWith('restored text from two', 'restored title from two')
110
+
111
+ next =>
112
+ expect($('.target')).toHaveText('restored text from two')
113
+ expect(location.pathname).toEqual('/two')
114
+ expect(document.title).toEqual('restored title from two')
115
+
116
+ history.back()
117
+
118
+ next.after waitForBrowser, =>
119
+ respondWith('restored text from one', 'restored title from one')
120
+
121
+ next =>
122
+ expect($('.target')).toHaveText('restored text from one')
123
+ expect(location.pathname).toEqual('/one')
124
+ expect(document.title).toEqual('restored title from one')
125
+
126
+ history.forward()
127
+
128
+ next.after waitForBrowser, =>
129
+ # Since the response is cached, we don't have to respond
130
+ expect($('.target')).toHaveText('restored text from two', 'restored title from two')
131
+ expect(location.pathname).toEqual('/two')
132
+ expect(document.title).toEqual('restored title from two')
133
+
134
+ it 'does not add additional history entries when linking to the current URL', asyncSpec (next) ->
135
+ up.history.config.enabled = true
111
136
 
112
137
  # By default, up.history will replace the <body> tag when
113
138
  # the user presses the back-button. We reconfigure this
@@ -123,43 +148,58 @@ describe 'up.link', ->
123
148
  </div>
124
149
  """
125
150
 
126
- followAndRespond = ($link, text) =>
127
- promise = up.follow($link)
128
- respondWith(text)
129
- promise
130
-
131
151
  $link1 = affix('a[href="/one"][up-target=".target"]')
132
152
  $link2 = affix('a[href="/two"][up-target=".target"]')
133
153
  $container = affix('.container')
134
154
  $target = affix('.target').appendTo($container).text('original text')
135
155
 
136
- followAndRespond($link1, 'text from one').then =>
156
+ up.follow($link1)
157
+
158
+ next =>
159
+ respondWith('text from one')
160
+
161
+ next =>
137
162
  expect($('.target')).toHaveText('text from one')
138
163
  expect(location.pathname).toEqual('/one')
139
164
 
140
- followAndRespond($link2, 'text from two').then =>
141
- expect($('.target')).toHaveText('text from two')
142
- expect(location.pathname).toEqual('/two')
165
+ up.follow($link2)
143
166
 
144
- followAndRespond($link2, 'text from two').then =>
145
- expect($('.target')).toHaveText('text from two')
146
- expect(location.pathname).toEqual('/two')
167
+ next =>
168
+ respondWith('text from two')
147
169
 
148
- history.back()
149
- u.setTimer 50, ->
150
- respondWith('restored text from one')
151
- expect($('.target')).toHaveText('restored text from one')
152
- expect(location.pathname).toEqual('/one')
170
+ next =>
171
+ expect($('.target')).toHaveText('text from two')
172
+ expect(location.pathname).toEqual('/two')
153
173
 
154
- history.forward()
155
- u.setTimer 50, ->
156
- respondWith('restored text from two')
157
- expect($('.target')).toHaveText('restored text from two')
158
- expect(location.pathname).toEqual('/two')
174
+ up.follow($link2)
159
175
 
160
- done()
176
+ next =>
177
+ respondWith('text from two')
161
178
 
162
- it 'does adds additional history entries when linking to the current URL, but with a different hash', (done) ->
179
+ next =>
180
+ expect($('.target')).toHaveText('text from two')
181
+ expect(location.pathname).toEqual('/two')
182
+
183
+ history.back()
184
+
185
+ next.after 50, =>
186
+ respondWith('restored text from one')
187
+
188
+ next =>
189
+ expect($('.target')).toHaveText('restored text from one')
190
+ expect(location.pathname).toEqual('/one')
191
+
192
+ history.forward()
193
+
194
+ next.after 50, =>
195
+ respondWith('restored text from two')
196
+
197
+ next =>
198
+ expect($('.target')).toHaveText('restored text from two')
199
+ expect(location.pathname).toEqual('/two')
200
+
201
+ it 'does adds additional history entries when linking to the current URL, but with a different hash', asyncSpec (next) ->
202
+ up.history.config.enabled = true
163
203
 
164
204
  # By default, up.history will replace the <body> tag when
165
205
  # the user presses the back-button. We reconfigure this
@@ -175,50 +215,68 @@ describe 'up.link', ->
175
215
  </div>
176
216
  """
177
217
 
178
- followAndRespond = ($link, text) =>
179
- promise = up.follow($link)
180
- respondWith(text)
181
- promise
182
-
183
218
  $link1 = affix('a[href="/one"][up-target=".target"]')
184
219
  $link2 = affix('a[href="/two"][up-target=".target"]')
185
220
  $link2WithHash = affix('a[href="/two#hash"][up-target=".target"]')
186
221
  $container = affix('.container')
187
222
  $target = affix('.target').appendTo($container).text('original text')
188
223
 
189
- followAndRespond($link1, 'text from one').then =>
224
+ up.follow($link1)
225
+
226
+ next =>
227
+ respondWith('text from one')
228
+
229
+ next =>
190
230
  expect($('.target')).toHaveText('text from one')
191
231
  expect(location.pathname).toEqual('/one')
192
232
  expect(location.hash).toEqual('')
193
233
 
194
- followAndRespond($link2, 'text from two').then =>
195
- expect($('.target')).toHaveText('text from two')
196
- expect(location.pathname).toEqual('/two')
197
- expect(location.hash).toEqual('')
198
-
199
- followAndRespond($link2WithHash, 'text from two with hash').then =>
200
- expect($('.target')).toHaveText('text from two with hash')
201
- expect(location.pathname).toEqual('/two')
202
- expect(location.hash).toEqual('#hash')
203
-
204
- history.back()
205
- u.setTimer 50, ->
206
- respondWith('restored text from two')
207
- expect($('.target')).toHaveText('restored text from two')
208
- expect(location.pathname).toEqual('/two')
209
- expect(location.hash).toEqual('')
210
-
211
- history.forward()
212
- u.setTimer 50, ->
213
- respondWith('restored text from two with hash')
214
- expect($('.target')).toHaveText('restored text from two with hash')
215
- expect(location.pathname).toEqual('/two')
216
- expect(location.hash).toEqual('#hash')
217
- done()
234
+ up.follow($link2)
235
+
236
+ next =>
237
+ respondWith('text from two')
238
+
239
+ next =>
240
+ expect($('.target')).toHaveText('text from two')
241
+ expect(location.pathname).toEqual('/two')
242
+ expect(location.hash).toEqual('')
243
+
244
+ up.follow($link2WithHash)
245
+
246
+ next =>
247
+ respondWith('text from two with hash')
248
+
249
+ next =>
250
+ expect($('.target')).toHaveText('text from two with hash')
251
+ expect(location.pathname).toEqual('/two')
252
+ expect(location.hash).toEqual('#hash')
253
+
254
+ history.back()
255
+
256
+ next.after 50, =>
257
+ respondWith('restored text from two')
258
+
259
+ next =>
260
+ expect($('.target')).toHaveText('restored text from two')
261
+ expect(location.pathname).toEqual('/two')
262
+ expect(location.hash).toEqual('')
263
+
264
+ history.forward()
265
+
266
+ next.after 50, =>
267
+ respondWith('restored text from two with hash')
268
+
269
+ next =>
270
+ expect($('.target')).toHaveText('restored text from two with hash')
271
+ expect(location.pathname).toEqual('/two')
272
+ expect(location.hash).toEqual('#hash')
218
273
 
219
274
  describe 'with { restoreScroll: true } option', ->
220
275
 
221
- it 'does not reveal, but instead restores the scroll positions of all viewports around the target', ->
276
+ beforeEach ->
277
+ up.history.config.enabled = true
278
+
279
+ it 'does not reveal, but instead restores the scroll positions of all viewports around the target', asyncSpec (next) ->
222
280
 
223
281
  $viewport = affix('div[up-viewport] .element').css
224
282
  'height': '100px'
@@ -237,76 +295,94 @@ describe 'up.link', ->
237
295
  """
238
296
 
239
297
  up.replace('.element', '/foo')
240
- # Provide the content at /foo with a link to /bar in the HTML
241
- respond('/bar')
242
298
 
243
- $viewport.scrollTop(65)
299
+ next =>
300
+ # Provide the content at /foo with a link to /bar in the HTML
301
+ respond('/bar')
302
+
303
+ next =>
304
+ $viewport.scrollTop(65)
305
+
306
+ # Follow the link to /bar
307
+ followLink()
308
+
309
+ next =>
310
+ # Provide the content at /bar with a link back to /foo in the HTML
311
+ respond('/foo')
244
312
 
245
- # Follow the link to /bar
246
- followLink()
313
+ next =>
314
+ # Follow the link back to /foo, restoring the scroll position of 65px
315
+ followLink(restoreScroll: true)
316
+ # No need to respond because /foo has been cached before
247
317
 
248
- # Provide the content at /bar with a link back to /foo in the HTML
249
- respond('/foo')
318
+ next =>
319
+ expect($viewport.scrollTop()).toEqual(65)
250
320
 
251
- # Follow the link back to /foo, restoring the scroll position of 65px
252
- followLink(restoreScroll: true)
253
- # No need to respond because /foo has been cached before
321
+ describe "when the browser is already on the link's destination", ->
254
322
 
255
- expect($viewport.scrollTop()).toEqual(65)
323
+ it "doesn't make a request and reveals the target container"
256
324
 
257
- # describe "when the browser is already on the link's destination", ->
258
- #
259
- # it "doesn't make a request and reveals the target container"
260
- #
261
- # it "doesn't make a request and reveals the target of a #hash in the URL"
325
+ it "doesn't make a request and reveals the target of a #hash in the URL"
262
326
 
263
327
  describe 'with { confirm } option', ->
264
328
 
265
- it 'follows the link after the user OKs a confirmation dialog', ->
329
+ it 'follows the link after the user OKs a confirmation dialog', asyncSpec (next) ->
266
330
  spyOn(up, 'replace')
267
331
  spyOn(window, 'confirm').and.returnValue(true)
268
332
  $link = affix('a[href="/danger"][up-target=".middle"]')
269
333
  up.follow($link, confirm: 'Do you really want to go there?')
270
- expect(window.confirm).toHaveBeenCalledWith('Do you really want to go there?')
271
- expect(up.replace).toHaveBeenCalled()
272
334
 
273
- it 'does not follow the link if the user cancels the confirmation dialog', ->
335
+ next =>
336
+ expect(window.confirm).toHaveBeenCalledWith('Do you really want to go there?')
337
+ expect(up.replace).toHaveBeenCalled()
338
+
339
+ it 'does not follow the link if the user cancels the confirmation dialog', asyncSpec (next) ->
274
340
  spyOn(up, 'replace')
275
341
  spyOn(window, 'confirm').and.returnValue(false)
276
342
  $link = affix('a[href="/danger"][up-target=".middle"]')
277
343
  up.follow($link, confirm: 'Do you really want to go there?')
278
- expect(window.confirm).toHaveBeenCalledWith('Do you really want to go there?')
279
- expect(up.replace).not.toHaveBeenCalled()
280
344
 
281
- it 'does not show a confirmation dialog if the option is not a present string', ->
345
+ next =>
346
+ expect(window.confirm).toHaveBeenCalledWith('Do you really want to go there?')
347
+ expect(up.replace).not.toHaveBeenCalled()
348
+
349
+ it 'does not show a confirmation dialog if the option is not a present string', asyncSpec (next) ->
282
350
  spyOn(up, 'replace')
283
351
  spyOn(window, 'confirm')
284
352
  $link = affix('a[href="/danger"][up-target=".middle"]')
285
353
  up.follow($link, confirm: '')
286
- expect(window.confirm).not.toHaveBeenCalled()
287
- expect(up.replace).toHaveBeenCalled()
288
354
 
289
- it 'does not show a confirmation dialog when preloading', ->
355
+ next =>
356
+ expect(window.confirm).not.toHaveBeenCalled()
357
+ expect(up.replace).toHaveBeenCalled()
358
+
359
+ it 'does not show a confirmation dialog when preloading', asyncSpec (next) ->
290
360
  spyOn(up, 'replace')
291
361
  spyOn(window, 'confirm')
292
362
  $link = affix('a[href="/danger"][up-target=".middle"]')
293
363
  up.follow($link, confirm: 'Are you sure?', preload: true)
294
- expect(window.confirm).not.toHaveBeenCalled()
295
- expect(up.replace).toHaveBeenCalled()
364
+
365
+ next =>
366
+ expect(window.confirm).not.toHaveBeenCalled()
367
+ expect(up.replace).toHaveBeenCalled()
296
368
 
297
369
  describeFallback 'canPushState', ->
298
-
299
- it 'follows the given link', ->
370
+
371
+ it 'follows the given link', asyncSpec (next) ->
300
372
  $link = affix('a[href="/path"]')
301
- spyOn(up.browser, 'loadPage')
373
+ spyOn(up.browser, 'navigate')
302
374
  up.follow($link)
303
- expect(up.browser.loadPage).toHaveBeenCalledWith('/path', jasmine.anything())
304
375
 
305
- it 'uses the method from a data-method attribute', ->
376
+ next =>
377
+ expect(up.browser.navigate).toHaveBeenCalledWith('/path', jasmine.anything())
378
+
379
+ it 'uses the method from a data-method attribute', asyncSpec (next) ->
306
380
  $link = affix('a[href="/path"][data-method="PUT"]')
307
- spyOn(up.browser, 'loadPage')
381
+ spyOn(up.browser, 'navigate')
308
382
  up.follow($link)
309
- expect(up.browser.loadPage).toHaveBeenCalledWith('/path', { method: 'PUT' })
383
+
384
+ next =>
385
+ expect(up.browser.navigate).toHaveBeenCalledWith('/path', { method: 'PUT' })
310
386
 
311
387
  describe 'up.link.makeFollowable', ->
312
388
 
@@ -331,126 +407,178 @@ describe 'up.link', ->
331
407
  expect($link.attr('up-follow')).toBeMissing()
332
408
 
333
409
  describe 'up.visit', ->
334
-
410
+
335
411
  it 'should have tests'
336
412
 
413
+ describe 'up.link.isFollowable', ->
414
+
415
+ it 'returns true for an [up-target] link', ->
416
+ $link = affix('a[href="/foo"][up-target=".target"]')
417
+ up.hello $link
418
+ expect(up.link.isFollowable($link)).toBe(true)
419
+
420
+ it 'returns true for an [up-follow] link', ->
421
+ $link = affix('a[href="/foo"][up-follow]')
422
+ up.hello $link
423
+ expect(up.link.isFollowable($link)).toBe(true)
424
+
425
+ it 'returns true for an [up-modal] link', ->
426
+ $link = affix('a[href="/foo"][up-modal=".target"]')
427
+ up.hello $link
428
+ expect(up.link.isFollowable($link)).toBe(true)
429
+
430
+ it 'returns true for an [up-popup] link', ->
431
+ $link = affix('a[href="/foo"][up-popup=".target"]')
432
+ up.hello $link
433
+ expect(up.link.isFollowable($link)).toBe(true)
434
+
435
+ it 'returns true for an [up-drawer] link', ->
436
+ $link = affix('a[href="/foo"][up-drawer=".target"]')
437
+ up.hello $link
438
+ expect(up.link.isFollowable($link)).toBe(true)
439
+
440
+ it 'returns true for an [up-target] span with [up-href]', ->
441
+ $link = affix('span[up-href="/foo"][up-target=".target"]')
442
+ up.hello $link
443
+ expect(up.link.isFollowable($link)).toBe(true)
444
+
445
+ it 'returns false if the given link will be handled by the browser', ->
446
+ $link = affix('a[href="/foo"]')
447
+ up.hello $link
448
+ expect(up.link.isFollowable($link)).toBe(false)
449
+
450
+ it 'returns false if the given link will be handled by Rails UJS', ->
451
+ $link = affix('a[href="/foo"][data-method="put"]')
452
+ up.hello $link
453
+ expect(up.link.isFollowable($link)).toBe(false)
454
+
337
455
  describe 'unobtrusive behavior', ->
338
456
 
339
457
  describe 'a[up-target]', ->
340
458
 
341
- it 'does not follow a form with up-target attribute (bugfix)', ->
459
+ it 'does not follow a form with up-target attribute (bugfix)', asyncSpec (next) ->
342
460
  $form = affix('form[up-target]')
343
461
  up.hello($form)
344
- followSpy = up.link.knife.mock('follow').and.returnValue(u.resolvedPromise())
462
+ followSpy = up.link.knife.mock('defaultFollow').and.returnValue(Promise.resolve())
345
463
  Trigger.clickSequence($form)
346
- expect(followSpy).not.toHaveBeenCalled()
464
+
465
+ next =>
466
+ expect(followSpy).not.toHaveBeenCalled()
347
467
 
348
468
  describeCapability 'canPushState', ->
349
469
 
350
- it 'adds a history entry', ->
470
+ it 'adds a history entry', asyncSpec (next) ->
471
+ up.history.config.enabled = true
472
+
351
473
  affix('.target')
352
474
  $link = affix('a[href="/path"][up-target=".target"]')
353
475
  Trigger.clickSequence($link)
354
- @respondWith('<div class="target">new text</div>')
355
- expect($('.target')).toHaveText('new text')
356
- expect(location.pathname).toEqual('/path')
357
476
 
358
- it 'respects a X-Up-Location header that the server sends in case of a redirect', ->
477
+ next =>
478
+ @respondWith('<div class="target">new text</div>')
479
+
480
+ next =>
481
+ expect($('.target')).toHaveText('new text')
482
+ expect(location.pathname).toEqual('/path')
483
+
484
+ it 'respects a X-Up-Location header that the server sends in case of a redirect', asyncSpec (next) ->
485
+ up.history.config.enabled = true
486
+
359
487
  affix('.target')
360
488
  $link = affix('a[href="/path"][up-target=".target"]')
361
489
  Trigger.clickSequence($link)
362
- @respondWith
363
- responseText: '<div class="target">new text</div>'
364
- responseHeaders: { 'X-Up-Location': '/other/path' }
365
- expect($('.target')).toHaveText('new text')
366
- expect(location.pathname).toEqual('/other/path')
490
+
491
+ next =>
492
+ @respondWith
493
+ responseText: '<div class="target">new text</div>'
494
+ responseHeaders: { 'X-Up-Location': '/other/path' }
495
+
496
+ next =>
497
+ expect($('.target')).toHaveText('new text')
498
+ expect(location.pathname).toEqual('/other/path')
367
499
 
368
500
  describe 'choice of target layer', ->
369
501
 
370
502
  beforeEach ->
371
503
  up.motion.config.enabled = false
372
504
 
373
- it 'prefers to update a container in the same layer as the clicked link', (done) ->
505
+ it 'prefers to update a container in the same layer as the clicked link', asyncSpec (next) ->
374
506
  affix('.document').affix('.target').text('old document text')
375
507
  up.modal.extract('.target', "<div class='target'>old modal text</div>")
376
508
 
377
- u.nextFrame =>
509
+ next =>
378
510
  expect($('.document .target')).toHaveText('old document text')
379
511
  expect($('.up-modal .target')).toHaveText('old modal text')
380
512
 
381
513
  $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"]')
382
514
  Trigger.clickSequence($linkInModal)
383
515
 
384
- u.nextFrame =>
385
- @respondWith '<div class="target">new text from modal link</div>'
386
-
387
- expect($('.document .target')).toHaveText('old document text')
388
- expect($('.up-modal .target')).toHaveText('new text from modal link')
516
+ next =>
517
+ @respondWith '<div class="target">new text from modal link</div>'
389
518
 
390
- done()
519
+ next =>
520
+ expect($('.document .target')).toHaveText('old document text')
521
+ expect($('.up-modal .target')).toHaveText('new text from modal link')
391
522
 
392
523
  describe 'with [up-layer] modifier', ->
393
524
 
394
- it 'allows to name a layer for the update', (done) ->
525
+ it 'allows to name a layer for the update', asyncSpec (next) ->
395
526
  affix('.document').affix('.target').text('old document text')
396
527
  up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
397
528
 
398
- u.nextFrame =>
529
+ next =>
399
530
  expect($('.document .target')).toHaveText('old document text')
400
531
  expect($('.up-modal .target')).toHaveText('old modal text')
401
532
 
402
533
  $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-layer="page"]')
403
534
  Trigger.clickSequence($linkInModal)
404
535
 
405
- u.nextFrame =>
406
- @respondWith '<div class="target">new text from modal link</div>'
407
-
408
- expect($('.document .target')).toHaveText('new text from modal link')
409
- expect($('.up-modal .target')).toHaveText('old modal text')
536
+ next =>
537
+ @respondWith '<div class="target">new text from modal link</div>'
410
538
 
411
- done()
539
+ next =>
540
+ expect($('.document .target')).toHaveText('new text from modal link')
541
+ expect($('.up-modal .target')).toHaveText('old modal text')
412
542
 
413
- it 'ignores [up-layer] if the server responds with a non-200 status code', (done) ->
543
+ it 'ignores [up-layer] if the server responds with a non-200 status code', asyncSpec (next) ->
414
544
  affix('.document').affix('.target').text('old document text')
415
545
  up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
416
546
 
417
- u.nextFrame =>
547
+ next =>
418
548
  expect($('.document .target')).toHaveText('old document text')
419
549
  expect($('.up-modal .target')).toHaveText('old modal text')
420
550
 
421
551
  $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-fail-target=".target"][up-layer="page"]')
422
552
  Trigger.clickSequence($linkInModal)
423
553
 
424
- u.nextFrame =>
425
- @respondWith
426
- responseText: '<div class="target">new failure text from modal link</div>'
427
- status: 500
428
-
429
- expect($('.document .target')).toHaveText('old document text')
430
- expect($('.up-modal .target')).toHaveText('new failure text from modal link')
554
+ next =>
555
+ @respondWith
556
+ responseText: '<div class="target">new failure text from modal link</div>'
557
+ status: 500
431
558
 
432
- done()
559
+ next =>
560
+ expect($('.document .target')).toHaveText('old document text')
561
+ expect($('.up-modal .target')).toHaveText('new failure text from modal link')
433
562
 
434
- it 'allows to name a layer for a non-200 response using an [up-fail-layer] modifier', (done) ->
563
+ it 'allows to name a layer for a non-200 response using an [up-fail-layer] modifier', asyncSpec (next) ->
435
564
  affix('.document').affix('.target').text('old document text')
436
565
  up.modal.extract('.target', "<div class='target'>old modal text</div>", sticky: true)
437
566
 
438
- u.nextFrame =>
567
+ next =>
439
568
  expect($('.document .target')).toHaveText('old document text')
440
569
  expect($('.up-modal .target')).toHaveText('old modal text')
441
570
 
442
571
  $linkInModal = $('.up-modal').affix('a[href="/bar"][up-target=".target"][up-fail-target=".target"][up-fail-layer="page"]')
443
572
  Trigger.clickSequence($linkInModal)
444
573
 
445
- u.nextFrame =>
446
- @respondWith
447
- responseText: '<div class="target">new failure text from modal link</div>'
448
- status: 500
449
-
450
- expect($('.document .target')).toHaveText('new failure text from modal link')
451
- expect($('.up-modal .target')).toHaveText('old modal text')
574
+ next =>
575
+ @respondWith
576
+ responseText: '<div class="target">new failure text from modal link</div>'
577
+ status: 500
452
578
 
453
- done()
579
+ next =>
580
+ expect($('.document .target')).toHaveText('new failure text from modal link')
581
+ expect($('.up-modal .target')).toHaveText('old modal text')
454
582
 
455
583
  describe 'with [up-fail-target] modifier', ->
456
584
 
@@ -459,145 +587,161 @@ describe 'up.link', ->
459
587
  affix('.failure-target').text('old failure text')
460
588
  @$link = affix('a[href="/path"][up-target=".success-target"][up-fail-target=".failure-target"]')
461
589
 
462
- it 'uses the [up-fail-target] selector for a failed response', (done) ->
590
+ it 'uses the [up-fail-target] selector for a failed response', asyncSpec (next) ->
463
591
  Trigger.clickSequence(@$link)
464
- u.nextFrame =>
592
+
593
+ next =>
465
594
  @respondWith('<div class="failure-target">new failure text</div>', status: 500)
466
- u.nextFrame =>
467
- expect($('.success-target')).toHaveText('old success text')
468
- expect($('.failure-target')).toHaveText('new failure text')
469
- done()
470
595
 
471
- it 'uses the [up-target] selector for a successful response', (done) ->
596
+ next =>
597
+ expect($('.success-target')).toHaveText('old success text')
598
+ expect($('.failure-target')).toHaveText('new failure text')
599
+
600
+ it 'uses the [up-target] selector for a successful response', asyncSpec (next) ->
472
601
  Trigger.clickSequence(@$link)
473
- u.nextFrame =>
602
+
603
+ next =>
474
604
  @respondWith('<div class="success-target">new success text</div>', status: 200)
475
- u.nextFrame =>
476
- expect($('.success-target')).toHaveText('new success text')
477
- expect($('.failure-target')).toHaveText('old failure text')
478
- done()
605
+
606
+ next =>
607
+ expect($('.success-target')).toHaveText('new success text')
608
+ expect($('.failure-target')).toHaveText('old failure text')
479
609
 
480
610
  describe 'with [up-transition] modifier', ->
481
611
 
482
- it 'morphs between the old and new target element', (done) ->
612
+ it 'morphs between the old and new target element', asyncSpec (next) ->
483
613
  affix('.target.old')
484
614
  $link = affix('a[href="/path"][up-target=".target"][up-transition="cross-fade"][up-duration="500"][up-easing="linear"]')
485
615
  Trigger.clickSequence($link)
486
- @respondWith '<div class="target new">new text</div>'
487
-
488
- $oldGhost = $('.target.old.up-ghost')
489
- $newGhost = $('.target.new.up-ghost')
490
- expect($oldGhost).toExist()
491
- expect($newGhost).toExist()
492
- expect(u.opacity($oldGhost)).toBeAround(1, 0.15)
493
- expect(u.opacity($newGhost)).toBeAround(0, 0.15)
494
- u.setTimer 250, ->
495
- expect(u.opacity($oldGhost)).toBeAround(0.5, 0.15)
496
- expect(u.opacity($newGhost)).toBeAround(0.5, 0.15)
497
- done()
616
+
617
+ next =>
618
+ @respondWith '<div class="target new">new text</div>'
619
+
620
+ next =>
621
+ @$oldGhost = $('.target.old.up-ghost')
622
+ @$newGhost = $('.target.new.up-ghost')
623
+ expect(@$oldGhost).toExist()
624
+ expect(@$newGhost).toExist()
625
+ expect(u.opacity(@$oldGhost)).toBeAround(1, 0.15)
626
+ expect(u.opacity(@$newGhost)).toBeAround(0, 0.15)
627
+
628
+ next.after 250, =>
629
+ expect(u.opacity(@$oldGhost)).toBeAround(0.5, 0.15)
630
+ expect(u.opacity(@$newGhost)).toBeAround(0.5, 0.15)
498
631
 
499
632
  describe 'wih a CSS selector in the [up-fallback] attribute', ->
500
633
 
501
- it 'uses the fallback selector if the [up-target] CSS does not exist on the page', ->
634
+ it 'uses the fallback selector if the [up-target] CSS does not exist on the page', asyncSpec (next) ->
502
635
  affix('.fallback').text('old fallback')
503
636
  $link = affix('a[href="/path"][up-target=".target"][up-fallback=".fallback"]')
504
637
  Trigger.clickSequence($link)
505
- u.nextFrame ->
638
+
639
+ next =>
506
640
  @respondWith """
507
641
  <div class="target">new target</div>
508
642
  <div class="fallback">new fallback</div>
509
643
  """
510
- u.nextFrame ->
511
- expect('.target').toHaveText('new fallback')
512
644
 
513
- it 'ignores the fallback selector if the [up-target] CSS exists on the page', ->
645
+ next =>
646
+ expect('.fallback').toHaveText('new fallback')
647
+
648
+ it 'ignores the fallback selector if the [up-target] CSS exists on the page', asyncSpec (next) ->
514
649
  affix('.target').text('old target')
515
650
  affix('.fallback').text('old fallback')
516
651
  $link = affix('a[href="/path"][up-target=".target"][up-fallback=".fallback"]')
517
652
  Trigger.clickSequence($link)
518
- u.nextFrame ->
653
+
654
+ next =>
519
655
  @respondWith """
520
656
  <div class="target">new target</div>
521
657
  <div class="fallback">new fallback</div>
522
658
  """
523
- u.nextFrame ->
524
- expect('.target').toHaveText('new target')
525
- expect('.fallback').toHaveText('old fallback')
526
659
 
527
- it 'does not add a history entry when an up-history attribute is set to "false"', ->
660
+ next =>
661
+ expect('.target').toHaveText('new target')
662
+ expect('.fallback').toHaveText('old fallback')
663
+
664
+ it 'does not add a history entry when an up-history attribute is set to "false"', asyncSpec (next) ->
665
+ up.history.config.enabled = true
666
+
528
667
  oldPathname = location.pathname
529
668
  affix('.target')
530
669
  $link = affix('a[href="/path"][up-target=".target"][up-history="false"]')
531
670
  Trigger.clickSequence($link)
532
- @respondWith
533
- responseText: '<div class="target">new text</div>'
534
- responseHeaders: { 'X-Up-Location': '/other/path' }
535
- expect($('.target')).toHaveText('new text')
536
- expect(location.pathname).toEqual(oldPathname)
671
+
672
+ next =>
673
+ @respondWith
674
+ responseText: '<div class="target">new text</div>'
675
+ responseHeaders: { 'X-Up-Location': '/other/path' }
676
+
677
+ next =>
678
+ expect($('.target')).toHaveText('new text')
679
+ expect(location.pathname).toEqual(oldPathname)
537
680
 
538
681
  describe 'a[up-follow]', ->
539
682
 
540
683
  beforeEach ->
541
- @$link = affix('a[href="/path"][up-follow]')
542
- @followSpy = up.link.knife.mock('follow').and.returnValue(u.resolvedPromise())
543
- @defaultSpy = up.link.knife.mock('allowDefault').and.callFake((event) -> event.preventDefault())
684
+ @$link = affix('a[href="/follow-path"][up-follow]')
685
+ @followSpy = up.link.knife.mock('defaultFollow').and.returnValue(Promise.resolve())
686
+ @defaultSpy = spyOn(up.link, 'allowDefault').and.callFake((event) -> event.preventDefault())
544
687
 
545
- it "calls up.follow with the clicked link", ->
688
+ it "calls up.follow with the clicked link", asyncSpec (next) ->
546
689
  Trigger.click(@$link)
547
- expect(@followSpy).toHaveBeenCalledWith(@$link)
690
+ next =>
691
+ expect(@followSpy).toHaveBeenCalledWith(@$link, {})
548
692
 
549
693
  # IE does not call JavaScript and always performs the default action on right clicks
550
- unless navigator.userAgent.match(/Trident/)
551
- it 'does nothing if the right mouse button is used', ->
694
+ unless AgentDetector.isIE() || AgentDetector.isEdge()
695
+ it 'does nothing if the right mouse button is used', asyncSpec (next) ->
552
696
  Trigger.click(@$link, button: 2)
553
- expect(@followSpy).not.toHaveBeenCalled()
697
+ next => expect(@followSpy).not.toHaveBeenCalled()
554
698
 
555
- it 'does nothing if shift is pressed during the click', ->
699
+ it 'does nothing if shift is pressed during the click', asyncSpec (next) ->
556
700
  Trigger.click(@$link, shiftKey: true)
557
- expect(@followSpy).not.toHaveBeenCalled()
701
+ next => expect(@followSpy).not.toHaveBeenCalled()
558
702
 
559
- it 'does nothing if ctrl is pressed during the click', ->
703
+ it 'does nothing if ctrl is pressed during the click', asyncSpec (next)->
560
704
  Trigger.click(@$link, ctrlKey: true)
561
- expect(@followSpy).not.toHaveBeenCalled()
705
+ next => expect(@followSpy).not.toHaveBeenCalled()
562
706
 
563
- it 'does nothing if meta is pressed during the click', ->
707
+ it 'does nothing if meta is pressed during the click', asyncSpec (next)->
564
708
  Trigger.click(@$link, metaKey: true)
565
- expect(@followSpy).not.toHaveBeenCalled()
709
+ next => expect(@followSpy).not.toHaveBeenCalled()
566
710
 
567
711
  describe 'with [up-instant] modifier', ->
568
712
 
569
713
  beforeEach ->
570
714
  @$link.attr('up-instant', '')
571
715
 
572
- it 'follows a link on mousedown (instead of on click)', ->
716
+ it 'follows a link on mousedown (instead of on click)', asyncSpec (next)->
573
717
  Trigger.mousedown(@$link)
574
- expect(@followSpy.calls.mostRecent().args[0]).toEqual(@$link)
718
+ next => expect(@followSpy.calls.mostRecent().args[0]).toEqual(@$link)
575
719
 
576
- it 'does nothing on mouseup', ->
720
+ it 'does nothing on mouseup', asyncSpec (next)->
577
721
  Trigger.mouseup(@$link)
578
- expect(@followSpy).not.toHaveBeenCalled()
722
+ next => expect(@followSpy).not.toHaveBeenCalled()
579
723
 
580
- it 'does nothing on click', ->
724
+ it 'does nothing on click', asyncSpec (next)->
581
725
  Trigger.click(@$link)
582
- expect(@followSpy).not.toHaveBeenCalled()
726
+ next => expect(@followSpy).not.toHaveBeenCalled()
583
727
 
584
728
  # IE does not call JavaScript and always performs the default action on right clicks
585
- unless navigator.userAgent.match(/Trident/)
586
- it 'does nothing if the right mouse button is pressed down', ->
729
+ unless AgentDetector.isIE() || AgentDetector.isEdge()
730
+ it 'does nothing if the right mouse button is pressed down', asyncSpec (next)->
587
731
  Trigger.mousedown(@$link, button: 2)
588
- expect(@followSpy).not.toHaveBeenCalled()
732
+ next => expect(@followSpy).not.toHaveBeenCalled()
589
733
 
590
- it 'does nothing if shift is pressed during mousedown', ->
734
+ it 'does nothing if shift is pressed during mousedown', asyncSpec (next) ->
591
735
  Trigger.mousedown(@$link, shiftKey: true)
592
- expect(@followSpy).not.toHaveBeenCalled()
736
+ next => expect(@followSpy).not.toHaveBeenCalled()
593
737
 
594
- it 'does nothing if ctrl is pressed during mousedown', ->
738
+ it 'does nothing if ctrl is pressed during mousedown', asyncSpec (next) ->
595
739
  Trigger.mousedown(@$link, ctrlKey: true)
596
- expect(@followSpy).not.toHaveBeenCalled()
740
+ next => expect(@followSpy).not.toHaveBeenCalled()
597
741
 
598
- it 'does nothing if meta is pressed during mousedown', ->
742
+ it 'does nothing if meta is pressed during mousedown', asyncSpec (next) ->
599
743
  Trigger.mousedown(@$link, metaKey: true)
600
- expect(@followSpy).not.toHaveBeenCalled()
744
+ next => expect(@followSpy).not.toHaveBeenCalled()
601
745
 
602
746
  describe '[up-dash]', ->
603
747
 
@@ -672,19 +816,21 @@ describe 'up.link', ->
672
816
  up.hello($area)
673
817
  expect($area.attr('up-follow')).toEqual('')
674
818
 
675
- it 'can be used to enlarge the click area of a link', ->
819
+ it 'can be used to enlarge the click area of a link', asyncSpec (next) ->
676
820
  $area = affix('div[up-expand] a[href="/path"]')
677
821
  up.hello($area)
678
822
  spyOn(up, 'replace')
679
823
  Trigger.clickSequence($area)
680
- expect(up.replace).toHaveBeenCalled()
824
+ next =>
825
+ expect(up.replace).toHaveBeenCalled()
681
826
 
682
- it 'does not trigger multiple replaces when the user clicks on the expanded area of an up-instant link (bugfix)', ->
827
+ it 'does not trigger multiple replaces when the user clicks on the expanded area of an [up-instant] link (bugfix)', asyncSpec (next) ->
683
828
  $area = affix('div[up-expand] a[href="/path"][up-follow][up-instant]')
684
829
  up.hello($area)
685
830
  spyOn(up, 'replace')
686
831
  Trigger.clickSequence($area)
687
- expect(up.replace.calls.count()).toEqual(1)
832
+ next =>
833
+ expect(up.replace.calls.count()).toEqual(1)
688
834
 
689
835
  it 'does not add an up-follow attribute if the expanded link is [up-dash] with a selector (bugfix)', ->
690
836
  $area = affix('div[up-expand] a[href="/path"][up-dash=".element"]')