watir 6.16.5 → 6.19.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/.github/actions/enable-safari/action.yml +11 -0
  3. data/.github/actions/install-chrome/action.yml +11 -0
  4. data/.github/workflows/linux.yml +61 -0
  5. data/.github/workflows/mac.yml +55 -0
  6. data/.github/workflows/unit.yml +37 -0
  7. data/.github/workflows/windows.yml +39 -0
  8. data/.rubocop.yml +32 -107
  9. data/.rubocop_todo.yml +36 -0
  10. data/CHANGES.md +52 -0
  11. data/Gemfile +3 -1
  12. data/LICENSE +2 -2
  13. data/README.md +9 -10
  14. data/Rakefile +4 -4
  15. data/lib/watir/adjacent.rb +8 -10
  16. data/lib/watir/after_hooks.rb +4 -4
  17. data/lib/watir/alert.rb +1 -0
  18. data/lib/watir/attribute_helper.rb +2 -0
  19. data/lib/watir/browser.rb +7 -3
  20. data/lib/watir/capabilities.rb +245 -97
  21. data/lib/watir/cookies.rb +3 -1
  22. data/lib/watir/element_collection.rb +21 -6
  23. data/lib/watir/elements/element.rb +66 -53
  24. data/lib/watir/elements/file_field.rb +1 -0
  25. data/lib/watir/elements/html_elements.rb +0 -1
  26. data/lib/watir/elements/iframe.rb +4 -3
  27. data/lib/watir/elements/link.rb +0 -9
  28. data/lib/watir/elements/radio.rb +1 -1
  29. data/lib/watir/elements/select.rb +22 -7
  30. data/lib/watir/generator/base/spec_extractor.rb +4 -4
  31. data/lib/watir/generator/html/generator.rb +1 -1
  32. data/lib/watir/has_window.rb +17 -15
  33. data/lib/watir/http_client.rb +17 -0
  34. data/lib/watir/js_execution.rb +3 -3
  35. data/lib/watir/js_snippets.rb +2 -2
  36. data/lib/watir/legacy_wait.rb +1 -1
  37. data/lib/watir/locators/element/selector_builder/xpath.rb +50 -15
  38. data/lib/watir/locators/element/selector_builder.rb +12 -13
  39. data/lib/watir/locators/text_field/selector_builder/xpath.rb +3 -1
  40. data/lib/watir/locators.rb +1 -3
  41. data/lib/watir/logger.rb +7 -20
  42. data/lib/watir/radio_set.rb +2 -2
  43. data/lib/watir/user_editable.rb +6 -2
  44. data/lib/watir/version.rb +1 -1
  45. data/lib/watir/wait/timer.rb +1 -1
  46. data/lib/watir/wait.rb +2 -0
  47. data/lib/watir/window.rb +8 -4
  48. data/lib/watir/window_collection.rb +114 -0
  49. data/lib/watir-webdriver.rb +1 -1
  50. data/lib/watir.rb +3 -1
  51. data/lib/watirspec/guards.rb +1 -1
  52. data/lib/watirspec/implementation.rb +3 -5
  53. data/lib/watirspec/rake_tasks.rb +2 -0
  54. data/lib/watirspec/runner.rb +6 -2
  55. data/lib/watirspec/server.rb +1 -1
  56. data/lib/watirspec.rb +2 -1
  57. data/spec/spec_helper.rb +2 -7
  58. data/spec/unit/capabilities_spec.rb +1234 -18
  59. data/spec/unit/container_spec.rb +1 -1
  60. data/spec/unit/logger_spec.rb +5 -7
  61. data/spec/unit/match_elements/element_spec.rb +17 -15
  62. data/spec/unit/selector_builder/button_spec.rb +16 -15
  63. data/spec/unit/selector_builder/element_spec.rb +58 -9
  64. data/spec/unit/selector_builder/text_field_spec.rb +14 -14
  65. data/spec/unit/unit_helper.rb +2 -4
  66. data/spec/watirspec/after_hooks_spec.rb +58 -68
  67. data/spec/watirspec/alert_spec.rb +69 -79
  68. data/spec/watirspec/browser_spec.rb +51 -48
  69. data/spec/watirspec/cookies_spec.rb +52 -37
  70. data/spec/watirspec/drag_and_drop_spec.rb +14 -38
  71. data/spec/watirspec/elements/button_spec.rb +2 -0
  72. data/spec/watirspec/elements/buttons_spec.rb +1 -1
  73. data/spec/watirspec/elements/checkbox_spec.rb +8 -4
  74. data/spec/watirspec/elements/date_field_spec.rb +18 -9
  75. data/spec/watirspec/elements/date_time_field_spec.rb +3 -4
  76. data/spec/watirspec/elements/div_spec.rb +62 -54
  77. data/spec/watirspec/elements/element_spec.rb +73 -88
  78. data/spec/watirspec/elements/elements_spec.rb +12 -3
  79. data/spec/watirspec/elements/filefield_spec.rb +25 -50
  80. data/spec/watirspec/elements/form_spec.rb +6 -8
  81. data/spec/watirspec/elements/frame_spec.rb +10 -13
  82. data/spec/watirspec/elements/iframe_spec.rb +12 -9
  83. data/spec/watirspec/elements/iframes_spec.rb +2 -2
  84. data/spec/watirspec/elements/link_spec.rb +23 -12
  85. data/spec/watirspec/elements/links_spec.rb +11 -3
  86. data/spec/watirspec/elements/option_spec.rb +15 -17
  87. data/spec/watirspec/elements/select_list_spec.rb +222 -117
  88. data/spec/watirspec/elements/text_field_spec.rb +8 -4
  89. data/spec/watirspec/elements/tr_spec.rb +0 -9
  90. data/spec/watirspec/html/forms_with_input_elements.html +1 -0
  91. data/spec/watirspec/html/iframes.html +3 -0
  92. data/spec/watirspec/html/non_control_elements.html +4 -4
  93. data/spec/watirspec/html/right_click.html +12 -0
  94. data/spec/watirspec/html/special_chars.html +3 -0
  95. data/spec/watirspec/html/wait.html +6 -6
  96. data/spec/watirspec/html/window_switching.html +10 -0
  97. data/spec/watirspec/legacy_wait_spec.rb +216 -0
  98. data/spec/watirspec/special_chars_spec.rb +10 -0
  99. data/spec/watirspec/support/rspec_matchers.rb +33 -14
  100. data/spec/watirspec/user_editable_spec.rb +1 -1
  101. data/spec/watirspec/wait_spec.rb +257 -305
  102. data/spec/watirspec/window_switching_spec.rb +347 -211
  103. data/spec/watirspec_helper.rb +17 -20
  104. data/support/doctest_helper.rb +0 -2
  105. data/watir.gemspec +6 -7
  106. metadata +37 -26
  107. data/.travis.yml +0 -84
  108. data/appveyor.yml +0 -12
  109. data/lib/watir/elements/area.rb +0 -10
  110. data/spec/watirspec/relaxed_locate_spec.rb +0 -113
