capybara 1.1.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. data/{History.txt → History.md} +138 -0
  2. data/License.txt +22 -0
  3. data/README.md +850 -0
  4. data/lib/capybara/cucumber.rb +2 -5
  5. data/lib/capybara/driver/base.rb +6 -6
  6. data/lib/capybara/driver/node.rb +3 -2
  7. data/lib/capybara/dsl.rb +13 -124
  8. data/lib/capybara/helpers.rb +33 -0
  9. data/lib/capybara/node/actions.rb +16 -30
  10. data/lib/capybara/node/base.rb +56 -13
  11. data/lib/capybara/node/element.rb +18 -30
  12. data/lib/capybara/node/finders.rb +28 -90
  13. data/lib/capybara/node/matchers.rb +121 -73
  14. data/lib/capybara/node/simple.rb +13 -11
  15. data/lib/capybara/query.rb +78 -0
  16. data/lib/capybara/rack_test/browser.rb +27 -39
  17. data/lib/capybara/rack_test/driver.rb +13 -3
  18. data/lib/capybara/rack_test/node.rb +31 -2
  19. data/lib/capybara/result.rb +72 -0
  20. data/lib/capybara/rspec/features.rb +4 -1
  21. data/lib/capybara/rspec/matchers.rb +33 -63
  22. data/lib/capybara/rspec.rb +7 -4
  23. data/lib/capybara/selector.rb +97 -34
  24. data/lib/capybara/selenium/driver.rb +15 -62
  25. data/lib/capybara/selenium/node.rb +14 -21
  26. data/lib/capybara/server.rb +32 -27
  27. data/lib/capybara/session.rb +90 -50
  28. data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
  29. data/lib/capybara/spec/public/jquery-ui.js +791 -0
  30. data/lib/capybara/spec/public/jquery.js +9046 -0
  31. data/lib/capybara/spec/public/test.js +3 -0
  32. data/lib/capybara/spec/session/all_spec.rb +61 -59
  33. data/lib/capybara/spec/session/assert_selector.rb +123 -0
  34. data/lib/capybara/spec/session/attach_file_spec.rb +72 -55
  35. data/lib/capybara/spec/session/body_spec.rb +21 -0
  36. data/lib/capybara/spec/session/check_spec.rb +68 -48
  37. data/lib/capybara/spec/session/choose_spec.rb +32 -18
  38. data/lib/capybara/spec/session/click_button_spec.rb +263 -232
  39. data/lib/capybara/spec/session/click_link_or_button_spec.rb +40 -29
  40. data/lib/capybara/spec/session/click_link_spec.rb +96 -96
  41. data/lib/capybara/spec/session/current_url_spec.rb +88 -10
  42. data/lib/capybara/spec/session/evaluate_script_spec.rb +6 -0
  43. data/lib/capybara/spec/session/execute_script_spec.rb +7 -0
  44. data/lib/capybara/spec/session/fill_in_spec.rb +119 -103
  45. data/lib/capybara/spec/session/find_button_spec.rb +16 -14
  46. data/lib/capybara/spec/session/find_by_id_spec.rb +16 -14
  47. data/lib/capybara/spec/session/find_field_spec.rb +23 -21
  48. data/lib/capybara/spec/session/find_link_spec.rb +15 -14
  49. data/lib/capybara/spec/session/find_spec.rb +93 -115
  50. data/lib/capybara/spec/session/first_spec.rb +51 -85
  51. data/lib/capybara/spec/session/has_button_spec.rb +22 -24
  52. data/lib/capybara/spec/session/has_css_spec.rb +190 -205
  53. data/lib/capybara/spec/session/has_field_spec.rb +170 -144
  54. data/lib/capybara/spec/session/has_link_spec.rb +26 -29
  55. data/lib/capybara/spec/session/has_select_spec.rb +161 -109
  56. data/lib/capybara/spec/session/has_selector_spec.rb +94 -100
  57. data/lib/capybara/spec/session/has_table_spec.rb +22 -88
  58. data/lib/capybara/spec/session/has_text_spec.rb +195 -0
  59. data/lib/capybara/spec/session/has_xpath_spec.rb +100 -96
  60. data/lib/capybara/spec/session/headers.rb +4 -17
  61. data/lib/capybara/spec/session/html_spec.rb +15 -0
  62. data/lib/capybara/spec/session/node_spec.rb +205 -0
  63. data/lib/capybara/spec/session/reset_session_spec.rb +42 -0
  64. data/lib/capybara/spec/session/response_code.rb +4 -17
  65. data/lib/capybara/spec/session/save_page_spec.rb +46 -0
  66. data/lib/capybara/spec/session/screenshot.rb +13 -0
  67. data/lib/capybara/spec/session/select_spec.rb +99 -88
  68. data/lib/capybara/spec/session/source_spec.rb +12 -0
  69. data/lib/capybara/spec/session/text_spec.rb +15 -12
  70. data/lib/capybara/spec/session/uncheck_spec.rb +22 -17
  71. data/lib/capybara/spec/session/unselect_spec.rb +69 -58
  72. data/lib/capybara/spec/session/visit_spec.rb +74 -0
  73. data/lib/capybara/spec/session/within_frame_spec.rb +31 -0
  74. data/lib/capybara/spec/session/within_spec.rb +118 -131
  75. data/lib/capybara/spec/session/within_window_spec.rb +38 -0
  76. data/lib/capybara/spec/spec_helper.rb +84 -0
  77. data/lib/capybara/spec/test_app.rb +32 -6
  78. data/lib/capybara/spec/views/form.erb +12 -10
  79. data/lib/capybara/spec/views/host_links.erb +2 -2
  80. data/lib/capybara/spec/views/tables.erb +6 -66
  81. data/lib/capybara/spec/views/with_html.erb +9 -4
  82. data/lib/capybara/spec/views/with_js.erb +11 -7
  83. data/lib/capybara/version.rb +1 -1
  84. data/lib/capybara.rb +125 -6
  85. data/spec/basic_node_spec.rb +17 -5
  86. data/spec/capybara_spec.rb +9 -0
  87. data/spec/dsl_spec.rb +31 -17
  88. data/spec/rack_test_spec.rb +157 -0
  89. data/spec/result_spec.rb +51 -0
  90. data/spec/rspec/features_spec.rb +19 -2
  91. data/spec/rspec/matchers_spec.rb +170 -89
  92. data/spec/rspec_spec.rb +1 -3
  93. data/spec/selenium_spec.rb +53 -0
  94. data/spec/server_spec.rb +37 -25
  95. data/spec/spec_helper.rb +1 -30
  96. metadata +39 -31
  97. data/README.rdoc +0 -722
  98. data/lib/capybara/spec/driver.rb +0 -301
  99. data/lib/capybara/spec/session/current_host_spec.rb +0 -68
  100. data/lib/capybara/spec/session/has_content_spec.rb +0 -106
  101. data/lib/capybara/spec/session/javascript.rb +0 -306
  102. data/lib/capybara/spec/session.rb +0 -154
  103. data/lib/capybara/util/save_and_open_page.rb +0 -44
  104. data/lib/capybara/util/timeout.rb +0 -27
  105. data/spec/driver/rack_test_driver_spec.rb +0 -89
  106. data/spec/driver/selenium_driver_spec.rb +0 -37
  107. data/spec/save_and_open_page_spec.rb +0 -155
  108. data/spec/session/rack_test_session_spec.rb +0 -55
  109. data/spec/session/selenium_session_spec.rb +0 -26
  110. data/spec/string_spec.rb +0 -77
  111. data/spec/timeout_spec.rb +0 -28
