watir 6.18.0 → 7.0.0.beta3

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/actions/install-chrome/action.yml +1 -0
  3. data/.github/actions/setup-linux/action.yml +8 -0
  4. data/.github/workflows/tests.yml +104 -0
  5. data/.rubocop.yml +2 -7
  6. data/CHANGES.md +51 -0
  7. data/README.md +2 -5
  8. data/Rakefile +1 -1
  9. data/lib/watir.rb +3 -45
  10. data/lib/watir/alert.rb +3 -8
  11. data/lib/watir/browser.rb +18 -4
  12. data/lib/watir/capabilities.rb +106 -106
  13. data/lib/watir/cell_container.rb +4 -4
  14. data/lib/watir/container.rb +4 -26
  15. data/lib/watir/elements/checkbox.rb +4 -4
  16. data/lib/watir/elements/date_field.rb +4 -4
  17. data/lib/watir/elements/date_time_field.rb +4 -4
  18. data/lib/watir/elements/element.rb +44 -52
  19. data/lib/watir/elements/file_field.rb +4 -4
  20. data/lib/watir/elements/font.rb +5 -4
  21. data/lib/watir/elements/hidden.rb +4 -4
  22. data/lib/watir/elements/html_elements.rb +444 -445
  23. data/lib/watir/elements/iframe.rb +4 -5
  24. data/lib/watir/elements/radio.rb +6 -6
  25. data/lib/watir/elements/select.rb +60 -103
  26. data/lib/watir/elements/svg_elements.rb +96 -96
  27. data/lib/watir/elements/text_field.rb +4 -4
  28. data/lib/watir/generator/base/generator.rb +4 -4
  29. data/lib/watir/generator/base/visitor.rb +0 -29
  30. data/lib/watir/generator/html/generator.rb +2 -1
  31. data/lib/watir/has_window.rb +6 -4
  32. data/lib/watir/http_client.rb +9 -0
  33. data/lib/watir/locators.rb +5 -5
  34. data/lib/watir/locators/button/matcher.rb +0 -23
  35. data/lib/watir/locators/button/selector_builder/xpath.rb +4 -15
  36. data/lib/watir/locators/element/matcher.rb +4 -19
  37. data/lib/watir/locators/element/selector_builder.rb +2 -40
  38. data/lib/watir/locators/element/selector_builder/xpath.rb +34 -41
  39. data/lib/watir/locators/option/matcher.rb +24 -0
  40. data/lib/watir/locators/option/selector_builder.rb +8 -0
  41. data/lib/watir/locators/option/selector_builder/xpath.rb +37 -0
  42. data/lib/watir/logger.rb +3 -74
  43. data/lib/watir/radio_set.rb +3 -2
  44. data/lib/watir/row_container.rb +4 -4
  45. data/lib/watir/screenshot.rb +2 -8
  46. data/lib/watir/user_editable.rb +10 -3
  47. data/lib/watir/version.rb +1 -1
  48. data/lib/watir/wait.rb +4 -74
  49. data/lib/watir/window.rb +21 -26
  50. data/lib/watir/window_collection.rb +21 -47
  51. data/lib/watirspec.rb +4 -2
  52. data/lib/watirspec/guards.rb +1 -1
  53. data/lib/watirspec/implementation.rb +4 -0
  54. data/lib/watirspec/runner.rb +1 -1
  55. data/lib/watirspec/server.rb +1 -1
  56. data/spec/spec_helper.rb +1 -16
  57. data/spec/unit/capabilities_spec.rb +560 -21
  58. data/spec/unit/match_elements/button_spec.rb +0 -13
  59. data/spec/unit/match_elements/element_spec.rb +49 -47
  60. data/spec/unit/match_elements/text_field_spec.rb +6 -6
  61. data/spec/unit/selector_builder/element_spec.rb +6 -23
  62. data/spec/unit/selector_builder/text_field_spec.rb +6 -7
  63. data/spec/watirspec/after_hooks_spec.rb +22 -45
  64. data/spec/watirspec/alert_spec.rb +4 -21
  65. data/spec/watirspec/browser_spec.rb +186 -207
  66. data/spec/watirspec/cookies_spec.rb +47 -52
  67. data/spec/watirspec/drag_and_drop_spec.rb +5 -7
  68. data/spec/watirspec/elements/area_spec.rb +1 -5
  69. data/spec/watirspec/elements/button_spec.rb +4 -18
  70. data/spec/watirspec/elements/checkbox_spec.rb +10 -24
  71. data/spec/watirspec/elements/date_field_spec.rb +13 -16
  72. data/spec/watirspec/elements/date_time_field_spec.rb +14 -13
  73. data/spec/watirspec/elements/dd_spec.rb +3 -4
  74. data/spec/watirspec/elements/del_spec.rb +10 -12
  75. data/spec/watirspec/elements/div_spec.rb +45 -84
  76. data/spec/watirspec/elements/divs_spec.rb +2 -2
  77. data/spec/watirspec/elements/dl_spec.rb +4 -12
  78. data/spec/watirspec/elements/element_spec.rb +190 -170
  79. data/spec/watirspec/elements/elements_spec.rb +8 -9
  80. data/spec/watirspec/elements/filefield_spec.rb +5 -7
  81. data/spec/watirspec/elements/form_spec.rb +3 -5
  82. data/spec/watirspec/elements/forms_spec.rb +3 -5
  83. data/spec/watirspec/elements/frame_spec.rb +17 -22
  84. data/spec/watirspec/elements/iframe_spec.rb +21 -27
  85. data/spec/watirspec/elements/ins_spec.rb +10 -12
  86. data/spec/watirspec/elements/link_spec.rb +24 -26
  87. data/spec/watirspec/elements/links_spec.rb +8 -9
  88. data/spec/watirspec/elements/radio_spec.rb +11 -14
  89. data/spec/watirspec/elements/select_list_spec.rb +253 -223
  90. data/spec/watirspec/elements/span_spec.rb +12 -14
  91. data/spec/watirspec/elements/spans_spec.rb +1 -1
  92. data/spec/watirspec/elements/strong_spec.rb +1 -1
  93. data/spec/watirspec/elements/table_nesting_spec.rb +31 -34
  94. data/spec/watirspec/elements/table_spec.rb +11 -13
  95. data/spec/watirspec/elements/tbody_spec.rb +10 -12
  96. data/spec/watirspec/elements/td_spec.rb +4 -6
  97. data/spec/watirspec/elements/text_field_spec.rb +10 -12
  98. data/spec/watirspec/elements/tr_spec.rb +5 -7
  99. data/spec/watirspec/html/non_control_elements.html +8 -3
  100. data/spec/watirspec/html/special_chars.html +3 -0
  101. data/spec/watirspec/special_chars_spec.rb +10 -0
  102. data/spec/watirspec/support/rspec_matchers.rb +4 -20
  103. data/spec/watirspec/user_editable_spec.rb +26 -28
  104. data/spec/watirspec/wait_spec.rb +255 -258
  105. data/spec/watirspec/window_switching_spec.rb +212 -245
  106. data/spec/watirspec_helper.rb +42 -34
  107. data/watir.gemspec +3 -4
  108. metadata +16 -37
  109. data/.github/workflows/linux.yml +0 -61
  110. data/.github/workflows/mac.yml +0 -55
  111. data/.github/workflows/unit.yml +0 -31
  112. data/.github/workflows/windows.yml +0 -39
  113. data/lib/watir/legacy_wait.rb +0 -123
  114. data/spec/implementation_spec.rb +0 -24
  115. data/spec/unit/container_spec.rb +0 -35
  116. data/spec/unit/logger_spec.rb +0 -81
  117. data/spec/watirspec/legacy_wait_spec.rb +0 -216
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29eeb6548d5f5f91ee744107d1e3c79f0d2baf8b688c9588752e25b75fa696ef
4
- data.tar.gz: 27502c2b89585471b25751b5564c08784578585d3c196f132f56b52243645735
3
+ metadata.gz: ebf40b52023085fd593f26f448268e0f00c51dbaf80fc3af9801d9d8c9d7703b
4
+ data.tar.gz: f42ee61445dc9ab61a6d236597bd67c84a2fdd837a5af0cc2236ae1eb6e19467
5
5
  SHA512:
6
- metadata.gz: d2a90695c68c0db0493d1fdeac5ab90ab51604a0916b4b6cbf0abeae595c6680f62269da98b9920c7ee7db4448e70c6afe31caa280ae76234bae2fc0b51c2912
7
- data.tar.gz: 645305ed2b0ae8b5777995c6620055e37850dcefdb3b5a5b609d98b4ce30f8d0cd14155a79fb2032a46862d8c10ad92e9c0112fc7fe68e31dac01b6da44cbbd9
6
+ metadata.gz: 61cd3f3f3cf9f3d3739ed006de8b41ad4cf60336953b518e9c993e0fafb09c7dd0d7903bbf2099d562987b91ff1aa4b351108b78767ea98b65e6eb53de78f451
7
+ data.tar.gz: '09017e544063c107aa91865759b4f61366476178b9c55f6b64f6bc81958eb6236d44621baff328ab4587d752a3e99be169ce9cf4be11443354d48dc019d6b04a'
@@ -1,4 +1,5 @@
1
1
  name: 'Install Chrome'
2
+ description: 'Install Chrome Stable'
2
3
  runs:
3
4
  using: "composite"
4
5
  steps:
@@ -0,0 +1,8 @@
1
+ name: 'Setup Linux'
2
+ description: 'Run Linux in Virtual Desktop'
3
+ runs:
4
+ using: "composite"
5
+ steps:
6
+ - shell: bash
7
+ run: |
8
+ Xvfb :99 &
@@ -0,0 +1,104 @@
1
+ name: All Tests
2
+
3
+ on:
4
+ - push
5
+ - pull_request
6
+
7
+ jobs:
8
+ documentation-test:
9
+ name: Yard Doctest
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6
16
+ - run: bundle install
17
+ - uses: ./.github/actions/install-chrome
18
+ - uses: ./.github/actions/setup-linux
19
+ - run: |
20
+ bundle exec rake yard:doctest
21
+
22
+ unit-test:
23
+ name: Unit Tests
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ ruby: ['2.5', '2.6', '2.7', '3.0']
29
+ steps:
30
+ - uses: actions/checkout@v2
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby }}
34
+ - run: bundle install
35
+ - uses: ./.github/actions/install-chrome
36
+ - uses: ./.github/actions/setup-linux
37
+ - run: |
38
+ bundle exec rake spec:unit
39
+ env:
40
+ DISPLAY: :99
41
+
42
+ linter-test:
43
+ name: Rubocop Tests
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v2
47
+ - uses: ruby/setup-ruby@v1
48
+ with:
49
+ ruby-version: 2.6
50
+ - run: bundle install
51
+ - run: bundle exec rubocop
52
+
53
+ local-tests:
54
+ name: Local Tests
55
+ runs-on: ${{ matrix.os }}
56
+ strategy:
57
+ fail-fast: false
58
+ matrix:
59
+ os: [ubuntu-latest, macos-latest, windows-latest]
60
+ ruby: [ 2.6, 3.0 ]
61
+ task: [ chrome, firefox, edge ]
62
+ include:
63
+ - os: 'macos-latest'
64
+ ruby: 2.6
65
+ task: 'safari'
66
+ - os: 'macos-latest'
67
+ ruby: 3.0
68
+ task: 'safari'
69
+ - os: 'windows-latest'
70
+ ruby: 2.6
71
+ task: 'ie'
72
+ - os: 'windows-latest'
73
+ ruby: 3.0
74
+ task: 'ie'
75
+ exclude:
76
+ - os: 'ubuntu-latest'
77
+ task: 'edge'
78
+ steps:
79
+ - uses: actions/checkout@v2
80
+ - uses: ./.github/actions/install-chrome
81
+ if: |
82
+ matrix.task == 'chrome' &&
83
+ matrix.os == 'ubuntu-latest'
84
+ - uses: ./.github/actions/setup-linux
85
+ if: matrix.os == 'ubuntu-latest'
86
+ - uses: browser-actions/setup-firefox@latest
87
+ with:
88
+ firefox-version: '86.0'
89
+ if: matrix.task == 'firefox'
90
+ - uses: ./.github/actions/enable-safari
91
+ if: matrix.task == 'safari'
92
+ - run: |
93
+ echo "COVERAGE=true" >> $GITHUB_ENV
94
+ if: |
95
+ matrix.os == 'ubuntu-latest' ||
96
+ matrix.os == 'macos-latest'
97
+ - uses: ruby/setup-ruby@v1
98
+ with:
99
+ ruby-version: ${{ matrix.ruby }}
100
+ - run: bundle install
101
+ - run: |
102
+ bundle exec rake spec:${{ matrix.task }}
103
+ env:
104
+ DISPLAY: :99
data/.rubocop.yml CHANGED
@@ -19,17 +19,12 @@ Lint/UnifiedInteger:
19
19
 
