watir 6.5.0 → 6.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +58 -21
  3. data/CHANGES.md +11 -0
  4. data/Rakefile +3 -5
  5. data/lib/watir.rb +14 -2
  6. data/lib/watir/adjacent.rb +20 -27
  7. data/lib/watir/alert.rb +1 -1
  8. data/lib/watir/attribute_helper.rb +1 -1
  9. data/lib/watir/browser.rb +6 -3
  10. data/lib/watir/capabilities.rb +95 -0
  11. data/lib/watir/cookies.rb +5 -6
  12. data/lib/watir/element_collection.rb +17 -0
  13. data/lib/watir/elements/element.rb +12 -15
  14. data/lib/watir/elements/iframe.rb +1 -1
  15. data/lib/watir/elements/option.rb +5 -6
  16. data/lib/watir/elements/select.rb +52 -36
  17. data/lib/watir/legacy_wait.rb +2 -2
  18. data/lib/watir/locators/button/selector_builder.rb +10 -7
  19. data/lib/watir/locators/element/locator.rb +2 -2
  20. data/lib/watir/locators/element/selector_builder.rb +10 -4
  21. data/lib/watir/locators/element/selector_builder/xpath.rb +22 -3
  22. data/lib/watir/logger.rb +109 -0
  23. data/lib/watir/wait.rb +6 -6
  24. data/lib/watirspec.rb +1 -1
  25. data/lib/watirspec/guards.rb +4 -4
  26. data/lib/watirspec/implementation.rb +13 -5
  27. data/lib/watirspec/remote_server.rb +38 -0
  28. data/lib/watirspec/runner.rb +2 -2
  29. data/lib/watirspec/server.rb +1 -1
  30. data/spec/browser_spec.rb +101 -17
  31. data/spec/element_locator_spec.rb +1 -1
  32. data/spec/element_spec.rb +1 -1
  33. data/spec/logger_spec.rb +46 -0
  34. data/spec/watirspec/adjacent_spec.rb +45 -0
  35. data/spec/watirspec/after_hooks_spec.rb +45 -40
  36. data/spec/watirspec/alert_spec.rb +20 -14
  37. data/spec/watirspec/browser_spec.rb +71 -77
  38. data/spec/watirspec/cookies_spec.rb +13 -16
  39. data/spec/watirspec/drag_and_drop_spec.rb +6 -6
  40. data/spec/watirspec/elements/button_spec.rb +14 -7
  41. data/spec/watirspec/elements/collections_spec.rb +18 -1
  42. data/spec/watirspec/elements/dd_spec.rb +4 -2
  43. data/spec/watirspec/elements/del_spec.rb +12 -10
  44. data/spec/watirspec/elements/div_spec.rb +17 -13
  45. data/spec/watirspec/elements/dl_spec.rb +4 -2
  46. data/spec/watirspec/elements/form_spec.rb +8 -6
  47. data/spec/watirspec/elements/frame_spec.rb +27 -19
  48. data/spec/watirspec/elements/iframe_spec.rb +28 -17
  49. data/spec/watirspec/elements/ins_spec.rb +12 -10
  50. data/spec/watirspec/elements/option_spec.rb +17 -33
  51. data/spec/watirspec/elements/select_list_spec.rb +111 -97
  52. data/spec/watirspec/elements/span_spec.rb +12 -10
  53. data/spec/watirspec/elements/table_spec.rb +13 -11
  54. data/spec/watirspec/elements/tbody_spec.rb +13 -11
  55. data/spec/watirspec/elements/td_spec.rb +6 -4
  56. data/spec/watirspec/elements/text_field_spec.rb +19 -17
  57. data/spec/watirspec/elements/tr_spec.rb +12 -8
  58. data/spec/watirspec/html/javascript/helpers.js +2 -2
  59. data/spec/watirspec/html/nested_elements.html +5 -5
  60. data/spec/watirspec/relaxed_locate_spec.rb +13 -19
  61. data/spec/watirspec/wait_spec.rb +279 -301
  62. data/spec/watirspec/window_switching_spec.rb +190 -174
  63. data/spec/watirspec_helper.rb +64 -122
  64. data/support/doctest_helper.rb +4 -0
  65. data/watir.gemspec +2 -2
  66. metadata +15 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e19bc6a7d28d78bba208d88dd97a58bce85fc9d