@@ -6,8 +6,9 @@ require 'capybara/rspec/matchers'
6
6
  World(Capybara::DSL)
7
7
  World(Capybara::RSpecMatchers)
8
8
 
9
- After do
9
+ Before do
10
10
  Capybara.reset_sessions!
11
+ Capybara.use_default_driver
11
12
  end
12
13
 
13
14
  Before '@javascript' do
@@ -22,7 +23,3 @@ Before do |scenario|
22
23
  end
23
24
  end
24
25
  end
25
-
26
- After do
27
- Capybara.use_default_driver
28
- end
@@ -15,7 +15,7 @@ class Capybara::Driver::Base
15
15
  raise NotImplementedError
16
16
  end
17
17
 
18
- def body
18
+ def html
19
19
  raise NotImplementedError
20
20
  end
21
21
 
@@ -27,6 +27,10 @@ class Capybara::Driver::Base
27
27
  raise Capybara::NotSupportedByDriverError
28
28
  end
29
29
 
30
+ def save_screenshot(path, options={})
31
+ raise Capybara::NotSupportedByDriverError
32
+ end
33
+
30
34
  def response_headers
31
35
  raise Capybara::NotSupportedByDriverError
32
36
  end
@@ -51,14 +55,10 @@ class Capybara::Driver::Base
51
55
  false
