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
@@ -21,21 +21,37 @@ describe 'up.rails', ->
21
21
  describe "on an [#{upAttribute}] element", ->
22
22
 
23
23
  it "is transformed to an up-method attribute so the element isn't handled a second time by Rails UJS", ->
24
- $element = affix("span[#{upAttribute}][data-method=\"put\"]")
24
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][data-method=\"put\"]")
25
25
  up.hello($element)
26
26
  expect($element.attr('data-method')).toBeUndefined()
27
27
  expect($element.attr('up-method')).toEqual('put')
28
28
 
29
29
  it "does not overwrite an existing up-method attribute, but gets deleted", ->
30
- $element = affix("span[#{upAttribute}][up-method=\"patch\"][data-method=\"put\"]")
30
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][up-method=\"patch\"][data-method=\"put\"]")
31
31
  up.hello($element)
32
32
  expect($element.attr('data-method')).toBeUndefined()
33
33
  expect($element.attr('up-method')).toEqual('patch')
34
34
 
35
+ it 'transforms an element that becomes followable through [up-expand]', ->
36
+ $element = affix('a[up-expand][data-method="put"]')
37
+ $child = $element.affix('span[up-href="/foo"][up-follow]')
38
+ up.hello($element)
39
+ expect($element.attr('up-href')).toEqual('/foo')
40
+ expect($element.attr('up-follow')).toEqual('')
41
+ expect($element.attr('data-method')).toBeUndefined()
42
+ expect($element.attr('up-method')).toEqual('put')
43
+
44
+ it 'transforms an element that becomes followable through a user macro like [content-link]', ->
45
+ up.macro '[user-make-followable]', ($element) -> $element.attr('up-follow', '')
46
+ $element = affix('a[user-make-followable][data-method="put"]')
47
+ up.hello($element)
48
+ expect($element.attr('data-method')).toBeUndefined()
49
+ expect($element.attr('up-method')).toEqual('put')
50
+
35
51
  describe 'on an element without Unpoly attributes', ->
36
52
 
37
53
  it "is not changed", ->
38
- $element = affix("span[data-method=\"put\"]")
54
+ $element = affix("a[href=\"/foo\"][data-method=\"put\"]")
39
55
  up.hello($element)
40
56
  expect($element.attr('data-method')).toEqual('put')
41
57
 
@@ -48,7 +64,7 @@ describe 'up.rails', ->
48
64
  describe "on an [#{upAttribute}] element", ->
49
65
 
50
66
  it "is not changed", ->
51
- $element = affix("span[#{upAttribute}][data-method=\"put\"]")
67
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][data-method=\"put\"]")
52
68
  up.hello($element)
53
69
  expect($element.attr('data-method')).toEqual('put')
54
70
 
@@ -69,13 +85,13 @@ describe 'up.rails', ->
69
85
  describe "on an [#{upAttribute}] element", ->
70
86
 
71
87
  it "is transformed to an up-confirm attribute so the element isn't handled a second time by Rails UJS", ->
72
- $element = affix("span[#{upAttribute}][data-confirm=\"Really?\"]")
88
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][data-confirm=\"Really?\"]")
73
89
  up.hello($element)
74
90
  expect($element.attr('data-confirm')).toBeUndefined()
75
91
  expect($element.attr('up-confirm')).toEqual('Really?')
76
92
 
77
93
  it "does not overwrite an existing up-confirm attribute, but gets deleted", ->
78
- $element = affix("span[#{upAttribute}][up-confirm=\"Seriously?\"][data-confirm=\"Really?\"]")
94
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][up-confirm=\"Seriously?\"][data-confirm=\"Really?\"]")
79
95
  up.hello($element)
80
96
  expect($element.attr('data-confirm')).toBeUndefined()
81
97
  expect($element.attr('up-confirm')).toEqual('Seriously?')
@@ -83,7 +99,7 @@ describe 'up.rails', ->
83
99
  describe 'on an element without Unpoly attributes', ->
84
100
 
85
101
  it "is not changed", ->
86
- $element = affix("span[data-confirm=\"Really?\"]")
102
+ $element = affix("a[href=\"/foo\"][data-confirm=\"Really?\"]")
87
103
  up.hello($element)
88
104
  expect($element.attr('data-confirm')).toEqual('Really?')
89
105
 
