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
@@ -19,136 +19,148 @@ describe 'up.form', ->
19
19
 
20
20
  describe "when the input receives a #{eventName} event", ->
21
21
 
22
- it "runs the callback if the value changed", (done) ->
22
+ it "runs the callback if the value changed", asyncSpec (next) ->
23
23
  $input = affix('input[value="old-value"]')
24
24
  callback = jasmine.createSpy('change callback')
25
25
  up.observe($input, callback)
26
26
  $input.val('new-value')
27
27
  u.times 2, -> $input.trigger(eventName)
28
- u.nextFrame ->
28
+ next =>
29
29
  expect(callback).toHaveBeenCalledWith('new-value', $input)
30
30
  expect(callback.calls.count()).toEqual(1)
31
- done()
32
31
 
33
- it "does not run the callback if the value didn't change", (done) ->
32
+ it "does not run the callback if the value didn't change", asyncSpec (next) ->
34
33
  $input = affix('input[value="old-value"]')
35
34
  callback = jasmine.createSpy('change callback')
36
35
  up.observe($input, callback)
37
36
  $input.trigger(eventName)
38
- u.nextFrame ->
37
+ next =>
39
38
  expect(callback).not.toHaveBeenCalled()
40
- done()
41
39
 
42
- it 'debounces the callback when the { delay } option is given', (done) ->
40
+ it 'debounces the callback when the { delay } option is given', asyncSpec (next) ->
43
41
  $input = affix('input[value="old-value"]')
44
42
  callback = jasmine.createSpy('change callback')
45
43
  up.observe($input, { delay: 100 }, callback)
46
44
  $input.val('new-value-1')
47
45
  $input.trigger(eventName)
48
- u.setTimer 50, ->
46
+
47
+ next.after 50, ->
49
48
  # 50 ms after change 1: We're still waiting for the 100ms delay to expire
50
49
  expect(callback.calls.count()).toEqual(0)
51
- u.setTimer 100, ->
52
- # 150 ms after change 1: The 100ms delay has expired
53
- expect(callback.calls.count()).toEqual(1)
54
- expect(callback.calls.mostRecent().args[0]).toEqual('new-value-1')
55
- $input.val('new-value-2')
56
- $input.trigger(eventName)
57
- u.setTimer 40, ->
58
- # 40 ms after change 2: We change again, resetting the delay
59
- expect(callback.calls.count()).toEqual(1)
60
- $input.val('new-value-3')
61
- $input.trigger(eventName)
62
- u.setTimer 85, ->
63
- # 125 ms after change 2, which was superseded by change 3
64
- # 85 ms after change 3
65
- expect(callback.calls.count()).toEqual(1)
66
- u.setTimer 65, ->
67
- # 190 ms after change 2, which was superseded by change 3
68
- # 150 ms after change 3
69
- expect(callback.calls.count()).toEqual(2)
70
- expect(callback.calls.mostRecent().args[0]).toEqual('new-value-3')
71
- done()
72
-
73
- it 'delays a callback if a previous async callback is taking long to execute', (done) ->
50
+
51
+ next.after 100, ->
52
+ # 150 ms after change 1: The 100ms delay has expired
53
+ expect(callback.calls.count()).toEqual(1)
54
+ expect(callback.calls.mostRecent().args[0]).toEqual('new-value-1')
55
+ $input.val('new-value-2')
56
+ $input.trigger(eventName)
57
+
58
+ next.after 40, ->
59
+ # 40 ms after change 2: We change again, resetting the delay
60
+ expect(callback.calls.count()).toEqual(1)
61
+ $input.val('new-value-3')
62
+ $input.trigger(eventName)
63
+
64
+ next.after 85, ->
65
+ # 125 ms after change 2, which was superseded by change 3
66
+ # 85 ms after change 3
67
+ expect(callback.calls.count()).toEqual(1)
68
+
69
+ next.after 65, ->
70
+ # 190 ms after change 2, which was superseded by change 3
71
+ # 150 ms after change 3
72
+ expect(callback.calls.count()).toEqual(2)
73
+ expect(callback.calls.mostRecent().args[0]).toEqual('new-value-3')
74
+
75
+ it 'delays a callback if a previous async callback is taking long to execute', asyncSpec (next) ->
74
76
  $input = affix('input[value="old-value"]')
75
77
  callbackCount = 0
76
78
  callback = ->
77
79
  callbackCount += 1
78
- u.promiseTimer(100)
80
+ return u.promiseTimer(100)
79
81
  up.observe($input, { delay: 1 }, callback)
80
82
  $input.val('new-value-1')
81
83
  $input.trigger(eventName)
82
- u.setTimer 30, ->
84
+
85
+ next.after 30, ->
83
86
  # Callback has been called and takes 100 ms to complete
84
87
  expect(callbackCount).toEqual(1)
85
88
  $input.val('new-value-2')
86
89
  $input.trigger(eventName)
87
- u.setTimer 30, ->
88
- # Second callback is triggerd, but waits for first callback to complete
89
- expect(callbackCount).toEqual(1)
90
- u.setTimer 100, ->
91
- expect(callbackCount).toEqual(2)
92
- done()
93
90
 
94
- it 'does not run multiple callbacks if a long-running callback has been blocking multiple subsequent callbacks'
91
+ next.after 30, ->
92
+ # Second callback is triggerd, but waits for first callback to complete
93
+ expect(callbackCount).toEqual(1)
95
94
 
96
- it "runs a callback in the same frame if the delay is 0", ->
97
- $input = affix('input[value="old-value"]')
98
- callback = jasmine.createSpy('change callback')
99
- up.observe($input, { delay: 0 }, callback)
100
- $input.val('new-value')
101
- $input.trigger(eventName)
102
- expect(callback.calls.count()).toEqual(1)
95
+ next.after 50, ->
96
+ expect(callbackCount).toEqual(2)
103
97
 
104
- it "runs multiple callbacks in the same frame if the delay is 0", ->
98
+ it 'only runs the last callback when a previous long-running callback has been delaying multiple callbacks', asyncSpec (next) ->
105
99
  $input = affix('input[value="old-value"]')
106
- callback = jasmine.createSpy('change callback')
107
- up.observe($input, { delay: 0 }, callback)
108
- $input.val('new-value')
109
- $input.trigger(eventName)
110
- $input.val('yet-another-value')
100
+
101
+ callbackArgs = []
102
+ callback = (value, field) ->
103
+ callbackArgs.push(value)
104
+ return u.promiseTimer(100)
105
+
106
+ up.observe($input, { delay: 1 }, callback)
107
+ $input.val('new-value-1')
111
108
  $input.trigger(eventName)
112
- expect(callback.calls.count()).toEqual(2)
109
+
110
+ next.after 10, ->
111
+ # Callback has been called and takes 100 ms to complete
112
+ expect(callbackArgs).toEqual ['new-value-1']
113
+ $input.val('new-value-2')
114
+ $input.trigger(eventName)
115
+
116
+ next.after 10, ->
117
+ expect(callbackArgs).toEqual ['new-value-1']
118
+ $input.val('new-value-3')
119
+ $input.trigger(eventName)
120
+
121
+ next.after 100, ->
122
+ expect(callbackArgs).toEqual ['new-value-1', 'new-value-3']
113
123
 