4
- data.tar.gz: 0031cc40646d67219270b7914369df5a7e084144
3
+ metadata.gz: da90c92ae28c4fd2e22b1bb60bdcbe18b060dee0
4
+ data.tar.gz: 9ff7214a544eda7ac4a60cd923c504f35ba92fec
5
5
  SHA512:
6
- metadata.gz: f71791589c4bc26c594d25ffb755fec75a8cbf41c2d93e0bf8c9671573a66e2fac01a21618159c169fa79a25387963a5a79c6940a329b177939b305ede9c3dbd
7
- data.tar.gz: 7ca2f02eb0a3c950f2e8b8e16ce8e1acb9c3dd8766637d8bc5c3594b49634c0dce2af3d7ec216add6d36f81968df69eb3b35215bd5a43c216b2c04883d350c98
6
+ metadata.gz: b6fbd488d5d064acaeb9b4dca1f9a3d8d6246c51b3b29d36089916e4cd3c048ccf5c343c88c8e962d1b533c8402c2a21ce3bd36db3b9dd96c2ddda89b51da2af
7
+ data.tar.gz: a42a2727efabda8ac3210efce1707636d61eab62f311ec8f3efe3542c065c02e8944e00ce41b785f260b94ad42b9abca5585868f49e89b0a2d824e5719c435f9
@@ -3,31 +3,68 @@
3
3
  # use host's /dev/shm.
4
4
  sudo: required
5
5
  dist: trusty
6
- rvm:
7
- - 2.2.7
8
- - 2.3.4
9
- - 2.4.1
10
- addons:
11
- firefox: latest
12
- apt:
13
- packages:
14
- - unzip
15
- - libxss1
16
- - google-chrome-stable
17
6
  cache: bundler
18
7
  notifications:
19
- recipients:
20
- - p0deje@gmail.com
21
- - jarmo.p@gmail.com
22
- - titusfortner@gmail.com
23
8
  slack:
24
9
  secure: BLsBCm33R32VNRccrLx9F0P24X6BVpVHj1OWaN4Kyn6g9qXteIwC2VKVMnKNbifpojfMkrn0OeFQFK1O1DSOsC3mgzn/udoB+DnUGcSemFUn04xhbYF5SI+3zGPKPo0JLvjjdEKSSma84YwKdrj88pGUK34p01gL8hiaqjFzWdk=
25
10
  before_script:
26
11
  - support/travis.sh
27
12
  script: bundle exec rake $RAKE_TASK
