watir 7.0.0.beta1 → 7.0.0.beta2

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +7 -3
  3. data/.rubocop.yml +2 -7
  4. data/CHANGES.md +16 -0
  5. data/lib/watir/browser.rb +18 -4
  6. data/lib/watir/capabilities.rb +1 -1
  7. data/lib/watir/elements/element.rb +32 -3
  8. data/lib/watir/elements/font.rb +1 -0
  9. data/lib/watir/elements/iframe.rb +0 -1
  10. data/lib/watir/elements/radio.rb +2 -2
  11. data/lib/watir/elements/select.rb +63 -40
  12. data/lib/watir/has_window.rb +2 -0
  13. data/lib/watir/locators.rb +4 -0
  14. data/lib/watir/locators/element/matcher.rb +1 -1
  15. data/lib/watir/locators/element/selector_builder.rb +0 -3
  16. data/lib/watir/locators/option/matcher.rb +24 -0
  17. data/lib/watir/locators/option/selector_builder.rb +8 -0
  18. data/lib/watir/locators/option/selector_builder/xpath.rb +37 -0
  19. data/lib/watir/logger.rb +3 -74
  20. data/lib/watir/radio_set.rb +1 -0
  21. data/lib/watir/screenshot.rb +2 -8
  22. data/lib/watir/user_editable.rb +10 -3
  23. data/lib/watir/version.rb +1 -1
  24. data/lib/watir/window.rb +15 -4
  25. data/lib/watir/window_collection.rb +9 -0
  26. data/lib/watirspec.rb +4 -2
  27. data/lib/watirspec/guards.rb +1 -1
  28. data/lib/watirspec/server.rb +1 -1
  29. data/spec/spec_helper.rb +0 -10
  30. data/spec/unit/capabilities_spec.rb +1 -1
  31. data/spec/unit/match_elements/element_spec.rb +11 -0
  32. data/spec/watirspec/after_hooks_spec.rb +22 -45
  33. data/spec/watirspec/browser_spec.rb +185 -206
  34. data/spec/watirspec/cookies_spec.rb +47 -52
  35. data/spec/watirspec/drag_and_drop_spec.rb +5 -7
  36. data/spec/watirspec/elements/area_spec.rb +1 -5
  37. data/spec/watirspec/elements/button_spec.rb +4 -8
  38. data/spec/watirspec/elements/checkbox_spec.rb +2 -4
  39. data/spec/watirspec/elements/date_field_spec.rb +13 -16
  40. data/spec/watirspec/elements/date_time_field_spec.rb +14 -13
  41. data/spec/watirspec/elements/dd_spec.rb +3 -4
  42. data/spec/watirspec/elements/del_spec.rb +10 -12
  43. data/spec/watirspec/elements/div_spec.rb +41 -50
  44. data/spec/watirspec/elements/dl_spec.rb +4 -12
  45. data/spec/watirspec/elements/element_spec.rb +155 -89
  46. data/spec/watirspec/elements/elements_spec.rb +8 -9
  47. data/spec/watirspec/elements/filefield_spec.rb +5 -7
  48. data/spec/watirspec/elements/form_spec.rb +1 -1
  49. data/spec/watirspec/elements/forms_spec.rb +3 -5
  50. data/spec/watirspec/elements/frame_spec.rb +17 -22
  51. data/spec/watirspec/elements/iframe_spec.rb +21 -27
  52. data/spec/watirspec/elements/ins_spec.rb +10 -12
  53. data/spec/watirspec/elements/link_spec.rb +24 -26
  54. data/spec/watirspec/elements/links_spec.rb +8 -9
  55. data/spec/watirspec/elements/radio_spec.rb +11 -14
  56. data/spec/watirspec/elements/select_list_spec.rb +248 -117
  57. data/spec/watirspec/elements/span_spec.rb +10 -12
  58. data/spec/watirspec/elements/table_nesting_spec.rb +31 -34
  59. data/spec/watirspec/elements/table_spec.rb +11 -13
  60. data/spec/watirspec/elements/tbody_spec.rb +10 -12
  61. data/spec/watirspec/elements/td_spec.rb +4 -6
  62. data/spec/watirspec/elements/text_field_spec.rb +10 -12
  63. data/spec/watirspec/elements/tr_spec.rb +5 -7
  64. data/spec/watirspec/user_editable_spec.rb +26 -28
  65. data/spec/watirspec/wait_spec.rb +255 -258
  66. data/spec/watirspec/window_switching_spec.rb +199 -200
  67. data/spec/watirspec_helper.rb +34 -31
  68. metadata +5 -6
  69. data/spec/implementation_spec.rb +0 -24
  70. data/spec/unit/logger_spec.rb +0 -81
