watir-webdriver 0.6.11 → 0.7.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -12
  3. data/CHANGES.md +17 -0
  4. data/LICENSE +1 -1
  5. data/README.md +8 -1
  6. data/Rakefile +7 -2
  7. data/lib/watir-webdriver/alert.rb +5 -1
  8. data/lib/watir-webdriver/attribute_helper.rb +4 -8
  9. data/lib/watir-webdriver/browser.rb +41 -21
  10. data/lib/watir-webdriver/element_collection.rb +1 -2
  11. data/lib/watir-webdriver/elements/button.rb +3 -5
  12. data/lib/watir-webdriver/elements/checkbox.rb +2 -11
  13. data/lib/watir-webdriver/elements/element.rb +93 -86
  14. data/lib/watir-webdriver/elements/file_field.rb +1 -2
  15. data/lib/watir-webdriver/elements/form.rb +2 -1
  16. data/lib/watir-webdriver/elements/generated.rb +24 -11
  17. data/lib/watir-webdriver/elements/iframe.rb +25 -17
  18. data/lib/watir-webdriver/elements/option.rb +6 -14
  19. data/lib/watir-webdriver/elements/radio.rb +2 -5
  20. data/lib/watir-webdriver/elements/select.rb +15 -7
  21. data/lib/watir-webdriver/exception.rb +0 -2
  22. data/lib/watir-webdriver/extensions/alerts.rb +0 -14
  23. data/lib/watir-webdriver/has_window.rb +2 -4
  24. data/lib/watir-webdriver/html/spec_extractor.rb +3 -2
  25. data/lib/watir-webdriver/html/visitor.rb +2 -2
  26. data/lib/watir-webdriver/locators/element_locator.rb +22 -21
  27. data/lib/watir-webdriver/locators/text_field_locator.rb +11 -3
  28. data/lib/watir-webdriver/user_editable.rb +5 -10
  29. data/lib/watir-webdriver/version.rb +1 -1
  30. data/lib/watir-webdriver/wait.rb +26 -26
  31. data/lib/watir-webdriver/window.rb +30 -25
  32. data/spec/always_locate_spec.rb +42 -0
  33. data/spec/browser_spec.rb +1 -1
  34. data/spec/element_locator_spec.rb +13 -1
  35. data/spec/element_spec.rb +43 -8
  36. data/spec/input_spec.rb +0 -31
  37. data/spec/spec_helper.rb +0 -1
  38. data/support/doctest_helper.rb +72 -0
  39. data/support/travis.sh +4 -0
  40. data/watir-webdriver.gemspec +2 -1
  41. metadata +50 -35
  42. data/spec/html/inner_outer.html +0 -5
@@ -27,7 +27,6 @@ module Watir
27
27
  def locate
28
28
  e = by_id and return e # short-circuit if :id is given
29
29
 
30
-
31
30
  if @selector.size == 1
32
31
  element = find_first_by_one
33
32
  else
@@ -39,7 +38,7 @@ module Watir
39
38
  # It is also used to alter behavior of methods locating more than one type of element
40
39
  # (e.g. text_field locates both input and textarea)
41
40
  validate_element(element) if element
42
- rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::ObsoleteElementError
41
+ rescue Selenium::WebDriver::Error::NoSuchElementError, Selenium::WebDriver::Error::StaleElementReferenceError
43
42
  nil
44
43
  end
45
44
 
@@ -253,8 +252,6 @@ module Watir
253
252
  return if tag_name && !tag_name_matches?(element.tag_name.downcase, tag_name)
254
253
 
255
254
  element
256
- rescue Selenium::WebDriver::Error::NoSuchElementError
257
- nil
258
255
  end
259
256
 
260
257
  def all_elements
@@ -298,26 +295,30 @@ module Watir
298
295
  def build_css(selectors)
299
296
  return unless use_css?(selectors)
300
297
 
301
- css = ''
302
- css << (selectors.delete(:tag_name) || '')
303
-
304
- klass = selectors.delete(:class)
305
- if klass
306
- if klass.include? ' '
307
- css << %([class="#{css_escape klass}"])
308
- else
309
- css << ".#{klass}"
298
+ if selectors.empty?
299
+ css = '*'
300
+ else
301
+ css = ''
302
+ css << (selectors.delete(:tag_name) || '')
303
+
304
+ klass = selectors.delete(:class)
305
+ if klass
306
+ if klass.include? ' '
307
+ css << %([class="#{css_escape klass}"])
308
+ else
309
+ css << ".#{klass}"
310
+ end
310
311
  end
311
- end
312
312
 