114
124
  describe 'when the first argument is a checkbox', ->
115
125
 
116
- it 'runs the callback when the checkbox changes its checked state', (done) ->
126
+ it 'runs the callback when the checkbox changes its checked state', asyncSpec (next) ->
117
127
  $form = affix('form')
118
- $checkbox = $form.affix('input[type="checkbox"]')
128
+ $checkbox = $form.affix('input[type="checkbox"][value="checkbox-value"]')
119
129
  callback = jasmine.createSpy('change callback')
120
130
  up.observe($checkbox, callback)
121
131
  expect($checkbox.is(':checked')).toBe(false)
122
132
  Trigger.clickSequence($checkbox)
123
- u.nextFrame ->
133
+
134
+ next =>
124
135
  expect($checkbox.is(':checked')).toBe(true)
125
136
  expect(callback.calls.count()).toEqual(1)
126
137
  Trigger.clickSequence($checkbox)
127
- u.nextFrame ->
128
- expect($checkbox.is(':checked')).toBe(false)
129
- expect(callback.calls.count()).toEqual(2)
130
- done()
131
138
 
132
- it 'runs the callback when the checkbox is toggled by clicking its label', (done) ->
139
+ next =>
140
+ expect($checkbox.is(':checked')).toBe(false)
141
+ expect(callback.calls.count()).toEqual(2)
142
+
143
+ it 'runs the callback when the checkbox is toggled by clicking its label', asyncSpec (next) ->
133
144
  $form = affix('form')
134
- $checkbox = $form.affix('input#tick[type="checkbox"]')
145
+ $checkbox = $form.affix('input#tick[type="checkbox"][value="checkbox-value"]')
135
146
  $label = $form.affix('label[for="tick"]').text('tick label')
136
147
  callback = jasmine.createSpy('change callback')
137
148
  up.observe($checkbox, callback)
138
149
  expect($checkbox.is(':checked')).toBe(false)
139
150
  Trigger.clickSequence($label)
140
- u.nextFrame ->
151
+
152
+ next =>
141
153
  expect($checkbox.is(':checked')).toBe(true)
142
154
  expect(callback.calls.count()).toEqual(1)
143
155
  Trigger.clickSequence($label)
144
- u.nextFrame ->
145
- expect($checkbox.is(':checked')).toBe(false)
146
- expect(callback.calls.count()).toEqual(2)
147
- done()
156
+
157
+ next =>
158
+ expect($checkbox.is(':checked')).toBe(false)
159
+ expect(callback.calls.count()).toEqual(2)
148
160
 
149
161
  describe 'when the first argument is a radio button group', ->
150
162
 
151
- it 'runs the callback when the group changes its selection', (done) ->
163
+ it 'runs the callback when the group changes its selection', asyncSpec (next) ->
152
164
  $form = affix('form')
153
165
  $radio1 = $form.affix('input[type="radio"][name="group"][value="1"]')
154
166
  $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
@@ -157,16 +169,17 @@ describe 'up.form', ->
157
169
  up.observe($group, callback)
158
170
  expect($radio1.is(':checked')).toBe(false)
159
171
  Trigger.clickSequence($radio1)
160
- u.nextFrame ->
172
+
173
+ next =>
161
174
  expect($radio1.is(':checked')).toBe(true)
162
175
  expect(callback.calls.count()).toEqual(1)
163
176
  Trigger.clickSequence($radio2)
164
- u.nextFrame ->
165
- expect($radio1.is(':checked')).toBe(false)
166
- expect(callback.calls.count()).toEqual(2)
167
- done()
168
177
 
169
- it "runs the callbacks when a radio button is selected or deselected by clicking a label in the group", (done) ->
178
+ next =>
179
+ expect($radio1.is(':checked')).toBe(false)
180
+ expect(callback.calls.count()).toEqual(2)
181
+
182
+ it "runs the callbacks when a radio button is selected or deselected by clicking a label in the group", asyncSpec (next) ->
170
183
  $form = affix('form')
171
184
  $radio1 = $form.affix('input#radio1[type="radio"][name="group"][value="1"]')
172
185
  $radio1Label = $form.affix('label[for="radio1"]').text('label 1')
@@ -177,16 +190,17 @@ describe 'up.form', ->
177
190
  up.observe($group, callback)
178
191
  expect($radio1.is(':checked')).toBe(false)
179
192
  Trigger.clickSequence($radio1Label)
180
- u.nextFrame ->
193
+
194
+ next =>
181
195
  expect($radio1.is(':checked')).toBe(true)
182
196
  expect(callback.calls.count()).toEqual(1)
183
197
  Trigger.clickSequence($radio2Label)
184
- u.nextFrame ->
185
- expect($radio1.is(':checked')).toBe(false)
186
- expect(callback.calls.count()).toEqual(2)
187
- done()
188
198
 
189
- it "takes the group's initial selected value into account", (done) ->
199
+ next =>
200
+ expect($radio1.is(':checked')).toBe(false)
201
+ expect(callback.calls.count()).toEqual(2)
202
+
203
+ it "takes the group's initial selected value into account", asyncSpec (next) ->
190
204
  $form = affix('form')
191
205
  $radio1 = $form.affix('input[type="radio"][name="group"][value="1"][checked="checked"]')
192
206
  $radio2 = $form.affix('input[type="radio"][name="group"][value="2"]')
@@ -196,18 +210,19 @@ describe 'up.form', ->
196
210
  expect($radio1.is(':checked')).toBe(true)
197
211
  expect($radio2.is(':checked')).toBe(false)
198
212
  Trigger.clickSequence($radio1)
199
- u.nextFrame ->
213
+
214
+ next =>
200
215
  # Since the radio button was already checked, the click doesn't do anything
201
216
  expect($radio1.is(':checked')).toBe(true)
202
217
  expect($radio2.is(':checked')).toBe(false)
203
218
  # Since the radio button was already checked, clicking it again won't trigger the callback
204
219
  expect(callback.calls.count()).toEqual(0)
205
220
  Trigger.clickSequence($radio2)
206
- u.nextFrame ->
207
- expect($radio1.is(':checked')).toBe(false)
208
- expect($radio2.is(':checked')).toBe(true)
209
- expect(callback.calls.count()).toEqual(1)
210
- done()
221
+
222
+ next =>
223
+ expect($radio1.is(':checked')).toBe(false)
224
+ expect($radio2.is(':checked')).toBe(true)
225
+ expect(callback.calls.count()).toEqual(1)
211
226
 
212
227
  describe 'when the first argument is a form', ->
213
228
 
@@ -215,27 +230,25 @@ describe 'up.form', ->
215
230
 
216
231
  describe "when any of the form's inputs receives a #{eventName} event", ->
217
232
 
218
- it "runs the callback if the value changed", (done) ->
233
+ it "runs the callback if the value changed", asyncSpec (next) ->
219
234
  $form = affix('form')