@@ -58,14 +58,14 @@
58
58
  <body>
59
59
  <div id="foo" custom="" style="display:block;">foo</div>
60
60
  <div id="bar" style="display:none;" onclick='this.innerHTML = "changed"'>bar</div>
61
- <a id="show_bar" href="#" onclick="setTimeoutDisplay('bar', 'block', 500);">show bar</a>
62
- <a id="hide_foo" href="#" onclick="setTimeoutDisplay('foo', 'none', 500);">hide foo</a>
61
+ <a id="show_bar" href="#" onclick="setTimeoutDisplay('bar', 'block', 1000);">show bar</a>
62
+ <a id="hide_foo" href="#" onclick="setTimeoutDisplay('foo', 'none', 1000);">hide foo</a>
63
63
  <a id="remove_foo" href="#" onclick="setTimeoutRemove('foo', 1000);">remove foo</a>
64
64
  <a id="add_foobar" href="#" onclick="setTimeoutAddDisplay('foobar', 'bar', 1000);">add foobar</a>
65
65
  <a id="readd_bar" href="#" onclick="setTimeoutRemove('bar', 500); setTimeoutAddDisplay('bar', 'foo', 1000);">re-add bar</a>
66
66
  <div id="buttons">
67
- <button id="btn" type="button" onclick="setDisabled('btn', true, 0)" disabled>Click To Disable!</button>
68
- <a id="enable_btn" href="#" onclick="setDisabled('btn', false, 500);">enable btn</a>
67
+ <button id="btn" type="button" onclick="setDisabled('btn', true, 0);" disabled>Click To Disable!</button>
68
+ <a id="enable_btn" href="#" onclick="setDisabled('btn', false, 1000);">enable btn</a>
69
69
  <button id="btn2" style="display:none;" type="button" disabled>Hidden and Disabled</button>