@@ -96,6 +112,6 @@ describe 'up.rails', ->
96
112
  describe "on an [#{upAttribute}] element", ->
97
113
 
98
114
  it "is not changed", ->
99
- $element = affix("span[#{upAttribute}][data-confirm=\"Really?\"]")
115
+ $element = affix("a[href=\"/foo\"][#{upAttribute}][data-confirm=\"Really?\"]")
100
116
  up.hello($element)
101
117
  expect($element.attr('data-confirm')).toEqual('Really?')
@@ -17,44 +17,55 @@ describe 'up.syntax', ->
17
17
 
18
18
  describe 'destructors', ->
19
19
 
20
- it 'allows compilers to return a function to call when the compiled element is destroyed', ->
20
+ it 'allows compilers to return a function to call when the compiled element is destroyed', asyncSpec (next) ->
21
21
  destructor = jasmine.createSpy('destructor')
22
22
  up.compiler '.child', ($element) ->
23
23
  destructor
24
24
 
25
25
  up.hello(affix('.container .child'))
26
- expect(destructor).not.toHaveBeenCalled()
27
26
 
28
- up.destroy('.container')
29
- expect(destructor).toHaveBeenCalled()
27
+ next =>
28
+ expect(destructor).not.toHaveBeenCalled()
29
+ up.destroy('.container')
30
30
 
31
- it 'allows compilers to return an array of functions to all when the compiled element is destroyed', ->
31
+ next =>
32
+ expect(destructor).toHaveBeenCalled()
33
+
34
+ it 'allows compilers to return an array of functions to call when the compiled element is destroyed', asyncSpec (next) ->
32
35
  destructor1 = jasmine.createSpy('destructor1')
33
36
  destructor2 = jasmine.createSpy('destructor2')
34
37
  up.compiler '.child', ($element) ->
35
38
  [ destructor1, destructor2 ]
36
39
 
37
40
  up.hello(affix('.container .child'))
38
- expect(destructor1).not.toHaveBeenCalled()
39
- expect(destructor2).not.toHaveBeenCalled()
40
41
 
41
- up.destroy('.container')
42
- expect(destructor1).toHaveBeenCalled()
43
- expect(destructor2).toHaveBeenCalled()
42
+ next =>
43
+ expect(destructor1).not.toHaveBeenCalled()
44
+ expect(destructor2).not.toHaveBeenCalled()
45
+
46
+ up.destroy('.container')
44
47
 
45
- it "does not consider a returned array to be a destructor unless it's comprised entirely of functions", ->
48
+ next =>
49
+ expect(destructor1).toHaveBeenCalled()
50
+ expect(destructor2).toHaveBeenCalled()
51
+
52
+ it "does not consider a returned array to be a destructor unless it's comprised entirely of functions", asyncSpec (next) ->
46
53
  value1 = jasmine.createSpy('non-destructor')
47
54
  value2 = 'two'
48
55
  up.compiler '.child', ($element) ->
49
56
  [ value1, value2 ]
50
57
 
51
58
  up.hello(affix('.container .child'))
52
- expect(value1).not.toHaveBeenCalled()
53
59
 
54
- up.destroy('.container')
55
- expect(value1).not.toHaveBeenCalled()
60
+ next =>
61
+ expect(value1).not.toHaveBeenCalled()
62
+
63
+ up.destroy('.container')
56
64
 
57
- it 'runs all destructors if multiple compilers are applied to the same element', ->
65
+ next =>
66
+ expect(value1).not.toHaveBeenCalled()
67
+
68
+ it 'runs all destructors if multiple compilers are applied to the same element', asyncSpec (next) ->
58
69
  destructor1 = jasmine.createSpy('destructor1')
59
70
  up.compiler '.one', ($element) -> destructor1
60
71
  destructor2 = jasmine.createSpy('destructor2')
@@ -62,22 +73,28 @@ describe 'up.syntax', ->
62
73
 
63
74
  $element = affix('.one.two')
64
75
  up.hello($element)
65
- expect(destructor1).not.toHaveBeenCalled()
66
- expect(destructor2).not.toHaveBeenCalled()
67
76
 
68
- up.destroy($element)
69
- expect(destructor1).toHaveBeenCalled()
70
- expect(destructor2).toHaveBeenCalled()
77
+ next =>
78
+ expect(destructor1).not.toHaveBeenCalled()
79
+ expect(destructor2).not.toHaveBeenCalled()
80
+
81
+ up.destroy($element)
71
82
 