220
235
  $input = $form.affix('input[value="old-value"]')
221
236
  callback = jasmine.createSpy('change callback')
222
237
  up.observe($form, callback)
223
238
  $input.val('new-value')
224
239
  u.times 2, -> $input.trigger(eventName)
225
- u.nextFrame ->
240
+ next =>
226
241
  expect(callback).toHaveBeenCalledWith('new-value', $input)
227
242
  expect(callback.calls.count()).toEqual(1)
228
- done()
229
243
 
230
- it "does not run the callback if the value didn't change", (done) ->
244
+ it "does not run the callback if the value didn't change", asyncSpec (next) ->
231
245
  $form = affix('form')
232
246
  $input = $form.affix('input[value="old-value"]')
233
247
  callback = jasmine.createSpy('change callback')
234
248
  up.observe($form, callback)
235
249
  $input.trigger(eventName)
236
- u.nextFrame ->
250
+ next =>
237
251
  expect(callback).not.toHaveBeenCalled()
238
- done()
239
252
 
240
253
  # it 'runs the callback only once when a radio button group changes its selection', ->
241
254
  # $form = affix('form')
@@ -252,104 +265,136 @@ describe 'up.form', ->
252
265
  describeCapability 'canPushState', ->
253
266
 
254
267
  beforeEach ->
255
- @$form = affix('form[action="/path/to"][method="put"][up-target=".response"]')
268
+ up.history.config.enabled = true
269
+ @$form = affix('form[action="/form-target"][method="put"][up-target=".response"]')
256
270
  @$form.append('<input name="field1" value="value1">')
257
271
  @$form.append('<input name="field2" value="value2">')
258
272
  affix('.response').text('old-text')
259
- @promise = up.submit(@$form)
260
- @request = @lastRequest()
261
273
 
262
- it 'submits the given form and replaces the target with the response', ->
263
- expect(@request.url).toMatch /\/path\/to$/
264
- expect(@request).toHaveRequestMethod('PUT')
265
- expect(@request.data()['field1']).toEqual(['value1'])
266
- expect(@request.data()['field2']).toEqual(['value2'])
267
- expect(@request.requestHeaders['X-Up-Target']).toEqual('.response')
268
-
269
- @respondWith """
270
- text-before
271
-
272
- <div class="response">
273
- new-text
274
- </div>
275
-
276
- text-after
277
- """
274
+ it 'submits the given form and replaces the target with the response', asyncSpec (next) ->
275
+ up.submit(@$form)
278
276
 
279
- it "places the response into the form and doesn't update the browser URL if the submission returns a 5xx status code", ->
277
+ next =>
278
+ expect(@lastRequest().url).toMatchUrl('/form-target')
279
+ expect(@lastRequest()).toHaveRequestMethod('PUT')
280
+ expect(@lastRequest().data()['field1']).toEqual(['value1'])
281
+ expect(@lastRequest().data()['field2']).toEqual(['value2'])
282
+ expect(@lastRequest().requestHeaders['X-Up-Target']).toEqual('.response')
283
+
284
+ @respondWith
285
+ responseHeaders:
286
+ 'X-Up-Location': '/redirect-target'
287
+ 'X-Up-Method': 'GET'
288
+ responseText: """
289
+ <div class='before'>
290
+ new-before
291
+ </div>
292
+
293
+ <div class="response">
294
+ new-text
295
+ </div>
296
+
297
+ <div class='after'>
298
+ new-after
299
+ </div>
300
+ """
301
+
302
+ next =>
303
+ expect(up.browser.url()).toMatchUrl('/redirect-target')
304
+ expect('.response').toHaveText('new-text')
305
+ # See that containers outside the form have not changed
306
+ expect('.before').not.toHaveText('old-before')
307
+ expect('.after').not.toHaveText('old-after')
308
+
309
+ it "places the response into the form and doesn't update the browser URL if the submission returns a 5xx status code", asyncSpec (next) ->
280
310
  up.submit(@$form)
281
- @respondWith
282
- status: 500
283
- contentType: 'text/html'
284
- responseText:
285
- """
286
- text-before
287
-
288
- <form>
289
- error-messages
290
- </form>
291
311
 
292
- text-after
293
- """
294
- expect(up.browser.url()).toEqual(@hrefBeforeExample)
295
- expect($('.response')).toHaveText('old-text')
296
- expect($('form')).toHaveText('error-messages')
297
- expect($('body')).not.toHaveText('text-before')
298
- expect($('body')).not.toHaveText('text-after')
312
+ next =>
313
+ @respondWith
314
+ status: 500
315
+ contentType: 'text/html'
316
+ responseText:
317
+ """
318
+ <div class='before'>
319
+ new-before
320
+ </div>
321
+
322
+ <form>
323
+ error-messages
324
+ </form>
325
+
326
+ <div class='after'>
327
+ new-after
328
+ </div>
329
+ """
330
+
331
+ next =>
332
+ expect(up.browser.url()).toEqual(@hrefBeforeExample)
333
+ expect('.response').toHaveText('old-text')
334
+ expect('form').toHaveText('error-messages')
335
+ # See that containers outside the form have not changed
336
+ expect('.before').not.toHaveText('old-before')
337
+ expect('.after').not.toHaveText('old-after')
299
338
 
300
- it 'respects X-Up-Method and X-Up-Location response headers so the server can show that it redirected to a GET URL', ->
339
+ it 'respects X-Up-Method and X-Up-Location response headers so the server can show that it redirected to a GET URL', asyncSpec (next) ->
301
340
  up.submit(@$form)
302
- @respondWith
303
- status: 200
304
- contentType: 'text/html'
305
- responseHeaders:
306
- 'X-Up-Location': '/other-path'
307
- 'X-Up-Method': 'GET'
308
- responseText:
309
- """
310
- <div class="response">
311
- new-text
312
- </div>
313
- """
314
341
 
315
- expect(up.browser.url()).toEqualUrl('/other-path')
342
+ next =>
343
+ @respondWith
344
+ status: 200
345
+ contentType: 'text/html'
346
+ responseHeaders:
347
+ 'X-Up-Location': '/other-path'
348
+ 'X-Up-Method': 'GET'
349
+ responseText:
350
+ """
351
+ <div class="response">
352
+ new-text
353
+ </div>
354
+ """
355
+
356
+ next =>
357
+ expect(up.browser.url()).toMatchUrl('/other-path')
316
358
 
317
359
  describe 'with { history } option', ->
318
360
 
319
- it 'uses the given URL as the new browser location if the request succeeded', ->
361
+ it 'uses the given URL as the new browser location if the request succeeded', asyncSpec (next) ->
320
362
  up.submit(@$form, history: '/given-path')
321
- @respondWith('<div class="response">new-text</div>')
322
- expect(up.browser.url()).toEqualUrl('/given-path')
363
+ next => @respondWith('<div class="response">new-text</div>')
364
+ next => expect(up.browser.url()).toMatchUrl('/given-path')
323
365
 
324
- it 'keeps the current browser location if the request failed', ->
366
+ it 'keeps the current browser location if the request failed', asyncSpec (next) ->
325
367
  up.submit(@$form, history: '/given-path', failTarget: '.response')
