watir 6.16.5 → 6.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +32 -107
  3. data/.travis.yml +24 -21
  4. data/CHANGES.md +16 -0
  5. data/Gemfile +3 -1
  6. data/Rakefile +3 -3
  7. data/appveyor.yml +2 -1
  8. data/lib/watir-webdriver.rb +1 -1
  9. data/lib/watir.rb +0 -1
  10. data/lib/watir/adjacent.rb +8 -10
  11. data/lib/watir/after_hooks.rb +4 -4
  12. data/lib/watir/browser.rb +5 -1
  13. data/lib/watir/capabilities.rb +9 -6
  14. data/lib/watir/cookies.rb +1 -1
  15. data/lib/watir/elements/element.rb +59 -46
  16. data/lib/watir/elements/file_field.rb +1 -0
  17. data/lib/watir/elements/iframe.rb +2 -2
  18. data/lib/watir/elements/link.rb +0 -9
  19. data/lib/watir/elements/radio.rb +1 -1
  20. data/lib/watir/elements/select.rb +2 -2
  21. data/lib/watir/generator/base/spec_extractor.rb +4 -4
  22. data/lib/watir/js_execution.rb +1 -1
  23. data/lib/watir/legacy_wait.rb +1 -1
  24. data/lib/watir/locators/element/selector_builder.rb +11 -12
  25. data/lib/watir/locators/element/selector_builder/xpath.rb +40 -13
  26. data/lib/watir/locators/text_field/selector_builder/xpath.rb +3 -1
  27. data/lib/watir/logger.rb +5 -2
  28. data/lib/watir/version.rb +1 -1
  29. data/lib/watir/window.rb +1 -1
  30. data/lib/watirspec.rb +1 -1
  31. data/lib/watirspec/guards.rb +1 -1
  32. data/lib/watirspec/rake_tasks.rb +2 -0
  33. data/lib/watirspec/runner.rb +4 -0
  34. data/spec/unit/container_spec.rb +1 -1
  35. data/spec/unit/logger_spec.rb +5 -7
  36. data/spec/unit/selector_builder/button_spec.rb +16 -15
  37. data/spec/unit/selector_builder/element_spec.rb +58 -9
  38. data/spec/unit/selector_builder/text_field_spec.rb +14 -14
  39. data/spec/watirspec/after_hooks_spec.rb +64 -78
  40. data/spec/watirspec/alert_spec.rb +69 -79
  41. data/spec/watirspec/browser_spec.rb +48 -46
  42. data/spec/watirspec/cookies_spec.rb +52 -37
  43. data/spec/watirspec/drag_and_drop_spec.rb +14 -38
  44. data/spec/watirspec/elements/button_spec.rb +2 -0
  45. data/spec/watirspec/elements/buttons_spec.rb +1 -1
  46. data/spec/watirspec/elements/checkbox_spec.rb +8 -4
  47. data/spec/watirspec/elements/date_field_spec.rb +18 -9
  48. data/spec/watirspec/elements/date_time_field_spec.rb +3 -4
  49. data/spec/watirspec/elements/div_spec.rb +62 -54
  50. data/spec/watirspec/elements/element_spec.rb +60 -78
  51. data/spec/watirspec/elements/elements_spec.rb +12 -3
  52. data/spec/watirspec/elements/filefield_spec.rb +25 -50
  53. data/spec/watirspec/elements/form_spec.rb +6 -8
  54. data/spec/watirspec/elements/frame_spec.rb +10 -13
  55. data/spec/watirspec/elements/iframe_spec.rb +17 -12
  56. data/spec/watirspec/elements/iframes_spec.rb +2 -2
  57. data/spec/watirspec/elements/link_spec.rb +18 -9
  58. data/spec/watirspec/elements/links_spec.rb +11 -3
  59. data/spec/watirspec/elements/option_spec.rb +15 -17
  60. data/spec/watirspec/elements/select_list_spec.rb +66 -80
  61. data/spec/watirspec/elements/text_field_spec.rb +8 -4
  62. data/spec/watirspec/elements/tr_spec.rb +0 -9
  63. data/spec/watirspec/html/forms_with_input_elements.html +1 -0
  64. data/spec/watirspec/html/iframes.html +3 -0
  65. data/spec/watirspec/html/non_control_elements.html +4 -4
  66. data/spec/watirspec/html/right_click.html +12 -0
  67. data/spec/watirspec/html/wait.html +1 -1
  68. data/spec/watirspec/relaxed_locate_spec.rb +16 -20
  69. data/spec/watirspec/support/rspec_matchers.rb +7 -6
  70. data/spec/watirspec/user_editable_spec.rb +1 -1
  71. data/spec/watirspec/wait_spec.rb +13 -17
  72. data/spec/watirspec/window_switching_spec.rb +162 -163
  73. data/spec/watirspec_helper.rb +7 -5
  74. data/watir.gemspec +4 -5
  75. metadata +14 -16
  76. data/lib/watir/elements/area.rb +0 -10
