watir 6.17.0 → 6.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/actions/enable-safari/action.yml +11 -0
- data/.github/actions/install-chrome/action.yml +11 -0
- data/.github/workflows/linux.yml +61 -0
- data/.github/workflows/mac.yml +55 -0
- data/.github/workflows/unit.yml +31 -0
- data/.github/workflows/windows.yml +39 -0
- data/.rubocop_todo.yml +36 -0
- data/CHANGES.md +14 -0
- data/LICENSE +2 -2
- data/README.md +9 -10
- data/Rakefile +1 -1
- data/lib/watir.rb +1 -0
- data/lib/watir/adjacent.rb +1 -1
- data/lib/watir/alert.rb +1 -0
- data/lib/watir/attribute_helper.rb +2 -0
- data/lib/watir/browser.rb +2 -2
- data/lib/watir/cookies.rb +2 -0
- data/lib/watir/element_collection.rb +21 -6
- data/lib/watir/elements/element.rb +10 -10
- data/lib/watir/elements/html_elements.rb +0 -1
- data/lib/watir/elements/iframe.rb +2 -1
- data/lib/watir/elements/select.rb +20 -5
- data/lib/watir/generator/html/generator.rb +1 -1
- data/lib/watir/has_window.rb +17 -15
- data/lib/watir/js_execution.rb +2 -2
- data/lib/watir/js_snippets.rb +2 -2
- data/lib/watir/locators.rb +1 -3
- data/lib/watir/locators/element/selector_builder.rb +1 -1
- data/lib/watir/logger.rb +2 -18
- data/lib/watir/radio_set.rb +2 -2
- data/lib/watir/user_editable.rb +6 -2
- data/lib/watir/version.rb +1 -1
- data/lib/watir/wait.rb +2 -0
- data/lib/watir/wait/timer.rb +1 -1
- data/lib/watir/window.rb +7 -3
- data/lib/watir/window_collection.rb +105 -0
- data/lib/watirspec.rb +1 -0
- data/lib/watirspec/implementation.rb +3 -5
- data/lib/watirspec/runner.rb +1 -1
- data/lib/watirspec/server.rb +1 -1
- data/spec/spec_helper.rb +2 -7
- data/spec/unit/match_elements/element_spec.rb +17 -15
- data/spec/unit/unit_helper.rb +2 -4
- data/spec/watirspec/after_hooks_spec.rb +15 -11
- data/spec/watirspec/browser_spec.rb +3 -2
- data/spec/watirspec/elements/element_spec.rb +14 -11
- data/spec/watirspec/elements/filefield_spec.rb +2 -2
- data/spec/watirspec/elements/iframe_spec.rb +5 -7
- data/spec/watirspec/elements/link_spec.rb +5 -3
- data/spec/watirspec/elements/select_list_spec.rb +156 -37
- data/spec/watirspec/html/wait.html +5 -5
- data/spec/watirspec/html/window_switching.html +10 -0
- data/spec/watirspec/legacy_wait_spec.rb +216 -0
- data/spec/watirspec/support/rspec_matchers.rb +10 -7
- data/spec/watirspec/wait_spec.rb +257 -301
- data/spec/watirspec/window_switching_spec.rb +282 -160
- data/spec/watirspec_helper.rb +10 -15
- data/support/doctest_helper.rb +0 -2
- data/watir.gemspec +2 -2
- metadata +25 -13
- data/.travis.yml +0 -87
- data/appveyor.yml +0 -13
- data/spec/watirspec/relaxed_locate_spec.rb +0 -109
@@ -149,7 +149,6 @@ module Watir
|
|
149
149
|
#
|
150
150
|
|
151
151
|
def click(*modifiers)
|
152
|
-
# TODO: Should wait_for_enabled be default, or `Button` specific behavior?
|
153
152
|
element_call(:wait_for_enabled) do
|
154
153
|
if modifiers.any?
|
155
154
|
action = driver.action
|
@@ -700,7 +699,7 @@ module Watir
|
|
700
699
|
return assert_enabled unless Watir.relaxed_locate?
|
701
700
|
|
702
701
|
wait_for_exists
|
703
|
-
return unless [Input, Button, Select, Option].any? { |c| is_a? c } ||
|
702
|
+
return unless [Input, Button, Select, Option].any? { |c| is_a? c } || content_editable
|
704
703
|
return if enabled?
|
705
704
|
|
706
705
|
begin
|
@@ -712,9 +711,7 @@ module Watir
|
|
712
711
|
|
713
712
|
def wait_for_writable
|
714
713
|
wait_for_enabled
|
715
|
-
unless Watir.relaxed_locate?
|
716
|
-
raise_writable unless !respond_to?(:readonly?) || !readonly?
|
717
|
-
end
|
714
|
+
raise_writable unless Watir.relaxed_locate? || (!respond_to?(:readonly?) || !readonly?)
|
718
715
|
|
719
716
|
return if !respond_to?(:readonly?) || !readonly?
|
720
717
|
|
@@ -734,7 +731,9 @@ module Watir
|
|
734
731
|
end
|
735
732
|
|
736
733
|
def ensure_context
|
737
|
-
if @query_scope.is_a?(Browser) || !@query_scope.located?
|
734
|
+
if @query_scope.is_a?(Browser) || !@query_scope.located? && @query_scope.is_a?(IFrame)
|
735
|
+
@query_scope.browser.locate
|
736
|
+
elsif @query_scope.located? && @query_scope.stale?
|
738
737
|
@query_scope.locate
|
739
738
|
end
|
740
739
|
@query_scope.switch_to! if @query_scope.is_a?(IFrame)
|
@@ -793,6 +792,7 @@ module Watir
|
|
793
792
|
# rubocop:disable Metrics/AbcSize
|
794
793
|
# rubocop:disable Metrics/MethodLength
|
795
794
|
# rubocop:disable Metrics/CyclomaticComplexity:
|
795
|
+
# rubocop:disable Metrics/PerceivedComplexity::
|
796
796
|
def element_call(precondition = nil, &block)
|
797
797
|
caller = caller_locations(1, 1)[0].label
|
798
798
|
already_locked = browser.timer.locked?
|
@@ -806,12 +806,12 @@ module Watir
|
|
806
806
|
element_call(:wait_for_exists, &block) if precondition.nil?
|
807
807
|
msg = e.message
|
808
808
|
msg += '; Maybe look in an iframe?' if @query_scope.iframe.exists?
|
809
|
-
custom_attributes = @locator.nil? ? [] : selector_builder.custom_attributes
|
809
|
+
custom_attributes = !defined?(@locator) || @locator.nil? ? [] : selector_builder.custom_attributes
|
810
810
|
unless custom_attributes.empty?
|
811
811
|
msg += "; Watir treated #{custom_attributes} as a non-HTML compliant attribute, ensure that was intended"
|
812
812
|
end
|
813
813
|
raise unknown_exception, msg
|
814
|
-
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
814
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::NoSuchElementError
|
815
815
|
reset!
|
816
816
|
retry
|
817
817
|
# TODO: - InvalidElementStateError is deprecated, so no longer calling `raise_disabled`
|
@@ -829,8 +829,8 @@ module Watir
|
|
829
829
|
end
|
830
830
|
# rubocop:enable Metrics/AbcSize
|
831
831
|
# rubocop:enable Metrics/MethodLength
|
832
|
-
|
833
|
-
# rubocop:enable Metrics/
|
832
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
833
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
834
834
|
|
835
835
|
def check_condition(condition, caller)
|
836
836
|
Watir.logger.debug "<- `Verifying precondition #{inspect}##{condition} for #{caller}`"
|
@@ -272,7 +272,6 @@ module Watir
|
|
272
272
|
attribute(String, :form, :form)
|
273
273
|
attribute(String, :label, :label)
|
274
274
|
attribute("Boolean", :defaultselected?, :defaultSelected)
|
275
|
-
attribute("Boolean", :selected?, :selected)
|
276
275
|
attribute(String, :value, :value)
|
277
276
|
attribute(Integer, :index, :index)
|
278
277
|
end
|
@@ -44,8 +44,9 @@ module Watir
|
|
44
44
|
# @see Watir::Browser#execute_script
|
45
45
|
#
|
46
46
|
|
47
|
-
def execute_script(script, *args)
|
47
|
+
def execute_script(script, *args, function_name: nil)
|
48
48
|
args.map! do |e|
|
49
|
+
Watir.logger.info "Executing Script on Frame: #{function_name}" if function_name
|
49
50
|
e.is_a?(Element) ? e.wait_until(&:exists?).wd : e
|
50
51
|
end
|
51
52
|
returned = driver.execute_script(script, *args)
|
@@ -30,8 +30,11 @@ module Watir
|
|
30
30
|
#
|
31
31
|
|
32
32
|
def select(*str_or_rx)
|
33
|
-
|
34
|
-
|
33
|
+
if str_or_rx.size > 1 || str_or_rx.first.is_a?(Array)
|
34
|
+
str_or_rx.flatten.map { |v| select_all_by v }.first
|
35
|
+
else
|
36
|
+
str_or_rx.flatten.map { |v| select_by v }.first
|
37
|
+
end
|
35
38
|
end
|
36
39
|
|
37
40
|
#
|
@@ -43,6 +46,10 @@ module Watir
|
|
43
46
|
#
|
44
47
|
|
45
48
|
def select_all(*str_or_rx)
|
49
|
+
Watir.logger.deprecate('#select_all',
|
50
|
+
'#select with an Array instance',
|
51
|
+
ids: [:select_all])
|
52
|
+
|
46
53
|
results = str_or_rx.flatten.map { |v| select_all_by v }
|
47
54
|
results.first
|
48
55
|
end
|
@@ -55,8 +62,11 @@ module Watir
|
|
55
62
|
#
|
56
63
|
|
57
64
|
def select!(*str_or_rx)
|
58
|
-
|
59
|
-
|
65
|
+
if str_or_rx.size > 1 || str_or_rx.first.is_a?(Array)
|
66
|
+
str_or_rx.flatten.map { |v| select_by! v, :multiple }.first
|
67
|
+
else
|
68
|
+
str_or_rx.flatten.map { |v| select_by! v, :single }.first
|
69
|
+
end
|
60
70
|
end
|
61
71
|
|
62
72
|
#
|
@@ -67,6 +77,10 @@ module Watir
|
|
67
77
|
#
|
68
78
|
|
69
79
|
def select_all!(*str_or_rx)
|
80
|
+
Watir.logger.deprecate('#select_all!',
|
81
|
+
'#select! with an Array instance',
|
82
|
+
ids: [:select_all])
|
83
|
+
|
70
84
|
results = str_or_rx.flatten.map { |v| select_by!(v, :multiple) }
|
71
85
|
results.first
|
72
86
|
end
|
@@ -145,7 +159,8 @@ module Watir
|
|
145
159
|
found = find_options(:value, str_or_rx)
|
146
160
|
|
147
161
|
if found.size > 1
|
148
|
-
Watir.logger.deprecate 'Selecting
|
162
|
+
Watir.logger.deprecate 'Selecting multiple options with #select using a String or Regexp value',
|
163
|
+
'#select with the desired values in an Array instance',
|
149
164
|
ids: [:select_by]
|
150
165
|
end
|
151
166
|
select_matching(found)
|
@@ -14,7 +14,7 @@ module Watir
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def ignored_attributes
|
17
|
-
%w[cells elements hash rows span text size selected? style width height tHead tFoot link options]
|
17
|
+
%w[cells elements hash rows span text size selected? style width height tHead tFoot link options selected]
|
18
18
|
end
|
19
19
|
|
20
20
|
def generator_implementation
|
data/lib/watir/has_window.rb
CHANGED
@@ -10,13 +10,7 @@ module Watir
|
|
10
10
|
#
|
11
11
|
|
12
12
|
def windows(*args)
|
13
|
-
|
14
|
-
|
15
|
-
if args.empty?
|
16
|
-
all
|
17
|
-
else
|
18
|
-
filter_windows extract_selector(args), all
|
19
|
-
end
|
13
|
+
WindowCollection.new self, extract_selector(args)
|
20
14
|
end
|
21
15
|
|
22
16
|
#
|
@@ -51,16 +45,24 @@ module Watir
|
|
51
45
|
@original_window ||= window
|
52
46
|
end
|
53
47
|
|
54
|
-
|
48
|
+
#
|
49
|
+
# Waits for and returns second window if present
|
50
|
+
# See Window#use
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# browser.switch_window
|
54
|
+
#
|
55
|
+
# @return [Window]
|
56
|
+
#
|
55
57
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
def switch_window
|
59
|
+
current_window = window
|
60
|
+
wins = windows
|
61
|
+
wait_until { (wins = windows) && wins.size > 1 } if wins.size == 1
|
62
|
+
raise StandardError, 'Unable to determine which window to switch to' if wins.size > 2
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
+
wins.find { |w| w != current_window }.use
|
65
|
+
window
|
64
66
|
end
|
65
67
|
end # HasWindow
|
66
68
|
end # Watir
|
data/lib/watir/js_execution.rb
CHANGED
@@ -3,8 +3,8 @@ module Watir
|
|
3
3
|
#
|
4
4
|
# Delegates script execution to Browser or IFrame.
|
5
5
|
#
|
6
|
-
def execute_script(script, *args)
|
7
|
-
@query_scope.execute_script(script, *args)
|
6
|
+
def execute_script(script, *args, function_name: nil)
|
7
|
+
@query_scope.execute_script(script, *args, function_name: function_name)
|
8
8
|
end
|
9
9
|
|
10
10
|
#
|
data/lib/watir/js_snippets.rb
CHANGED
@@ -6,11 +6,11 @@ module Watir
|
|
6
6
|
|
7
7
|
def execute_js(function_name, *arguments)
|
8
8
|
file = File.expand_path("../js_snippets/#{function_name}.js", __FILE__)
|
9
|
-
raise Exception::Error, "Can not
|
9
|
+
raise Exception::Error, "Can not execute script as #{function_name}.js does not exist" unless File.exist?(file)
|
10
10
|
|
11
11
|
js = File.read(file)
|
12
12
|
script = "return (#{js}).apply(null, arguments)"
|
13
|
-
@query_scope.execute_script(script, *arguments)
|
13
|
+
@query_scope.execute_script(script, *arguments, function_name: function_name)
|
14
14
|
end
|
15
15
|
end # JSSnippets
|
16
16
|
end # Watir
|
data/lib/watir/locators.rb
CHANGED
@@ -142,7 +142,7 @@ module Watir
|
|
142
142
|
|
143
143
|
# Extensions implement this method when creating a different selector builder
|
144
144
|
def implementation_class
|
145
|
-
|
145
|
+
Watir.const_get("#{self.class.name}::XPath")
|
146
146
|
end
|
147
147
|
|
148
148
|
def build_wd_selector(selector)
|
data/lib/watir/logger.rb
CHANGED
@@ -2,7 +2,7 @@ require 'forwardable'
|
|
2
2
|
require 'logger'
|
3
3
|
|
4
4
|
# Code adapted from Selenium Implementation
|
5
|
-
# https://github.com/SeleniumHQ/selenium/blob/
|
5
|
+
# https://github.com/SeleniumHQ/selenium/blob/trunk/rb/lib/selenium/webdriver/common/logger.rb
|
6
6
|
|
7
7
|
module Watir
|
8
8
|
#
|
@@ -25,7 +25,7 @@ module Watir
|
|
25
25
|
:warn?,
|
26
26
|
:error, :error?,
|
27
27
|
:fatal, :fatal?,
|
28
|
-
:level
|
28
|
+
:level, :level=
|
29
29
|
|
30
30
|
def initialize(progname = 'Watir')
|
31
31
|
@logger = create_logger($stdout)
|
@@ -50,22 +50,6 @@ module Watir
|
|
50
50
|
@logger.warn(msg, &block) unless (@ignored & ids).any?
|
51
51
|
end
|
52
52
|
|
53
|
-
#
|
54
|
-
# For Ruby < 2.4 compatibility
|
55
|
-
# Based on https://github.com/ruby/ruby/blob/ruby_2_3/lib/logger.rb#L250
|
56
|
-
#
|
57
|
-
|
58
|
-
def level=(severity)
|
59
|
-
if severity.is_a?(Integer)
|
60
|
-
@logger.level = severity
|
61
|
-
else
|
62
|
-
levels = %w[debug info warn error fatal unknown]
|
63
|
-
raise ArgumentError, "invalid log level: #{severity}" unless levels.include? severity.to_s.downcase
|
64
|
-
|
65
|
-
@logger.level = severity.to_s.upcase
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
53
|
#
|
70
54
|
# Returns IO object used by logger internally.
|
71
55
|
#
|
data/lib/watir/radio_set.rb
CHANGED
@@ -4,7 +4,7 @@ module Watir
|
|
4
4
|
include Exception
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
delegate %i[exists? present? visible? browser] => :source
|
7
|
+
delegate %i[exist? exists? present? visible? browser] => :source
|
8
8
|
|
9
9
|
attr_reader :source, :frame
|
10
10
|
|
@@ -201,7 +201,7 @@ module Watir
|
|
201
201
|
end
|
202
202
|
alias eql? ==
|
203
203
|
|
204
|
-
#
|
204
|
+
# Delegating to Private Methods
|
205
205
|
%i[assert_exists element_call].each do |method|
|
206
206
|
define_method(method) do |*args, &blk|
|
207
207
|
source.send(method, *args, &blk)
|
data/lib/watir/user_editable.rb
CHANGED
@@ -21,13 +21,17 @@ module Watir
|
|
21
21
|
# @param [String, Symbol] args
|
22
22
|
#
|
23
23
|
|
24
|
+
def content_editable
|
25
|
+
defined?(@content_editable) && content_editable?
|
26
|
+
end
|
27
|
+
|
24
28
|
def set!(*args)
|
25
29
|
msg = '#set! does not support special keys, use #set instead'
|
26
30
|
raise ArgumentError, msg if args.any? { |v| v.is_a?(::Symbol) }
|
27
31
|
|
28
32
|
input_value = args.join
|
29
33
|
set input_value[0]
|
30
|
-
return content_editable_set!(*args) if
|
34
|
+
return content_editable_set!(*args) if content_editable
|
31
35
|
|
32
36
|
element_call { execute_js(:setValue, @element, input_value[0..-2]) }
|
33
37
|
append(input_value[-1])
|
@@ -43,7 +47,7 @@ module Watir
|
|
43
47
|
#
|
44
48
|
|
45
49
|
def append(*args)
|
46
|
-
raise NotImplementedError, '#append method is not supported with contenteditable element' if
|
50
|
+
raise NotImplementedError, '#append method is not supported with contenteditable element' if content_editable
|
47
51
|
|
48
52
|
send_keys(*args)
|
49
53
|
end
|
data/lib/watir/version.rb
CHANGED
data/lib/watir/wait.rb
CHANGED
data/lib/watir/wait/timer.rb
CHANGED
data/lib/watir/window.rb
CHANGED
@@ -6,7 +6,7 @@ module Watir
|
|
6
6
|
|
7
7
|
attr_reader :browser
|
8
8
|
|
9
|
-
def initialize(browser, selector)
|
9
|
+
def initialize(browser, selector = {})
|
10
10
|
@browser = browser
|
11
11
|
@driver = browser.driver
|
12
12
|
@selector = selector
|
@@ -16,7 +16,7 @@ module Watir
|
|
16
16
|
elsif selector.key? :handle
|
17
17
|
@handle = selector.delete :handle
|
18
18
|
else
|
19
|
-
return if selector.keys.all? { |k| %i[title url index].include? k }
|
19
|
+
return if selector.keys.all? { |k| %i[title url index element].include? k }
|
20
20
|
|
21
21
|
raise ArgumentError, "invalid window selector: #{selector_string}"
|
22
22
|
end
|
@@ -207,6 +207,9 @@ module Watir
|
|
207
207
|
if @selector.empty?
|
208
208
|
nil
|
209
209
|
elsif @selector.key?(:index)
|
210
|
+
Watir.logger.deprecate 'Using :index as a selector for Window', ':title or :url or :element',
|
211
|
+
reference: 'http://watir.com/guides/windows/#locating-by-index-is-no-longer-supported',
|
212
|
+
ids: [:window_index]
|
210
213
|
@driver.window_handles[Integer(@selector[:index])]
|
211
214
|
else
|
212
215
|
@driver.window_handles.find { |wh| matches?(wh) }
|
@@ -230,8 +233,9 @@ module Watir
|
|
230
233
|
@driver.switch_to.window(handle) do
|
231
234
|
matches_title = @selector[:title].nil? || @browser.title =~ /#{@selector[:title]}/
|
232
235
|
matches_url = @selector[:url].nil? || @browser.url =~ /#{@selector[:url]}/
|
236
|
+
matches_element = @selector[:element].nil? || @selector[:element].exists?
|
233
237
|
|
234
|
-
matches_title && matches_url
|
238
|
+
matches_title && matches_url && matches_element
|
235
239
|
end
|
236
240
|
rescue Selenium::WebDriver::Error::NoSuchWindowError
|
237
241
|
# the window may disappear while we're iterating.
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Watir
|
2
|
+
class WindowCollection
|
3
|
+
include Enumerable
|
4
|
+
include Waitable
|
5
|
+
|
6
|
+
def initialize(browser, selector = {})
|
7
|
+
unless selector.keys.all? { |k| %i[title url element].include? k }
|
8
|
+
raise ArgumentError, "invalid window selector: #{selector.inspect}"
|
9
|
+
end
|
10
|
+
|
11
|
+
@browser = browser
|
12
|
+
@selector = selector
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Yields each window in collection.
|
17
|
+
#
|
18
|
+
# @yieldparam [Watir::Window]
|
19
|
+
#
|
20
|
+
|
21
|
+
def each(&blk)
|
22
|
+
reset!
|
23
|
+
to_a.each(&blk)
|
24
|
+
end
|
25
|
+
|
26
|
+
alias length count
|
27
|
+
alias size count
|
28
|
+
alias empty? none?
|
29
|
+
|
30
|
+
#
|
31
|
+
# First window of the collection
|
32
|
+
#
|
33
|
+
# @note windows in a collection are not ordered so this is not reliably
|
34
|
+
# @deprecated use Browser#switch_window or a better Window locator
|
35
|
+
# @return [Watir::Window] Returns an instance of a Watir::Window
|
36
|
+
#
|
37
|
+
|
38
|
+
def first
|
39
|
+
self[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Last window of the collection
|
44
|
+
#
|
45
|
+
# @note windows in a collection are not ordered so this is not reliably
|
46
|
+
# @deprecated use Browser#switch_window or a better Window locator
|
47
|
+
# @return [Watir::Window] Returns an instance of a Watir::Window
|
48
|
+
#
|
49
|
+
|
50
|
+
def last
|
51
|
+
self[-1]
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Get the window at the given index or range.
|
56
|
+
#
|
57
|
+
# @note windows in a collection are not ordered so this is not reliably
|
58
|
+
# @deprecated use Browser#switch_window or a better Window locator
|
59
|
+
# @param [Integer, Range] value Index (0-based) or Range of desired window(s)
|
60
|
+
# @return [Watir::Window] Returns an instance of a Watir::Window
|
61
|
+
#
|
62
|
+
|
63
|
+
def [](value)
|
64
|
+
old = 'using indexing with windows'
|
65
|
+
new = 'Browser#switch_window or Browser#window with :title, :url or :element selectors'
|
66
|
+
reference = 'http://watir.com/window_indexes'
|
67
|
+
Watir.logger.deprecate old, new, reference: reference, ids: [:window_index]
|
68
|
+
|
69
|
+
to_a[value]
|
70
|
+
end
|
71
|
+
|
72
|
+
def ==(other)
|
73
|
+
to_a == other.to_a
|
74
|
+
end
|
75
|
+
alias eql? ==
|
76
|
+
|
77
|
+
def to_a
|
78
|
+
@to_a ||= begin
|
79
|
+
handles = @browser.driver.window_handles.select { |wh| matches?(wh) }
|
80
|
+
handles.map { |wh| Window.new(@browser, handle: wh) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def reset!
|
85
|
+
@to_a = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# NOTE: This is the exact same code from `Window#matches?`
|
91
|
+
# TODO: Move this code into a separate WindowLocator class
|
92
|
+
def matches?(handle)
|
93
|
+
@selector.empty? || @browser.driver.switch_to.window(handle) do
|
94
|
+
matches_title = @selector[:title].nil? || @browser.title =~ /#{@selector[:title]}/
|
95
|
+
matches_url = @selector[:url].nil? || @browser.url =~ /#{@selector[:url]}/
|
96
|
+
matches_element = @selector[:element].nil? || @selector[:element].exists?
|
97
|
+
|
98
|
+
matches_title && matches_url && matches_element
|
99
|
+
end
|
100
|
+
rescue Selenium::WebDriver::Error::NoSuchWindowError
|
101
|
+
# the window may disappear while we're iterating.
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end # Window
|
105
|
+
end # Watir
|