326
- @respondWith('<div class="response">new-text</div>', status: 500)
327
- expect(up.browser.url()).toEqual(@hrefBeforeExample)
368
+ next => @respondWith('<div class="response">new-text</div>', status: 500)
369
+ next => expect(up.browser.url()).toEqual(@hrefBeforeExample)
328
370
 
329
- it 'keeps the current browser location if the option is set to false', ->
371
+ it 'keeps the current browser location if the option is set to false', asyncSpec (next) ->
330
372
  up.submit(@$form, history: false)
331
- @respondWith('<div class="response">new-text</div>')
332
- expect(up.browser.url()).toEqual(@hrefBeforeExample)
373
+ next => @respondWith('<div class="response">new-text</div>')
374
+ next =>expect(up.browser.url()).toEqual(@hrefBeforeExample)
333
375
 
334
376
  describe 'in a form with file inputs', ->
335
377
 
336
378
  beforeEach ->
379
+ @$form.affix('input[name="text-field"][type="text"]').val("value")
337
380
  @$form.affix('input[name="file-field"][type="file"]')
338
381
 
339
- it 'transfers the form fields via FormData', ->
382
+ it 'transfers the form fields via FormData', asyncSpec (next) ->
340
383
  up.submit(@$form)
341
- data = @lastRequest().data()
342
- expect(u.isFormData(data)).toBe(true)
384
+ next =>
385
+ data = @lastRequest().data()
386
+ expect(u.isFormData(data)).toBe(true)
343
387
 
344
388
  describeFallback 'canPushState', ->
345
389
 
346
- it 'falls back to a vanilla form submission', ->
390
+ it 'falls back to a vanilla form submission', asyncSpec (next) ->
347
391
  $form = affix('form[action="/path/to"][method="put"][up-target=".response"]')
348
392
  form = $form.get(0)
349
393
  spyOn(form, 'submit')
350
394
 
351
395
  up.submit($form)
352
- expect(form.submit).toHaveBeenCalled()
396
+
397
+ next => expect(form.submit).toHaveBeenCalled()
353
398
 
354
399
  describe 'unobtrusive behavior', ->
355
400
 
@@ -359,101 +404,98 @@ describe 'up.form', ->
359
404
 
360
405
  describe 'submit buttons', ->
361
406
 
362
- it 'includes the clicked submit button in the params', (done) ->
407
+ it 'includes the clicked submit button in the params', asyncSpec (next) ->
363
408
  $form = affix('form[action="/action"][up-target=".target"]')
364
409
  $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
365
410
  $submitButton = $form.affix('input[type="submit"][name="submit-button"][value="submit-button-value"]')
366
411
  up.hello($form)
367
412
  Trigger.clickSequence($submitButton)
368
- u.nextFrame =>
413
+
414
+ next =>
369
415
  params = @lastRequest().data()
370
416
  expect(params['text-field']).toEqual(['text-field-value'])
371
417
  expect(params['submit-button']).toEqual(['submit-button-value'])
372
- done()
373
418
 
374
- it 'excludes an unused submit button in the params', (done) ->
419
+ it 'excludes an unused submit button in the params', asyncSpec (next) ->
375
420
  $form = affix('form[action="/action"][up-target=".target"]')
376
421
  $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
377
422
  $submitButton1 = $form.affix('input[type="submit"][name="submit-button-1"][value="submit-button-1-value"]')
378
423
  $submitButton2 = $form.affix('input[type="submit"][name="submit-button-2"][value="submit-button-2-value"]')
379
424
  up.hello($form)
380
425
  Trigger.clickSequence($submitButton2)
381
- u.nextFrame =>
426
+
427
+ next =>
382
428
  params = @lastRequest().data()
383
429
  expect(params['text-field']).toEqual(['text-field-value'])
384
430
  expect(params['submit-button-1']).toBeUndefined()
385
431
  expect(params['submit-button-2']).toEqual(['submit-button-2-value'])
386
- done()
387
432
 
388
- it 'includes the first submit button if the form was submitted with enter', (done) ->
433
+ it 'includes the first submit button if the form was submitted with enter', asyncSpec (next) ->
389
434
  $form = affix('form[action="/action"][up-target=".target"]')
390
435
  $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
391
436
  $submitButton1 = $form.affix('input[type="submit"][name="submit-button-1"][value="submit-button-1-value"]')
392
437
  $submitButton2 = $form.affix('input[type="submit"][name="submit-button-2"][value="submit-button-2-value"]')
393
438
  up.hello($form)
394
439
  $form.submit() # sorry
395
- u.nextFrame =>
440
+
441
+ next =>
396
442
  params = @lastRequest().data()
397
443
  expect(params['text-field']).toEqual(['text-field-value'])
398
444
  expect(params['submit-button-1']).toEqual(['submit-button-1-value'])
399
445
  expect(params['submit-button-2']).toBeUndefined()
400
- done()
401
446
 
402
- it 'does not explode if the form has no submit buttons', (done) ->
447
+ it 'does not explode if the form has no submit buttons', asyncSpec (next) ->
403
448
  $form = affix('form[action="/action"][up-target=".target"]')
404
449
  $textField = $form.affix('input[type="text"][name="text-field"][value="text-field-value"]')
405
450
  up.hello($form)
406
451
  $form.submit() # sorry
407
- u.nextFrame =>
452
+
453
+ next =>
408
454
  params = @lastRequest().data()
409
455
  keys = Object.keys(params)
410
456
  expect(keys).toEqual(['text-field'])
411
- done()
412
457
 
413
458
  describe 'input[up-autosubmit]', ->
414
459
 
415
- it 'submits the form when a change is observed in the given form field', (done) ->
460
+ it 'submits the form when a change is observed in the given form field', asyncSpec (next) ->
416
461
  $form = affix('form')
417
462
  $field = $form.affix('input[up-autosubmit][val="old-value"]')
418
463
  up.hello($field)
419
464
  submitSpy = up.form.knife.mock('submit').and.returnValue(u.unresolvablePromise())
420
465
  $field.val('new-value')
421
466
  $field.trigger('change')
422
- u.nextFrame ->
423
- expect(submitSpy).toHaveBeenCalled()
424
- done()
467
+ next => expect(submitSpy).toHaveBeenCalled()
425
468
 
426
- it 'marks the field with an .up-active class while the form is submitting', (done) ->
469
+ it 'marks the field with an .up-active class while the form is submitting', asyncSpec (next) ->
427
470
  $form = affix('form')
428
471
  $field = $form.affix('input[up-autosubmit][val="old-value"]')
429
472
  up.hello($field)
430
- submission = $.Deferred()
473
+ submission = u.newDeferred()
431
474
  submitSpy = up.form.knife.mock('submit').and.returnValue(submission)
432
475
  $field.val('new-value')
433
476
  $field.trigger('change')
434
- u.nextFrame ->
477
+ next =>
435
478
  expect(submitSpy).toHaveBeenCalled()
436
479
  expect($field).toHaveClass('up-active')