@@ -36,7 +36,9 @@ module Watir
36
36
 
37
37
  def negative_type_text
38
38
  Watir::TextField::NON_TEXT_TYPES.map { |type|
39
- "#{lhs_for(:type, true)}!=#{SelectorBuilder::XpathSupport.escape type}"
39
+ lhs = lhs_for(:type, downcase: true)
40
+ rhs = SelectorBuilder::XpathSupport.downcase(SelectorBuilder::XpathSupport.escape(type))
41
+ "#{lhs}!=#{rhs}"
40
42
  }.join(' and ')
41
43
  end
42
44
  end
@@ -34,8 +34,7 @@ module Watir
34
34
  end
35
35
 
36
36
  def ignore(ids)
37
- ids = [ids] unless ids.is_a? Array
38
- @ignored.concat ids.map(&:to_s)
37
+ @ignored.concat Array(ids).map(&:to_s)
39
38
  end
40
39
 
41
40
  def output=(io)
@@ -96,6 +95,10 @@ module Watir
96
95
  warn "[DEPRECATION] #{msg}#{old} is deprecated. Use #{new} instead#{ref_msg}"
97
96
  end
98
97
 
98
+ def selenium=(val)
99
+ Selenium::WebDriver.logger.level = val
100
+ end
101
+
99
102
  private
100
103
 
101
104
  def create_logger(output)
@@ -1,3 +1,3 @@
1
1
  module Watir
2
- VERSION = '6.16.5'.freeze
2
+ VERSION = '6.17.0'.freeze
3
3
  end
@@ -233,7 +233,7 @@ module Watir
233
233
 
234
234
  matches_title && matches_url
235
235
  end
236
- rescue Selenium::WebDriver::Error::NoSuchWindowError, Selenium::WebDriver::Error::NoSuchDriverError
236
+ rescue Selenium::WebDriver::Error::NoSuchWindowError
237
237
  # the window may disappear while we're iterating.
238
238
  false
239
239
  end
@@ -31,7 +31,7 @@ module WatirSpec
31
31
 
32
32
  def load_support
33
33
  root = File.expand_path('../spec/watirspec', __dir__)
34
- Dir.glob("#{root}/support/**/*.rb").each do |file|
34
+ Dir.glob("#{root}/support/**/*.rb").sort.each do |file|
35
35
  require file
36
36
  end
37
37
  end
@@ -17,7 +17,7 @@ module WatirSpec
17
17
  "\tnone."
18
18
  else
19
19
  gs.each do |guard|
20
- guard[:data][:file] = guard[:data][:file][%r{\/spec\/(.*):}, 1]
20
+ guard[:data][:file] = guard[:data][:file][%r{/spec/(.*):}, 1]
21
21
  guard_name = "#{guard[:name]}:".ljust(15)
22
22
  str << " \t#{guard_name} #{guard[:data].inspect}\n"
23
23
  end
@@ -3,6 +3,8 @@ require 'rake/tasklib'
3
3
  module WatirSpec
4
4
  class RakeTasks < Rake::TaskLib
5
5
  def initialize
6
+ super
7
+
6
8
  namespace :watirspec do
7
9
  desc 'Initialize WatirSpec'
8
10
  task :init do
@@ -10,6 +10,10 @@ module WatirSpec
10
10
  def messages
11
11
  browser.div(id: 'messages').divs.map(&:text)
12
12
  end
13
+
14
+ def event_log
15
+ browser.div(id: 'log').wait_until(&:present?).ps.map(&:text)
16
+ end
13
17
  end