@@ -1,5 +1,7 @@
1
1
  module Watir
2
2
  module HasWindow
3
+ attr_writer :original_window
4
+
3
5
  #
4
6
  # Returns browser windows array.
5
7
  #
@@ -14,6 +14,10 @@ require 'watir/locators/button/matcher'
14
14
  require 'watir/locators/cell/selector_builder'
15
15
  require 'watir/locators/cell/selector_builder/xpath'
16
16
 
17
+ require 'watir/locators/option/matcher'
18
+ require 'watir/locators/option/selector_builder'
19
+ require 'watir/locators/option/selector_builder/xpath'
20
+
17
21
  require 'watir/locators/row/selector_builder'
18
22
  require 'watir/locators/row/selector_builder/xpath'
19
23
 
@@ -82,7 +82,7 @@ module Watir
82
82
  when :tag_name
83
83
  element.tag_name.downcase
84
84
  when :text
85
- execute_js(:getTextContent, element)
85
+ execute_js(:getTextContent, element).gsub(/\s+/, ' ').strip
86
86
  when :visible
87
87
  element.displayed?
88
88
  when :visible_text
@@ -88,9 +88,6 @@ module Watir
88
88
 
89
89
  def normalize_locator(how, what)
90
90
  case how
91
- when 'text'
92
- Watir.logger.deprecate "String 'text' as a locator", 'Symbol :text', ids: [:text_string]
93
- [:text, what]
94
91
  when :tag_name
95
92
  what = what.to_s if what.is_a?(::Symbol)
96
93
  [how, what]
@@ -0,0 +1,24 @@
1
+ module Watir
2
+ module Locators
3
+ class Option
4
+ class Matcher < Element::Matcher
5
+ def fetch_value(element, how)
6
+ case how
7
+ when :any
8
+ [element.attribute(:value),
9
+ execute_js(:getTextContent, element).gsub(/\s+/, ' ').strip,
10
+ element.attribute(:label)]
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def matches_values?(found, expected)
17
+ return super unless found.is_a?(Array)
18
+
19
+ found.find { |possible| matches_values?(possible, expected) }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module Watir
2
+ module Locators
3
+ class Option
4
+ class SelectorBuilder < Element::SelectorBuilder
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ module Watir
2
+ module Locators
3
+ class Option
4
+ class SelectorBuilder
5
+ class XPath < Element::SelectorBuilder::XPath
6
+ private
7
+
8
+ def attribute_string
9
+ result = if @selector.key?(:any)
10
+ to_match = @selector.delete :any
11
+ value = process_attribute(:value, to_match)
12
+ text = process_attribute(:text, to_match)
13
+ label = process_attribute(:label, to_match)
14
+ "[#{value} or #{text} or #{label}]"
15
+ else
16
+ ''
17
+ end
18
+
19
+ attributes = @selector.keys.map { |key|
20
+ process_attribute(key, @selector.delete(key))
21
+ }.flatten.compact
22
+ attribute_values = attributes.empty? ? '' : "[#{attributes.join(' and ')}]"
23
+ "#{result}#{attribute_values}"
24
+ end
25
+
26
+ def add_to_matching(key, regexp, results = nil)
27
+ return unless results.nil? || requires_matching?(results, regexp)
28
+
29
+ return super unless %i[value text label].include? key
30
+
31
+ @built[:any] = regexp
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/watir/logger.rb CHANGED
@@ -16,84 +16,13 @@ module Watir
16
16
  # Watir.logger.info('This is info message')
17
17
  # Watir.logger.warn('This is warning message')
18
18
  #