72
- it 'does not throw an error if both container and child have a destructor, and the container gets destroyed', ->
83
+ next =>
84
+ expect(destructor1).toHaveBeenCalled()
85
+ expect(destructor2).toHaveBeenCalled()
86
+
87
+ it 'does not throw an error if both container and child have a destructor, and the container gets destroyed', asyncSpec (next) ->
73
88
  up.compiler '.container', ($element) ->
74
89
  return (->)
75
90
 
76
91
  up.compiler '.child', ($element) ->
77
92
  return (->)
78
93
 
79
- destruction = -> up.destroy('.container')
80
- expect(destruction).not.toThrowError()
94
+ promise = up.destroy('.container')
95
+
96
+ promiseState(promise).then (result) ->
97
+ expect(result.state).toEqual('fulfilled')
81
98
 
82
99
  it 'parses an up-data attribute as JSON and passes the parsed object as a second argument to the initializer', ->
83
100
 
@@ -6,23 +6,26 @@ describe 'up.tooltip', ->
6
6
 
7
7
  describe 'up.tooltip.attach', ->
8
8
 
9
- it 'opens a tooltip with the given text', ->
9
+ it 'opens a tooltip with the given text', (done) ->
10
10
  $link = affix('span')
11
- up.tooltip.attach($link, html: 'tooltip text')
12
- $tooltip = $('.up-tooltip')
13
- expect($tooltip).toHaveText('tooltip text')
11
+ up.tooltip.attach($link, html: 'tooltip text').then ->
12
+ $tooltip = $('.up-tooltip')
13
+ expect($tooltip).toHaveText('tooltip text')
14
+ done()
14
15
 
15
- it 'allows HTML for the tooltip text when contents are given as { html } option', ->
16
+ it 'allows HTML for the tooltip text when contents are given as { html } option', (done) ->
16
17
  $link = affix('span')
17
- up.tooltip.attach($link, html: '<b>text</b>')
18
- $tooltip = $('.up-tooltip')
19
- expect($tooltip.html()).toEqual('<b>text</b>')
18
+ up.tooltip.attach($link, html: '<b>text</b>').then ->
19
+ $tooltip = $('.up-tooltip')
20
+ expect($tooltip.html()).toEqual('<b>text</b>')
21
+ done()
20
22
 
21
- it 'escapes HTML for the tooltip text when contents given as { text } option', ->
23
+ it 'escapes HTML for the tooltip text when contents given as { text } option', (done) ->
22
24
  $link = affix('span')
23
- up.tooltip.attach($link, text: '<b>text</b>')
24
- $tooltip = $('.up-tooltip')
25
- expect($tooltip.html()).toEqual('&lt;b&gt;text&lt;/b&gt;')
25
+ up.tooltip.attach($link, text: '<b>text</b>').then ->
26
+ $tooltip = $('.up-tooltip')
27
+ expect($tooltip.html()).toEqual('&lt;b&gt;text&lt;/b&gt;')
28
+ done()
26
29
 
27
30
  describe 'positioning', ->
28
31
 
@@ -44,58 +47,61 @@ describe 'up.tooltip', ->
44
47
 
45
48
  describe 'with { position: "top" }', ->
46
49
 
47
- it 'centers the tooltip above the given element', ->
50
+ it 'centers the tooltip above the given element', (done) ->
48
51
  @linkBox = @$link.get(0).getBoundingClientRect()
49
- up.tooltip.attach(@$link, html: 'tooltip text', position: 'top')
50
- $tooltip = $('.up-tooltip')
51
- tooltipBox = $tooltip.get(0).getBoundingClientRect()
52
- expect(tooltipBox.top).toBeAround(@linkBox.top - tooltipBox.height, 15)
53
- expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
52
+ up.tooltip.attach(@$link, html: 'tooltip text', position: 'top').then =>
53
+ $tooltip = $('.up-tooltip')
54
+ tooltipBox = $tooltip.get(0).getBoundingClientRect()
55
+ expect(tooltipBox.top).toBeAround(@linkBox.top - tooltipBox.height, 15)
56
+ expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
57
+ done()
54
58
 
55
59
  describe 'with { position: "right" }', ->
56
60
 