28
- env:
29
- - RAKE_TASK=spec:firefox
30
- - RAKE_TASK=spec:firefox RELAXED_LOCATE=false
31
- - RAKE_TASK=spec:chrome
32
- - RAKE_TASK=spec:chrome RELAXED_LOCATE=false
33
- - RAKE_TASK=yard:doctest
13
+
14
+ _version:
15
+ two: &two
16
+ language: ruby
17
+ rvm: 2.2.7
18
+ three: &three
19
+ language: ruby
20
+ rvm: 2.3.4
21
+ four: &four
22
+ language: ruby
23
+ rvm: 2.4.1
24
+
25
+ _browsers:
26
+ firefox: &firefox-latest
27
+ addons:
28
+ firefox: latest
29
+ chrome: &chrome
30
+ addons:
31
+ chrome: stable
32
+
33
+ matrix:
34
+ include:
35
+ - env: RAKE_TASK=spec:remote_firefox
36
+ <<: *four
37
+ <<: *firefox-latest
38
+ - env: RAKE_TASK=spec:remote_chrome
39
+ <<: *four
40
+ <<: *chrome
41
+ - env: RAKE_TASK=spec:firefox RELAXED_LOCATE=false
42
+ <<: *four
43
+ <<: *firefox-latest
44
+ - env: RAKE_TASK=spec:firefox
45
+ <<: *four
46
+ <<: *firefox-latest
47
+ - env: RAKE_TASK=spec:firefox
48
+ <<: *three
49
+ <<: *firefox-latest
50
+ - env: RAKE_TASK=spec:firefox
51
+ <<: *two
52
+ <<: *firefox-latest
53
+ - env: RAKE_TASK=spec:chrome
54
+ <<: *four
55
+ <<: *chrome
56
+ - env: RAKE_TASK=spec:chrome
57
+ <<: *three
58
+ <<: *chrome
59
+ - env: RAKE_TASK=spec:chrome
60
+ <<: *two
61
+ <<: *chrome
62
+ - env: RAKE_TASK=spec:chrome RELAXED_LOCATE=false
63
+ <<: *four
64
+ <<: *chrome
65
+ - env: RAKE_TASK=spec:chrome HEADLESS=true
66
+ <<: *four
67
+ <<: *chrome
68
+ - env: RAKE_TASK=yard:doctest
69
+ <<: *four
70
+ <<: *chrome
data/CHANGES.md CHANGED
@@ -1,3 +1,14 @@
1
+ ### 6.6.0 (2017-08-02)
2
+
3
+ * Implement `Select#select_all` for selecting multiple options in select list
4
+ * Deprecate `Select#select` for selecting multiple options in a list
5
+ * Implement `ElementCollection#empty?` and `ElementCollection#locate?`
6
+ * Implement `Watir::Logger` class
7
+ * Implement `Watir::Capabilities` class
8
+ * Add support for relocating elements created with `Element#to_subtype`
9
+ * Add support for locating adjacent elements with any Watir locator
10
+ * Allow locating buttons by type attribute (thanks Justin Ko )
11
+
1
12
  ### 6.5.0 (2017-07-25)
2
13
 
3
14
  * Add support for locating multiple classes using :class parameter
data/Rakefile CHANGED
@@ -125,7 +125,6 @@ namespace :spec do
125
125
  desc 'Run specs locally for all browsers'
126
126
  task browsers: [:chrome,
127
127
  :firefox,
128
- :ff_legacy,
129
128
  (:safari if Selenium::WebDriver::Platform.mac?),
130
129
  (:ie if Selenium::WebDriver::Platform.windows?),
131
130
  (:edge if Selenium::WebDriver::Platform.windows?)].compact
@@ -133,12 +132,11 @@ namespace :spec do
133
132
  desc 'Run specs remotely for all browsers'
134
133
  task remote_browsers: [:remote_chrome,
135
134
  :remote_firefox,
136
- :remote_ff_legacy,
137
135
  (:remote_safari if Selenium::WebDriver::Platform.mac?),
138
136
  (:remote_ie if Selenium::WebDriver::Platform.windows?),
139
137
  (:remote_edge if Selenium::WebDriver::Platform.windows?)].compact
140
138
 
141
- %w(firefox ff_legacy chrome safari ie edge).each do |browser|
139
+ %w(firefox chrome safari ie edge).each do |browser|
142
140
  desc "Run specs in #{browser}"
143
141
  task browser do
144
142
  ENV['WATIR_BROWSER'] = browser
@@ -147,8 +145,8 @@ namespace :spec do
147
145
 
148
146
  desc "Run specs in Remote #{browser}"
149
147
  task "remote_#{browser}" do
150
- ENV['WATIR_BROWSER'] = 'remote'
151
- ENV['REMOTE_BROWSER'] = browser
148
+ ENV['WATIR_BROWSER'] = browser
149
+ ENV["USE_REMOTE"] = 'true'
152
150
  Rake::Task[:spec].execute
153
151
  end
154
152
  end
@@ -11,9 +11,11 @@ require 'watir/alert'
11
11
  require 'watir/atoms'
12
12
  require 'watir/container'
13
13
  require 'watir/cookies'
14
+ require 'watir/capabilities'
14
15
  require 'watir/browser'
15
16
  require 'watir/screenshot'