70
70
  <a id="show_and_enable_btn" href="#" onclick="setTimeoutDisplay('btn2', 'block', 500); setDisabled('btn2', false, 1000);">
71
71
  show and enable btn
@@ -78,10 +78,10 @@
78
78
  <form>
79
79
  <label for="textfield">Not Displayed Yet</label>
80
80
  <input type="textfield" title="Text Displayed" name="textfield" id="textfield" style="display:none;" /> <br />
81
- <a id="show_textfield" href="#" onclick="setTimeoutDisplay('textfield', 'block', 2000);">show textfield</a>
81
+ <a id="show_textfield" href="#" onclick="setTimeoutDisplay('textfield', 'block', 1000);">show textfield</a>
82
82
  <label for="writable">Not Writable</label>
83
83
  <input type="text" title="Not Writable" name="writable" id="writable" readonly/> <br />
84
- <a id="make-writable" onclick="makeWritable('writable', 2000);">Make Writable</a>
84
+ <a id="make-writable" onclick="makeWritable('writable', 1000);">Make Writable</a>
85
85
  <fieldset>
86
86
  <select name="languages" id="languages", style="display: none">
87
87
  <option id="danish" value="1">Danish</option>
@@ -2,11 +2,21 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>window switching</title>
5
+ <script>
6
+ function windowOpenDelayed(timeout) {
7
+ setTimeout(function() {
8
+ window.open("closeable.html");
9
+ }, timeout);
10
+ }
11
+ </script>
5
12
  </head>
6
13
 
7
14
  <body>
8
15
  <p>
9
16
  Click <a id="open" href="#" onclick='window.open("closeable.html")'>here</a> to open a new window.
10
17
  </p>
18
+ <p>
19
+ Click <a id="delayed" href="#" onclick=windowOpenDelayed(1000)>here</a> to open a new window after a delay.
20
+ </p>
11
21
  </body>
12
22
  </html>