14
18
 
15
19
  module_function
@@ -17,7 +17,7 @@ describe Watir::Container do
17
17
  end
18
18
 
19
19
  it 'returns the hash given' do
20
- expect(@container.public_extract_selector([how: 'what'])).to eq Hash[how: 'what']
20
+ expect(@container.public_extract_selector([{how: 'what'}])).to eq Hash[how: 'what']
21
21
  end
22
22
 
23
23
  it 'returns an empty hash if given no args' do
@@ -34,13 +34,11 @@ module Watir
34
34
  end
35
35
 
36
36
  it 'allows to output to file' do
37
- begin
38
- Watir.logger.output = 'test.log'
39
- Watir.logger.warn('message')
40
- expect(File.read('test.log')).to include('WARN Watir message')
41
- ensure
42
- File.delete('test.log')
43
- end
37
+ Watir.logger.output = 'test.log'
38
+ Watir.logger.warn('message')
39
+ expect(File.read('test.log')).to include('WARN Watir message')
40
+ ensure
41
+ File.delete('test.log')
44
42
  end
45
43
 
46
44
  it 'allows to deprecate functionality' do
@@ -7,10 +7,10 @@ describe Watir::Locators::Button::SelectorBuilder do
7
7
  let(:uppercase) { 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ' }
8
8
  let(:lowercase) { 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ' }
9
9
  let(:default_types) do
10
- "translate(@type,'#{uppercase}','#{lowercase}')='button' or" \
11
- " translate(@type,'#{uppercase}','#{lowercase}')='reset' or"\
12
- " translate(@type,'#{uppercase}','#{lowercase}')='submit' or"\
13
- " translate(@type,'#{uppercase}','#{lowercase}')='image'"
10
+ "translate(@type,'#{uppercase}','#{lowercase}')=translate('button','#{uppercase}','#{lowercase}') or " \
11
+ "translate(@type,'#{uppercase}','#{lowercase}')=translate('reset','#{uppercase}','#{lowercase}') or "\
12
+ "translate(@type,'#{uppercase}','#{lowercase}')=translate('submit','#{uppercase}','#{lowercase}') or "\
13
+ "translate(@type,'#{uppercase}','#{lowercase}')=translate('image','#{uppercase}','#{lowercase}')"
14
14
  end
15
15
 
16
16
  describe '#build' do
@@ -36,9 +36,10 @@ describe Watir::Locators::Button::SelectorBuilder do
36
36
 
37
37
  it 'locates input or button element with specified type' do
38
38
  selector = {type: 'reset'}
39
+ type = "translate('reset','#{uppercase}','#{lowercase}')"
39
40
  built = {xpath: ".//*[(local-name()='button' and " \
40
- "translate(@type,'#{uppercase}','#{lowercase}')='reset') or " \
41
- "(local-name()='input' and (translate(@type,'#{uppercase}','#{lowercase}')='reset'))]"}
41
+ "translate(@type,'#{uppercase}','#{lowercase}')=#{type}) or " \
42
+ "(local-name()='input' and (translate(@type,'#{uppercase}','#{lowercase}')=#{type}))]"}
42
43
  expect(selector_builder.build(selector)).to eq built
43
44
  end
44
45
 
@@ -75,35 +76,35 @@ describe Watir::Locators::Button::SelectorBuilder do
75
76
 
76
77
  it 'locates value of input element with simple Regexp' do
77
78
  selector = {text: /Button/}
78
- built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Button')) or " \
79
+ built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), 'Button')) or " \
79
80
  "(local-name()='input' and (#{default_types}) and contains(@value, 'Button'))]"}
80
81
  expect(selector_builder.build(selector)).to eq built
81
82
  end
82
83
 
83
84
  it 'locates text of button element with simple Regexp' do
84
85
  selector = {text: /Button 2/}
85
- built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Button 2')) or " \
86
+ built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), 'Button 2')) or " \
86
87
  "(local-name()='input' and (#{default_types}) and contains(@value, 'Button 2'))]"}
87
88
  expect(selector_builder.build(selector)).to eq built
88
89
  end
89
90
 
90
91
  it 'Simple Regexp for text' do
91
92
  selector = {text: /n 2/}