16
17
  require 'watir/after_hooks'
18
+ require 'watir/logger'
17
19
 
18
20
  module Watir
19
21
 
@@ -43,7 +45,7 @@ module Watir
43
45
  end
44
46
 
45
47
  def always_locate_message
46
- warn <<-EOS
48
+ Watir.logger.warn <<-EOS
47
49
  Watir#always_locate is deprecated; elements are always cached and will always
48
50
  be re-located if they go stale before use.
49
51
  Use Element#stale? or Element#wait_until(&:stale?) if needed for flow control.
@@ -60,7 +62,7 @@ Use Element#stale? or Element#wait_until(&:stale?) if needed for flow control.
60
62
  end
61
63
 
62
64
  def prefer_css_message
63
- warn <<-EOS
65
+ Watir.logger.warn <<-EOS
64
66
  Watir#prefer_css is deprecated; all elements that can not be passed directly
65
67
  as Selenium locators will be translated to XPath. To continue using CSS Selectors
66
68
  require the watir_css gem - https://github.com/watir/watir_css
@@ -101,6 +103,16 @@ require the watir_css gem - https://github.com/watir/watir_css
101
103
  end
102
104
  end
103
105
 
106
+ #
107
+ # Returns logger instance that can be used across the whole Selenium.
108
+ #
109
+ # @return [Logger]
110
+ #
111
+
112
+ def self.logger
113
+ @logger ||= Watir::Logger.new
114
+ end
115
+
104
116
  end
105
117
 
106
118
  require 'watir/attribute_helper'
@@ -10,8 +10,7 @@ module Watir
10
10
  #
11
11
 
12
12
  def parent(opt = {})
13
- opt[:index] ||= 0
14
- xpath_adjacent("ancestor::", opt)
13
+ xpath_adjacent(opt.merge(adjacent: :ancestor, plural: false))
15
14
  end
16
15
 
17
16
  #
@@ -23,8 +22,7 @@ module Watir
23
22
  #
24
23
 
25
24
  def preceding_sibling(opt = {})
26
- opt[:index] ||= 0
27
- xpath_adjacent("preceding-sibling::", opt)
25
+ xpath_adjacent(opt.merge(adjacent: :preceding, plural: false))
28
26
  end
29
27
  alias_method :previous_sibling, :preceding_sibling
30
28
 
@@ -38,7 +36,7 @@ module Watir
38
36
 
39
37
  def preceding_siblings(opt = {})
40
38
  raise ArgumentError, "#previous_siblings can not take an index value" if opt[:index]
41
- xpath_adjacent("preceding-sibling::", opt)
39
+ xpath_adjacent(opt.merge(adjacent: :preceding, plural: true))
42
40
  end
43
41
  alias_method :previous_siblings, :preceding_siblings
44
42
 
@@ -51,8 +49,7 @@ module Watir
51
49
  #
52
50
 
53
51
  def following_sibling(opt = {})
54
- opt[:index] ||= 0
55
- xpath_adjacent("following-sibling::", opt)
52
+ xpath_adjacent(opt.merge(adjacent: :following, plural: false))
56
53
  end
57
54
  alias_method :next_sibling, :following_sibling
58
55
 
@@ -66,7 +63,7 @@ module Watir
66
63
 
67
64
  def following_siblings(opt = {})
68
65
  raise ArgumentError, "#next_siblings can not take an index value" if opt[:index]
69
- xpath_adjacent("following-sibling::", opt)
66
+ xpath_adjacent(opt.merge(adjacent: :following, plural: true))
70
67
  end
71
68
  alias_method :next_siblings, :following_siblings
72
69
 
@@ -79,8 +76,7 @@ module Watir
79
76
  #
80
77
 
81
78
  def child(opt = {})
82
- opt[:index] ||= 0
83
- xpath_adjacent('', opt)
79
+ xpath_adjacent(opt.merge(adjacent: :child, plural: false))
84
80
  end
85
81
 
86
82
  #
@@ -93,27 +89,24 @@ module Watir
93
89
 