@@ -0,0 +1,216 @@
1
+ require 'watirspec_helper'
2
+
3
+ describe Watir::Element do
4
+ before do
5
+ browser.goto WatirSpec.url_for('wait.html')
6
+ end
7
+
8
+ compliant_on :relaxed_locate do
9
+ describe '#wait_until_present' do
10
+ it 'waits until the element appears' do
11
+ browser.a(id: 'show_bar').click
12
+ expect {
13
+ expect { browser.div(id: 'bar').wait_until_present(timeout: 5) }.to_not raise_exception
14
+ }.to have_deprecated_wait_until_present
15
+ end
16
+
17
+ bug 'Safari does not recognize date type', :safari do
18
+ it 'waits until the element re-appears' do
19
+ browser.link(id: 'readd_bar').click
20
+ expect {
21
+ expect { browser.div(id: 'bar').wait_until_present }.to_not raise_exception
22
+ }.to have_deprecated_wait_until_present
23
+ end
24
+ end
25
+
26
+ it "times out if the element doesn't appear" do
27
+ inspected = '#<Watir::Div: located: true; {:id=>"bar", :tag_name=>"div"}>'
28
+ error = Watir::Wait::TimeoutError
29
+ message = "timed out after 1 seconds, waiting for #{inspected} to become present"
30
+
31
+ expect {
32
+ expect { browser.div(id: 'bar').wait_until_present(timeout: 1) }.to raise_error(error, message)
33
+ }.to have_deprecated_wait_until_present
34
+ end
35
+
36
+ it 'uses provided interval' do
37
+ element = browser.div(id: 'bar')
38
+ expect(element).to receive(:present?).twice
39
+
40
+ expect {
41
+ expect { element.wait_until_present(timeout: 0.4, interval: 0.2) }.to raise_timeout_exception
42
+ }.to have_deprecated_wait_until_present
43
+ end
44
+ end
45
+
46
+ describe '#wait_while_present' do
47
+ it 'waits until the element disappears' do
48
+ browser.a(id: 'hide_foo').click
49
+ expect {
50
+ expect { browser.div(id: 'foo').wait_while_present(timeout: 2) }.to_not raise_exception
51
+ }.to have_deprecated_wait_while_present
52
+ end
53
+
54
+ it "times out if the element doesn't disappear" do
55
+ error = Watir::Wait::TimeoutError
56
+ inspected = '#<Watir::Div: located: true; {:id=>"foo", :tag_name=>"div"}>'
57
+ message = "timed out after 1 seconds, waiting for #{inspected} not to be present"
58
+ expect {
59
+ expect { browser.div(id: 'foo').wait_while_present(timeout: 1) }.to raise_error(error, message)
60
+ }.to have_deprecated_wait_while_present
61
+ end
62
+
63
+ it 'uses provided interval' do
64
+ error = Watir::Wait::TimeoutError
65
+ element = browser.div(id: 'foo')
66
+ expect(element).to receive(:present?).and_return(true).twice
67
+
68
+ expect {
69
+ expect { element.wait_while_present(timeout: 0.4, interval: 0.2) }.to raise_error(error)
70
+ }.to have_deprecated_wait_while_present
71
+ end
72
+
73
+ it 'does not error when element goes stale' do
74
+ element = browser.div(id: 'foo').locate
75
+
76
+ allow(element).to receive(:stale?).and_return(false, true)
77
+
78
+ browser.a(id: 'hide_foo').click
79
+ expect {
80
+ expect { element.wait_while_present(timeout: 2) }.to_not raise_exception
81
+ }.to have_deprecated_wait_while_present
82
+ end
83
+
84
+ it 'waits until the selector no longer matches' do
85
+ element = browser.link(name: 'add_select').wait_until(&:exists?)
86
+ browser.link(id: 'change_select').click
87
+ expect {
88
+ expect { element.wait_while_present }.not_to raise_error
89
+ }.to have_deprecated_wait_while_present
90
+ end
91
+ end
92
+ end
93
+
94
+ not_compliant_on :relaxed_locate do
95
+ describe '#when_present' do
96
+ it 'invokes subsequent method calls when the element becomes present' do
97
+ browser.a(id: 'show_bar').click
98
+
99
+ bar = browser.div(id: 'bar')
100
+ bar.when_present(2).click
101
+ expect(bar.text).to eq 'changed'
102
+ end
103
+
104
+ it 'times out when given a block' do
105
+ expect { browser.div(id: 'bar').when_present(1) {} }.to raise_error(Watir::Wait::TimeoutError)
106
+ end
107
+
108
+ it 'times out when not given a block' do
109
+ locator = '(\{:id=>"bar", :tag_name=>"div"\}|\{:tag_name=>"div", :id=>"bar"\})'
110
+ msg = /^timed out after 1 seconds, waiting for #{locator} to become present$/
111
+ expect { browser.div(id: 'bar').when_present(1).click }.to raise_error(Watir::Wait::TimeoutError, msg)
112
+ end
113
+
114
+ it 'responds to Element methods' do
115
+ decorator = browser.div.when_present
116
+
117
+ expect(decorator).to respond_to(:exist?)
118
+ expect(decorator).to respond_to(:present?)
119
+ expect(decorator).to respond_to(:click)
120
+ end
121
+
122
+ it 'delegates present? to element' do
123
+ Object.class_eval do
124
+ def present?
125
+ false
126
+ end
127
+ end
128
+ element = browser.a(id: 'show_bar').when_present(1)
129
+ expect(element).to be_present
130
+ end
131
+
132
+ it 'processes before calling present?' do
133
+ browser.a(id: 'show_bar').click
134
+ expect(browser.div(id: 'bar').when_present.present?).to be true
135
+ end
136
+ end
137
+
138
+ describe '#wait_until &:enabled?' do
139
+ it 'invokes subsequent method calls when the element becomes enabled' do
140
+ browser.a(id: 'enable_btn').click
141
+
142
+ btn = browser.button(id: 'btn')
143
+ btn.wait_until(timeout: 2, &:enabled?).click
144
+ Watir::Wait.while { btn.enabled? }
145
+ expect(btn.disabled?).to be true
146
+ end
147
+
148
+ it 'times out' do
149
+ error = Watir::Wait::TimeoutError
150
+ inspected = '#<Watir::Button: located: true; {:id=>"btn", :tag_name=>"button"}>'
151
+ message = "timed out after 1 seconds, waiting for true condition on #{inspected}"
152
+ element = browser.button(id: 'btn')
153
+ expect { element.wait_until(timeout: 1, &:enabled?).click }.to raise_error(error, message)
154
+ end
155
+
156
+ it 'responds to Element methods' do
157
+ element = browser.button.wait_until { true }
158
+
159
+ expect(element).to respond_to(:exist?)
160
+ expect(element).to respond_to(:present?)
161
+ expect(element).to respond_to(:click)
162
+ end
163
+
164
+ it 'can be chained with #wait_until &:present?' do
165
+ browser.a(id: 'show_and_enable_btn').click
166
+ browser.button(id: 'btn2').wait_until(&:present?).wait_until(&:enabled?).click
167
+
168
+ expect(browser.button(id: 'btn2')).to exist
169
+ expect(browser.button(id: 'btn2')).to be_enabled
170
+ end
171
+ end
172
+
173
+ context 'when acting on an element that is never present' do
174
+ it 'raises exception immediately' do
175
+ element = browser.link(id: 'not_there')
176
+ start_time = ::Time.now
177
+ expect { element.click }.to raise_exception(Watir::Exception::UnknownObjectException)
178
+ expect(::Time.now - start_time).to be < 1
179
+ end
180
+ end
181
+
182
+ context 'when acting on an element that eventually becomes present' do
183
+ it 'raises exception immediately' do
184
+ start_time = ::Time.now
185
+ browser.a(id: 'show_bar').click
186
+
187
+ expect { browser.div(id: 'bar').click }.to raise_unknown_object_exception
188
+
189
+ expect(::Time.now - start_time).to be < 1
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ describe Watir::Window do
196
+ not_compliant_on :relaxed_locate do
197
+ describe '#wait_until &:present?' do
198
+ before do
199
+ browser.goto WatirSpec.url_for('window_switching.html')
200
+ browser.a(id: 'open').click
201
+ Watir::Wait.until { browser.windows.size == 2 }
202
+ end
203
+
204
+ after do
205
+ browser.original_window.use
206
+ browser.windows.reject(&:current?).each(&:close)
207
+ end
208
+
209
+ it 'times out waiting for a non-present window' do
210
+ expect {
211
+ browser.window(title: 'noop').wait_until(timeout: 0.5, &:present?)
212
+ }.to raise_error(Watir::Wait::TimeoutError)
213
+ end
214
+ end
215
+ end
216
+ end
@@ -8,4 +8,14 @@ describe Watir::Browser do
8
8
  it 'finds elements with single quotes' do