92
- built = {xpath: ".//*[(local-name()='button' and contains(text(), 'n 2')) or " \
93
+ built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), 'n 2')) or " \
93
94
  "(local-name()='input' and (#{default_types}) and contains(@value, 'n 2'))]"}
94
95
  expect(selector_builder.build(selector)).to eq built
95
96
  end
96
97
 
97
98
  it 'Simple Regexp for value' do
98
99
  selector = {text: /Prev/}
99
- built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Prev')) or " \
100
+ built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), 'Prev')) or " \
100
101
  "(local-name()='input' and (#{default_types}) and contains(@value, 'Prev'))]"}
101
102
  expect(selector_builder.build(selector)).to eq built
102
103
  end
103
104
 
104
105
  it 'returns complex Regexp to the locator' do
105
106
  selector = {text: /^foo$/}
106
- built = {xpath: ".//*[(local-name()='button' and contains(text(), 'foo')) or " \
107
+ built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), 'foo')) or " \
107
108
  "(local-name()='input' and (#{default_types}) and contains(@value, 'foo'))]", text: /^foo$/}
108
109
  expect(selector_builder.build(selector)).to eq built
109
110
  end
@@ -127,14 +128,14 @@ describe Watir::Locators::Button::SelectorBuilder do
127
128
  it 'input element value with simple Regexp' do
128
129
  selector = {value: /Prev/}
129
130
  built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
130
- "[contains(text(), 'Prev') or contains(@value, 'Prev')]"}
131
+ "[contains(normalize-space(), 'Prev') or contains(@value, 'Prev')]"}
131
132
  expect(selector_builder.build(selector)).to eq built
132
133
  end
133
134
 
134
135
  it 'button element value with simple Regexp' do
135
136
  selector = {value: /on_2/}
136
137
  built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
137
- "[contains(text(), 'on_2') or contains(@value, 'on_2')]"}
138
+ "[contains(normalize-space(), 'on_2') or contains(@value, 'on_2')]"}
138
139
  expect(selector_builder.build(selector)).to eq built
139
140
  end
140
141
 
@@ -148,14 +149,14 @@ describe Watir::Locators::Button::SelectorBuilder do
148
149
  it 'button element text with simple Regexp' do
149
150
  selector = {value: /ton 2/}
150
151
  built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
151
- "[contains(text(), 'ton 2') or contains(@value, 'ton 2')]"}
152
+ "[contains(normalize-space(), 'ton 2') or contains(@value, 'ton 2')]"}
152
153
  expect(selector_builder.build(selector)).to eq built
153
154
  end
154
155
 
155
156
  it 'returns complex Regexp to the locator' do
156
157
  selector = {value: /^foo$/}
157
158
  built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
158
- "[contains(text(), 'foo') or contains(@value, 'foo')]", value: /^foo$/}
159
+ "[contains(normalize-space(), 'foo') or contains(@value, 'foo')]", value: /^foo$/}
159
160
  expect(selector_builder.build(selector)).to eq built
160
161
  end
161
162
  end
@@ -51,7 +51,7 @@ describe Watir::Locators::Element::SelectorBuilder do
51
51
 
52
52
  it 'raises exception when not a String' do
53
53
  selector = {xpath: 7}
54
- msg = /expected one of \[String\], got 7:(Fixnum|Integer)/
54
+ msg = /expected one of \[String\], got 7:Integer/
55
55
 
56
56
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
57
57
  end
@@ -81,7 +81,7 @@ describe Watir::Locators::Element::SelectorBuilder do
81
81
 
82
82
  it 'raises exception when not a String or Regexp' do
83
83
  selector = {tag_name: 7}
84
- msg = /expected one of \[String, Regexp, Symbol\], got 7:(Fixnum|Integer)/
84
+ msg = /expected one of \[String, Regexp, Symbol\], got 7:Integer/
85
85
 
86
86
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
87
87
  end
@@ -186,14 +186,14 @@ describe Watir::Locators::Element::SelectorBuilder do
186
186
 
187
187
  it 'raises exception when not a String or Regexp or Array' do
188
188
  selector = {class: 7}
189
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
189
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
190
190
 
191
191
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
192
192
  end
193
193
 
194
194
  it 'raises exception when Array values are not a String or Regexp' do
195
195
  selector = {class: [7]}