52
56
  end
53
57
 
54
- def wait_until(*args)
55
- end
56
-
57
58
  def reset!
58
59
  end
59
60
 
60
- def has_shortcircuit_timeout?
61
+ def needs_server?
61
62
  false
62
63
  end
63
-
64
64
  end
@@ -20,6 +20,7 @@ module Capybara
20
20
  raise NotImplementedError
21
21
  end
22
22
 
23
+ # @param value String or Array. Array is only allowed if node has 'multiple' attribute
23
24
  def set(value)
24
25
  raise NotImplementedError
25
26
  end
@@ -65,9 +66,9 @@ module Capybara
65
66
  end
66
67
 
67
68
  def inspect
68
- %(#<Capybara::Driver::Node tag="#{tag_name}" path="#{path}">)
69
+ %(#<#{self.class} tag="#{tag_name}" path="#{path}">)
69
70
  rescue NotSupportedByDriverError
70
- %(#<Capybara::Driver::Node tag="#{tag_name}">)
71
+ %(#<#{self.class} tag="#{tag_name}">)
71
72
  end
72
73
  end
73
74
  end
data/lib/capybara/dsl.rb CHANGED
@@ -1,127 +1,20 @@
1
1
  require 'capybara'
2
2
 
3
3
  module Capybara
4
- def self.included(base)
5
- base.send(:include, Capybara::DSL)
6
- warn "`include Capybara` is deprecated please use `include Capybara::DSL` instead."
7
- end
8
-
9
- class << self
10
- attr_writer :default_driver, :current_driver, :javascript_driver, :session_name
11
-
12
- attr_accessor :app
13
-
14
- ##
15
- #
16
- # @return [Symbol] The name of the driver to use by default
17
- #
18
- def default_driver
19
- @default_driver || :rack_test
20
- end
21
-
22
- ##
23
- #
24
- # @return [Symbol] The name of the driver currently in use
25
- #
26
- def current_driver
27
- @current_driver || default_driver
28
- end
29
- alias_method :mode, :current_driver
30
-
31
- ##
32
- #
33
- # @return [Symbol] The name of the driver used when JavaScript is needed
34
- #
35
- def javascript_driver
36
- @javascript_driver || :selenium
37
- end
38
-
39
- ##
40
- #
41
- # Use the default driver as the current driver
42
- #
43
- def use_default_driver
44
- @current_driver = nil
45
- end
46
-
47
- ##
48
- #
49
- # Yield a block using a specific driver
50
- #
51
- def using_driver(driver)
52
- previous_driver = Capybara.current_driver
53
- Capybara.current_driver = driver
54
- yield
55
- ensure
56
- @current_driver = previous_driver
57
- end
58
-
59
- ##
60
- #
61
- # Yield a block using a specific wait time
62
- #
63
- def using_wait_time(seconds)
64
- previous_wait_time = Capybara.default_wait_time
65
- Capybara.default_wait_time = seconds
66
- yield
67
- ensure
68
- Capybara.default_wait_time = previous_wait_time
69
- end
70
-
71
- ##
72
- #
73
- # The current Capybara::Session base on what is set as Capybara.app and Capybara.current_driver
74
- #
75
- # @return [Capybara::Session] The currently used session
76
- #
77
- def current_session
78
- session_pool["#{current_driver}:#{session_name}:#{app.object_id}"] ||= Capybara::Session.new(current_driver, app)
79
- end
80
-
81
- ##
82
- #
83
- # Reset sessions, cleaning out the pool of sessions. This will remove any session information such
84
- # as cookies.
85
- #
86
- def reset_sessions!
87
- session_pool.each { |mode, session| session.reset! }
88
- end
89
- alias_method :reset!, :reset_sessions!
90
-
91
- ##
92
- #
93
- # The current session name.
94
- #
95
- # @return [Symbol] The name of the currently used session.
96
- #
97
- def session_name
98
- @session_name ||= :default
99
- end
100
-
101
- ##
102
- #
103
- # Yield a block using a specific session name.
104
- #
105
- def using_session(name)
106
- self.session_name = name
107
- yield
108
- ensure
109
- self.session_name = :default
4
+ module DSL
5
+ def self.included(base)
6
+ warn "including Capybara::DSL in the global scope is not recommended!" if base == Object
7
+ super
110
8
  end
111
9
 
112
- private
113
-
114
- def session_pool
115
- @session_pool ||= {}
10
+ def self.extended(base)
11
+ warn "extending the main object with Capybara::DSL is not recommended!" if base == TOPLEVEL_BINDING.eval("self")
12
+ super
116
13
  end
117
- end
118
-
119
- module DSL
120
14
 
121
15
  ##
122
16
  #
123
- # Shortcut to working in a different session. This is useful when Capybara is included
124
- # in a class or module.
17
+ # Shortcut to working in a different session.
125
18
  #
126
19
  def using_session(name, &block)
127
20
  Capybara.using_session(name, &block)
@@ -129,8 +22,7 @@ module Capybara
129
22
 
130
23
  ##
131
24
  #
132
- # Shortcut to working in a different session. This is useful when Capybara is included
133
- # in a class or module.
25
+ # Shortcut to using a different wait time.
134
26
  #
135
27
  def using_wait_time(seconds, &block)
136
28
  Capybara.using_wait_time(seconds, &block)
@@ -138,8 +30,7 @@ module Capybara
138
30
 
139
31
  ##
140
32
  #
141
- # Shortcut to accessing the current session. This is useful when Capybara is included in a
142
- # class or module.
33
+ # Shortcut to accessing the current session.
143
34
  #
144
35
  # class MyClass
145
36
  # include Capybara::DSL
@@ -156,11 +47,9 @@ module Capybara
156
47
  end
157
48
 
158
49
  Session::DSL_METHODS.each do |method|
159
- class_eval <<-RUBY, __FILE__, __LINE__+1
160
- def #{method}(*args, &block)
161
- page.#{method}(*args, &block)
162
- end
163
- RUBY
50
+ define_method method do |*args, &block|
51
+ page.send method, *args, &block
52
+ end
164
53
  end
165
54
  end
166
55
 
@@ -0,0 +1,33 @@
1
+ module Capybara
2
+ module Helpers
3
+ class << self
4
+ ##
5
+ #
6
+ # Normalizes whitespace space by stripping leading and trailing
7
+ # whitespace and replacing sequences of whitespace characters
8
+ # with a single space.
9
+ #
10
+ # @param [String] text Text to normalize
11
+ # @return [String] Normalized text
12
+ #
13
+ def normalize_whitespace(text)
14
+ # http://en.wikipedia.org/wiki/Whitespace_character#Unicode
15
+ # We should have a better reference.
16
+ # See also http://stackoverflow.com/a/11758133/525872
17
+ text.to_s.gsub(/[\s\u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]+/, ' ').strip
18
+ end
19
+
20
+ ##
21
+ #
22
+ # Escapes any characters that would have special meaning in a regexp
23
+ # if text is not a regexp
24
+ #
25
+ # @param [String] text Text to escape
26
+ # @return [String] Escaped text
27
+ #
28
+ def to_regexp(text)
29
+ text.is_a?(Regexp) ? text : Regexp.escape(normalize_whitespace(text))
30
+ end
31
+ end
32
+ end
33
+ end
@@ -10,8 +10,7 @@ module Capybara
10
10
  # @param [String] locator Text, id or value of link or button
11
11
  #
12
12
  def click_link_or_button(locator)
13
- msg = "no link or button '#{locator}' found"
14
- find(:xpath, XPath::HTML.link_or_button(locator), :message => msg).click
13
+ find(:link_or_button, locator).click
15
14
  end
16
15
  alias_method :click_on, :click_link_or_button
17
16
 
@@ -23,8 +22,7 @@ module Capybara
23
22
  # @param [String] locator Text, id or text of link
24
23
  #
25
24
  def click_link(locator)
26
- msg = "no link with title, id or text '#{locator}' found"
27
- find(:xpath, XPath::HTML.link(locator), :message => msg).click
25
+ find(:link, locator).click
28
26
  end
29
27
 
30
28
  ##
@@ -34,8 +32,7 @@ module Capybara
34
32
  # @param [String] locator Text, id or value of button
35
33
  #
36
34
  def click_button(locator)
37
- msg = "no button with value or id or text '#{locator}' found"
38
- find(:xpath, XPath::HTML.button(locator), :message => msg).click
35
+ find(:button, locator).click
39
36
  end
40
37
 
41
38
  ##
@@ -49,9 +46,8 @@ module Capybara
49
46
  # @param [Hash{:with => String}] The value to fill in
50
47
  #
51
48
  def fill_in(locator, options={})
52
- msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found"
53
49
  raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
54
- find(:xpath, XPath::HTML.fillable_field(locator), :message => msg).set(options[:with])
50
+ find(:fillable_field, locator).set(options[:with])
55
51
  end
56
52
 
57
53
  ##
@@ -64,8 +60,7 @@ module Capybara
64
60
  # @param [String] locator Which radio button to choose
65
61
  #
66
62
  def choose(locator)
67
- msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found"
68
- find(:xpath, XPath::HTML.radio_button(locator), :message => msg).set(true)
63
+ find(:radio_button, locator).set(true)
69
64
  end
70
65
 
71
66
  ##
@@ -78,8 +73,7 @@ module Capybara
78
73
  # @param [String] locator Which check box to check
79
74
  #
80
75
  def check(locator)
81
- msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found"
82
- find(:xpath, XPath::HTML.checkbox(locator), :message => msg).set(true)
76
+ find(:checkbox, locator).set(true)
83
77
  end
84
78
 
85
79
  ##
@@ -92,8 +86,7 @@ module Capybara
92
86
  # @param [String] locator Which check box to uncheck
93
87
  #
94
88
  def uncheck(locator)
95
- msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found"
96
- find(:xpath, XPath::HTML.checkbox(locator), :message => msg).set(false)
89
+ find(:checkbox, locator).set(false)
97
90
  end
98
91
 
99
92
  ##
@@ -109,13 +102,9 @@ module Capybara
109
102
  #
110
103
  def select(value, options={})
111
104
  if options.has_key?(:from)
112
- no_select_msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found"
113
- no_option_msg = "cannot select option, no option with text '#{value}' in select box '#{options[:from]}'"
114
- select = find(:xpath, XPath::HTML.select(options[:from]), :message => no_select_msg)
115
- select.find(:xpath, XPath::HTML.option(value), :message => no_option_msg).select_option
105
+ find(:select, options[:from]).find(:option, value).select_option
116
106
  else
117
- no_option_msg = "cannot select option, no option with text '#{value}'"
118
- find(:xpath, XPath::HTML.option(value), :message => no_option_msg).select_option
107
+ find(:option, value).select_option
119
108
  end
120
109
  end
121
110
 
@@ -132,13 +121,9 @@ module Capybara
132
121
  #
133
122
  def unselect(value, options={})
134
123
  if options.has_key?(:from)
135
- no_select_msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found"
136
- no_option_msg = "cannot unselect option, no option with text '#{value}' in select box '#{options[:from]}'"
137
- select = find(:xpath, XPath::HTML.select(options[:from]), :message => no_select_msg)
138
- select.find(:xpath, XPath::HTML.option(value), :message => no_option_msg).unselect_option
124
+ find(:select, options[:from]).find(:option, value).unselect_option
139
125
  else
140
- no_option_msg = "cannot unselect option, no option with text '#{value}'"
141
- find(:xpath, XPath::HTML.option(value), :message => no_option_msg).unselect_option
126
+ find(:option, value).unselect_option
142
127
  end
143
128
  end
144
129
 
@@ -150,12 +135,13 @@ module Capybara
150
135
  # page.attach_file(locator, '/path/to/file.png')
151
136
  #
152
137
  # @param [String] locator Which field to attach the file to
153
- # @param [String] path The path of the file that will be attached
138
+ # @param [String] path The path of the file that will be attached, or an array of paths
154
139
  #
155
140
  def attach_file(locator, path)
156
- raise Capybara::FileNotFound, "cannot attach file, #{path} does not exist" unless File.exist?(path.to_s)
157
- msg = "cannot attach file, no file field with id, name, or label '#{locator}' found"
158
- find(:xpath, XPath::HTML.file_field(locator), :message => msg).set(path)
141
+ (String === path ? [path] : path).each do |p|
142
+ raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
143
+ end
144
+ find(:file_field, locator).set(path)
159
145
  end
160
146
  end
161
147
  end
@@ -33,29 +33,52 @@ module Capybara
33
33
  @base = base
34
34
  end
35
35
 
36
+ # overridden in subclasses, e.g. Capybara::Node::Element
36
37
  def reload
37
38
  self
38
39
  end
39
40
 
40
- def without_wait
41
- orig = @wait_disabled
42
- @wait_disabled = true
43
- yield
44
- ensure
45
- @wait_disabled = orig
46
- end
47
-
48
- protected
49
-
50
- def wait_until(seconds=Capybara.default_wait_time)
41
+ ##
42
+ #
43
+ # This method is Capybara's primary defence agains asynchronicity
44
+ # problems. It works by attempting to run a given block of code until it
45
+ # succeeds. The exact behaviour of this method depends on a number of
46
+ # factors. Basically there are certain exceptions which, when raised
47
+ # from the block, instead of bubbling up, are caught, and the block is
48
+ # re-run.
49
+ #
50
+ # Certain drivers, such as RackTest, have no support for aynchronous
51
+ # processes, these drivers run the block, and any error raised bubbles up
52
+ # immediately. This allows faster turn around in the case where an
53
+ # expectation fails.
54
+ #
55
+ # Only exceptions that are {Capybara::ElementNotFound} or any subclass
56
+ # thereof cause the block to be rerun. Drivers may specify additional
57
+ # exceptions which also cause reruns. This usually occurs when a node is
58
+ # manipulated which no longer exists on the page. For example, the
59
+ # Selenium driver specifies
60
+ # `Selenium::WebDriver::Error::ObsoleteElementError`.
61
+ #
62
+ # As long as any of these exceptions are thrown, the block is re-run,
63
+ # until a certain amount of time passes. The amount of time defaults to
64
+ # {Capybara.default_wait_time} and can be overriden through the `seconds`
65
+ # argument. This time is compared with the system time to see how much
66
+ # time has passed. If the return value of {Time.now} is stubbed out,
67
+ # Capybara will raise `Capybara::FrozenInTime`.
68
+ #
69
+ # @param [Integer] seconds Number of seconds to retry this block
70
+ # @return [Object] The result of the given block
71
+ # @raise [Capybara::FrozenInTime] If the return value of {Time.now} appears stuck
72
+ #
73
+ def synchronize(seconds=Capybara.default_wait_time)
51
74
  start_time = Time.now
52
75
 
53
76
  begin
54
77
  yield
55
78
  rescue => e
56
- raise e if @wait_disabled
79
+ raise e if @unsynchronized
57
80
  raise e unless driver.wait?
58
- raise e unless (driver.respond_to?(:invalid_element_errors) and driver.invalid_element_errors.include?(e.class)) or e.is_a?(Capybara::ElementNotFound)
81
+ raise e unless driver.invalid_element_errors.include?(e.class) || e.is_a?(Capybara::ElementNotFound)
59
82
  raise e if (Time.now - start_time) >= seconds
60
83
  sleep(0.05)
61
84
  raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == start_time
@@ -64,6 +87,26 @@ module Capybara
64
87
  end
65
88
  end
66
89
 
90
+ ##
91
+ #
92
+ # Within the given block, prevent synchronize from having any effect.
93
+ #
94
+ # This is an internal method which should not be called unless you are
95
+ # absolutely sure of what you're doing.
96
+ #
97
+ # @api private
98
+ # @return [Object] The result of the given block
99
+ #
100
+ def unsynchronized
101
+ orig = @unsynchronized
102
+ @unsynchronized = true
103
+ yield
104
+ ensure
105
+ @unsynchronized = orig
106
+ end
107
+
108
+ protected
109
+
67
110
  def driver
68
111
  session.driver
69
112
  end
@@ -22,10 +22,10 @@ module Capybara
22
22
  #
23
23
  class Element < Base
24
24
 
25
- def initialize(session, base, parent, selector)
25
+ def initialize(session, base, parent, query)
26
26
  super(session, base)
27
27
  @parent = parent
28
- @selector = selector
28
+ @query = query
29
29
  end
30
30
 
31
31
  def allow_reload!
@@ -37,7 +37,7 @@ module Capybara
37
37
  # @return [Object] The native element from the driver, this allows access to driver specific methods
38
38
  #
39
39
  def native
40
- wait_until { base.native }
40
+ synchronize { base.native }
41
41
  end
42
42
 
43
43
  ##
@@ -45,7 +45,7 @@ module Capybara
45
45
  # @return [String] The text of the element
46
46
  #
47
47
  def text
48
- wait_until { base.text }
48
+ synchronize { base.text }
49
49
  end
50
50
 
51
51
  ##
@@ -58,7 +58,7 @@ module Capybara
58
58
  # @return [String] The value of the attribute
59
59
  #
60
60
  def [](attribute)
61
- wait_until { base[attribute] }
61
+ synchronize { base[attribute] }
62
62
  end
63
63
 
64
64
  ##
@@ -66,7 +66,7 @@ module Capybara
66
66
  # @return [String] The value of the form element
67
67
  #
68
68
  def value
69
- wait_until { base.value }
69
+ synchronize { base.value }
70
70
  end
71
71
 
72
72
  ##
@@ -76,7 +76,7 @@ module Capybara
76
76
  # @param [String] value The new value
77
77
  #
78
78
  def set(value)
79
- wait_until { base.set(value) }
79
+ synchronize { base.set(value) }
80
80
  end
81
81
 
82
82
  ##
@@ -84,7 +84,7 @@ module Capybara
84
84
  # Select this node if is an option element inside a select tag
85
85
  #
86
86
  def select_option
87
- wait_until { base.select_option }
87
+ synchronize { base.select_option }
88
88
  end
89
89
 
90
90
  ##
@@ -92,7 +92,7 @@ module Capybara
92
92
  # Unselect this node if is an option element inside a multiple select tag
93
93
  #
94
94
  def unselect_option
95
- wait_until { base.unselect_option }
95
+ synchronize { base.unselect_option }
96
96
  end
97
97
 
98
98
  ##
@@ -100,7 +100,7 @@ module Capybara
100
100
  # Click the Element
101
101
  #
102
102
  def click
103
- wait_until { base.click }
103
+ synchronize { base.click }
104
104
  end
105
105
 
106
106
  ##
@@ -108,7 +108,7 @@ module Capybara
108
108
  # @return [String] The tag name of the element
109
109
  #
110
110
  def tag_name
111
- wait_until { base.tag_name }
111
+ synchronize { base.tag_name }
112
112
  end
113
113
 
114
114
  ##
@@ -119,7 +119,7 @@ module Capybara
119
119
  # @return [Boolean] Whether the element is visible
120
120
  #
121
121
  def visible?
122
- wait_until { base.visible? }
122
+ synchronize { base.visible? }
123
123
  end
124
124
 
125
125
  ##
@@ -129,7 +129,7 @@ module Capybara
129
129
  # @return [Boolean] Whether the element is checked
130
130
  #
131
131
  def checked?
132
- wait_until { base.checked? }
132
+ synchronize { base.checked? }
133
133
  end
134
134
 
135
135
  ##
@@ -139,7 +139,7 @@ module Capybara
139
139
  # @return [Boolean] Whether the element is selected
140
140
  #
141
141
  def selected?
142
- wait_until { base.selected? }
142
+ synchronize { base.selected? }
143
143
  end
144
144
 
145
145
  ##
@@ -149,7 +149,7 @@ module Capybara
149
149
  # @return [String] An XPath expression
150
150
  #
151
151
  def path
152
- wait_until { base.path }
152
+ synchronize { base.path }
153
153
  end
154
154
 
155
155
  ##
@@ -160,7 +160,7 @@ module Capybara
160
160
  # @param [String] event The name of the event to trigger
161
161
  #
162
162
  def trigger(event)
163
- wait_until { base.trigger(event) }
163
+ synchronize { base.trigger(event) }
164
164
  end
165
165
 
166
166
  ##
@@ -174,24 +174,12 @@ module Capybara
174
174
  # @param [Capybara::Element] node The element to drag to
175
175
  #
176
176
  def drag_to(node)
177
- wait_until { base.drag_to(node.base) }
178
- end
179
-
180
- def find(*args)
181
- wait_until { super }
182
- end
183
-
184
- def first(*args)
185
- wait_until { super }
186
- end
187
-
188
- def all(*args)
189
- wait_until { super }
177
+ synchronize { base.drag_to(node.base) }
190
178
  end
191
179
 
192
180
  def reload
193
181
  if @allow_reload
194
- reloaded = parent.reload.first(@selector.name, @selector.locator, @selector.options)
182
+ reloaded = parent.reload.first(@query.name, @query.locator, @query.options)
195
183
  @base = reloaded.base if reloaded
196
184
  end
197
185
  self