57
- it 'centers the tooltip at the right side of the given element', ->
61
+ it 'centers the tooltip at the right side of the given element', (done) ->
58
62
  @linkBox = @$link.get(0).getBoundingClientRect()
59
- up.tooltip.attach(@$link, html: 'tooltip text', position: 'right')
60
- $tooltip = $('.up-tooltip')
61
- tooltipBox = $tooltip.get(0).getBoundingClientRect()
62
- expect(tooltipBox.top).toBeAround(@linkBox.top + 0.5 * (@linkBox.height - tooltipBox.height), 15)
63
- expect(tooltipBox.left).toBeAround(@linkBox.left + @linkBox.width, 15)
63
+ up.tooltip.attach(@$link, html: 'tooltip text', position: 'right').then =>
64
+ $tooltip = $('.up-tooltip')
65
+ tooltipBox = $tooltip.get(0).getBoundingClientRect()
66
+ expect(tooltipBox.top).toBeAround(@linkBox.top + 0.5 * (@linkBox.height - tooltipBox.height), 15)
67
+ expect(tooltipBox.left).toBeAround(@linkBox.left + @linkBox.width, 15)
68
+ done()
64
69
 
65
70
  describe 'with { position: "bottom" }', ->
66
71
 
67
- it 'centers the tooltip below the given element', ->
72
+ it 'centers the tooltip below the given element', (done) ->
68
73
  @linkBox = @$link.get(0).getBoundingClientRect()
69
- up.tooltip.attach(@$link, html: 'tooltip text', position: 'bottom')
70
- $tooltip = $('.up-tooltip')
71
- tooltipBox = $tooltip.get(0).getBoundingClientRect()
72
- expect(tooltipBox.top).toBeAround(@linkBox.top + @linkBox.height, 15)
73
- expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
74
+ up.tooltip.attach(@$link, html: 'tooltip text', position: 'bottom').then =>
75
+ $tooltip = $('.up-tooltip')
76
+ tooltipBox = $tooltip.get(0).getBoundingClientRect()
77
+ expect(tooltipBox.top).toBeAround(@linkBox.top + @linkBox.height, 15)
78
+ expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
79
+ done()
74
80
 
75
81
  describe 'with { position: "left" }', ->
76
82
 
77
- it 'centers the tooltip at the left side of the given element', ->
83
+ it 'centers the tooltip at the left side of the given element', (done) ->
78
84
  @linkBox = @$link.get(0).getBoundingClientRect()
79
- up.tooltip.attach(@$link, html: 'tooltip text', position: 'left')
80
- $tooltip = $('.up-tooltip')
81
- tooltipBox = $tooltip.get(0).getBoundingClientRect()
82
- expect(tooltipBox.top).toBeAround(@linkBox.top + 0.5 * (@linkBox.height - tooltipBox.height), 15)
83
- expect(tooltipBox.left).toBeAround(@linkBox.left - tooltipBox.width, 15)
84
-
85
- it 'gives the tooltip { position: "fixed" } if the given link is fixed', ->
85
+ up.tooltip.attach(@$link, html: 'tooltip text', position: 'left').then =>
86
+ $tooltip = $('.up-tooltip')
87
+ tooltipBox = $tooltip.get(0).getBoundingClientRect()
88
+ expect(tooltipBox.top).toBeAround(@linkBox.top + 0.5 * (@linkBox.height - tooltipBox.height), 15)
89
+ expect(tooltipBox.left).toBeAround(@linkBox.left - tooltipBox.width, 15)
90
+ done()
91
+
92
+ it 'gives the tooltip { position: "fixed" } if the given link is fixed', (done) ->
86
93
  # Let's test the harder case where the document is scrolled
87
94
  up.layout.scroll(document, 50)
88
95
  @$link.css(position: 'fixed')
89
96
  @linkBox = @$link.get(0).getBoundingClientRect()
90
97
 