196
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
196
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
197
197
 
198
198
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
199
199
  end
@@ -244,14 +244,14 @@ describe Watir::Locators::Element::SelectorBuilder do
244
244
 
245
245
  it 'raises exception when attribute value is not a Boolean, String or Regexp' do
246
246
  selector = {foo: 7}
247
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
247
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
248
248
 
249
249
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
250
250
  end
251
251
 
252
252
  it 'raises exception when attribute key is not a String or Regexp' do
253
253
  selector = {7 => 'foo'}
254
- msg = /Unable to build XPath using 7:(Fixnum|Integer)/
254
+ msg = /Unable to build XPath using 7:Integer/
255
255
 
256
256
  expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
257
257
  end
@@ -292,7 +292,7 @@ describe Watir::Locators::Element::SelectorBuilder do
292
292
 
293
293
  it 'raises exception when text is not a String or Regexp' do
294
294
  selector = {text: 7}
295
- msg = /expected one of \[String, Regexp\], got 7:(Fixnum|Integer)/
295
+ msg = /expected one of \[String, Regexp\], got 7:Integer/
296
296
 
297
297
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
298
298
  end
@@ -574,7 +574,10 @@ describe Watir::Locators::Element::SelectorBuilder do
574
574
  selector = {action: /ME/i}
575
575
  built = {xpath: './/*[contains(translate(@action,' \
576
576
  "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
577
- "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'), 'me')]"}
577
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'), " \
578
+ "translate('me'," \
579
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
580
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'))]"}
578
581
 
579
582
  expect(selector_builder.build(selector)).to eq built
580
583
  end
@@ -662,7 +665,7 @@ describe Watir::Locators::Element::SelectorBuilder do
662
665
 
663
666
  it 'raises exception when visible text is not a String or Regexp' do
664
667
  selector = {visible_text: 7}
665
- msg = /expected one of \[String, Regexp\], got 7:(Fixnum|Integer)/
668
+ msg = /expected one of \[String, Regexp\], got 7:Integer/
666
669
 
667
670
  expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
668
671
  end
@@ -762,5 +765,51 @@ describe Watir::Locators::Element::SelectorBuilder do
762
765
  expect(build_selector).to eq built
763
766
  end
764
767
  end
768
+
769
+ context 'with case-insensitive attributes' do
770
+ it 'respects case when locating uknown element with uknown attribute' do
771
+ expect(selector_builder.build(hreflang: 'en')).to eq(xpath: ".//*[@hreflang='en']")
772
+ expect(selector_builder.build(hreflang: /en/)).to eq(xpath: ".//*[contains(@hreflang, 'en')]")
773
+ end
774
+
775
+ it 'ignores case when locating uknown element with defined attribute' do
776
+ lhs = 'translate(@lang,' \
777
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
778
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')"
779
+ rhs = "translate('en'," \
780
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
781
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')"
782
+ expect(selector_builder.build(lang: 'en')).to eq(xpath: ".//*[#{lhs}=#{rhs}]")
783
+ expect(selector_builder.build(lang: /en/)).to eq(xpath: ".//*[contains(#{lhs}, #{rhs})]")
784
+ expect(selector_builder.build(tag_name: /a/, lang: 'en'))
785
+ .to eq(xpath: ".//*[contains(local-name(), 'a')][#{lhs}=#{rhs}]")
786
+ expect(selector_builder.build(tag_name: /a/, lang: /en/))
787
+ .to eq(xpath: ".//*[contains(local-name(), 'a')][contains(#{lhs}, #{rhs})]")
788
+ end
789
+
790
+ it 'ignores case when attribute is defined for element' do
791
+ lhs = 'translate(@hreflang,' \
792
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
793
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')"
794
+ rhs = "translate('en'," \
795
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
796
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')"
797
+ expect(selector_builder.build(tag_name: 'a', hreflang: 'en'))
798
+ .to eq(xpath: ".//*[local-name()='a'][#{lhs}=#{rhs}]")
799
+ expect(selector_builder.build(tag_name: 'a', hreflang: /en/))
800
+ .to eq(xpath: ".//*[local-name()='a'][contains(#{lhs}, #{rhs})]")
801
+ end
802
+
803
+ it 'respects case when attribute is not defined for element' do
804
+ expect(selector_builder.build(tag_name: 'table', hreflang: 'en'))
805
+ .to eq(xpath: ".//*[local-name()='table'][@hreflang='en']")
806
+ expect(selector_builder.build(tag_name: 'table', hreflang: /en/))
807
+ .to eq(xpath: ".//*[local-name()='table'][contains(@hreflang, 'en')]")
808
+ expect(selector_builder.build(tag_name: /a/, hreflang: 'en'))
809
+ .to eq(xpath: ".//*[contains(local-name(), 'a')][@hreflang='en']")
810
+ expect(selector_builder.build(tag_name: /a/, hreflang: /en/))
811
+ .to eq(xpath: ".//*[contains(local-name(), 'a')][contains(@hreflang, 'en')]")
812
+ end
813
+ end
765
814
  end