20
20
  # Default: 17
21
21
  Metrics/AbcSize:
22
- Max: 20
22
+ Max: 22
23
23
  Exclude:
24
- - 'lib/watir/capabilities.rb'
25
24
  - 'lib/watir/locators/element/selector_builder.rb'
26
- - 'lib/watir/locators/element/selector_builder/regexp_disassembler.rb'
27
- - 'lib/watir/locators/element/selector_builder/xpath.rb'
28
- - 'lib/watir/locators/element/locator.rb'
25
+ - 'lib/watir/locators/element/selector_builder/*.rb'
29
26
  - 'lib/watir/generator/base/generator.rb'
30
- - 'lib/watir/generator/base/visitor.rb'
31
27
  - 'spec/locator_spec_helper.rb'
32
- - 'spec/watirspec_helper.rb'
33
28
 
34
29
  Metrics/BlockLength:
35
30
  Exclude:
data/CHANGES.md CHANGED
@@ -1,3 +1,54 @@
1
+ ### 7.0.0.beta3 (2021-05-05)
2
+
3
+ * Fix Bug preventing proper use of vendor extension capabilities
4
+ * Changed how timeouts are supported in Watir Capabilities (#932)
5
+ * Changed the default Alert Behavior not to automatically get dismissed when an exception happens (#931)
6
+
7
+ ### 7.0.0.beta2 (2021-03-28)
8
+
9
+ * Replace Watir Logger implementation with Selenium Logger subclass
10
+ * Change Watir Guards to use Selenium's new Guards. Tests run as pending when guarded.
11
+ * Implement `#set` as standard interface for each Input Element (#405)
12
+ * Implement `Element#set` to take correct `#set` behavior based on evaluated element (#664)
13
+ * Optimize Performance for Select Lists (#846)
14
+ * Allow user to set values on Select List exclusively by `:label`, `:text`, or `:value` (#846)
15
+ * Allow user to check if option selected in Select List by `:label`, `:text`, or `:value` (#929)
16
+ * Implement `Window#restore!` to return to original Window and close all others (#923)
17
+ * Minor performance improvement for iterating over windows (#923)
18
+ * Implement `Browser#closed?`; same as `Browser#exists?` without the Windows checks (#923)
19
+ * Update methods that use Selenium's Actions class to scroll element into view before acting (#847)
20
+ * Fix bug for `:text` locator with `Regexp` value based on whitespace (#924)
21
+ * Remove executing after hooks when changing frames (#888)
22
+
23
+ ### 7.0.0.beta1 (2021-03-18)
24
+
25
+ * Requires Selenium 4
26
+ * Supports Ruby 3
27
+ * Add support for Microsoft Edge Chromium
28
+ * Remove support for all deprecated functionality
29
+
30
+ ### 6.19.1 (2021-03-17)
31
+
32
+ * Fix bug preventing using Selenium 4
33
+ * Fix bug preventing non-xml characters in attributes (#787)
34
+
35
+ ### 6.19.0 (2021-03-12)
36
+
37
+ * Create custom Watir HTTP Client
38
+ * Require minimum of Selenium 3.142.7
39
+ * Add support for starting browser with :http_client and :service hashes
40
+ * Allow inferring desired browser from Capabilities or Options if browser not specified
41
+ * Deprecate WindowCollection#to_a method
42
+ * Deprecate starting browser with both Capabilities and Options
43
+ * Deprecate starting browser with both URL and Service
44
+ * Deprecate using :desired_capabilities
45
+ * Deprecate starting browser service keywords in top level Hash
46
+ * Deprecate using :remote to start a browser; browser name must be specified
47
+ * Deprecate sending unknown keywords into the top level
48
+ * Fix bug preventing Safari Options from being recognized
49
+ * Fix bug preventing options provided without :remote keyword from being properly recognized (#812, #870)
50
+ * Fix bug preventing :headless from being recognized when :options specified (#692)
51
+
1
52
  ### 6.18.0 (2021-02-26)
2
53
 
3
54
  * Implement `WindowCollection` to manage multiple `Window` objects
data/README.md CHANGED
@@ -3,12 +3,9 @@
3
3
  Watir Powered By Selenium!
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/watir.svg)](http://badge.fury.io/rb/watir)
6
- [![Unit Tests](https://github.com/titusfortner/watir/workflows/Unit%20Tests/badge.svg)](https://github.com/watir/watir/actions?query=workflow%3A%22Unit+Tests%22)
7
- [![Mac Tests](https://github.com/titusfortner/watir/workflows/Mac%20Tests/badge.svg)](https://github.com/watir/watir/actions?query=workflow%3A%22Mac+Tests%22)
8
- [![Windows Tests](https://github.com/titusfortner/watir/workflows/Windows%20Tests/badge.svg)](https://github.com/watir/watir/actions?query=workflow%3A%22Windows+Tests%22)
9
- [![Linux Tests](https://github.com/titusfortner/watir/workflows/Linux%20Tests/badge.svg)](https://github.com/watir/watir/actions?query=workflow%3A%22Linux+Tests%22)
6
+ [![All Tests](https://github.com/watir/watir/actions/workflows/tests.yml/badge.svg)](https://github.com/watir/watir/actions/workflows/tests.yml)
10
7
  [![Code Climate](https://codeclimate.com/github/watir/watir.svg)](https://codeclimate.com/github/watir/watir)
11
- [![Coverage Status](https://coveralls.io/repos/github/watir/watir/badge.svg?branch=main)](https://coveralls.io/github/watir/watir?branch=master)
8
+ [![Coverage Status](https://coveralls.io/repos/github/watir/watir/badge.svg?branch=main)](https://coveralls.io/github/watir/watir?branch=main)
12
9
 
13
10
  ## Using Watir
14
11
 
data/Rakefile CHANGED
@@ -25,7 +25,7 @@ end
25
25
 
26
26
  {
27
27
  html: 'https://www.w3.org/TR/html52/single-page.html',
28
- svg: 'http://www.w3.org/TR/SVG2/single-page.html'
28
+ svg: 'https://www.w3.org/TR/2018/CR-SVG2-20180807/single-page.html'
29
29
  }.each do |type, spec_uri|
30
30
  namespace type do
31
31
  spec_path = "support/#{type}.html"
data/lib/watir.rb CHANGED
@@ -2,7 +2,6 @@ require 'selenium-webdriver'
2
2
  require 'time'
3
3
 
4
4
  require 'watir/scroll'
5
- require 'watir/legacy_wait'
6
5
  require 'watir/wait'
7
6
  require 'watir/exception'
8
7
  require 'watir/window'
@@ -14,59 +13,18 @@ require 'watir/alert'
14
13
  require 'watir/js_snippets'
15
14
  require 'watir/container'
16
15
  require 'watir/cookies'
16
+ require 'watir/http_client'
17
17
  require 'watir/capabilities'
18
18
  require 'watir/navigation'
19
19
  require 'watir/browser'
20
20
  require 'watir/screenshot'
21
21
  require 'watir/after_hooks'
22
22
  require 'watir/logger'
23
+ require 'watir/version'
23
24
 
24
25
  module Watir
25
- @relaxed_locate = true
26
-
27
26
  class << self
28
- attr_writer :relaxed_locate, :always_locate, :default_timeout, :prefer_css
29
-
30
- #
31
- # Whether or not Watir should wait for an element to be found or present
32
- # before taking an action.
33
- # Defaults to true.
34
- #
35
-
36
- def relaxed_locate?
37
- @relaxed_locate
38
- end
39
-
40
- #
41
- # Whether or not Watir should re-locate a stale Element on use.
42
- #
43
-
44
- def always_locate?
45
- always_locate_message
46
- true
47
- end
48
-
49
- def always_locate_message
50
- msg = 'Watir#always_locate'
51
- repl_msg = 'Element#stale? or Element#wait_until(&:stale?) if needed for flow control'
52
- Watir.logger.deprecate msg, repl_msg, ids: [:always_locate]
53
- end
54
-
55
- #
56
- # Whether or not Watir should prefer CSS when translating the Watir selector to Selenium.
57
- #
58
-
59
- def prefer_css?
60
- prefer_css_message
61
- false
62
- end
63
-
64
- def prefer_css_message
65
- msg = 'Watir#prefer_css'
66
- repl_msg = 'watir_css gem - https://github.com/watir/watir_css'
67
-
68
- Watir.logger.deprecate msg, repl_msg, ids: [:prefer_css]
69
- end
27
+ attr_writer :default_timeout
70
28
 
71
29
  #
72
30
  # Default wait time for wait methods.
data/lib/watir/alert.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Watir
2
2
  class Alert
3
- include EventuallyPresent
4
3
  include Waitable
5
4
  include Exception
6
5
 
@@ -104,13 +103,9 @@ module Watir
104
103
  end
105
104
 
106
105
  def wait_for_exists
107
- return assert_exists unless Watir.relaxed_locate?
108
-
109
- begin
110
- wait_until(message: 'waiting for alert', &:exists?)
111
- rescue Wait::TimeoutError
112
- raise UnknownObjectException, 'unable to locate alert'
113
- end
106
+ wait_until(message: 'waiting for alert', &:exists?)
107
+ rescue Wait::TimeoutError
108
+ raise UnknownObjectException, 'unable to locate alert'
114
109
  end
115
110
  end # Alert
116
111
  end # Watir
data/lib/watir/browser.rb CHANGED
@@ -55,16 +55,21 @@ module Watir
55
55
  @default_context = true
56
56
  end
57
57
 
58
+ # rubocop:disable Metrics/AbcSize
59
+ # TODO: w3c default behavior does not like checking if alert exists
58
60
  def inspect
59
61
  if alert.exists?
60
62
  format('#<%s:0x%x alert=true>', self.class, hash * 2)
61
63
  else
62
64
  format('#<%s:0x%x url=%s title=%s>', self.class, hash * 2, url.inspect, title.inspect)
63
65
  end
66
+ rescue Selenium::WebDriver::Error::NoSuchWindowError
67
+ format('#<%s:0x%x closed=%s>', self.class, hash * 2, closed?)
64
68
  rescue Errno::ECONNREFUSED
65
69
  format('#<%s:0x%x closed=true>', self.class, hash * 2)
66
70
  end
67
71
  alias selector_string inspect
72
+ # rubocop:enable Metrics/AbcSize
68
73
 
69
74
  #
70
75
  # Returns URL of current page.
@@ -101,13 +106,23 @@ module Watir
101
106
  #
102
107
 
103
108
  def close
104
- return if @closed
109
+ return if closed?
105
110
 
106
111
  @driver.quit
107
112
  @closed = true
108
113
  end
109
114
  alias quit close
110
115
 
116
+ #
117
+ # Returns true if browser is closed and false otherwise.
118
+ #
119
+ # @return [Boolean]
120
+ #
121
+
122
+ def closed?
123
+ @closed
124
+ end
125
+
111
126
  #
112
127
  # Handles cookies.
113
128
  #
@@ -252,12 +267,12 @@ module Watir
252
267
  #
253
268
 
254
269
  def exist?
255
- !@closed && window.present?
270
+ !closed? && window.present?
256
271
  end
257
272
  alias exists? exist?
258
273
 
259
274
  def locate
260
- raise Error, 'browser was closed' if @closed
275
+ raise Error, 'browser was closed' if closed?
261
276
 
262
277
  ensure_context
263
278
  end
@@ -267,7 +282,6 @@ module Watir
267
282
 
268
283
  driver.switch_to.default_content
269
284
  @default_context = true
270
- after_hooks.run
271
285
  end
272
286
 
273
287
  def browser
@@ -2,19 +2,23 @@ module Watir
2
2
  class Capabilities
3
3
  attr_reader :options
4
4
 
5
- def initialize(browser, options = {})
5
+ def initialize(browser = nil, options = {})
6
+ if browser.is_a?(Hash)
7
+ options = browser
8
+ browser = nil
9
+ end
10
+
6
11
  @options = options.dup
7
12
  Watir.logger.info "Creating Browser instance of #{browser} with user provided options: #{@options.inspect}"
8
- @browser = if browser == :remote && @options.key?(:browser)
9
- @options.delete(:browser)
10
- elsif browser == :remote && @options.key?(:desired_capabilities)
11
- @options[:desired_capabilities].browser_name.to_sym
12
- else
13
- browser.to_sym
14
- end
15
- @selenium_browser = browser == :remote || options[:url] ? :remote : browser
16
-
17
- @selenium_opts = {}
13
+
14
+ if @options.key?(:capabilities) && @options.key?(:options)
15
+ raise(ArgumentError, ':capabilities and :options are not both allowed')
16
+ end
17
+ raise(ArgumentError, ':url and :service are not both allowed') if @options.key?(:service) && @options.key?(:url)
18
+
19
+ @browser = browser.nil? && infer_browser || browser
20
+
21
+ @selenium_browser = @options.key?(:url) ? :remote : @browser
18
22
  end
19
23
 
20
24
  def to_args
@@ -24,129 +28,125 @@ module Watir
24
28
  private
25
29
 
26
30
  def process_arguments
27
- url = @options.delete(:url)
28
- if url
29
- @selenium_opts[:url] = url
30
- elsif @options.key?(:service)
31
- @selenium_opts[:service] = options.delete(:service)
31
+ selenium_opts = {}
32
+ selenium_opts[:listener] = @options.delete(:listener) if @options.key?(:listener)
33
+
34
+ if @options.key?(:url)
35
+ selenium_opts[:url] = @options.delete(:url)
36
+ else
37
+ service = process_service
38
+ selenium_opts[:service] = service if service
32
39
  end
33
40
 
34
- create_http_client
41
+ selenium_opts[:http_client] = process_http_client
42
+ selenium_opts[:capabilities] = @options.delete(:capabilities) || process_browser_options
43
+
44
+ Watir.logger.info "Creating Browser instance with Watir processed options: #{selenium_opts.inspect}"
45
+ selenium_opts
46
+ end
47
+
48
+ def process_http_client
49
+ http_client = @options.delete(:http_client) || Watir::HttpClient.new
50
+
51
+ case http_client
52
+ when Hash
53
+ Watir::HttpClient.new(**http_client)
54
+ when Watir::HttpClient
55
+ http_client
56
+ when Selenium::WebDriver::Remote::Http::Common
57
+ Watir.logger.warn 'Check out the new Watir::HttpClient and let us know if there are missing features you need',
58
+ id: [:watir_client]
59
+ http_client
60
+ else
61
+ raise TypeError, ':http_client must be a Hash or a Selenium HTTP Client instance'
62
+ end
63
+ end
64
+
65
+ def process_browser_options
66
+ browser_options = @options.delete(:options).dup || {}
67
+ vendor_caps = process_vendor_capabilities(browser_options)
35
68
 
36
- @selenium_opts[:port] = @options.delete(:port) if @options.key?(:port)
37
- @selenium_opts[:driver_opts] = @options.delete(:driver_opts) if @options.key?(:driver_opts)
38
- @selenium_opts[:listener] = @options.delete(:listener) if @options.key?(:listener)
69
+ options = if browser_options.is_a? Selenium::WebDriver::Options
70
+ browser_options
71
+ else
72
+ convert_timeouts(browser_options)
73
+ Selenium::WebDriver::Options.send(@browser, **browser_options)
74
+ end
39
75
 
40
- process_browser_options
41
- process_capabilities
42
- Watir.logger.info "Creating Browser instance with Watir processed options: #{@selenium_opts.inspect}"
76
+ options.unhandled_prompt_behavior ||= :ignore
77
+ browser_specific_options(options)
78
+ raise ArgumentError, "#{@options} are unrecognized arguments for Browser constructor" unless @options.empty?
43
79
 
44
- @selenium_opts
80
+ vendor_caps << options
45
81
  end
46
82
 
47
- def create_http_client
48
- client_timeout = @options.delete(:client_timeout)
49
- open_timeout = @options.delete(:open_timeout)
50
- read_timeout = @options.delete(:read_timeout)
83
+ def process_vendor_capabilities(opts)
84
+ return [] unless opts.is_a? Hash
51
85
 
52
- http_client = @options.delete(:http_client)
86
+ vendor = opts.select { |key, _val| key.to_s.include?(':') && opts.delete(key) }
87
+ vendor.map { |k, v| Selenium::WebDriver::Remote::Capabilities.new(k => v) }
88
+ end
53
89
 
54
- %i[open_timeout read_timeout client_timeout].each do |t|
55
- next if http_client.nil? || !respond_to?(t)
90
+ def convert_timeouts(browser_options)
91
+ browser_options[:timeouts] ||= {}
92
+ browser_options[:timeouts].keys.each do |key|
93
+ raise(ArgumentError, 'do not set implicit wait, Watir handles waiting automatically') if key.to_s == 'implicit'
56
94
 
57
- msg = "You can pass #{t} value directly into Watir::Browser opt without needing to use :http_client"
58
- Watir.logger.warn msg, ids: %i[http_client use_capabilities]
95
+ Watir.logger.deprecate('using timeouts directly in options',
96
+ ":#{key}_timeout",
97
+ id: 'timeouts')
98
+ end
99
+ if browser_options.key?(:page_load_timeout)
100
+ browser_options[:timeouts][:page_load] = browser_options.delete(:page_load_timeout) * 1000
59
101
  end
60
102
 
61
- http_client ||= Selenium::WebDriver::Remote::Http::Default.new
103
+ return unless browser_options.key?(:script_timeout)
62
104
 
63
- http_client.timeout = client_timeout if client_timeout
64
- http_client.open_timeout = open_timeout if open_timeout
65
- http_client.read_timeout = read_timeout if read_timeout
66
- @selenium_opts[:http_client] = http_client
105
+ browser_options[:timeouts][:script] = browser_options.delete(:script_timeout) * 1000
67
106
  end
68
107
 
69
- # TODO: - this will get addressed with Capabilities Update
70
- # rubocop:disable Metrics/MethodLength
71
- # rubocop:disable Metrics/PerceivedComplexity:
72
- # rubocop:disable Metrics/CyclomaticComplexity::
73
- def process_browser_options
74
- browser_options = @options.delete(:options) || {}
75
-
76
- case @selenium_browser
77
- when :chrome
78
- if @options.key?(:args) || @options.key?(:switches)
79
- browser_options ||= {}
80
- browser_options[:args] = (@options.delete(:args) || @options.delete(:switches)).dup
81
- end
108
+ def browser_specific_options(options)
109
+ case @browser
110
+ when :chrome, :edge, :microsoftedge
82
111
  if @options.delete(:headless)
83
- browser_options ||= {}
84
- browser_options[:args] ||= []
85
- browser_options[:args] += ['--headless', '--disable-gpu']
112
+ options.args << '--headless'
113
+ options.args << '--disable-gpu'
114
+ options.args << '--no-sandbox'
86
115
  end
87
- @selenium_opts[:options] = browser_options if browser_options.is_a? Selenium::WebDriver::Chrome::Options
88
- @selenium_opts[:options] ||= Selenium::WebDriver::Chrome::Options.new(**browser_options)
89
116
  when :firefox
90
- profile = @options.delete(:profile)
91
- if browser_options.is_a? Selenium::WebDriver::Firefox::Options
92
- @selenium_opts[:options] = browser_options
93
- if profile
94
- msg = 'Initializing Browser with both :profile and :option', ':profile as a key inside :option'
95
- Watir.logger.deprecate msg, ids: [:firefox_profile]
96
- end
97
- end
98
- if @options.delete(:headless)
99
- browser_options ||= {}
100
- browser_options[:args] ||= []
101
- browser_options[:args] += ['--headless']
102
- end
103
- @selenium_opts[:options] ||= Selenium::WebDriver::Firefox::Options.new(**browser_options)
104
- @selenium_opts[:options].profile = profile if profile
117
+ options.headless! if @options.delete(:headless)
105
118
  when :safari
106
119
  Selenium::WebDriver::Safari.technology_preview! if @options.delete(:technology_preview)
107
- when :remote
108
- if @browser == :chrome && @options.delete(:headless)
109
- args = @options.delete(:args) || @options.delete(:switches) || []
110
- @options['chromeOptions'] = {'args' => args + ['--headless', '--disable-gpu']}
111
- end
112
- if @browser == :firefox && @options.delete(:headless)
113
- args = @options.delete(:args) || @options.delete(:switches) || []
114
- @options[Selenium::WebDriver::Firefox::Options::KEY] = {'args' => args + ['--headless']}
115
- end
116
- if @browser == :safari && @options.delete(:technology_preview)
117
- @options['safari.options'] = {'technologyPreview' => true}
118
- end
119
- when :ie
120
- if @options.key?(:args)
121
- browser_options ||= {}
122
- browser_options[:args] = @options.delete(:args).dup
123
- end
124
- unless browser_options.is_a? Selenium::WebDriver::IE::Options
125
- ie_caps = browser_options.select { |k| Selenium::WebDriver::IE::Options::CAPABILITIES.include?(k) }
126
- browser_options = Selenium::WebDriver::IE::Options.new(**browser_options)
127
- ie_caps.each { |k, v| browser_options.add_option(k, v) }
128
- end
129
- @selenium_opts[:options] = browser_options
130
120
  end
131
121
  end
132
122
 
133
- # rubocop:enable Metrics/MethodLength
134
- # rubocop:enable Metrics/PerceivedComplexity:
135
- # rubocop:enable Metrics/CyclomaticComplexity::
123
+ def process_service
124
+ service = @options.delete(:service)
136
125
 
137
- def process_capabilities
138
- caps = @options.delete(:desired_capabilities)
126
+ case service
127
+ when nil
128
+ nil
129
+ when Hash
130
+ return if service.empty?
139
131
 
140
- if caps
141
- msg = 'You can pass values directly into Watir::Browser opt without needing to use :desired_capabilities'
142
- Watir.logger.warn msg,
143
- ids: [:use_capabilities]
144
- @selenium_opts.merge!(@options)
132
+ Selenium::WebDriver::Service.send(@browser, **service)
133
+ when Selenium::WebDriver::Service
134
+ service
145
135
  else
146
- caps = Selenium::WebDriver::Remote::Capabilities.send @browser, @options
136
+ raise TypeError, "#{service} needs to be Selenium Service or Hash instance"
147
137
  end
138
+ end
148
139
 
149
- @selenium_opts[:desired_capabilities] = caps
140
+ def infer_browser
141
+ if @options.key?(:browser)
142
+ @options.delete(:browser)
143
+ elsif @options.key?(:capabilities)
144
+ @options[:capabilities].browser_name.tr(' ', '_').downcase.to_sym
145
+ elsif @options.key?(:options)
146
+ @options[:options].class.to_s.split('::')[-2].downcase.to_sym
147
+ else
148
+ :chrome
149
+ end
150
150
  end
151
151
  end
152
152
  end