9
9
  expect(browser.div(text: "single 'quotes'")).to exist
10
10
  end
11
+
12
+ it 'finds elements with non-standard character locators' do
13
+ expect(browser.div('we{ird' => 'foo')).to exist
14
+ expect(browser.div('we{ird': 'foo')).to exist
15
+ end
16
+
17
+ it 'finds element with underscored attribute' do
18
+ expect(browser.div('underscored_attribute' => 'true')).to exist
19
+ expect(browser.div('underscored_attribute' => true)).to exist
20
+ end
11
21
  end
@@ -1,5 +1,18 @@
1
1
  if defined?(RSpec)
2
2
  DEPRECATION_WARNINGS = %i[selector_parameters
3
+ options_capabilities
4
+ firefox_profile
5
+ remote_keyword
6
+ desired_capabilities
7
+ port_keyword
8
+ switches_keyword
9
+ args_keyword
10
+ url_service
11
+ driver_opts_keyword
12
+ http_open_timeout
13
+ http_read_timeout
14
+ http_client_timeout
15
+ unknown_keyword
3
16
  element_cache
4
17
  ready_state
5
18
  caption
@@ -8,18 +21,23 @@ if defined?(RSpec)
8
21
  visible_text
9
22
  link_text
10
23
  text_regexp
24
+ scroll_into_view
11
25
  stale_exists
12
26
  stale_visible
13
27
  stale_present
28
+ select_all
14
29
  select_by
15
30
  value_button
16
31
  wait_until_present
17
- wait_while_present].freeze
32
+ wait_while_present
33
+ window_index].freeze
18
34
 