437
480
  submission.resolve()
481
+
482
+ next =>
438
483
  expect($field).not.toHaveClass('up-active')
439
- done()
440
484
 
441
485
  describe 'form[up-autosubmit]', ->
442
486
 
443
- it 'submits the form when a change is observed in any of its fields', (done) ->
487
+ it 'submits the form when a change is observed in any of its fields', asyncSpec (next) ->
444
488
  $form = affix('form[up-autosubmit]')
445
489
  $field = $form.affix('input[val="old-value"]')
446
490
  up.hello($form)
447
491
  submitSpy = up.form.knife.mock('submit').and.returnValue(u.unresolvablePromise())
448
492
  $field.val('new-value')
449
493
  $field.trigger('change')
450
- u.nextFrame ->
451
- expect(submitSpy).toHaveBeenCalled()
452
- done()
494
+ next => expect(submitSpy).toHaveBeenCalled()
453
495
 
454
496
  describe 'with [up-delay] modifier', ->
455
497
 
456
- it 'debounces the form submission', (done) ->
498
+ it 'debounces the form submission', asyncSpec (next) ->
457
499
  $form = affix('form[up-autosubmit][up-delay="50"]')
458
500
  $field = $form.affix('input[val="old-value"]')
459
501
  up.hello($form)
@@ -463,49 +505,47 @@ describe 'up.form', ->
463
505
  $field.val('new-value-2')
464
506
  $field.trigger('change')
465
507
 
466
- u.nextFrame ->
508
+ next =>
467
509
  expect(submitSpy.calls.count()).toBe(0)
468
- u.setTimer 80, ->
469
- expect(submitSpy.calls.count()).toBe(1)
470
- done()
510
+
511
+ next.after 80, =>
512
+ expect(submitSpy.calls.count()).toBe(1)
471
513
 
472
514
  describe 'input[up-observe]', ->
473
515
 
474
516
  afterEach ->
475
517
  window.observeCallbackSpy = undefined
476
518
 
477
- it 'runs the JavaScript code in the attribute value when a change is observed in the field', (done) ->
519
+ it 'runs the JavaScript code in the attribute value when a change is observed in the field', asyncSpec (next) ->
478
520
  $form = affix('form')
479
521
  window.observeCallbackSpy = jasmine.createSpy('observe callback')
480
522
  $field = $form.affix('input[val="old-value"][up-observe="window.observeCallbackSpy(value, $field.get(0))"]')
481
523
  up.hello($form)
482
524
  $field.val('new-value')
483
525
  $field.trigger('change')
484
- u.nextFrame ->
526
+
527
+ next =>
485
528
  expect(window.observeCallbackSpy).toHaveBeenCalledWith('new-value', $field.get(0))
486
- done()
487
529
 
488
530
  describe 'with [up-delay] modifier', ->
489
531
 
490
- it 'debounces the callback', (done) ->
532
+ it 'debounces the callback', asyncSpec (next) ->
491
533
  $form = affix('form')
492
534
  window.observeCallbackSpy = jasmine.createSpy('observe callback')
493
535
  $field = $form.affix('input[val="old-value"][up-observe="window.observeCallbackSpy()"][up-delay="50"]')
494
536
  up.hello($form)
495
537
  $field.val('new-value')
496
538
  $field.trigger('change')
497
- u.nextFrame ->
498
- expect(window.observeCallbackSpy).not.toHaveBeenCalled()
499
- u.setTimer 80, ->
500
- expect(window.observeCallbackSpy).toHaveBeenCalled()
501
- done()
539
+
540
+ next => expect(window.observeCallbackSpy).not.toHaveBeenCalled()
541
+ next.after 80, => expect(window.observeCallbackSpy).toHaveBeenCalled()
502
542
 
503
543
  describe 'form[up-observe]', ->
504
544
 
505
545
  afterEach ->
506
546
  window.observeCallbackSpy = undefined
507
547
 
508
- it 'runs the JavaScript code in the attribute value when a change is observed in any contained field', (done) ->
548
+ it 'runs the JavaScript code in the attribute value when a change is observed in any contained field', asyncSpec (next) ->
509
549
  window.observeCallbackSpy = jasmine.createSpy('observe callback')
510
550
  $form = affix('form[up-observe="window.observeCallbackSpy(value, $field.get(0))"]')
511
551
  $field1 = $form.affix('input[val="field1-old-value"]')
@@ -513,21 +553,21 @@ describe 'up.form', ->
513
553
  up.hello($form)
514
554
  $field1.val('field1-new-value')
515
555
  $field1.trigger('change')
516
- u.nextFrame ->
556
+
557
+ next =>
517
558
  expect(window.observeCallbackSpy.calls.allArgs()).toEqual [['field1-new-value', $field1.get(0)]]
518
559
 
519
560
  $field2.val('field2-new-value')
520
561
  $field2.trigger('change')
521
562
 
522
- u.nextFrame ->
523
- expect(window.observeCallbackSpy.calls.allArgs()).toEqual [['field1-new-value', $field1.get(0)], ['field2-new-value', $field2.get(0)]]
524
- done()
563
+ next =>
564
+ expect(window.observeCallbackSpy.calls.allArgs()).toEqual [['field1-new-value', $field1.get(0)], ['field2-new-value', $field2.get(0)]]
525
565
 
526
566
  describe 'input[up-validate]', ->
527
567
 
528
568
  describe 'when a selector is given', ->
529
569
 
530
- it "submits the input's form with an 'X-Up-Validate' header and replaces the selector with the response", ->
570
+ it "submits the input's form with an 'X-Up-Validate' header and replaces the selector with the response", asyncSpec (next) ->
531
571
 
532
572
  $form = affix('form[action="/path/to"]')
533
573
  $group = $("""
@@ -537,24 +577,26 @@ describe 'up.form', ->
537
577
  """).appendTo($form)
538
578
  $group.find('input').trigger('change')
539
579
 
540
- request = @lastRequest()
541
- expect(request.requestHeaders['X-Up-Validate']).toEqual('user')
542
- expect(request.requestHeaders['X-Up-Target']).toEqual(".field-group:has([name='user'])")
580
+ next =>
581
+ request = @lastRequest()
582
+ expect(request.requestHeaders['X-Up-Validate']).toEqual('user')
583
+ expect(request.requestHeaders['X-Up-Target']).toEqual(".field-group:has([name='user'])")
543
584
 
544
- @respondWith """
545
- <div class="field-group has-error">
546
- <div class='error'>Username has already been taken</div>
547
- <input name="user" value="judy" up-validate=".field-group:has(&)">
548
- </div>
549
- """
585
+ @respondWith """
586
+ <div class="field-group has-error">
587
+ <div class='error'>Username has already been taken</div>
588
+ <input name="user" value="judy" up-validate=".field-group:has(&)">
589
+ </div>
590
+ """
550
591
 
551
- $group = $('.field-group')
552
- expect($group.length).toBe(1)
553
- expect($group).toHaveClass('has-error')
554
- expect($group).toHaveText('Username has already been taken')
592
+ next =>
593
+ $group = $('.field-group')
594
+ expect($group.length).toBe(1)
595
+ expect($group).toHaveClass('has-error')
596
+ expect($group).toHaveText('Username has already been taken')
555
597
 
