watir 6.12.0 → 6.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea86da9b066569e766ab50f2f0657d7bc77501ab
4
- data.tar.gz: 07ad7bd26a6dc2b01b998fe64ef5254289541dc1
3
+ metadata.gz: ee77498367fb399c13c754467a7e0b751cff3b3e
4
+ data.tar.gz: 38566fb0f06601dc54206268cc4904d184d193fa
5
5
  SHA512:
6
- metadata.gz: 4814e526875cba217e35219544f3322baecd947df1e00cb347224bf544cdc806bcd51768ca6394130f792b575010240dbcaba141468760aab448cfcd9e14228e
7
- data.tar.gz: a6fc636ad8301a955430501f5d293094b4028337a80ef9b2c7a6dfdc634f4482dab0c7c84216651f8a8037b5c0f310be06467e359a43707a0477eb6e64bf1c89
6
+ metadata.gz: 3538e96c26022ffc51d3a9e8bf3a40eedf4ac739001547059f015cc3d034b24c3dd9a99b3477a7a3c3125ee074edb94cdaa130f440ac8e5e6ff0c32f5f43de36
7
+ data.tar.gz: 480541837a063fa207523e68e32a72f6ad8d39dc18362d466c25adc410bf1686370e0a58b9fbf2e06dcbf4c03f4706ca93c55c486f0492795233086b45f5ce6d
data/.document CHANGED
@@ -1,5 +1,4 @@
1
1
  README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
2
  LICENSE
3
+ lib/watir/**/*.rb
4
+ lib/watir.rb
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ ### 6.13.0 (2018-09-02)
2
+
3
+ * Allow wait methods to wait for values of any attribute
4
+ * Allow locating custom elements with adjacent methods
5
+ * Support how latest IEDrivers are handling stale elements
6
+ * Restore support for using of previously cached elements in collections
7
+ * Fix bug preventing clicking option when select list is not displayed
8
+ * Allow elements with content-editable attribute to use UserEditable module methods
9
+
1
10
  ### 6.12.0 (2018-07-24)
2
11
 
3
12
  * Allow elements to be located with attributes that have underscores (thanks John Fitisoff)
data/README.md CHANGED
@@ -17,21 +17,27 @@ require 'watir'
17
17
  browser = Watir::Browser.new
18
18
 
19
19
  browser.goto 'watir.com'
20
- browser.link(text: 'documentation').click
20
+ browser.link(text: 'Guides').click
21
21
 
22
22
  puts browser.title
23
- # => 'Documentation – Watir Project...'
23
+ # => 'Guides – Watir Project'
24
24
  browser.close