19
- class Logger
20
- extend Forwardable
21
- include ::Logger::Severity
22
-
23
- def_delegators :@logger, :debug, :debug?,
24
- :info, :info?,
25
- :warn?,
26
- :error, :error?,
27
- :fatal, :fatal?,
28
- :level, :level=
29
-
30
- def initialize(progname = 'Watir')
31
- @logger = create_logger($stdout)
32
- @logger.progname = progname
33
- @ignored = []
34
- end
35
-
36
- def ignore(ids)
37
- @ignored.concat Array(ids).map(&:to_s)
38
- end
39
-
40
- def output=(io)
41
- @logger.reopen(io)
42
- end
43
-
44
- #
45
- # Only log a warn message if it is not set to be ignored.
46
- #
47
- def warn(message, ids: [], &block)
48
- msg = ids.empty? ? '' : "[#{ids.map!(&:to_s).map(&:inspect).join(', ')}] "
49
- msg += message
50
- @logger.warn(msg, &block) unless (@ignored & ids).any?
51
- end
52
-
53
- #
54
- # Returns IO object used by logger internally.
55
- #
56
- # Normally, we would have never needed it, but we want to
57
- # use it as IO object for all child processes to ensure their
58
- # output is redirected there.
59
- #
60
- # It is only used in debug level, in other cases output is suppressed.
61
- #
62
- # @api private
63
- #
64
- def io
65
- @logger.instance_variable_get(:@logdev).instance_variable_get(:@dev)
66
- end
67
-
68
- #
69
- # Marks code as deprecated with replacement.
70
- #
71
- # @param [String] old
72
- # @param [String] new
73
- #
74
- def deprecate(old, new, reference: '', ids: [])
75
- return if @ignored.include?('deprecations') || (@ignored & ids.map!(&:to_s)).any?
76
-
77
- msg = ids.empty? ? '' : "[#{ids.map(&:inspect).join(', ')}] "
78
- ref_msg = reference.empty? ? '.' : "; see explanation for this deprecation: #{reference}."
79
- warn "[DEPRECATION] #{msg}#{old} is deprecated. Use #{new} instead#{ref_msg}"
19
+ class Logger < Selenium::WebDriver::Logger
20
+ def initialize
21
+ super('Watir')
80
22
  end
81
23
 
82
24
  def selenium=(val)
83
25
  Selenium::WebDriver.logger.level = val
84
26
  end
85
-
86
- private
87
-
88
- def create_logger(output)
89
- logger = ::Logger.new(output)
90
- logger.progname = 'Watir'
91
- logger.level = ($DEBUG ? DEBUG : WARN)
92
- logger.formatter = proc do |severity, time, progname, msg|
93
- "#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
94
- end
95
-
96
- logger
97
- end
98
27
  end
99
28
  end
@@ -139,6 +139,7 @@ module Watir
139
139
  end
140
140
  raise UnknownObjectException, "Unable to locate radio matching #{str_or_rx.inspect}"
141
141
  end
142
+ alias set select
142
143
 
143
144
  #
144
145
  # Returns true if any of the radio button label matches the given value.
@@ -1,14 +1,8 @@
1
1
  module Watir
2
2
  class Screenshot
3
3
  def initialize(browser)
4
- if browser.is_a? Selenium::WebDriver::Driver
5
- msg = 'Initializing `Watir::Screenshot` with a `Selenium::Driver` instance', 'a `Watir::Browser` instance'
6
- Watir.logger.deprecate msg, ids: [:screenshot_driver]
7
- @driver = browser
8
- else
9
- @browser = browser
10
- @driver = browser.wd
11
- end
4
+ @browser = browser
5
+ @driver = browser.wd
12
6
  end
13
7
 
14
8
  #
@@ -15,16 +15,23 @@ module Watir
15
15
  alias value= set
16
16
 
17
17
  #
18
- # Uses JavaScript to enter most of the given value.
19
- # Selenium is used to enter the first and last characters
18
+ # Returns true if element is user_editable because it has a content_editable attribute set
20
19
  #
21
- # @param [String, Symbol] args
20
+ # @return [Boolean]
22
21
  #
23
22
 
24
23
  def content_editable
25
24
  defined?(@content_editable) && content_editable?
26
25
  end
27
26
 
27
+ #
28
+ # Uses JavaScript to enter most of the given value.
29
+ # Selenium is used to enter the first and last characters
30
+ # This might provide a performance improvement when entering a lot of text on a local machine
31
+ #
32
+ # @param [String, Symbol] args
33
+ #
34
+
28
35
  def set!(*args)
29
36
  msg = '#set! does not support special keys, use #set instead'
30
37
  raise ArgumentError, msg if args.any? { |v| v.is_a?(::Symbol) }
data/lib/watir/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Watir
2
- VERSION = '7.0.0.beta1'.freeze
2
+ VERSION = '7.0.0.beta2'.freeze
3
3
  end