556
- it 'does not reveal the updated fragment (bugfix)', ->
557
- revealSpy = up.layout.knife.mock('reveal').and.returnValue(u.resolvedDeferred())
598
+ it 'does not reveal the updated fragment (bugfix)', asyncSpec (next) ->
599
+ revealSpy = up.layout.knife.mock('reveal').and.returnValue(Promise.resolve())
558
600
 
559
601
  $form = affix('form[action="/path/to"]')
560
602
  $group = $("""
@@ -564,21 +606,21 @@ describe 'up.form', ->
564
606
  """).appendTo($form)
565
607
  $group.find('input').trigger('change')
566
608
 
567
- request = @lastRequest()
568
-
569
- @respondWith """
570
- <div class="field-group has-error">
571
- <div class='error'>Username has already been taken</div>
572
- <input name="user" value="judy" up-validate=".field-group:has(&)">
573
- </div>
574
- """
609
+ next =>
610
+ @respondWith """
611
+ <div class="field-group has-error">
612
+ <div class='error'>Username has already been taken</div>
613
+ <input name="user" value="judy" up-validate=".field-group:has(&)">
614
+ </div>
615
+ """
575
616
 
576
- expect(revealSpy).not.toHaveBeenCalled()
617
+ next =>
618
+ expect(revealSpy).not.toHaveBeenCalled()
577
619
 
578
620
 
579
621
  describe 'when no selector is given', ->
580
622
 
581
- it 'automatically finds a form group around the input field and only updates that', ->
623
+ it 'automatically finds a form group around the input field and only updates that', asyncSpec (next) ->
582
624
 