766
815
  end
@@ -7,18 +7,18 @@ describe Watir::Locators::TextField::SelectorBuilder do
7
7
  let(:uppercase) { 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ' }
8
8
  let(:lowercase) { 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ' }
9
9
  let(:negative_types) do
10
- "translate(@type,'#{uppercase}','#{lowercase}')!='file' and "\
11
- "translate(@type,'#{uppercase}','#{lowercase}')!='radio' and " \
12
- "translate(@type,'#{uppercase}','#{lowercase}')!='checkbox' and " \
13
- "translate(@type,'#{uppercase}','#{lowercase}')!='submit' and " \
14
- "translate(@type,'#{uppercase}','#{lowercase}')!='reset' and " \
15
- "translate(@type,'#{uppercase}','#{lowercase}')!='image' and " \
16
- "translate(@type,'#{uppercase}','#{lowercase}')!='button' and " \
17
- "translate(@type,'#{uppercase}','#{lowercase}')!='hidden' and " \
18
- "translate(@type,'#{uppercase}','#{lowercase}')!='range' and " \
19
- "translate(@type,'#{uppercase}','#{lowercase}')!='color' and " \
20
- "translate(@type,'#{uppercase}','#{lowercase}')!='date' and " \
21
- "translate(@type,'#{uppercase}','#{lowercase}')!='datetime-local'"
10
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('file','#{uppercase}','#{lowercase}') and "\
11
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('radio','#{uppercase}','#{lowercase}') and " \
12
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('checkbox','#{uppercase}','#{lowercase}') and " \
13
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('submit','#{uppercase}','#{lowercase}') and " \
14
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('reset','#{uppercase}','#{lowercase}') and " \
15
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('image','#{uppercase}','#{lowercase}') and " \
16
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('button','#{uppercase}','#{lowercase}') and " \
17
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('hidden','#{uppercase}','#{lowercase}') and " \
18
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('range','#{uppercase}','#{lowercase}') and " \
19
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('color','#{uppercase}','#{lowercase}') and " \
20
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('date','#{uppercase}','#{lowercase}') and " \
21
+ "translate(@type,'#{uppercase}','#{lowercase}')!=translate('datetime-local','#{uppercase}','#{lowercase}')"
22
22
  end
23
23
 
24
24
  describe '#build' do
@@ -33,7 +33,7 @@ describe Watir::Locators::TextField::SelectorBuilder do
33
33
  it 'specified text field type that is text' do
34
34
  selector = {type: 'text'}
35
35
  built = {xpath: ".//*[local-name()='input']" \
36
- "[translate(@type,'#{uppercase}','#{lowercase}')='text']"}
36
+ "[translate(@type,'#{uppercase}','#{lowercase}')=translate('text','#{uppercase}','#{lowercase}')]"}
37
37
 
38
38
  expect(selector_builder.build(selector)).to eq built
39
39
  end
@@ -41,7 +41,7 @@ describe Watir::Locators::TextField::SelectorBuilder do
41
41
  it 'specified text field type that is not text' do
42
42
  selector = {type: 'number'}
43
43
  built = {xpath: ".//*[local-name()='input']" \
44
- "[translate(@type,'#{uppercase}','#{lowercase}')='number']"}
44
+ "[translate(@type,'#{uppercase}','#{lowercase}')=translate('number','#{uppercase}','#{lowercase}')]"}
45
45
 
46
46
  expect(selector_builder.build(selector)).to eq built
47
47
  end