data/lib/watir/window.rb CHANGED
@@ -179,10 +179,21 @@ module Watir
179
179
  # end
180
180
  #
181
181
 
182
- def use(&blk)
183
- @browser.original_window ||= current_window
182
+ def use
184
183
  wait_for_exists
185
- @driver.switch_to.window(handle, &blk)
184
+ cache_current = current_window
185
+ @browser.original_window ||= cache_current
186
+ restore_to = unless cache_current == handle
187
+ @driver.switch_to.window(handle)
188
+ cache_current
189
+ end
190
+ if block_given?
191
+ begin
192
+ yield
193
+ ensure
194
+ @driver.switch_to.window(restore_to) if restore_to
195
+ end
196
+ end
186
197
  self
187
198
  end
188
199
 
@@ -205,7 +216,7 @@ module Watir
205
216
  end
206
217
 
207
218
  def assert_exists
208
- return if @driver.window_handles.include?(handle)
219
+ return if !handle.nil? && @driver.window_handles.include?(handle)
209
220
 
210
221
  raise(NoMatchingWindowFoundException, selector_string)
211
222
  end
@@ -39,6 +39,15 @@ module Watir
39
39
  end
40
40
  alias eql? ==
41
41
 
42
+ def restore!
43
+ return if @browser.closed?
44
+
45
+ window_list.reject { |win| win.handle == @browser.original_window.handle }.each(&:close)
46
+ @browser.original_window.use
47
+ rescue StandardError
48
+ @browser.close
49
+ end
50
+
42
51
  def reset!
43
52
  @window_list = nil
44
53
  end
data/lib/watirspec.rb CHANGED
@@ -53,7 +53,9 @@ module WatirSpec
53
53
  @implementation = imp
54
54
  end
55
55
 
56
- def new_browser
56
+ def new_browser(pause = 1)
57
+ sleep pause
58
+
57
59
  klass = WatirSpec.implementation.browser_class
58
60
  args = Array(WatirSpec.implementation.browser_args).map { |e| e.is_a?(Hash) ? e.dup : e }
59
61
 
@@ -80,7 +82,7 @@ module WatirSpec
80
82
  info << @implementation.driver_info
81
83
 
82
84
  Watir.logger.warn "running watirspec against #{info.join ' '} using:\n#{WatirSpec.implementation.inspect_args}",
83
- ids: [:browser_info]
85
+ id: [:browser_info]
84
86
  rescue StandardError
85
87
  # ignored
86
88
  end
@@ -21,7 +21,7 @@ module WatirSpec
21
21
  guard_name = "#{guard[:name]}:".ljust(15)
22
22
  str << " \t#{guard_name} #{guard[:data].inspect}\n"
23
23
  end
24
- Watir.logger.warn str, ids: [:guard_names]
24
+ Watir.logger.warn str, id: [:guard_names]
25
25
  end
26
26
  end
27
27
  end # class << self
@@ -56,7 +56,7 @@ module WatirSpec
56
56
 
57
57
  client.write(response(status, headers, body))
58
58
  rescue Errno::ECONNRESET
59
- Watir.logger.warn 'Client reset connection, skipping.', ids: [:reset_connection]
59
+ Watir.logger.warn 'Client reset connection, skipping.', id: [:reset_connection]
60
60
  ensure
61
61
  client.close
62
62
  end
data/spec/spec_helper.rb CHANGED
@@ -20,13 +20,3 @@ end
20
20
  require 'watir'
21
21
  require 'locator_spec_helper'
22
22
  require 'rspec'
23
-
24
- if ENV['AUTOMATIC_RETRY']
25
- require 'rspec/retry'
26
- RSpec.configure do |config|
27
- config.verbose_retry = true
28
- config.display_try_failure_messages = true
29
- config.default_retry_count = 3
30
- config.exceptions_to_retry = [IOError, Net::ReadTimeout]
31
- end
32
- end
@@ -1,4 +1,4 @@
1
- require 'watirspec_helper'
1
+ require_relative 'unit_helper'
2
2
 
3
3
  describe Watir::Capabilities do
4
4
  before(:all) { Watir.logger.ignore(:watir_client) }
@@ -332,6 +332,17 @@ describe Watir::Locators::Element::Matcher do
332
332
  end
333
333
 
334
334
  context 'when matching Regular Expressions' do