583
625
  @appendFixture """
584
626
  <form action="/users" id="registration">
@@ -596,25 +638,27 @@ describe 'up.form', ->
596
638
 
597
639
  $('#registration input[name=password]').trigger('change')
598
640
 
599
- @respondWith """
600
- <form action="/users" id="registration">
641
+ next =>
642
+ @respondWith """
643
+ <form action="/users" id="registration">
601
644
 
602
- <label>
603
- Validation message
604
- <input type="text" name="email" up-validate />
605
- </label>
645
+ <label>
646
+ Validation message
647
+ <input type="text" name="email" up-validate />
648
+ </label>
606
649
 
607
- <label>
608
- Validation message
609
- <input type="password" name="password" up-validate />
610
- </label>
650
+ <label>
651
+ Validation message
652
+ <input type="password" name="password" up-validate />
653
+ </label>
611
654
 
612
- </form>
613
- """
655
+ </form>
656
+ """
614
657
 
615
- $labels = $('#registration label')
616
- expect($labels[0]).not.toHaveText('Validation message')
617
- expect($labels[1]).toHaveText('Validation message')
658
+ next =>
659
+ $labels = $('#registration label')
660
+ expect($labels[0]).not.toHaveText('Validation message')
661
+ expect($labels[1]).toHaveText('Validation message')
618
662
 
619
663
  describe '[up-switch]', ->
620
664
 
@@ -627,80 +671,120 @@ describe 'up.form', ->
627
671
  @$barOption = @$select.affix('option[value="bar"]').text('Bar')
628
672
  @$bazOption = @$select.affix('option[value="baz"]').text('Baz')
629
673
 
630
- it "shows the target element iff its up-show-for attribute contains the select value", ->
674
+ it "shows the target element iff its up-show-for attribute contains the select value", asyncSpec (next) ->
631
675
  $target = affix('.target[up-show-for="something bar other"]')
632
676
  up.hello(@$select)
633
- expect($target).toBeHidden()
634
- @$select.val('bar').change()
635
- expect($target).toBeVisible()
636
677
 
637
- it "shows the target element iff its up-hide-for attribute doesn't contain the select value", ->
678
+ next =>
679
+ expect($target).toBeHidden()
680
+ @$select.val('bar').change()
681
+
682
+ next =>
683
+ expect($target).toBeVisible()
684
+
685
+ it "shows the target element iff its up-hide-for attribute doesn't contain the select value", asyncSpec (next) ->
638
686
  $target = affix('.target[up-hide-for="something bar other"]')
639
687
  up.hello(@$select)
640
- expect($target).toBeVisible()
641
- @$select.val('bar').change()
642
- expect($target).toBeHidden()
643
688
 
644
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the select value is present", ->
689
+ next =>
690
+ expect($target).toBeVisible()
691
+ @$select.val('bar').change()
692
+
693
+ next =>
694
+ expect($target).toBeHidden()
695
+
696
+ it "shows the target element iff it has neither up-show-for nor up-hide-for and the select value is present", asyncSpec (next) ->
645
697
  $target = affix('.target')
646
698
  up.hello(@$select)
647
- expect($target).toBeHidden()
648
- @$select.val('bar').change()
649
- expect($target).toBeVisible()
650
699
 
651
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the select value is present", ->
700
+ next =>
701
+ expect($target).toBeHidden()
702
+ @$select.val('bar').change()
703
+
704
+ next =>
705
+ expect($target).toBeVisible()
706
+
707
+ it "shows the target element iff its up-show-for attribute contains a value ':present' and the select value is present", asyncSpec (next) ->
652
708
  $target = affix('.target[up-show-for=":present"]')
653
709
  up.hello(@$select)
654
- expect($target).toBeHidden()
655
- @$select.val('bar').change()
656
- expect($target).toBeVisible()
657
710
 
658
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the select value is blank", ->
711
+ next =>
712
+ expect($target).toBeHidden()
713
+ @$select.val('bar').change()
714
+
715
+ next =>
716
+ expect($target).toBeVisible()
717
+
718
+ it "shows the target element iff its up-show-for attribute contains a value ':blank' and the select value is blank", asyncSpec (next) ->
659
719
  $target = affix('.target[up-show-for=":blank"]')
660
720
  up.hello(@$select)
661
- expect($target).toBeVisible()
662
- @$select.val('bar').change()
663
- expect($target).toBeHidden()
721
+
722
+ next =>
723
+ expect($target).toBeVisible()
724
+ @$select.val('bar').change()
725
+
726
+ next =>
727
+ expect($target).toBeHidden()
664
728
 
665
729
  describe 'on a checkbox', ->
666
730
 
667
731
  beforeEach ->
668
732
  @$checkbox = affix('input[type="checkbox"][value="1"][up-switch=".target"]')
669
733
 
670
- it "shows the target element iff its up-show-for attribute is :checked and the checkbox is checked", ->
734
+ it "shows the target element iff its up-show-for attribute is :checked and the checkbox is checked", asyncSpec (next) ->
671
735
  $target = affix('.target[up-show-for=":checked"]')
672
736
  up.hello(@$checkbox)
673
- expect($target).toBeHidden()
674
- @$checkbox.prop('checked', true).change()
675
- expect($target).toBeVisible()
676
737
 
677
- it "shows the target element iff its up-show-for attribute is :unchecked and the checkbox is unchecked", ->
738
+ next =>
739
+ expect($target).toBeHidden()
740
+ @$checkbox.prop('checked', true).change()
741
+
742
+ next =>
743
+ expect($target).toBeVisible()
744
+
745
+ it "shows the target element iff its up-show-for attribute is :unchecked and the checkbox is unchecked", asyncSpec (next) ->
678
746
  $target = affix('.target[up-show-for=":unchecked"]')
679
747
  up.hello(@$checkbox)
680
- expect($target).toBeVisible()
681
- @$checkbox.prop('checked', true).change()
682
- expect($target).toBeHidden()
683
748
 
684
- it "shows the target element iff its up-hide-for attribute is :checked and the checkbox is unchecked", ->
749
+ next =>
750
+ expect($target).toBeVisible()
751
+ @$checkbox.prop('checked', true).change()
752
+
753
+ next =>
754
+ expect($target).toBeHidden()
755
+
756
+ it "shows the target element iff its up-hide-for attribute is :checked and the checkbox is unchecked", asyncSpec (next) ->
685
757
  $target = affix('.target[up-hide-for=":checked"]')
686
758
  up.hello(@$checkbox)
687
- expect($target).toBeVisible()
688
- @$checkbox.prop('checked', true).change()
689
- expect($target).toBeHidden()
690
759
 
691
- it "shows the target element iff its up-hide-for attribute is :unchecked and the checkbox is checked", ->
760
+ next =>
761
+ expect($target).toBeVisible()
762
+ @$checkbox.prop('checked', true).change()
763
+
764
+ next =>
765
+ expect($target).toBeHidden()
766
+
767
+ it "shows the target element iff its up-hide-for attribute is :unchecked and the checkbox is checked", asyncSpec (next) ->
692
768
  $target = affix('.target[up-hide-for=":unchecked"]')
693
769
  up.hello(@$checkbox)
694
- expect($target).toBeHidden()
695
- @$checkbox.prop('checked', true).change()
696
- expect($target).toBeVisible()
697
770
 
698
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the checkbox is checked", ->
771
+ next =>
772
+ expect($target).toBeHidden()
773
+ @$checkbox.prop('checked', true).change()
774
+
775
+ next =>
776
+ expect($target).toBeVisible()
777
+
778
+ it "shows the target element iff it has neither up-show-for nor up-hide-for and the checkbox is checked", asyncSpec (next) ->
699
779
  $target = affix('.target')
700
780
  up.hello(@$checkbox)
701
- expect($target).toBeHidden()
702
- @$checkbox.prop('checked', true).change()
703
- expect($target).toBeVisible()
781
+
782
+ next =>
783
+ expect($target).toBeHidden()
784
+ @$checkbox.prop('checked', true).change()
785
+
786
+ next =>
787
+ expect($target).toBeVisible()
704
788
 
705
789
  describe 'on a group of radio buttons', ->
706
790
 
@@ -711,119 +795,174 @@ describe 'up.form', ->
711
795
  @$barButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('bar')
712
796
  @$bazkButton = @$buttons.affix('input[type="radio"][name="group"][up-switch=".target"]').val('baz')
713
797
 
714
- it "shows the target element iff its up-show-for attribute contains the selected button value", ->
798
+ it "shows the target element iff its up-show-for attribute contains the selected button value", asyncSpec (next) ->
715
799
  $target = affix('.target[up-show-for="something bar other"]')
716
800
  up.hello(@$buttons)
717
- expect($target).toBeHidden()
718
- @$barButton.prop('checked', true).change()
719
- expect($target).toBeVisible()
720
801
 
721
- it "shows the target element iff its up-hide-for attribute doesn't contain the selected button value", ->
802
+ next =>
803
+ expect($target).toBeHidden()
804
+ @$barButton.prop('checked', true).change()
805
+
806
+ next =>
807
+ expect($target).toBeVisible()
808
+
809
+ it "shows the target element iff its up-hide-for attribute doesn't contain the selected button value", asyncSpec (next) ->
722
810
  $target = affix('.target[up-hide-for="something bar other"]')
723
811
  up.hello(@$buttons)
724
- expect($target).toBeVisible()
725
- @$barButton.prop('checked', true).change()
726
- expect($target).toBeHidden()
727
812
 
728
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the selected button value is present", ->
813
+ next =>
814
+ expect($target).toBeVisible()
815
+ @$barButton.prop('checked', true).change()
816
+
817
+ next =>
818
+ expect($target).toBeHidden()
819
+
820
+ it "shows the target element iff it has neither up-show-for nor up-hide-for and the selected button value is present", asyncSpec (next) ->
729
821
  $target = affix('.target')
730
822
  up.hello(@$buttons)
731
- expect($target).toBeHidden()
732
- @$barButton.prop('checked', true).change()
733
- expect($target).toBeVisible()
734
823
 
735
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the selected button value is present", ->
824
+ next =>
825
+ expect($target).toBeHidden()
826
+ @$barButton.prop('checked', true).change()
827
+
828
+ next =>
829
+ expect($target).toBeVisible()
830
+
831
+ it "shows the target element iff its up-show-for attribute contains a value ':present' and the selected button value is present", asyncSpec (next) ->
736
832
  $target = affix('.target[up-show-for=":present"]')
737
833
  up.hello(@$buttons)
738
- expect($target).toBeHidden()
739
- @$blankButton.prop('checked', true).change()
740
- expect($target).toBeHidden()
741
- @$barButton.prop('checked', true).change()
742
- expect($target).toBeVisible()
743
834
 
744
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the selected button value is blank", ->
835
+ next =>
836
+ expect($target).toBeHidden()
837
+ @$blankButton.prop('checked', true).change()
838
+
839
+ next =>
840
+ expect($target).toBeHidden()
841
+ @$barButton.prop('checked', true).change()
842
+
843
+ next =>
844
+ expect($target).toBeVisible()
845
+
846
+ it "shows the target element iff its up-show-for attribute contains a value ':blank' and the selected button value is blank", asyncSpec (next) ->
745
847
  $target = affix('.target[up-show-for=":blank"]')
746
848
  up.hello(@$buttons)
747
- expect($target).toBeVisible()
748
- @$blankButton.prop('checked', true).change()
749
- expect($target).toBeVisible()
750
- @$barButton.prop('checked', true).change()
751
- expect($target).toBeHidden()
752
849
 
753
- it "shows the target element iff its up-show-for attribute contains a value ':checked' and any button is checked", ->
850
+ next =>
851
+ expect($target).toBeVisible()
852
+ @$blankButton.prop('checked', true).change()
853
+
854
+ next =>
855
+ expect($target).toBeVisible()
856
+ @$barButton.prop('checked', true).change()
857
+
858
+ next =>
859
+ expect($target).toBeHidden()
860
+
861
+ it "shows the target element iff its up-show-for attribute contains a value ':checked' and any button is checked", asyncSpec (next) ->
754
862
  $target = affix('.target[up-show-for=":checked"]')
755
863
  up.hello(@$buttons)
756
- expect($target).toBeHidden()
757
- @$blankButton.prop('checked', true).change()
758
- expect($target).toBeVisible()
759
864
 
760
- it "shows the target element iff its up-show-for attribute contains a value ':unchecked' and no button is checked", ->
865
+ next =>
866
+ expect($target).toBeHidden()
867
+ @$blankButton.prop('checked', true).change()
868
+
869
+ next =>
870
+ expect($target).toBeVisible()
871
+
872
+ it "shows the target element iff its up-show-for attribute contains a value ':unchecked' and no button is checked", asyncSpec (next) ->
761
873
  $target = affix('.target[up-show-for=":unchecked"]')
762
874
  up.hello(@$buttons)
763
- expect($target).toBeVisible()
764
- @$blankButton.prop('checked', true).change()
765
- expect($target).toBeHidden()
875
+
876
+ next =>
877
+ expect($target).toBeVisible()
878
+ @$blankButton.prop('checked', true).change()
879
+
880
+ next =>
881
+ expect($target).toBeHidden()
766
882
 
767
883
  describe 'on a text input', ->
768
884
 
769
885
  beforeEach ->
770
886
  @$textInput = affix('input[type="text"][up-switch=".target"]')
771
887
 
772
- it "shows the target element iff its up-show-for attribute contains the input value", ->
888
+ it "shows the target element iff its up-show-for attribute contains the input value", asyncSpec (next) ->
773
889
  $target = affix('.target[up-show-for="something bar other"]')
774
890
  up.hello(@$textInput)
775
- expect($target).toBeHidden()
776
- @$textInput.val('bar').change()
777
- expect($target).toBeVisible()
778
891
 
779
- it "shows the target element iff its up-hide-for attribute doesn't contain the input value", ->
892
+ next =>
893
+ expect($target).toBeHidden()
894
+ @$textInput.val('bar').change()
895
+
896
+ next =>
897
+ expect($target).toBeVisible()
898
+
899
+ it "shows the target element iff its up-hide-for attribute doesn't contain the input value", asyncSpec (next) ->
780
900
  $target = affix('.target[up-hide-for="something bar other"]')
781
901
  up.hello(@$textInput)
782
- expect($target).toBeVisible()
783
- @$textInput.val('bar').change()
784
- expect($target).toBeHidden()
785
902
 
786
- it "shows the target element iff it has neither up-show-for nor up-hide-for and the input value is present", ->
903
+ next =>
904
+ expect($target).toBeVisible()
905
+ @$textInput.val('bar').change()
906
+
907
+ next =>
908
+ expect($target).toBeHidden()
909
+
910
+ it "shows the target element iff it has neither up-show-for nor up-hide-for and the input value is present", asyncSpec (next) ->
787
911
  $target = affix('.target')
788
912
  up.hello(@$textInput)
789
- expect($target).toBeHidden()
790
- @$textInput.val('bar').change()
791
- expect($target).toBeVisible()
792
913
 
793
- it "shows the target element iff its up-show-for attribute contains a value ':present' and the input value is present", ->
914
+ next =>
915
+ expect($target).toBeHidden()
916
+ @$textInput.val('bar').change()
917
+
918
+ next =>
919
+ expect($target).toBeVisible()
920
+
921
+ it "shows the target element iff its up-show-for attribute contains a value ':present' and the input value is present", asyncSpec (next) ->
794
922
  $target = affix('.target[up-show-for=":present"]')
795
923
  up.hello(@$textInput)
796
- expect($target).toBeHidden()
797
- @$textInput.val('bar').change()
798
- expect($target).toBeVisible()
799
924
 
800
- it "shows the target element iff its up-show-for attribute contains a value ':blank' and the input value is blank", ->
925
+ next =>
926
+ expect($target).toBeHidden()
927
+ @$textInput.val('bar').change()
928
+
929
+ next =>
930
+ expect($target).toBeVisible()
931
+
932
+ it "shows the target element iff its up-show-for attribute contains a value ':blank' and the input value is blank", asyncSpec (next) ->
801
933
  $target = affix('.target[up-show-for=":blank"]')
802
934
  up.hello(@$textInput)
803
- expect($target).toBeVisible()
804
- @$textInput.val('bar').change()
805
- expect($target).toBeHidden()
935
+
936
+ next =>
937
+ expect($target).toBeVisible()
938
+ @$textInput.val('bar').change()
939
+
940
+ next =>
941
+ expect($target).toBeHidden()
806
942
 
807
943
  describe 'when an [up-show-for] element is dynamically inserted later', ->
808
944
 
809
- it "shows the element iff it matches the [up-switch] control's value", ->
945
+ it "shows the element iff it matches the [up-switch] control's value", asyncSpec (next) ->
810
946
  $select = affix('select[up-switch=".target"]')
811
947
  $select.affix('option[value="foo"]').text('Foo')
812
948
  $select.affix('option[value="bar"]').text('Bar')
813
949
  $select.val('foo')
814
950
  up.hello($select)
815
951
 
816
- # New target enters the DOM after [up-switch] has been compiled
817
- $target = affix('.target[up-show-for="bar"]')
818
- up.hello($target)
952
+ next =>
953
+ # New target enters the DOM after [up-switch] has been compiled
954
+ @$target = affix('.target[up-show-for="bar"]')
955
+ up.hello(@$target)
819
956
 
820
- expect($target).toBeHidden()
957
+ next =>
958
+ expect(@$target).toBeHidden()
821
959
 
822
- # Check that the new element will notify subsequent changes
823
- $select.val('bar').change()
824
- expect($target).toBeVisible()
960
+ next =>
961
+ # Check that the new element will notify subsequent changes
962
+ $select.val('bar').change()
963
+ expect(@$target).toBeVisible()
825
964
 
826
- it "doesn't re-switch targets that were part of the original compile run", ->
965
+ it "doesn't re-switch targets that were part of the original compile run", asyncSpec (next) ->
827
966
  $container = affix('.container')
828
967
 
829
968
  $select = $container.affix('select[up-switch=".target"]')
@@ -836,10 +975,12 @@ describe 'up.form', ->
836
975
 
837
976
  up.hello($container)
838
977
 
839
- # New target enters the DOM after [up-switch] has been compiled
840
- $lateTarget = $container.affix('.target.late[up-show-for="bar"]')
841
- up.hello($lateTarget)
978
+ next =>
979
+ # New target enters the DOM after [up-switch] has been compiled
980
+ @$lateTarget = $container.affix('.target.late[up-show-for="bar"]')
981
+ up.hello(@$lateTarget)
842
982
 
843
- expect(switchTargetSpy.calls.count()).toBe(2)
844
- expect(switchTargetSpy.calls.argsFor(0)[0]).toEqual($existingTarget)
845
- expect(switchTargetSpy.calls.argsFor(1)[0]).toEqual($lateTarget)
983
+ next =>
984
+ expect(switchTargetSpy.calls.count()).toBe(2)
985
+ expect(switchTargetSpy.calls.argsFor(0)[0]).toEqual($existingTarget)
986
+ expect(switchTargetSpy.calls.argsFor(1)[0]).toEqual(@$lateTarget)