25
25
  ```
26
26
 
27
- ## Description
27
+ ## Using Watir
28
28
 
29
- The majority of element methods Watir provides with is autogenerated from specifications.
29
+ Everything you need is on the [Watir website](http://watir.com): news, guides, additional resources, support information and more.
30
+
31
+ If you are interested in contributing to the project or the ecosystem, continue reading this README.
32
+
33
+ ## Implementation
34
+
35
+ The majority of element methods Watir provides is autogenerated from specifications.
30
36
  This is done by extracting the IDL parts from the spec and processing them with the WebIDL gem (link below).
31
37
  Currently supported specifications are:
32
38
 
33
- * [HTML](https://www.whatwg.org/specs/web-apps/current-work/) (`lib/watir/elements/html_generated.rb`)
34
- * [SVG](http://www.w3.org/TR/SVG2/single-page.html) (`lib/watir/elements/svg_generated.rb`)
39
+ * [HTML](https://www.w3.org/TR/2017/PR-html51-20170803/single-page.html) (`lib/watir/elements/html_elements.rb`)
40
+ * [SVG](https://www.w3.org/TR/2016/CR-SVG2-20160915/single-page.html) (`lib/watir/elements/svg_elements.rb`)
35
41
 
36
42
  ## Specs
37
43
 
@@ -65,7 +71,7 @@ After initialized, just follow the instructions to customize Watir implementatio
65
71
 
66
72
  Specs specific to Watir are found in `spec/*_spec.rb`, with watirspec in `spec/watirspec/`.
67
73
 
68
- ## Doctests
74
+ ### Doctests
69
75
 
70
76
  Watir uses [yard-doctest](https://github.com/p0deje/yard-doctest) for testing documentation examples.
71
77
 
@@ -73,31 +79,16 @@ Watir uses [yard-doctest](https://github.com/p0deje/yard-doctest) for testing do
73
79
  rake yard:doctest
74
80
  ```
75
81
 
76
- ## API Documentation
77
-
78
- * http://rdoc.info/gems/watir/ (updated on every release)
79
-
80
- ## See Also
81
-
82
- * http://watir.github.io
83
- * http://github.com/jarib/webidl
84
- * http://github.com/watir/watirspec
85
- * https://github.com/seleniumhq/selenium
86
-
87
- ## Dependencies
88
-
89
- * selenium-webdriver
90
- * rack (for watirspec)
91
-
92
82
  ## Note on Patches/Pull Requests
93
83
 
94
84
  * Fork the project.
85
+ * Clone onto your local machine.
86
+ * Create a new feature branch (bonus points for good names).
95
87
  * Make your feature addition or bug fix.
96
- * Add tests for it. This is important so I don't break it in a
97
- future version unintentionally.
98
- * Commit, do not mess with Rakefile, version, or history.
99
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
100
- * Send me a pull request. Bonus points for topic branches.
88
+ * Add tests for it. This is important so we don't unintentionally break it in a future version.
89
+ * Commit, do not change Rakefile, gemspec, or CHANGES files.
90
+ * Push to your forked repository.
91
+ * Send a pull request.
101
92
 
102
93
  ## Copyright
103
94
 
data/lib/watir.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'selenium-webdriver'
2
+ require 'time'
2
3
 
3
4
  require 'watir/legacy_wait'
4
5
  require 'watir/wait'
@@ -111,11 +111,11 @@ module Watir
111
111
  plural = opt.delete(:plural)
112
112
  opt[:index] ||= 0 unless plural || opt.values.any? { |e| e.is_a? Regexp }
113
113
  klass = if !plural && opt[:tag_name]
114
- Watir.tag_to_class[opt[:tag_name].to_sym]
114
+ Watir.element_class_for(opt[:tag_name])
115
115
  elsif !plural
116
116
  HTMLElement
117
117
  elsif opt[:tag_name]
118
- Object.const_get("#{self.send(opt[:tag_name]).class}Collection")
118
+ Object.const_get("#{Watir.element_class_for(opt[:tag_name])}Collection")
119
119
  else
120
120
  HTMLElementCollection
121
121
  end
data/lib/watir/browser.rb CHANGED
@@ -127,7 +127,7 @@ module Watir
127
127
  # @example
128
128
  # browser.goto "watir.github.io"
129
129
  # browser.title
130
- # #=> "Watir is... – Watir Project – Watir stands for Web Application Testing In Ruby. It facilitates the writing of automated tests by mimicking the behavior of a user interacting with a website."
130
+ # #=> "Watir Project"
131
131
  #
132
132
  # @return [String]
133
133
  #
@@ -51,6 +51,8 @@ module Watir
51
51
  to_a[value]
52
52
  elsif @selector.key? :adjacent
53
53
  to_a[value] || element_class.new(@query_scope, {invalid_locator: true})
54
+ elsif @to_a && @to_a[value]
55
+ @to_a[value]
54
56
  else
55
57
  element_class.new(@query_scope, @selector.merge(index: value))
56
58
  end
@@ -88,7 +90,7 @@ module Watir
88
90
  elements.map.with_index do |e, idx|
89
91
  element = element_class.new(@query_scope, @selector.merge(element: e, index: idx))
90
92
  if [Watir::HTMLElement, Watir::Input].include? element.class
91
- tag_name = element.tag_name.to_sym
93
+ tag_name = @selector[:tag_name] || element.tag_name.to_sym
92
94
  hash[tag_name] ||= 0
93
95
  hash[tag_name] += 1
94
96
  Watir.element_class_for(tag_name).new(@query_scope, @selector.merge(element: e,
@@ -513,16 +513,15 @@ module Watir
513
513
 
514
514
  def stale?
515
515
  raise Watir::Exception::Error, "Can not check staleness of unused element" unless @element
516
- return false unless stale_in_context?
517
516
  @query_scope.ensure_context
518
- stale_in_context?
517
+ @stale || stale_in_context?
519
518
  end
520
519
 
521
520
  def stale_in_context?
522
521
  @element.enabled? # any wire call will check for staleness
523
522
  false
524
523
  rescue Selenium::WebDriver::Error::ObsoleteElementError
525
- true
524
+ @stale = true
526
525
  end
527
526
 
528
527
  def reset!
@@ -703,6 +702,10 @@ module Watir
703
702
  method = meth.to_s
704
703
  if method =~ Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE
705
704
  attribute_value(method.tr('_', '-'), *args)
705
+ elsif UserEditable.instance_methods(false).include?(meth) && content_editable?
706
+ @content_editable = true
707
+ self.extend UserEditable
708
+ send(meth, *args, &blk)
706
709
  else
707
710
  super
708
711
  end
@@ -14,12 +14,13 @@ module Watir
14
14
 
15
15
  #
16
16
  # Gets all the options in the select list
17
+ # Use Element#options rather than Select element attribute "options"
17
18
  #
18
19
  # @return [Watir::OptionCollection]
19
20
  #
20
21
 
21
22
  def options(*)
22
- element_call(:wait_for_present) { super }
23
+ super
23
24
  end
24
25
 
25
26
  #
@@ -16,7 +16,7 @@ module Watir
16
16
  end
17
17
 
18
18
  def ignored_attributes
19
- %w(cells elements hash rows span text size selected? style width height tHead tFoot)
19
+ %w(cells elements hash rows span text size selected? style width height tHead tFoot link options)
20
20
  end
21
21
 
22
22
  def generator_implementation
@@ -0,0 +1,3 @@
1
+ function(){
2
+ arguments[0].textContent=arguments[1]
3
+ }
@@ -115,10 +115,18 @@ module Watir
115
115
  idx = idx.abs - 1
116
116
  end
117
117
 
118
+ counter = 0
119
+
118
120
  # Lazy evaluation to avoid fetching values for elements that will be discarded
119
- matches = elements.lazy.select { |el| matches_selector?(el, selector) }
120
- matches.take(idx + 1).to_a[idx]
121
+ matches = elements.lazy.select do |el|
122
+ counter += 1
123
+ matches_selector?(el, selector)
124
+ end
125
+ val = matches.take(idx + 1).to_a[idx]
126
+ Watir.logger.debug "Filtered through #{counter} elements to locate #{@selector.inspect}"
127
+ val
121
128
  else
129
+ Watir.logger.debug "Iterated through #{elements.size} elements to locate all #{@selector.inspect}"
122
130
  elements.select { |el| matches_selector?(el, selector) }
123
131
  end
124
132
  end
@@ -216,19 +224,21 @@ module Watir
216
224
  end
217
225
  end
218
226
 
219
- if selector[:text]
220
- text_content = Watir::Element.new(@query_scope, element: element).send(:execute_js, :getTextContent, element).strip
221
- text_content_matches = selector[:text] === text_content
222
- unless matches == text_content_matches
223
- key = @selector.key?(:text) ? "text" : "label"
224
- Watir.logger.deprecate("Using :#{key} locator with RegExp #{selector[:text].inspect} to match an element that includes hidden text", ":visible_#{key}",
225
- ids: [:text_regexp])
226
- end
227
- end
227
+ text_regexp_deprecation(element, selector, matches) if selector[:text]
228
228
 
229
229
  matches
230
230
  end
231
231
 
232
+ def text_regexp_deprecation(element, selector, matches)
233
+ text_content = Watir::Element.new(@query_scope, element: element).send(:execute_js, :getTextContent, element).strip
234
+ text_content_matches = selector[:text] === text_content
235
+ unless matches == text_content_matches
236
+ key = @selector.key?(:text) ? "text" : "label"
237
+ Watir.logger.deprecate("Using :#{key} locator with RegExp #{selector[:text].inspect} to match an element that includes hidden text", ":visible_#{key}",
238
+ ids: [:text_regexp])
239
+ end
240
+ end
241
+
232
242
  def can_convert_regexp_to_contains?
233
243
  true
234
244
  end
@@ -59,9 +59,10 @@ module Watir
59
59
  end
60
60
 
61
61
  def build(selector)
62
+ inspect = selector.inspect
62
63
  return given_xpath_or_css(selector) if selector.key?(:xpath) || selector.key?(:css)
63
64
  built = build_wd_selector(selector)
64
- Watir.logger.debug "Converted #{selector.inspect} to #{built}"
65
+ Watir.logger.debug "Converted #{inspect} to #{built}"
65
66
  built
66
67
  end
67
68
 
@@ -6,11 +6,7 @@ module Watir
6
6
  return if selectors.values.any? { |e| e.kind_of? Regexp }
7
7
  selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
8
8
 
9
- tag_name = @query_scope.tag_name.downcase
10
- expressions = %w[./tr]
11
- unless %w[tbody tfoot thead].include?(tag_name)
12
- expressions += %w[./tbody/tr ./thead/tr ./tfoot/tr]
13
- end
9
+ expressions = generate_expressions(@query_scope.tag_name.downcase)
14
10
 
15
11
  attr_expr = xpath_builder.attribute_expression(nil, selectors)
16
12
 
@@ -24,6 +20,16 @@ module Watir
24
20
 
25
21
  [:xpath, xpath]
26
22
  end
23
+
24
+ protected
25
+
26
+ def generate_expressions(tag_name)
27
+ expressions = %w[./tr]
28
+ unless %w[tbody tfoot thead].include?(tag_name)
29
+ expressions += %w[./tbody/tr ./thead/tr ./tfoot/tr]
30
+ end
31
+ expressions
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -26,9 +26,11 @@ module Watir
26
26
  raise ArgumentError, "#set! does not support special keys, use #set instead" if args.any? { |v| v.kind_of?(::Symbol) }
27
27
  input_value = args.join
28
28
  set input_value[0]
29
+ return set_content_editable!(*args) if @content_editable
29
30
  element_call { execute_js(:setValue, @element, input_value[0..-2]) }
30
31
  append(input_value[-1])
31
- raise Watir::Exception::Error, "#set! value does not match expected input" unless value == input_value
32
+ return if value == input_value
33
+ raise Watir::Exception::Error, "#set! value: '#{value}' does not match expected input: '#{input_value}'"
32
34
  end
33
35
 
34
36
  #
@@ -38,6 +40,7 @@ module Watir
38
40
  #
39
41
 
40
42
  def append(*args)
43
+ raise NotImplementedError, "#append method is not supported with contenteditable element" if @content_editable
41
44
  send_keys(*args)
42
45
  end
43
46
  alias_method :<<, :append
@@ -52,5 +55,13 @@ module Watir
52
55
  end
53
56
  end
54
57
 
58
+ private
59
+
60
+ def set_content_editable!(*args)
61
+ input_text = args.join
62
+ element_call { execute_js(:setText, @element, input_text) }
63
+ return if text == input_text
64
+ raise Watir::Exception::Error, "#set! text: '#{text}' does not match expected input: '#{input_text}'"
65
+ end
55
66
  end # UserEditable
56
67
  end # Watir
data/lib/watir/wait.rb CHANGED
@@ -111,19 +111,24 @@ module Watir
111
111
  # browser.text_field(name: "new_user_first_name").wait_until(&:present?).click
112
112
  # browser.text_field(name: "new_user_first_name").wait_until(message: 'foo') { |field| field.present? }
113
113
  # browser.text_field(name: "new_user_first_name").wait_until(timeout: 60, &:present?)
114
+ # browser.text_field(name: "new_user_first_name").wait_until(timeout: 60, name: 'new_user_first_name')
114
115
  #
115
116
  # @param [Integer] timeout seconds to wait before timing out
116
117
  # @param [String] message error message for when times out
117
118
  #
118
119
 
119
- def wait_until(deprecated_timeout = nil, deprecated_message = nil, timeout: nil, message: nil, interval: nil, &blk)
120
+ def wait_until(deprecated_timeout = nil, deprecated_message = nil, timeout: nil, message: nil, interval: nil, **opt, &blk)
120
121
  if deprecated_message || deprecated_timeout
121
122
  Watir.logger.deprecate "Using arguments for #wait_until", "keywords", ids: [:timeout_arguments]
122
123
  timeout = deprecated_timeout
123
124
  message = deprecated_message
124
125
  end
125
126
  message ||= Proc.new { |obj| "waiting for true condition on #{obj.inspect}" }
126
- Wait.until(timeout: timeout, message: message, interval: interval, object: self, &blk)
127
+
128
+ raise ArgumentError, "Unknown keyword(s): #{opt.keys} " if block_given? && !opt.empty?
129
+ proc = block_given? ? blk : create_proc(opt)
130
+
131
+ Wait.until(timeout: timeout, message: message, interval: interval, object: self, &proc)
127
132
 
128
133
  self
129
134
  end
@@ -135,6 +140,7 @@ module Watir
135
140
  # browser.wait_while(timeout: 2) do |browser|
136
141
  # !browser.exists?
137
142
  # end
143
+ # browser.wait_while(timeout: 2, title: 'No')
138
144
  #
139
145
  # @todo add element example
140
146
  #
@@ -142,14 +148,18 @@ module Watir
142
148
  # @param [String] message error message for when times out
143
149
  #
144
150
 
145
- def wait_while(deprecated_timeout = nil, deprecated_message = nil, timeout: nil, message: nil, interval: nil, &blk)
151
+ def wait_while(deprecated_timeout = nil, deprecated_message = nil, timeout: nil, message: nil, interval: nil, **opt, &blk)
146
152
  if deprecated_message || deprecated_timeout
147
153
  Watir.logger.deprecate "Using arguments for #wait_while", "keywords", ids: [:timeout_arguments]
148
154
  timeout = deprecated_timeout
149
155
  message = deprecated_message
150
156
  end
151
157
  message ||= Proc.new { |obj| "waiting for false condition on #{obj.inspect}" }
152
- Wait.while(timeout: timeout, message: message, interval: interval, object: self, &blk)
158
+
159
+ raise ArgumentError, "Unknown keyword(s): #{opt.keys} " if block_given? && !opt.empty?
160
+ proc = block_given? ? blk : create_proc(opt)
161
+
162
+ Wait.while(timeout: timeout, message: message, interval: interval, object: self, &proc)
153
163
 
154
164
  self
155
165
  end
@@ -216,5 +226,26 @@ module Watir
216
226
  end
217
227
  end
218
228
 
229
+ private
230
+
231
+ def create_proc(opt)
232
+ Proc.new do
233
+ opt.keys.all? do |key|
234
+ expected = opt[key]
235
+ actual = if self.is_a?(Watir::Element) && !self.respond_to?(key)
236
+ self.attribute_value(key)
237
+ else
238
+ self.send(key)
239
+ end
240
+ case expected
241
+ when Regexp
242
+ expected =~ actual
243
+ else
244
+ expected.to_s == actual
245
+ end
246
+ end
247
+ end
248
+ end
249
+
219
250
  end # Waitable
220
251
  end # Watir
@@ -21,6 +21,11 @@ describe "Adjacent Elements" do
21
21
  expect(browser.div(id: "first_sibling").parent(tag_name: :div)).to be_a Watir::Div
22
22
  end
23
23
 
24
+ it "accepts custom tag_name argument" do
25
+ expect(browser.div(id: "regular_child").parent(tag_name: :grandelement).id).to eq 'custom_grandparent'
26
+ expect(browser.div(id: "regular_child").parent(tag_name: :grandelement)).to be_a Watir::HTMLElement
27
+ end
28
+
24
29
  it "accepts class_name argument" do
25
30
  expect(browser.div(id: "first_sibling").parent(class_name: 'parent').id).to eq 'parent_span'
26
31
  end
@@ -51,6 +56,12 @@ describe "Adjacent Elements" do
51
56
  expect(siblings.all? { |sib| sib.is_a? Watir::Div }).to eq true
52
57
  end
53
58
 
59
+ it "accepts custom tag name argument" do
60
+ siblings = browser.div(id: "regular_child").siblings(tag_name: :childelement)
61
+ expect(siblings.size).to eq 3
62
+ expect(siblings.all? { |sib| sib.is_a? Watir::HTMLElement }).to eq true
63
+ end
64
+
54
65
  it "accepts a class_name argument" do
55
66
  siblings = browser.div(id: "second_sibling").siblings(class_name: 'b')
56
67
  expect(siblings.first).to be_a Watir::Div
@@ -191,6 +202,11 @@ describe "Adjacent Elements" do
191
202
  expect(browser.div(id: "parent").child(tag_name: :span)).to be_a Watir::Span
192
203
  end
193
204
 
205
+ it "accepts custom tag_name argument" do
206
+ expect(browser.element(id: "custom_parent").child(tag_name: :childelement).id).to eq 'custom_child'
207
+ expect(browser.element(id: "custom_parent").child(tag_name: :childelement)).to be_a Watir::HTMLElement
208
+ end
209
+
194
210
  it "accepts class_name argument" do
195
211
  expect(browser.div(id: "parent").child(class_name: 'b').id).to eq 'second_sibling'
196
212
  end
@@ -221,6 +237,12 @@ describe "Adjacent Elements" do
221
237
  expect(children.all? { |child| child.is_a? Watir::Div }).to eq true
222
238
  end
223
239
 
240
+ it "accepts custom tag_name argument" do
241
+ children = browser.element(id: "custom_parent").children(tag_name: :childelement)
242
+ expect(children.size).to eq 3
243
+ expect(children.all? { |child| child.is_a? Watir::HTMLElement }).to eq true
244
+ end
245
+
224
246
  it "accepts a class_name argument" do
225
247
  children = browser.div(id: "parent").children(class_name: 'b')
226
248
  expect(children.size).to eq 2
@@ -286,26 +286,28 @@ describe "Browser" do
286
286
  end
287
287
 
288
288
  compliant_on :chrome do
289
- it "takes port and driver_opt as arguments" do
290
- @original = WatirSpec.implementation.clone
291
- browser.close
292
- @opts = WatirSpec.implementation.browser_args.last
289
+ not_compliant_on :watigiri do
290
+ it "takes port and driver_opt as arguments" do
291
+ @original = WatirSpec.implementation.clone
292
+ browser.close
293
+ @opts = WatirSpec.implementation.browser_args.last
293
294
 
294
- @opts.merge!(port: '2314',
295
- driver_opts: {args: ['foo']},
296
- listener: LocalConfig::SelectorListener.new)
295
+ @opts.merge!(port: '2314',
296
+ driver_opts: {args: ['foo']},
297
+ listener: LocalConfig::SelectorListener.new)
297
298
 
298
- @new_browser = WatirSpec.new_browser
299
+ @new_browser = WatirSpec.new_browser
299
300
 
300
- bridge = @new_browser.wd.instance_variable_get('@bridge')
301
- expect(bridge).to be_a Selenium::WebDriver::Support::EventFiringBridge
302
- service = @new_browser.wd.instance_variable_get("@service")
303
- expect(service.instance_variable_get("@extra_args")).to eq ["foo"]
304
- expect(service.instance_variable_get("@port")).to eq 2314
301
+ bridge = @new_browser.wd.instance_variable_get('@bridge')
302
+ expect(bridge).to be_a Selenium::WebDriver::Support::EventFiringBridge
303
+ service = @new_browser.wd.instance_variable_get("@service")
304
+ expect(service.instance_variable_get("@extra_args")).to eq ["foo"]
305
+ expect(service.instance_variable_get("@port")).to eq 2314
305
306
 
306
- @new_browser.close
307
- WatirSpec.implementation = @original.clone
308
- $browser = WatirSpec.new_browser
307
+ @new_browser.close
308
+ WatirSpec.implementation = @original.clone
309
+ $browser = WatirSpec.new_browser
310
+ end
309
311
  end
310
312
  end
311
313
 
@@ -49,4 +49,28 @@ describe "Collections" do
49
49
  expect(spans).to receive(:elements).and_return([])
50
50
  expect(spans.locate).to be_a Watir::SpanCollection
51
51
  end
52
+
53
+ it "lazy loads collections referenced with #[]" do
54
+ browser.goto(WatirSpec.url_for("collections.html"))
55
+ expect(browser.wd).to_not receive(:find_elements)
56
+ browser.spans[3]
57
+ end
58
+
59
+ it "does not relocate collections when previously evaluated" do
60
+ browser.goto(WatirSpec.url_for("collections.html"))
61
+ elements = browser.spans.tap(&:to_a)
62
+
63
+ expect(browser.wd).to_not receive(:find_elements)
64
+ elements[1].id
65
+ end
66
+
67
+ it "relocates cached elements that go stale" do
68
+ browser.goto(WatirSpec.url_for("collections.html"))
69
+ elements = browser.spans.tap(&:to_a)
70
+
71
+ browser.refresh
72
+ expect(elements[1]).to be_stale
73
+ expect { elements[1] }.to_not raise_unknown_object_exception
74
+ end
75
+
52
76
  end
@@ -151,12 +151,16 @@ describe "Div" do
151
151
  expect { browser.div(text: /some visible/).exists? }.not_to have_deprecated_text_regexp
152
152
  end
153
153
 
154
- it "throws deprecation when no longer matched by text content" do
155
- expect { browser.div(text: /some visible$/).exists? }.to have_deprecated_text_regexp
154
+ not_compliant_on :watigiri do
155
+ it "throws deprecation when no longer matched by text content" do
156
+ expect { browser.div(text: /some visible$/).exists? }.to have_deprecated_text_regexp
157
+ end
156
158
  end
157
159
 
158
- it "throws deprecation when begins to be matched by text content" do
159
- expect { browser.div(text: /some hidden/).exists? }.to have_deprecated_text_regexp
160
+ not_compliant_on :watigiri do
161
+ it "throws deprecation when begins to be matched by text content" do
162
+ expect { browser.div(text: /some hidden/).exists? }.to have_deprecated_text_regexp
163
+ end
160
164
  end
161
165
 
162
166
  it "does not throw deprecation when still not matched by text content" do
@@ -333,15 +333,31 @@ describe "Element" do
333
333
  end
334
334
 
335
335
  it "returns true if the element is enabled" do
336
- expect(browser.element(name: 'new_user_submit')).to be_enabled
336
+ expect(browser.button(name: 'new_user_submit')).to be_enabled
337
337
  end
338
338
 
339
339
  it "returns false if the element is disabled" do
340
- expect(browser.element(name: 'new_user_submit_disabled')).to_not be_enabled
340
+ expect(browser.button(name: 'new_user_submit_disabled')).to_not be_enabled
341
341
  end
342
342
 
343
343
  it "raises UnknownObjectException if the element doesn't exist" do
344
- expect { browser.element(name: "no_such_name").enabled? }.to raise_unknown_object_exception
344
+ expect { browser.button(name: "no_such_name").enabled? }.to raise_unknown_object_exception
345
+ end
346
+ end
347
+
348
+ describe "#stale?" do
349
+ it "returns true if the element is stale" do
350
+ element = browser.button(name: 'new_user_submit_disabled').tap(&:exists?)
351
+
352
+ browser.refresh
353
+
354
+ expect(element).to be_stale
355
+ end
356
+
357
+ it "returns false if the element is not stale" do
358
+ element = browser.button(name: 'new_user_submit_disabled').tap(&:exists?)
359
+
360
+ expect(element).to_not be_stale
345
361
  end
346
362
  end
347
363
 
@@ -207,165 +207,4 @@ describe "TextField" do
207
207
  expect { browser.text_field(id: 'new_user_code').set 'foo' }.to raise_object_read_only_exception
208
208
  end
209
209
  end
210
-
211
- # Manipulation methods
212
- not_compliant_on :safari do
213
- describe "#append" do
214
- it "appends the text to the text field" do
215
- browser.text_field(name: "new_user_occupation").append(" Append This")
216
- expect(browser.text_field(name: "new_user_occupation").value).to eq "Developer Append This"
217
- end
218
-
219
- it "appends multi-byte characters" do
220
- browser.text_field(name: "new_user_occupation").append(" ijij")
221
- expect(browser.text_field(name: "new_user_occupation").value).to eq "Developer ijij"
222
- end
223
-
224
- it "raises ObjectReadOnlyException if the object is read only" do
225
- expect { browser.text_field(id: "new_user_code").append("Append This") }.to raise_object_read_only_exception
226
- end
227
-
228
- it "raises ObjectDisabledException if the object is disabled" do
229
- expect { browser.text_field(name: "new_user_species").append("Append This") }.to raise_object_disabled_exception
230
- end
231
-
232
- it "raises UnknownObjectException if the object doesn't exist" do
233
- expect { browser.text_field(name: "no_such_name").append("Append This") }.to raise_unknown_object_exception
234
- end
235
- end
236
- end
237
-
238
- describe "#clear" do
239
- it "removes all text from the text field" do
240
- browser.text_field(name: "new_user_occupation").clear
241
- expect(browser.text_field(name: "new_user_occupation").value).to be_empty
242
- browser.textarea(id: "delete_user_comment").clear
243
- expect(browser.textarea(id: "delete_user_comment").value).to be_empty
244
- end
245
-
246
- it "raises UnknownObjectException if the text field doesn't exist" do
247
- expect { browser.text_field(id: "no_such_id").clear }.to raise_unknown_object_exception
248
- end
249
-
250
- it "raises ObjectReadOnlyException if the object is read only" do
251
- expect { browser.text_field(id: "new_user_code").clear }.to raise_object_read_only_exception
252
- end
253
- end
254
-
255
- describe "#value=" do
256
- it "sets the value of the element" do
257
- browser.text_field(id: 'new_user_email').value = 'Hello Cruel World'
258
- expect(browser.text_field(id: "new_user_email").value).to eq 'Hello Cruel World'
259
- end
260
-
261
- it "is able to set multi-byte characters" do
262
- browser.text_field(name: "new_user_occupation").value = "ijij"
263
- expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
264
- end
265
-
266
- it "sets the value of a textarea element" do
267
- browser.textarea(id: 'delete_user_comment').value = 'Hello Cruel World'
268
- expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
269
- end
270
-
271
- it "raises UnknownObjectException if the text field doesn't exist" do
272
- expect { browser.text_field(name: "no_such_name").value = 'yo' }.to raise_unknown_object_exception
273
- end
274
- end
275
-
276
- describe "#set" do
277
- it "sets the value of the element" do
278
- browser.text_field(id: 'new_user_email').set('Bye Cruel World')
279
- expect(browser.text_field(id: "new_user_email").value).to eq 'Bye Cruel World'
280
- end
281
-
282
- it "sets the value of a textarea element" do
283
- browser.textarea(id: 'delete_user_comment').set('Hello Cruel World')
284
- expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
285
- end
286
-
287
- it "fires events" do
288
- browser.text_field(id: "new_user_username").set("Hello World")
289
- expect(browser.span(id: "current_length").text).to eq "11"
290
- end
291
-
292
- it "sets the value of a password field" do
293
- browser.text_field(name: 'new_user_password').set('secret')
294
- expect(browser.text_field(name: 'new_user_password').value).to eq 'secret'
295
- end
296
-
297
- it "sets the value when accessed through the enclosing Form" do
298
- browser.form(id: 'new_user').text_field(name: 'new_user_password').set('secret')
299
- expect(browser.form(id: 'new_user').text_field(name: 'new_user_password').value).to eq 'secret'
300
- end
301
-
302
- it "is able to set multi-byte characters" do
303
- browser.text_field(name: "new_user_occupation").set("ijij")
304
- expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
305
- end
306
-
307
- it "sets the value to a concatenation of multiple arguments" do
308
- browser.text_field(id: 'new_user_email').set('Bye', 'Cruel', 'World')
309
- expect(browser.text_field(id: "new_user_email").value).to eq 'ByeCruelWorld'
310
- end
311
-
312
- it "sets the value to blank when no arguments are provided" do
313
- browser.text_field(id: 'new_user_email').set
314
- expect(browser.text_field(id: "new_user_email").value).to eq ''
315
- end
316
-
317
- it "raises UnknownObjectException if the text field doesn't exist" do
318
- expect { browser.text_field(id: "no_such_id").set('secret') }.to raise_unknown_object_exception
319
- end
320
- end
321
-
322
- describe "#set!" do
323
- it "sets the value of the element" do
324
- browser.text_field(id: 'new_user_email').set!('Bye Cruel World')
325
- expect(browser.text_field(id: "new_user_email").value).to eq 'Bye Cruel World'
326
- end
327
-
328
- it "sets the value of a textarea element" do
329
- browser.textarea(id: 'delete_user_comment').set!('Hello Cruel World')
330
- expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
331
- end
332
-
333
- it "fires events" do
334
- browser.text_field(id: "new_user_username").set!("Hello World")
335
- expect(browser.span(id: "current_length").text).to eq "11"
336
- end
337
-
338
- it "sets the value of a password field" do
339
- browser.text_field(name: 'new_user_password').set!('secret')
340
- expect(browser.text_field(name: 'new_user_password').value).to eq 'secret'
341
- end
342
-
343
- it "sets the value when accessed through the enclosing Form" do
344
- browser.form(id: 'new_user').text_field(name: 'new_user_password').set!('secret')
345
- expect(browser.form(id: 'new_user').text_field(name: 'new_user_password').value).to eq 'secret'
346
- end
347
-
348
- it "is able to set multi-byte characters" do
349
- browser.text_field(name: "new_user_occupation").set!("ijij")
350
- expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
351
- end
352
-
353
- it "sets the value to a concatenation of multiple arguments" do
354
- browser.text_field(id: 'new_user_email').set!('Bye', 'Cruel', 'World')
355
- expect(browser.text_field(id: "new_user_email").value).to eq 'ByeCruelWorld'
356
- end
357
-
358
- it "sets the value to blank when no arguments are provided" do
359
- browser.text_field(id: 'new_user_email').set!
360
- expect(browser.text_field(id: "new_user_email").value).to eq ''
361
- end
362
-
363
- it "raises ArgumentError for special keys" do
364
- expect { browser.text_field(id: 'new_user_email').set!('a', :tab) }.to raise_error(ArgumentError)
365
- end
366
-
367
- it "raises UnknownObjectException if the text field doesn't exist" do
368
- expect { browser.text_field(id: "no_such_id").set!('secret') }.to raise_unknown_object_exception
369
- end
370
- end
371
210
  end
@@ -161,6 +161,8 @@
161
161
  <div id="wants_newsletter" style="display: none;"></div>
162
162
  <div id="onfocus_test"></div>
163
163
 
164
+ <div id="contenteditable" contenteditable="true">Foo</div>
165
+
164
166
  <!-- option disappears onchange -->
165
167
  <select id="obsolete" onchange="this.innerHTML = '';">
166
168
  <option value="norway">norway</option>
@@ -6,7 +6,7 @@
6
6
  </head>
7
7
 
8
8
  <body>
9
- <span id="grandparent_span">
9
+ <span id="grandparent_span">
10
10
  <div id="grandparent">
11
11
  <span class="parent" id="parent_span">
12
12
  <div id="parent">
@@ -30,5 +30,15 @@
30
30
  </span>
31
31
  </div>
32
32
  </span>
33
+ <div>
34
+ <grandelement id="custom_grandparent">
35
+ <parentelement id="custom_parent">
36
+ <div id="regular_child"></div>
37
+ <childelement id="custom_child" class="custom_child a"></childelement>
38
+ <childelement class="custom_child b"></childelement>
39
+ <childelement class="custom_child c"></childelement>
40
+ </parentelement>
41
+ </grandelement>
42
+ </div>
33
43
  </body>
34
44
  </html>
@@ -11,7 +11,9 @@
11
11
 
12
12
  function setTimeoutDisplay(id, display, timeout) {
13
13
  setTimeout(function() {
14
- document.getElementById(id).style.display = display;
14
+ var el = document.getElementById(id)
15
+ el.style.display = display;
16
+ el.setAttribute("custom", id)
15
17
  }, timeout);
16
18
  }
17
19
 
@@ -54,7 +56,7 @@
54
56
  </head>
55
57
 
56
58
  <body>
57
- <div id="foo" style="display:block;">foo</div>
59
+ <div id="foo" custom="" style="display:block;">foo</div>
58
60
  <div id="bar" style="display:none;" onclick='this.innerHTML = "changed"'>bar</div>
59
61
  <a id="show_bar" href="#" onclick="setTimeoutDisplay('bar', 'block', 500);">show bar</a>
60
62
  <a id="hide_foo" href="#" onclick="setTimeoutDisplay('foo', 'none', 500);">hide foo</a>
@@ -0,0 +1,202 @@
1
+ require "watirspec_helper"
2
+
3
+ describe Watir::UserEditable do
4
+
5
+ before :each do
6
+ browser.goto(WatirSpec.url_for("forms_with_input_elements.html"))
7
+ end
8
+
9
+ not_compliant_on :safari do
10
+ describe "#append" do
11
+ it "appends the text to the text field" do
12
+ browser.text_field(name: "new_user_occupation").append(" Append This")
13
+ expect(browser.text_field(name: "new_user_occupation").value).to eq "Developer Append This"
14
+ end
15
+
16
+ it "appends multi-byte characters" do
17
+ browser.text_field(name: "new_user_occupation").append(" ijij")
18
+ expect(browser.text_field(name: "new_user_occupation").value).to eq "Developer ijij"
19
+ end
20
+
21
+ it "raises NotImplementedError if the object is content editable element" do
22
+ msg = "#append method is not supported with contenteditable element"
23
+ expect { browser.div(id: 'contenteditable').append("bar") }.to raise_exception(NotImplementedError, msg)
24
+ end
25
+
26
+ it "raises ObjectReadOnlyException if the object is read only" do
27
+ expect { browser.text_field(id: "new_user_code").append("Append This") }.to raise_object_read_only_exception
28
+ end
29
+
30
+ it "raises ObjectDisabledException if the object is disabled" do
31
+ expect { browser.text_field(name: "new_user_species").append("Append This") }.to raise_object_disabled_exception
32
+ end
33
+
34
+ it "raises UnknownObjectException if the object doesn't exist" do
35
+ expect { browser.text_field(name: "no_such_name").append("Append This") }.to raise_unknown_object_exception
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#clear" do
41
+ it "removes all text from the text field" do
42
+ browser.text_field(name: "new_user_occupation").clear
43
+ expect(browser.text_field(name: "new_user_occupation").value).to be_empty
44
+ browser.textarea(id: "delete_user_comment").clear
45
+ expect(browser.textarea(id: "delete_user_comment").value).to be_empty
46
+ end
47
+
48
+ it "removes all text from the content editable element" do
49
+ browser.div(id: 'contenteditable').clear
50
+ expect(browser.div(id: 'contenteditable').text).to eq ""
51
+ end
52
+
53
+ it "raises UnknownObjectException if the text field doesn't exist" do
54
+ expect { browser.text_field(id: "no_such_id").clear }.to raise_unknown_object_exception
55
+ end
56
+
57
+ it "raises ObjectReadOnlyException if the object is read only" do
58
+ expect { browser.text_field(id: "new_user_code").clear }.to raise_object_read_only_exception
59
+ end
60
+ end
61
+
62
+ describe "#value=" do
63
+ it "sets the value of the element" do
64
+ browser.text_field(id: 'new_user_email').value = 'Hello Cruel World'
65
+ expect(browser.text_field(id: "new_user_email").value).to eq 'Hello Cruel World'
66
+ end
67
+
68
+ it "is able to set multi-byte characters" do
69
+ browser.text_field(name: "new_user_occupation").value = "ijij"
70
+ expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
71
+ end
72
+
73
+ it "sets the value of a textarea element" do
74
+ browser.textarea(id: 'delete_user_comment').value = 'Hello Cruel World'
75
+ expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
76
+ end
77
+
78
+ it "raises UnknownObjectException if the text field doesn't exist" do
79
+ expect { browser.text_field(name: "no_such_name").value = 'yo' }.to raise_unknown_object_exception
80
+ end
81
+ end
82
+
83
+ describe "#set" do
84
+ it "sets the value of the element" do
85
+ browser.text_field(id: 'new_user_email').set('Bye Cruel World')
86
+ expect(browser.text_field(id: "new_user_email").value).to eq 'Bye Cruel World'
87
+ end
88
+
89
+ it "sets the value of a textarea element" do
90
+ browser.textarea(id: 'delete_user_comment').set('Hello Cruel World')
91
+ expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
92
+ end
93
+
94
+ it "sets the value of a content editable element" do
95
+ browser.div(id: 'contenteditable').set("Bar")
96
+ expect(browser.div(id: 'contenteditable').text).to eq "Bar"
97
+ end
98
+
99
+ it "fires events" do
100
+ browser.text_field(id: "new_user_username").set("Hello World")
101
+ expect(browser.span(id: "current_length").text).to eq "11"
102
+ end
103
+
104
+ it "sets the value of a password field" do
105
+ browser.text_field(name: 'new_user_password').set('secret')
106
+ expect(browser.text_field(name: 'new_user_password').value).to eq 'secret'
107
+ end
108
+
109
+ it "sets the value when accessed through the enclosing Form" do
110
+ browser.form(id: 'new_user').text_field(name: 'new_user_password').set('secret')
111
+ expect(browser.form(id: 'new_user').text_field(name: 'new_user_password').value).to eq 'secret'
112
+ end
113
+
114
+ it "is able to set multi-byte characters" do
115
+ browser.text_field(name: "new_user_occupation").set("ijij")
116
+ expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
117
+ end
118
+
119
+ it "sets the value to a concatenation of multiple arguments" do
120
+ browser.text_field(id: 'new_user_email').set('Bye', 'Cruel', 'World')
121
+ expect(browser.text_field(id: "new_user_email").value).to eq 'ByeCruelWorld'
122
+ end
123
+
124
+ it "sets the value to blank when no arguments are provided" do
125
+ browser.text_field(id: 'new_user_email').set
126
+ expect(browser.text_field(id: "new_user_email").value).to eq ''
127
+ end
128
+
129
+ it "raises UnknownObjectException if the text field doesn't exist" do
130
+ expect { browser.text_field(id: "no_such_id").set('secret') }.to raise_unknown_object_exception
131
+ end
132
+ end
133
+
134
+ describe "#set!" do
135
+ it "sets the value of the element" do
136
+ browser.text_field(id: 'new_user_email').set!('Bye Cruel World')
137
+ expect(browser.text_field(id: "new_user_email").value).to eq 'Bye Cruel World'
138
+ end
139
+
140
+ it "sets the value of a textarea element" do
141
+ browser.textarea(id: 'delete_user_comment').set!('Hello Cruel World')
142
+ expect(browser.textarea(id: "delete_user_comment").value).to eq 'Hello Cruel World'
143
+ end
144
+
145
+ it "sets the value of a content editable element" do
146
+ browser.div(id: 'contenteditable').set!("foo")
147
+ expect(browser.div(id: 'contenteditable').text).to eq "foo"
148
+ end
149
+
150
+ it "fires events" do
151
+ browser.text_field(id: "new_user_username").set!("Hello World")
152
+ expect(browser.span(id: "current_length").text).to eq "11"
153
+ end
154
+
155
+ it "sets the value of a password field" do
156
+ browser.text_field(name: 'new_user_password').set!('secret')
157
+ expect(browser.text_field(name: 'new_user_password').value).to eq 'secret'
158
+ end
159
+
160
+ it "sets the value when accessed through the enclosing Form" do
161
+ browser.form(id: 'new_user').text_field(name: 'new_user_password').set!('secret')
162
+ expect(browser.form(id: 'new_user').text_field(name: 'new_user_password').value).to eq 'secret'
163
+ end
164
+
165
+ it "is able to set multi-byte characters" do
166
+ browser.text_field(name: "new_user_occupation").set!("ijij")
167
+ expect(browser.text_field(name: "new_user_occupation").value).to eq "ijij"
168
+ end
169
+
170
+ it "sets the value to a concatenation of multiple arguments" do
171
+ browser.text_field(id: 'new_user_email').set!('Bye', 'Cruel', 'World')
172
+ expect(browser.text_field(id: "new_user_email").value).to eq 'ByeCruelWorld'
173
+ end
174
+
175
+ it "sets the value to blank when no arguments are provided" do
176
+ browser.text_field(id: 'new_user_email').set!
177
+ expect(browser.text_field(id: "new_user_email").value).to eq ''
178
+ end
179
+
180
+ it "raises ArgumentError for special keys" do
181
+ expect { browser.text_field(id: 'new_user_email').set!('a', :tab) }.to raise_error(ArgumentError)
182
+ end
183
+
184
+ it "raises UnknownObjectException if the text field doesn't exist" do
185
+ expect { browser.text_field(id: "no_such_id").set!('secret') }.to raise_unknown_object_exception
186
+ end
187
+
188
+ it "raises Exception if the value of text field doesn't match" do
189
+ element = browser.text_field(id: "new_user_password")
190
+ allow(element).to receive(:value).and_return("wrong")
191
+ msg = "#set! value: 'wrong' does not match expected input: 'secret'"
192
+ expect { element.set!('secret') }.to raise_exception(Watir::Exception::Error, msg)
193
+ end
194
+
195
+ it "raises Exception if the text of content editable element doesn't match" do
196
+ element = browser.div(id: "contenteditable")
197
+ allow(element).to receive(:text).and_return("wrong")
198
+ msg = "#set! text: 'wrong' does not match expected input: 'secret'"
199
+ expect { element.set!('secret') }.to raise_exception(Watir::Exception::Error, msg)
200
+ end
201
+ end
202
+ end
@@ -204,6 +204,49 @@ describe Watir::Element do
204
204
  element = browser.div(id: 'bar')
205
205
  expect { element.wait_until(interval: 0.1) { true } }.to_not raise_exception
206
206
  end
207
+
208
+ context "accepts keywords instead of block" do
209
+ before { browser.refresh }
210
+
211
+ it "accepts text keyword" do
212
+ element = browser.div(id: 'bar')
213
+ browser.a(id: 'show_bar').click
214
+ expect { element.wait_until(text: 'bar') }.to_not raise_exception
215
+ end
216
+
217
+ it "accepts regular expression value" do
218
+ element = browser.div(id: 'bar')
219
+ browser.a(id: 'show_bar').click
220
+ expect { element.wait_until(style: /block/) }.to_not raise_exception
221
+ end
222
+
223
+ it "accepts multiple keywords" do
224
+ element = browser.div(id: 'bar')
225
+ browser.a(id: 'show_bar').click
226
+ expect { element.wait_until(text: 'bar', style: /block/) }.to_not raise_exception
227
+ end
228
+
229
+ it "accepts custom keyword" do
230
+ element = browser.div(id: 'bar')
231
+ browser.a(id: 'show_bar').click
232
+ expect { element.wait_until(custom: 'bar') }.to_not raise_exception
233
+ end
234
+
235
+ it "times out when single keyword not met" do
236
+ element = browser.div(id: 'bar')
237
+ expect { element.wait_until(id: 'foo') }.to raise_timeout_exception
238
+ end
239
+
240
+ it "times out when one of multiple keywords not met" do
241
+ element = browser.div(id: 'bar')
242
+ expect { element.wait_until(id: 'bar', text: 'foo') }.to raise_timeout_exception
243
+ end
244
+
245
+ it "times out when a custom keywords not met" do
246
+ element = browser.div(id: 'bar')
247
+ expect { element.wait_until(custom: 'foo') }.to raise_timeout_exception
248
+ end
249
+ end
207
250
  end
208
251
 
209
252
  describe "#wait_while" do
@@ -240,6 +283,48 @@ describe Watir::Element do
240
283
  element = browser.div(id: 'foo')
241
284
  expect { element.wait_while(interval: 0.1) { false } }.to_not raise_exception
242
285
  end
286
+
287
+ context "accepts keywords instead of block" do
288
+ it "accepts text keyword" do
289
+ element = browser.div(id: 'foo')
290
+ browser.a(id: 'hide_foo').click
291
+ expect { element.wait_while(text: 'foo') }.to_not raise_exception
292
+ end
293
+
294
+ it "accepts regular expression value" do
295
+ element = browser.div(id: 'foo')
296
+ browser.a(id: 'hide_foo').click
297
+ expect { element.wait_while(style: /block/) }.to_not raise_exception
298
+ end
299
+
300
+ it "accepts multiple keywords" do
301
+ element = browser.div(id: 'foo')
302
+ browser.a(id: 'hide_foo').click
303
+ expect { element.wait_while(text: 'foo', style: /block/) }.to_not raise_exception
304
+ end
305
+
306
+ it "accepts custom attributes" do
307
+ element = browser.div(id: 'foo')
308
+ browser.a(id: 'hide_foo').click
309
+ expect { element.wait_while(custom: '') }.to_not raise_exception
310
+ end
311
+
312
+ it "times out when single keyword not met" do
313
+ element = browser.div(id: 'foo')
314
+ expect { element.wait_while(id: 'foo') }.to raise_timeout_exception
315
+ end
316
+
317
+ it "times out when one of multiple keywords not met" do
318
+ element = browser.div(id: 'foo')
319
+ browser.a(id: 'hide_foo').click
320
+ expect { element.wait_while(id: 'foo', style: /block/) }.to raise_timeout_exception
321
+ end
322
+
323
+ it "times out when one of custom keywords not met" do
324
+ element = browser.div(id: 'foo')
325
+ expect { element.wait_while(custom: '') }.to raise_timeout_exception
326
+ end
327
+ end
243
328
  end
244
329
  end
245
330
 
data/watir.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'watir'
5
- s.version = '6.12.0'
5
+ s.version = '6.13.0'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Alex Rodionov', 'Titus Fortner']
8
8
  s.email = ['p0deje@gmail.com', 'titusfortner@gmail.com']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watir
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.12.0
4
+ version: 6.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Rodionov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-07-24 00:00:00.000000000 Z
12
+ date: 2018-09-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: selenium-webdriver
@@ -292,6 +292,7 @@ files:
292
292
  - lib/watir/js_snippets/selectOptionsValue.js
293
293
  - lib/watir/js_snippets/selectText.js
294
294
  - lib/watir/js_snippets/selectedOptions.js
295
+ - lib/watir/js_snippets/setText.js
295
296
  - lib/watir/js_snippets/setValue.js
296
297
  - lib/watir/legacy_wait.rb
297
298
  - lib/watir/locators.rb
@@ -497,6 +498,7 @@ files:
497
498
  - spec/watirspec/screenshot_spec.rb
498
499
  - spec/watirspec/special_chars_spec.rb
499
500
  - spec/watirspec/support/rspec_matchers.rb
501
+ - spec/watirspec/user_editable_spec.rb
500
502
  - spec/watirspec/wait_spec.rb
501
503
  - spec/watirspec/window_switching_spec.rb
502
504
  - spec/watirspec_helper.rb
@@ -697,6 +699,7 @@ test_files:
697
699
  - spec/watirspec/screenshot_spec.rb
698
700
  - spec/watirspec/special_chars_spec.rb
699
701
  - spec/watirspec/support/rspec_matchers.rb
702
+ - spec/watirspec/user_editable_spec.rb
700
703
  - spec/watirspec/wait_spec.rb
701
704
  - spec/watirspec/window_switching_spec.rb
702
705
  - spec/watirspec_helper.rb