19
35
  DEPRECATION_WARNINGS.each do |deprecation|
20
36
  RSpec::Matchers.define "have_deprecated_#{deprecation}" do
21
37
  match do |actual|
22
- warning = /\[DEPRECATION\] \["#{deprecation}"\]/
38
+ return actual.call if ENV['IGNORE_DEPRECATIONS']
39
+
40
+ warning = /\[DEPRECATION\] \["#{deprecation}"/
23
41
  expect {
24
42
  actual.call
25
43
  @stdout_message = File.read $stdout if $stdout.is_a?(File)
@@ -62,10 +80,10 @@ if defined?(RSpec)
62
80
  begin
63
81
  actual.call
64
82
  false
65
- rescue exception => ex
66
- return true if message.nil? || ex.message.match(message)
83
+ rescue exception => e
84
+ return true if message.nil? || e.message.match(message)
67
85
 
68
- raise exception, "expected '#{message}' to be included in: '#{ex.message}'"
86
+ raise exception, "expected '#{message}' to be included in: '#{e.message}'"
69
87
  ensure
70
88
  Watir.default_timeout = original_timeout
71
89
  end
@@ -88,10 +106,10 @@ if defined?(RSpec)
88
106
  start_time = ::Time.now
89
107
  actual.call
90
108
  false
91
- rescue exception => ex
109
+ rescue exception => e
92
110
  finish_time = ::Time.now
93
- unless message.nil? || ex.message.match(message)
94
- raise exception, "expected '#{message}' to be included in: '#{ex.message}'"
111
+ unless message.nil? || e.message.match(message)
112
+ raise exception, "expected '#{message}' to be included in: '#{e.message}'"
95
113
  end
96
114
 
97
115
  @time_difference = finish_time - start_time
@@ -116,27 +134,28 @@ if defined?(RSpec)
116
134
  end
117
135
  end
118
136
 
119
- RSpec::Matchers.define :execute_immediately do |timeout: 10|
137
+ RSpec::Matchers.define :execute_when_satisfied do |min: 0, max: nil|
138
+ max ||= min + 1
120
139
  match do |actual|
121
140
  original_timeout = Watir.default_timeout
122
- Watir.default_timeout = timeout
141
+ Watir.default_timeout = max
123
142
  begin
124
143
  start_time = ::Time.now
125
144
  actual.call
126
145
  @time_difference = ::Time.now - start_time
127
- @time_difference < timeout
146
+ @time_difference > min && @time_difference < max
128
147
  ensure
129
148
  Watir.default_timeout = original_timeout
130
149
  end
131
150
  end
132
151
 
133
152
  failure_message_when_negated do
134
- "expected action to take more than provided timeout (#{timeout} seconds), " \
153
+ "expected action to take less than #{min} seconds or more than #{max} seconds, " \
135
154
  "instead it took #{@time_difference} seconds"
136
155
  end
137
156
 
138
157
  failure_message do
139
- "expected action to take less than provided timeout (#{timeout} seconds), " \
158
+ "expected action to take more than #{min} seconds and less than #{max} seconds, " \
140
159
  "instead it took #{@time_difference} seconds"
141
160
  end
142
161
 
@@ -147,7 +166,7 @@ if defined?(RSpec)
147
166
 
148
167
  RSpec::Matchers.define :exist do |*args|
149
168
  match do |actual|
150
- actual.exists?(*args)
169
+ actual.exist?(*args)
151
170
  end
152
171
 
153
172
  failure_message do |obj|
@@ -5,7 +5,7 @@ describe Watir::UserEditable do
5
5
  browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
6
6
  end
7
7
 
8
- not_compliant_on :safari do
8
+ bug 'incorrectly clears first', :safari do
9
9
  describe '#append' do
10
10
  it 'appends the text to the text field' do
11
11
  browser.text_field(name: 'new_user_occupation').append(' Append This')