@@ -83,7 +83,7 @@ describe 'Browser::AfterHooks' do
83
83
  expect(@yield).to be true
84
84
  end
85
85
 
86
- not_compliant_on :safari do
86
+ bug 'https://gist.github.com/titusfortner/bd32f27ec2458b3a733d83374d156940', :safari do
87
87
  it 'runs after_hooks after Element#submit' do
88
88
  browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
89
89
  @page_after_hook = proc { @yield = browser.div(id: 'messages').text == 'submit' }
@@ -93,24 +93,24 @@ describe 'Browser::AfterHooks' do
93
93
  end
94
94
  end
95
95
 
96
- bug 'MoveTargetOutOfBoundsError', :firefox do
97
- it 'runs after_hooks after Element#double_click' do
98
- browser.goto(WatirSpec.url_for('non_control_elements.html'))
99
- @page_after_hook = proc { @yield = browser.title == 'Non-control elements' }
100
- browser.after_hooks.add @page_after_hook
101
- browser.div(id: 'html_test').double_click
102
- expect(@yield).to be true
103
- end
96
+ it 'runs after_hooks after Element#double_click' do
97
+ browser.goto(WatirSpec.url_for('non_control_elements.html'))
98
+ @page_after_hook = proc { @yield = browser.title == 'Non-control elements' }
99
+ browser.after_hooks.add @page_after_hook
100
+ div = browser.div(id: 'html_test')
101
+ div.scroll.to
102
+ div.double_click
103
+ expect(@yield).to be true
104
104
  end
105
105
 
106
- not_compliant_on %i[remote firefox] do
107
- it 'runs after_hooks after Element#right_click' do
108
- browser.goto(WatirSpec.url_for('right_click.html'))
109
- @page_after_hook = proc { @yield = browser.title == 'Right Click Test' }
110
- browser.after_hooks.add @page_after_hook
111
- browser.div(id: 'click').right_click
112
- expect(@yield).to be true
113
- end
106
+ it 'runs after_hooks after Element#right_click' do
107
+ browser.goto(WatirSpec.url_for('right_click.html'))
108
+ @page_after_hook = proc { @yield = browser.title == 'Right Click Test' }
109
+ browser.after_hooks.add @page_after_hook
110
+ div = browser.div(id: 'click')
111
+ div.scroll.to
112
+ div.right_click
113
+ expect(@yield).to be true
114
114
  end
115
115
 
116
116
  it 'runs after_hooks after FramedDriver#switch!' do
@@ -135,82 +135,68 @@ describe 'Browser::AfterHooks' do
135
135
  expect(@yield).to be true
136
136
  end
137
137
 
138
- not_compliant_on :headless do
139
- it 'runs after_hooks after Alert#ok' do
140
- browser.goto(WatirSpec.url_for('alerts.html'))
141
- @page_after_hook = proc { @yield = browser.title == 'Alerts' }
142
- browser.after_hooks.add @page_after_hook
143
- browser.after_hooks.without { browser.button(id: 'alert').click }
144
- browser.alert.ok
145
- expect(@yield).to be true
146
- end
138
+ it 'runs after_hooks after Alert#ok' do
139
+ browser.goto(WatirSpec.url_for('alerts.html'))
140
+ @page_after_hook = proc { @yield = browser.title == 'Alerts' }
141
+ browser.after_hooks.add @page_after_hook
142
+ browser.after_hooks.without { browser.button(id: 'alert').click }
143
+ browser.alert.ok
144
+ expect(@yield).to be true
147
145
  end
148
146
 
149
- not_compliant_on :headless do
150
- bug 'https://code.google.com/p/chromedriver/issues/detail?id=26', [:chrome, :macosx] do
151
- it 'runs after_hooks after Alert#close' do
152
- browser.goto(WatirSpec.url_for('alerts.html'))
153
- @page_after_hook = proc { @yield = browser.title == 'Alerts' }
154
- browser.after_hooks.add @page_after_hook
155
- browser.after_hooks.without { browser.button(id: 'alert').click }
156
- browser.alert.close
157
- expect(@yield).to be true
158
- end
159
- end
147
+ it 'runs after_hooks after Alert#close' do
148
+ browser.goto(WatirSpec.url_for('alerts.html'))
149
+ @page_after_hook = proc { @yield = browser.title == 'Alerts' }
150
+ browser.after_hooks.add @page_after_hook
151
+ browser.after_hooks.without { browser.button(id: 'alert').click }
152
+ browser.alert.close
153
+ expect(@yield).to be true
160
154
  end