313
- href = selectors.delete(:href)
314
- if href
315
- css << %([href~="#{css_escape href}"])
316
- end
313
+ href = selectors.delete(:href)
314
+ if href
315
+ css << %([href~="#{css_escape href}"])
316
+ end
317
317
 
318
- selectors.each do |key, value|
319
- key = key.to_s.gsub("_", "-")
320
- css << %([#{key}="#{css_escape value}"]) # TODO: proper escaping
318
+ selectors.each do |key, value|
319
+ key = key.to_s.gsub("_", "-")
320
+ css << %([#{key}="#{css_escape value}"]) # TODO: proper escaping
321
+ end
321
322
  end
322
323
 
323
324
  [:css, css]
@@ -65,15 +65,23 @@ module Watir
65
65
  end
66
66
 
67
67
  def by_id
68
- el = super
69
- el if el and not NON_TEXT_TYPES.include? el.attribute(:type)
68
+ element = super
69
+
70
+ if element && !NON_TEXT_TYPES.include?(element.attribute(:type))
71
+ check_deprecation(element)
72
+ element
73
+ end
70
74
  end
71
75
 
72
76
  def validate_element(element)
77
+ check_deprecation(element)
78
+ super
79
+ end
80
+
81
+ def check_deprecation(element)
73
82
  if element.tag_name.downcase == 'textarea'
74
83
  warn "Locating textareas with '#text_field' is deprecated. Please, use '#textarea' method instead."
75
84
  end
76
- super
77
85
  end
78
86
 
79
87
  end # TextFieldLocator
@@ -8,11 +8,8 @@ module Watir
8
8
  #
9
9
 
10
10
  def set(*args)
11
- assert_exists
12
- assert_writable
13
-
14
- @element.clear
15
- @element.send_keys(*args)
11
+ clear
12
+ element_call { @element.send_keys(*args) }
16
13
  end
17
14
  alias_method :value=, :set
18
15
 
@@ -23,10 +20,7 @@ module Watir
23
20
  #
24
21
 
25
22
  def append(*args)
26
- assert_exists
27
- assert_writable
28
-
29
- @element.send_keys(*args)
23
+ send_keys(*args)
30
24
  end
31
25
  alias_method :<<, :append
32
26
 
@@ -36,7 +30,8 @@ module Watir
36
30
 
37
31
  def clear
38
32
  assert_exists
39
- @element.clear
33
+ assert_writable
34
+ element_call { @element.clear }
40
35
  end
41
36
 
42
37
  end # UserEditable
@@ -1,3 +1,3 @@
1
1
  module Watir
2
- VERSION = "0.6.11"
2
+ VERSION = '0.7.0'
3
3
  end
@@ -29,22 +29,15 @@ module Watir
29
29
  # Waits until the block evaluates to true or times out.
30
30
  #
31
31
  # @example
32
- # Watir::Wait.until { browser.a(:id => "ajaxed").visible? }
32
+ # Watir::Wait.until { browser.text_field(:name => "new_user_first_name").visible? }
33
33
  #
34
34
  # @param [Fixnum] timeout How long to wait in seconds
35
35
  # @param [String] message Message to raise if timeout is exceeded
36
36
  # @raise [TimeoutError] if timeout is exceeded
37
37
  #
38
38
 
39
- def until(timeout = nil, message = nil, &block)
40
- timeout ||= Watir.default_timeout
41
-
42
- timer.wait(timeout) do
43
- result = yield(self)
44
- return result if result
45
- sleep INTERVAL
46
- end
47
-
39
+ def until(timeout = nil, message = nil)
40
+ run_with_timer(timeout) { return true if yield(self) }
48
41
  raise TimeoutError, message_for(timeout, message)
49
42
  end
50
43
 
@@ -52,21 +45,15 @@ module Watir
52
45
  # Wait while the block evaluates to true or times out.
53
46
  #
54
47
  # @example
55
- # Watir::Wait.while { browser.a(:id => "ajaxed").visible? }
48
+ # Watir::Wait.while { browser.text_field(:name => "abrakadbra").present? }
56
49
  #
57
50
  # @param [Fixnum] timeout How long to wait in seconds
58
51
  # @param [String] message Message to raise if timeout is exceeded
59
52
  # @raise [TimeoutError] if timeout is exceeded
60
53
  #
61
54
 
62
- def while(timeout = nil, message = nil, &block)
63
- timeout ||= Watir.default_timeout
64
-
65
- timer.wait(timeout) do
66
- return unless yield(self)
67
- sleep INTERVAL
68
- end
69
-
55
+ def while(timeout = nil, message = nil)
56
+ run_with_timer(timeout) { return unless yield(self) }
70
57
  raise TimeoutError, message_for(timeout, message)
71
58
  end
72
59
 
@@ -79,6 +66,19 @@ module Watir
79
66
  err
80
67
  end
81
68
 
69
+ def run_with_timer(timeout = nil, &block)
70
+ timeout ||= Watir.default_timeout
71
+
72
+ if timeout == 0
73
+ block.call
74
+ else
75
+ timer.wait(timeout) do
76
+ block.call
77
+ sleep INTERVAL
78
+ end
79
+ end
80
+ end
81
+
82
82
  end # self
83
83
  end # Wait
84
84
 
@@ -134,9 +134,9 @@ module Watir
134
134
  # Waits until the element is present.
135
135
  #
136
136
  # @example
137
- # browser.button(:id => 'foo').when_present.click
138
- # browser.div(:id => 'bar').when_present { |div| ... }
139
- # browser.p(:id => 'baz').when_present(60).text
137
+ # browser.text_field(:name => "new_user_first_name").when_present.click
138
+ # browser.text_field(:name => "new_user_first_name").when_present { |field| field.set "Watir" }
139
+ # browser.text_field(:name => "new_user_first_name").when_present(60).text
140
140
  #
141
141
  # @param [Fixnum] timeout seconds to wait before timing out
142
142
  #
@@ -160,7 +160,7 @@ module Watir
160
160
  # Waits until the element is present.
161
161
  #
162
162
  # @example
163
- # browser.button(:id => 'foo').wait_until_present
163
+ # browser.text_field(:name => "new_user_first_name").wait_until_present
164
164
  #
165
165
  # @param [Fixnum] timeout seconds to wait before timing out
166
166
  #
@@ -178,9 +178,9 @@ module Watir
178
178
  # Waits while the element is present.
179
179
  #
180
180
  # @example
181
- # browser.button(:id => 'foo').wait_while_present
181
+ # browser.text_field(:name => "abrakadbra").wait_while_present
182
182
  #
183
- # @param [Integer] timeout seconds to wait before timing out
183
+ # @param [Fixnum] timeout seconds to wait before timing out
184
184
  #
185
185
  # @see Watir::Wait
186
186
  # @see Watir::Element#present?
@@ -190,7 +190,7 @@ module Watir
190
190
  timeout ||= Watir.default_timeout
191
191
  message = "waiting for #{selector_string} to disappear"
192
192
  Watir::Wait.while(timeout, message) { present? }
193
- rescue Selenium::WebDriver::Error::ObsoleteElementError
193
+ rescue Selenium::WebDriver::Error::StaleElementReferenceError
194
194
  # it's not present
195
195
  end
196
196
 
@@ -3,11 +3,11 @@ module Watir
3
3
  include EventuallyPresent
4
4
 
5
5
  def initialize(driver, selector)
6
- @driver = driver
6
+ @driver = driver
7
7
  @selector = selector
8
8
 
9
9
  if selector.empty?
10
- @handle = driver.window_handle
10
+ @handle = current_window
11
11
  elsif selector.has_key? :handle
12
12
  @handle = selector.delete :handle
13
13
  else
@@ -103,29 +103,21 @@ module Watir
103
103
  #
104
104
 
105
105
  def exists?
106
- handle
106
+ assert_exists
107
107
  true
108
108
  rescue Exception::NoMatchingWindowFoundException
109
109
  false
110
110
  end
111
111
 
112
- #
113
- # Returns true if window is present.
114
- #
115
- # @return [Boolean]
116
- #
117
-
118
- def present?
119
- @handle = nil # relocate
120
-
121
- exists?
122
- end
112
+ alias_method :present?, :exists?
113
+ alias_method :exist?, :exists?
123
114
 
124
115
  #
125
116
  # Returns true if two windows are equal.
126
117
  #
127
118
  # @example
128
- # browser.window(:index => 1) == browser.window(:index => 2)
119
+ # browser.window(:index => 0) == browser.window(:index => 1)
120
+ # #=> false
129
121
  #
130
122
  # @param [Window] other
131
123
  #
@@ -150,11 +142,11 @@ module Watir
150
142
  #
151
143
 
152
144
  def current?
153
- @driver.window_handle == handle
145
+ current_window == handle
154
146
  end
155
147
 
156
148
  #
157
- # CLoses window.
149
+ # Closes window.
158
150
  #
159
151
 
160
152
  def close
@@ -191,12 +183,13 @@ module Watir
191
183
  # Switches to given window and executes block, then switches back.
192
184
  #
193
185
  # @example
194
- # browser.window(:title => "2nd window").use do
195
- # browser.button(:id => "close").click
186
+ # browser.window(:title => "closeable window").use do
187
+ # browser.a(:id => "close").click
196
188
  # end
197
189
  #
198
190
 
199
191
  def use(&blk)
192
+ assert_exists
200
193
  @driver.switch_to.window(handle, &blk)
201
194
  self
202
195
  end
@@ -209,18 +202,30 @@ module Watir
209
202
 
210
203
  private
211
204
 
205
+ # Referenced in EventuallyPresent
212
206
  def selector_string
213
207
  @selector.inspect
214
208
  end
215
209
 
216
210
  def locate
217
- handle = if @selector.has_key?(:index)
218
- @driver.window_handles[Integer(@selector[:index])]
219
- else
220
- @driver.window_handles.find { |wh| matches?(wh) }
221
- end
211
+ if @selector.empty?
212
+ nil
213
+ elsif @selector.has_key?(:index)
214
+ @driver.window_handles[Integer(@selector[:index])]
215
+ else
216
+ @driver.window_handles.find { |wh| matches?(wh) }
217
+ end
218
+ end
219
+
220
+ def assert_exists
221
+ raise(Exception::NoMatchingWindowFoundException, @selector.inspect) unless @driver.window_handles.include?(handle)
222
+ end
222
223
 
223
- handle or raise Exception::NoMatchingWindowFoundException, @selector.inspect
224
+ # return a handle to the currently active window if it is still open; otherwise nil
225
+ def current_window
226
+ @driver.window_handle
227
+ rescue Selenium::WebDriver::Error::NoSuchWindowError
228
+ nil
224
229
  end
225
230
 
226
231
  def matches?(handle)
@@ -0,0 +1,42 @@
1
+ require File.expand_path('watirspec/spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'Watir' do
4
+ describe '#always_locate?' do
5
+
6
+ before do
7
+ browser.goto WatirSpec.url_for('removed_element.html', :needs_server => true)
8
+ end
9
+
10
+ it 'determines whether #exist? returns false for stale element' do
11
+ element = browser.div(:id => "text")
12
+ expect(element.exists?).to be true
13
+
14
+ browser.refresh
15
+
16
+ expect(element.exists?).to be Watir.always_locate?
17
+ end
18
+
19
+ it 'allows using cached elements regardless of setting, when element is not stale' do
20
+ element = browser.div(:id => "text")
21
+ expect(element.exists?).to be true
22
+
23
+ # exception raised if element is re-looked up
24
+ allow(browser.driver).to receive(:find_element).with(:id, 'text') { raise }
25
+
26
+ expect { element.exists? }.to_not raise_error
27
+ end
28
+
29
+ it 'determines whether an exception is raised when taking an action on a stale element' do
30
+ element = browser.div(:id => "text")
31
+ expect(element.exists?).to be true
32
+
33
+ browser.refresh
34
+
35
+ if Watir.always_locate?
36
+ expect { element.text }.to_not raise_error
37
+ else
38
+ expect { element.text }.to raise_error
39
+ end
40
+ end
41
+ end
42
+ end
@@ -70,7 +70,7 @@ describe Watir::Browser do
70
70
  b.goto WatirSpec.url_for "definition_lists.html"
71
71
  b.close
72
72
 
73
- expect { b.dl(:id => "experience-list").id }.to raise_error(Error, "browser was closed")
73
+ expect { b.dl(:id => "experience-list").id }.to raise_error(Watir::Exception::Error, "browser was closed")
74
74
  end
75
75
 
76
76
  describe "#wait_while" do
@@ -368,7 +368,7 @@ describe Watir::ElementLocator do
368
368
  valid_attributes = Watir::Input.attributes
369
369
 
370
370
  expect { locate_one(bad_selector, valid_attributes) }.to \
371
- raise_error(MissingWayOfFindingObjectException, "invalid attribute: :href")
371
+ raise_error(Watir::Exception::MissingWayOfFindingObjectException, "invalid attribute: :href")
372
372
  end
373
373
  end
374
374
  end
@@ -383,6 +383,18 @@ describe Watir::ElementLocator do
383
383
  end
384
384
  end
385
385
 
386
+ describe "with an empty selector" do
387
+ it "finds all when an empty selctor is given" do
388
+ if Watir.prefer_css?
389
+ expect_all :css, '*'
390
+ else
391
+ expect_all :xpath, './/*'
392
+ end
393
+
394
+ locate_all({})
395
+ end
396
+ end
397
+
386
398
  describe "with selectors not supported by webdriver" do
387
399
  it "handles selector with tag name and a single attribute" do
388
400
  if Watir.prefer_css?