94
90
  def children(opt = {})
95
91
  raise ArgumentError, "#children can not take an index value" if opt[:index]
96
- xpath_adjacent('', opt)
92
+ xpath_adjacent(opt.merge(adjacent: :child, plural: true))
97
93
  end
98
94
 
99
95
  private
100
96
 
101
- def xpath_adjacent(direction = '', opt = {})
102
- opt = opt.dup
103
- index = opt.delete :index
104
- tag_name = opt.delete :tag_name
105
- unless opt.empty?
106
- caller = caller_locations(1, 1)[0].label
107
- raise ArgumentError, "unsupported locators: #{opt.inspect} for ##{caller} method"
108
- end
109
-
110
- if index
111
- klass = tag_name ? self.send(tag_name).class : HTMLElement
112
- klass.new(self, xpath: "./#{direction}#{tag_name || '*'}[#{index + 1}]")
113
- else
114
- klass = tag_name ? Object.const_get("#{self.send(tag_name).class}Collection") : HTMLElementCollection
115
- klass.new(self, xpath: "./#{direction}#{tag_name || '*'}")
116
- end
97
+ def xpath_adjacent(opt = {})
98
+ plural = opt.delete(:plural)
99
+ opt[:index] ||= 0 unless plural || opt.values.any? { |e| e.is_a? Regexp }
100
+ klass = if !plural && opt[:tag_name]
101
+ self.send(opt[:tag_name]).class
102
+ elsif !plural
103
+ HTMLElement
104
+ elsif opt[:tag_name]
105
+ Object.const_get("#{self.send(opt[:tag_name]).class}Collection")
106
+ else
107
+ HTMLElementCollection
108
+ end
109
+ klass.new(self, opt)
117
110
  end
118
111
 
119
112
  end # Adjacent
@@ -110,7 +110,7 @@ module Watir
110
110
  message = "This code has slept for the duration of the default timeout "
111
111
  message << "waiting for an Alert to exist. If the test is still passing, "
112
112
  message << "consider using Alert#exists? instead of rescuing UnknownObjectException"
113
- warn message
113
+ Watir.logger.warn message
114
114
  end
115
115
  raise Exception::UnknownObjectException, 'unable to locate alert'
116
116
  end
@@ -62,7 +62,7 @@ module Watir
62
62
  when 'Float'
63
63
  define_float_attribute(name, attr)
64
64
  else
65
- # $stderr.puts "treating #{type.inspect} as string for now"
65
+ Watir.logger.debug "treating #{type.inspect} as string for now"
66
66
  end
67
67
  end
68
68
 
@@ -44,7 +44,8 @@ module Watir
44
44
  def initialize(browser = :chrome, *args)
45
45
  case browser
46
46
  when ::Symbol, String
47
- @driver = Selenium::WebDriver.for browser.to_sym, *args
47
+ selenium_args = Watir::Capabilities.new(browser, *args).to_args
48
+ @driver = Selenium::WebDriver.for *selenium_args
48
49
  when Selenium::WebDriver::Driver
49
50
  @driver = browser
50
51
  else
@@ -58,8 +59,10 @@ module Watir
58
59
 
59
60
  def inspect
60
61
  '#<%s:0x%x url=%s title=%s>' % [self.class, hash*2, url.inspect, title.inspect]
61
- rescue
62
- '#<%s:0x%x closed=%s>' % [self.class, hash*2, @closed.to_s]
62
+ rescue Errno::ECONNREFUSED
63
+ '#<%s:0x%x closed=true>' % [self.class, hash*2]
64
+ rescue Selenium::WebDriver::Error::UnhandledAlertError
65
+ '#<%s:0x%x alert=true>' % [self.class, hash*2]
63
66
  end
64
67
  alias selector_string inspect
65
68
 