161
155
 
162
- not_compliant_on :safari, :headless do
163
- it 'does not run error checks with alert present' do
164
- browser.goto WatirSpec.url_for('alerts.html')
156
+ it 'does not run error checks with alert present' do
157
+ browser.goto WatirSpec.url_for('alerts.html')
165
158
 
166
- @page_after_hook = proc { @yield = browser.title == 'Alerts' }
167
- browser.after_hooks.add @page_after_hook
159
+ @page_after_hook = proc { @yield = browser.title == 'Alerts' }
160
+ browser.after_hooks.add @page_after_hook
168
161
 
169
- browser.button(id: 'alert').click
170
- expect(@yield).to be_nil
162
+ browser.button(id: 'alert').click
163
+ expect(@yield).to be_nil
171
164
 
172
- browser.alert.ok
173
- expect(@yield).to eq true
174
- end
165
+ browser.alert.ok
166
+ expect(@yield).to eq true
175
167
  end
176
168
 
177
- not_compliant_on :headless do
178
- it 'does not raise error when running error checks using #after_hooks#without with alert present' do
179
- url = WatirSpec.url_for('alerts.html')
180
- @page_after_hook = proc { browser.url }
181
- browser.after_hooks.add @page_after_hook
182
- browser.goto url
183
- expect { browser.after_hooks.without { browser.button(id: 'alert').click } }.to_not raise_error
184
- browser.alert.ok
185
- end
169
+ it 'does not raise error when running error checks using #after_hooks#without with alert present' do
170
+ url = WatirSpec.url_for('alerts.html')
171
+ @page_after_hook = proc { browser.url }
172
+ browser.after_hooks.add @page_after_hook
173
+ browser.goto url
174
+ expect { browser.after_hooks.without { browser.button(id: 'alert').click } }.to_not raise_error
175
+ browser.alert.ok
176
+ end
177
+
178
+ it 'does not raise error if no error checks are defined with alert present' do
179
+ url = WatirSpec.url_for('alerts.html')
180
+ @page_after_hook = proc { browser.url }
181
+ browser.after_hooks.add @page_after_hook
182
+ browser.goto url
183
+ browser.after_hooks.delete @page_after_hook
184
+ expect { browser.button(id: 'alert').click }.to_not raise_error
185
+ browser.alert.ok
186
186
  end
187
187
 
188
- not_compliant_on :headless do
189
- it 'does not raise error if no error checks are defined with alert present' do
190
- url = WatirSpec.url_for('alerts.html')
188
+ bug 'Clicking an Element that Closes a Window is returning NoMatchingWindowFoundException', :safari do
189
+ it 'does not raise error when running error checks on closed window' do
190
+ url = WatirSpec.url_for('window_switching.html')
191
191
  @page_after_hook = proc { browser.url }
192
192
  browser.after_hooks.add @page_after_hook
193
193
  browser.goto url
194
- browser.after_hooks.delete @page_after_hook
195
- expect { browser.button(id: 'alert').click }.to_not raise_error
196
- browser.alert.ok
197
- end
198
- end
194
+ browser.a(id: 'open').click
199
195
 
200
- bug 'https://bugzilla.mozilla.org/show_bug.cgi?id=1223277', :firefox do
201
- not_compliant_on :headless do
202
- it 'does not raise error when running error checks on closed window' do
203
- url = WatirSpec.url_for('window_switching.html')
204
- @page_after_hook = proc { browser.url }
205
- browser.after_hooks.add @page_after_hook
206
- browser.goto url
207
- browser.a(id: 'open').click
208
-
209
- window = browser.window(title: 'closeable window')
210
- window.use
211
- expect { browser.a(id: 'close').click }.to_not raise_error
212
- browser.original_window.use
213
- end
196
+ window = browser.window(title: 'closeable window')
197
+ window.use
198
+ expect { browser.a(id: 'close').click }.to_not raise_error
199
+ browser.original_window.use
214
200
  end
215
201
  end
216
202
  end