91
- up.tooltip.attach(@$link, html: 'tooltip text', position: 'top')
92
- $tooltip = $('.up-tooltip')
93
- tooltipBox = $tooltip.get(0).getBoundingClientRect()
94
-
95
- expect($tooltip.css('position')).toEqual('fixed')
96
- expect(tooltipBox.top).toBeAround(@linkBox.top - tooltipBox.height, 15)
97
- expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
98
-
98
+ up.tooltip.attach(@$link, html: 'tooltip text', position: 'top').then =>
99
+ $tooltip = $('.up-tooltip')
100
+ tooltipBox = $tooltip.get(0).getBoundingClientRect()
101
+ expect($tooltip.css('position')).toEqual('fixed')
102
+ expect(tooltipBox.top).toBeAround(@linkBox.top - tooltipBox.height, 15)
103
+ expect(tooltipBox.left).toBeAround(@linkBox.left + 0.5 * (@linkBox.width - tooltipBox.width), 15)
104
+ done()
99
105
 
100
106
  it 'closes an existing tooltip'
101
107
 
@@ -122,44 +128,52 @@ describe 'up.tooltip', ->
122
128
  beforeEach ->
123
129
  up.motion.config.enabled = false
124
130
 
125
- it 'closes the tooltip', (done) ->
131
+ it 'closes the tooltip', asyncSpec (next) ->
126
132
  $link = affix('.link')
127
133
  up.tooltip.attach($link, text: 'Tooltip text')
128
- expect(up.tooltip.isOpen()).toBe(true)
129
- Trigger.clickSequence($('body'))
130
- u.nextFrame ->
134
+
135
+ next =>
136
+ expect(up.tooltip.isOpen()).toBe(true)
137
+ Trigger.clickSequence($('body'))
138
+
139
+ next =>
131
140
  expect(up.tooltip.isOpen()).toBe(false)
132
- done()
133
141
 
134
- it 'closes the tooltip when a an [up-instant] link removes its parent (and thus a click event never bubbles up to the document)', (done) ->
142
+ it 'closes the tooltip when a an [up-instant] link removes its parent (and thus a click event never bubbles up to the document)', asyncSpec (next) ->
135
143
  $parent = affix('.parent')
136
144
  $parentReplacingLink = $parent.affix('a[href="/foo"][up-target=".parent"][up-instant]')
137
145
  $tooltipOpener = affix('.link')
138
146
  up.tooltip.attach($tooltipOpener, text: 'Tooltip text')
139
- expect(up.tooltip.isOpen()).toBe(true)
140
- Trigger.clickSequence($parentReplacingLink)
141
- u.nextFrame ->
147
+
148
+ next =>
149
+ expect(up.tooltip.isOpen()).toBe(true)
150
+ Trigger.clickSequence($parentReplacingLink)
151
+
152
+ next =>
142
153
  expect(up.tooltip.isOpen()).toBe(false)
143
- done()
144
154
 
145
- it 'closes a tooltip when the user clicks on an [up-target] link outside the tooltip', (done) ->
155
+ it 'closes a tooltip when the user clicks on an [up-target] link outside the tooltip', asyncSpec (next) ->
146
156
  $target = affix('.target')
147
157
  $outsideLink = affix('a[href="/foo"][up-target=".target"]')
148
158
  $tooltipOpener = affix('.link')
149
159
  up.tooltip.attach($tooltipOpener, text: 'Tooltip text')
150
- expect(up.tooltip.isOpen()).toBe(true)
151
- Trigger.clickSequence($outsideLink)
152
- u.nextFrame ->
160
+
161
+ next =>
162
+ expect(up.tooltip.isOpen()).toBe(true)
163
+ Trigger.clickSequence($outsideLink)
164
+
165
+ next =>
153
166
  expect(up.tooltip.isOpen()).toBe(false)
154
- done()
155
167
 
156
- it 'closes a tooltip when the user clicks on an [up-instant] link outside the tooltip', (done) ->
168
+ it 'closes a tooltip when the user clicks on an [up-instant] link outside the tooltip', asyncSpec (next) ->
157
169
  $target = affix('.target')
158
170
  $outsideLink = affix('a[href="/foo"][up-target=".target"][up-instant]')
159
171
  $tooltipOpener = affix('.link')
160
172
  up.tooltip.attach($tooltipOpener, text: 'Tooltip text')
161
- expect(up.tooltip.isOpen()).toBe(true)
162
- Trigger.clickSequence($outsideLink)
163
- u.nextFrame ->
173
+
174
+ next =>
175
+ expect(up.tooltip.isOpen()).toBe(true)
176
+ Trigger.clickSequence($outsideLink)
177
+
178
+ next =>
164
179
  expect(up.tooltip.isOpen()).toBe(false)
165
- done()