@@ -0,0 +1,95 @@
1
+ module Watir
2
+ class Capabilities
3
+
4
+ attr_reader :options
5
+
6
+ def initialize(browser, options = {})
7
+ @browser = browser == :remote ? @options.delete(:browser).to_sym : browser.to_sym
8
+ @selenium_browser = browser == :remote || options[:url] ? :remote : browser
9
+
10
+ @options = options
11
+ @selenium_opts = {}
12
+ end
13
+
14
+ def to_args
15
+ [@selenium_browser, process_capabilities]
16
+ end
17
+
18
+ private
19
+
20
+ def process_capabilities
21
+ url = @options.delete(:url)
22
+ @selenium_opts[:url] = url if url
23
+
24
+ create_http_client
25
+
26
+ @selenium_opts[:port] = @options.delete(:port) if @options.key?(:port)
27
+
28
+ process_browser_options
29
+ process_caps
30
+
31
+ @selenium_opts
32
+ end
33
+
34
+ def create_http_client
35
+ client_timeout = @options.delete(:client_timeout)
36
+ open_timeout = @options.delete(:open_timeout)
37
+ read_timeout = @options.delete(:read_timeout)
38
+
39
+ http_client = @options.delete(:http_client)
40
+
41
+ %i(open_timeout read_timeout client_timeout).each do |t|
42
+ next if http_client.nil? || !respond_to?(t)
43
+ warn "You can now pass #{t} value directly into Watir::Browser opt without needing to use :http_client"
44
+ end
45
+
46
+ http_client ||= Selenium::WebDriver::Remote::Http::Default.new
47
+
48
+ http_client.timeout = client_timeout if client_timeout
49
+ http_client.open_timeout = open_timeout if open_timeout
50
+ http_client.read_timeout = read_timeout if read_timeout
51
+ @selenium_opts[:http_client] = http_client
52
+ end
53
+
54
+ def process_browser_options
55
+ browser_options = @options.delete(:options)
56
+
57
+ case @selenium_browser
58
+ when :chrome
59
+ if @options.key?(:args)
60
+ browser_options ||= {}
61
+ browser_options[:args] = @options.delete(:args)
62
+ end
63
+ if @options.delete(:headless)
64
+ browser_options ||= {}
65
+ browser_options[:args] << '--headless'
66
+ browser_options[:args] << '--disable-gpu'
67
+ end
68
+ @selenium_opts[:options] = Selenium::WebDriver::Chrome::Options.new(browser_options) if browser_options
69
+ when :firefox
70
+ @selenium_opts[:options] = Selenium::WebDriver::Firefox::Options.new(options) if browser_options
71
+ when :safari
72
+ @selenium_opts["safari.options"] = {'technologyPreview' => true} if @options[:technology_preview]
73
+ when :remote
74
+ if @browser == :chrome && @options.delete(:headless)
75
+ @options.delete(:args)
76
+ @options['chromeOptions'] = {'args' => ['--headless', '--disable-gpu']}
77
+ end
78
+ end
79
+ end
80
+
81
+ def process_caps
82
+ caps = @options.delete(:desired_capabilities)
83
+
84
+ if caps
85
+ warn 'You can now pass values directly into Watir::Browser opt without needing to use :desired_capabilities'
86
+ @selenium_opts.merge!(@options)
87
+ else
88
+ caps = Selenium::WebDriver::Remote::Capabilities.send @browser, @options
89
+ end
90
+
91
+ @selenium_opts[:desired_capabilities] = caps
92
+ end
93
+
94
+ end
95
+ end
@@ -56,12 +56,11 @@ module Watir
56
56
  def add(name, value, opts = {})
57
57
  cookie = {
58
58
  name: name,
59
- value: value,
60
- secure: opts[:secure],
61
- path: opts[:path],
62
- expires: opts[:expires],
63
- domain: opts[:domain]
64
- }
59
+ value: value}
60
+ cookie[:secure] = opts[:secure] if opts.key?(:secure)
61
+ cookie[:path] = opts[:path] if opts.key?(:path)
62
+ cookie[:expires] = opts[:expires] if opts.key?(:expires)
63
+ cookie[:domain] = opts[:domain] if opts.key?(:domain)
65
64
 
66
65
  @control.add_cookie cookie
67
66
  end