335
+ it 'with white space' do
336
+ allow(browser).to receive(:execute_script).and_return("\n match this \n", 'no', 'match this')
337
+
338
+ elements = [wd_element,
339
+ wd_element,
340
+ wd_element]
341
+ @values_to_match = {text: /^match this$/}
342
+
343
+ expect(matcher.match(elements, values_to_match, @filter)).to eq [elements[0], elements[2]]
344
+ end
345
+
335
346
  it 'with tag_name' do
336
347
  elements = [wd_element(tag_name: 'div'),
337
348
  wd_element(tag_name: 'span'),
@@ -85,14 +85,12 @@ describe 'Browser::AfterHooks' do
85
85
  expect(@yield).to be true
86
86
  end
87
87
 
88
- bug 'https://gist.github.com/titusfortner/bd32f27ec2458b3a733d83374d156940', :safari do
89
- it 'runs after_hooks after Element#submit' do
90
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
91
- @page_after_hook = proc { @yield = browser.div(id: 'messages').text == 'submit' }
92
- browser.after_hooks.add @page_after_hook
93
- browser.form(id: 'new_user').submit
94
- expect(@yield).to be true
95
- end
88
+ it 'runs after_hooks after Element#submit' do
89
+ browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
90
+ @page_after_hook = proc { @yield = browser.div(id: 'messages').text == 'submit' }
91
+ browser.after_hooks.add @page_after_hook
92
+ browser.form(id: 'new_user').submit
93
+ expect(@yield).to be true
96
94
  end
97
95
 
98
96
  it 'runs after_hooks after Element#double_click' do
@@ -115,28 +113,6 @@ describe 'Browser::AfterHooks' do
115
113
  expect(@yield).to be true
116
114
  end
117
115
 
118
- it 'runs after_hooks after FramedDriver#switch!' do
119
- browser.goto(WatirSpec.url_for('iframes.html'))
120
- @page_after_hook = proc { @yield = browser.title == 'Iframes' }
121
- browser.after_hooks.add @page_after_hook
122
-
123
- browser.iframe.element(css: '#senderElement').exists?
124
-
125
- expect(@yield).to be true
126
- end
127
-
128
- it 'runs after_hooks after Browser#ensure_context if not @default_context' do
129
- browser.goto(WatirSpec.url_for('iframes.html'))
130
- browser.iframe.element(css: '#senderElement').locate
131
-
132
- @page_after_hook = proc { @yield = browser.title == 'Iframes' }
133
- browser.after_hooks.add @page_after_hook
134
-
135
- browser.locate
136
-
137
- expect(@yield).to be true
138
- end
139
-
140
116
  it 'runs after_hooks after Alert#ok' do
141
117
  browser.goto(WatirSpec.url_for('alerts.html'))
142
118
  @page_after_hook = proc { @yield = browser.title == 'Alerts' }
@@ -187,21 +163,22 @@ describe 'Browser::AfterHooks' do
187
163
  browser.alert.ok
188
164
  end
189
165
 
190
- bug 'Clicking an Element that Closes a Window is returning NoMatchingWindowFoundException', :safari do
191
- bug 'https://github.com/mozilla/geckodriver/issues/1847', :firefox do
192
- it 'does not raise error when running error checks on closed window' do
193
- url = WatirSpec.url_for('window_switching.html')
194
- @page_after_hook = proc { browser.url }
195
- browser.after_hooks.add @page_after_hook
196
- browser.goto url
197
- browser.a(id: 'open').click
198
-
199
- window = browser.window(title: 'closeable window')
200
- window.use
201
- expect { browser.a(id: 'close').click }.to_not raise_error
202
- browser.original_window.use
203
- end
204
- end
166
+ it 'does not raise error when running error checks on closed window',
167
+ except: {browser: :safari,
168
+ reason: 'Clicking an Element that Closes a Window is returning NoMatchingWindowFoundException'},
169
+ exclude: {browser: :firefox,
170
+ platform: :windows,
171
+ reason: 'https://github.com/mozilla/geckodriver/issues/1847'} do
172
+ url = WatirSpec.url_for('window_switching.html')
173
+ @page_after_hook = proc { browser.url }
174
+ browser.after_hooks.add @page_after_hook
175
+ browser.goto url
176
+ browser.a(id: 'open').click
177
+
178
+ window = browser.window(title: 'closeable window')
179
+ window.use
180
+ expect { browser.a(id: 'close').click }.to_not raise_error
181
+ browser.original_window.use
205
182
  end
206
183
  end
207
184