cuprite 0.8 → 0.13
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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +108 -104
- data/lib/capybara/cuprite.rb +0 -6
- data/lib/capybara/cuprite/browser.rb +15 -5
- data/lib/capybara/cuprite/driver.rb +43 -9
- data/lib/capybara/cuprite/javascripts/index.js +3 -3
- data/lib/capybara/cuprite/node.rb +13 -8
- data/lib/capybara/cuprite/page.rb +19 -11
- data/lib/capybara/cuprite/version.rb +1 -1
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e515ee98354d04170f435ea87fc5d9256a21f2ca7484a83b8078c76478bfeb73
|
4
|
+
data.tar.gz: 4a08d6b9957090cad3bb732199a9706bf0aa7e6dfe152cf41b1364d4f11a95d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '049bfdaf42c6bd78fdc40fcd6cc059ef6b38b5b3e0a7e03e4ee871fcb8c072cd5ec6215f5b5640f2e289505d582ffe9c3b9e84f688af9afc4e48616bfa5f7473'
|
7
|
+
data.tar.gz: 9b6c78303752248b85c6ca1dc2068dcc57687d94c141e2b10c75a54e9a6a8e767de3a804d98fe788580be0ec36d1230006ec784eb4b675c48752efee61e2a1fd
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,26 +1,25 @@
|
|
1
|
-
# Cuprite - Headless Chrome driver for Capybara
|
1
|
+
# Cuprite - Headless Chrome driver for Capybara
|
2
2
|
|
3
|
-
|
3
|
+
Cuprite is a pure Ruby driver (read as _no_ Selenium/WebDriver/ChromeDriver
|
4
|
+
dependency) for [Capybara](https://github.com/teamcapybara/capybara). It allows
|
5
|
+
you to run Capybara tests on a headless Chrome or Chromium. Under the hood it
|
6
|
+
uses [Ferrum](https://github.com/rubycdp/ferrum#index) which is high-level API
|
7
|
+
to the browser by CDP protocol. The design of the driver is as close to
|
8
|
+
[Poltergeist](https://github.com/teampoltergeist/poltergeist) as possible though
|
9
|
+
it's not a goal.
|
4
10
|
|
5
|
-
Cuprite is
|
6
|
-
|
7
|
-
you to run your Capybara tests on a headless [Chrome](https://www.google.com/chrome/)
|
8
|
-
or [Chromium](https://www.chromium.org/) by [CDP protocol](https://chromedevtools.github.io/devtools-protocol/).
|
9
|
-
Under the hood it uses [Ferrum](https://github.com/route/ferrum) which is
|
10
|
-
high-level API to the browser again by CDP protocol.
|
11
|
+
[Cuprite](https://evrone.com/cuprite) website is designed & supported by [Evrone](https://evrone.com/)
|
12
|
+
What else we build [with Ruby](https://evrone.com/ruby)
|
11
13
|
|
12
|
-
The emphasis was made on raw CDP protocol because Headless Chrome allows you to
|
13
|
-
do so many things that are barely supported by WebDriver because it should have
|
14
|
-
consistent design with other browsers. The design of the driver will be as
|
15
|
-
close to [Poltergeist](https://github.com/teampoltergeist/poltergeist) as
|
16
|
-
possible though it's not a goal.
|
17
14
|
|
18
|
-
## Install
|
15
|
+
## Install
|
19
16
|
|
20
|
-
Add
|
17
|
+
Add this to your `Gemfile` and run `bundle install`.
|
21
18
|
|
22
19
|
``` ruby
|
23
|
-
|
20
|
+
group :test do
|
21
|
+
gem "cuprite"
|
22
|
+
end
|
24
23
|
```
|
25
24
|
|
26
25
|
In your test setup add:
|
@@ -33,21 +32,31 @@ Capybara.register_driver(:cuprite) do |app|
|
|
33
32
|
end
|
34
33
|
```
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
if you use `Docker` don't forget to pass `no-sandbox` option:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
Capybara::Cuprite::Driver.new(app, browser_options: { 'no-sandbox': nil })
|
39
|
+
```
|
40
|
+
|
41
|
+
Since Cuprite uses [Ferrum](https://github.com/rubycdp/ferrum#examples) there
|
42
|
+
are many useful methods you can call even using this driver:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
browser = page.driver.browser
|
46
|
+
browser.mouse.move(x: 123, y: 456).down.up
|
47
|
+
```
|
48
|
+
|
49
|
+
If you already have tests on Poltergeist then it should simply work, for
|
50
|
+
Selenium you better check your code for `manage` calls because it works
|
51
|
+
differently in Cuprite, see the documentation below.
|
39
52
|
|
40
|
-
## Install Chrome ##
|
41
53
|
|
42
|
-
|
43
|
-
way because it either will be outdated or unofficial, both are bad. Download it
|
44
|
-
from official [source](https://www.chromium.org/getting-involved/download-chromium).
|
45
|
-
Chrome binary should be in the `PATH` or `BROWSER_PATH` or you can pass it as an
|
46
|
-
option
|
54
|
+
## Customization
|
47
55
|
|
48
|
-
|
56
|
+
See the full list of options for
|
57
|
+
[Ferrum](https://github.com/rubycdp/ferrum#customization).
|
49
58
|
|
50
|
-
You can
|
59
|
+
You can pass options with the following code in your test setup:
|
51
60
|
|
52
61
|
``` ruby
|
53
62
|
Capybara.register_driver(:cuprite) do |app|
|
@@ -55,47 +64,52 @@ Capybara.register_driver(:cuprite) do |app|
|
|
55
64
|
end
|
56
65
|
```
|
57
66
|
|
58
|
-
|
67
|
+
`Cuprite`-specific options are:
|
68
|
+
|
69
|
+
* options `Hash`
|
70
|
+
* `:url_blacklist` (Array) - array of strings to match against requested URLs
|
71
|
+
* `:url_whitelist` (Array) - array of strings to match against requested URLs
|
59
72
|
|
60
|
-
|
73
|
+
|
74
|
+
## Debugging
|
75
|
+
|
76
|
+
If you pass `inspector` option, remote debugging will be enabled if you run
|
77
|
+
tests with `INSPECTOR=true`. Then you can put `page.driver.debug` or
|
78
|
+
`page.driver.debug(binding)` in your test to pause it. This will launch the
|
79
|
+
browser where you can inspect the content.
|
61
80
|
|
62
81
|
```ruby
|
63
|
-
Capybara
|
82
|
+
Capybara.register_driver :cuprite do |app|
|
83
|
+
Capybara::Cuprite::Driver.new(app, inspector: ENV['INSPECTOR'])
|
84
|
+
end
|
64
85
|
```
|
65
86
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
* `:port` (Integer) - Remote debugging port for headless Chrome
|
84
|
-
* `:host` (String) - Remote debugging address for headless Chrome
|
85
|
-
* `:url` (String) - URL for a running instance of Chrome. If this is set, a
|
86
|
-
browser process will not be spawned.
|
87
|
-
* `:url_blacklist` (Array) - array of strings to match against requested URLs
|
88
|
-
* `:url_whitelist` (Array) - array of strings to match against requested URLs
|
89
|
-
* `:process_timeout` (Integer) - How long to wait for the Chrome process to
|
90
|
-
respond on startup
|
87
|
+
then somewhere in the test:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
it "does something useful" do
|
91
|
+
visit root_path
|
92
|
+
|
93
|
+
fill_in "field", with: "value"
|
94
|
+
page.driver.debug(binding)
|
95
|
+
|
96
|
+
expect(page).to have_content("value")
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
In the middle of the execution Chrome will open a new tab where you can inspect
|
101
|
+
the content and also if you passed `binding` an `irb` or `pry` console will be
|
102
|
+
opened where you can further experiment with the test.
|
103
|
+
|
91
104
|
|
92
|
-
|
105
|
+
## Clicking/Scrolling
|
93
106
|
|
94
107
|
* `page.driver.click(x, y)` Click a very specific area of the screen.
|
95
|
-
* `page.driver.scroll_to(left, top)` Scroll to given position.
|
96
|
-
* `element.send_keys(*keys)` Send keys to given node.
|
108
|
+
* `page.driver.scroll_to(left, top)` Scroll to a given position.
|
109
|
+
* `element.send_keys(*keys)` Send keys to a given node.
|
97
110
|
|
98
|
-
|
111
|
+
|
112
|
+
## Request headers
|
99
113
|
|
100
114
|
Manipulate HTTP request headers like a boss:
|
101
115
|
|
@@ -111,11 +125,11 @@ Notice that `headers=` will overwrite already set headers. You should use
|
|
111
125
|
subsequent HTTP requests (including requests for assets, AJAX, etc). They will
|
112
126
|
be automatically cleared at the end of the test.
|
113
127
|
|
114
|
-
### Network traffic ###
|
115
128
|
|
116
|
-
|
117
|
-
loaded) on the current page. This returns an array of request objects.
|
129
|
+
## Network traffic
|
118
130
|
|
131
|
+
* `page.driver.network_traffic` Inspect network traffic (loaded resources) on
|
132
|
+
the current page. This returns an array of request objects.
|
119
133
|
|
120
134
|
```ruby
|
121
135
|
page.driver.network_traffic # => [Request, ...]
|
@@ -123,11 +137,30 @@ request = page.driver.network_traffic.first
|
|
123
137
|
request.response
|
124
138
|
```
|
125
139
|
|
140
|
+
* `page.driver.wait_for_network_idle` Natively waits for network idle and if
|
141
|
+
there are no active connections returns or raises `TimeoutError` error. Accepts
|
142
|
+
the same options as
|
143
|
+
[`wait_for_idle`](https://github.com/rubycdp/ferrum#wait_for_idleoptions)
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
page.driver.wait_for_network_idle
|
147
|
+
page.driver.refresh
|
148
|
+
```
|
149
|
+
|
126
150
|
Please note that network traffic is not cleared when you visit new page. You can
|
127
151
|
manually clear the network traffic by calling `page.driver.clear_network_traffic`
|
128
152
|
or `page.driver.reset`
|
129
153
|
|
130
|
-
|
154
|
+
* `page.driver.wait_for_reload` unlike `wait_for_network_idle` will wait until
|
155
|
+
the whole page is reloaded or raise a timeout error. It's useful when you know
|
156
|
+
that for example after clicking autocomplete suggestion you expect page to be
|
157
|
+
reloaded, you have a few choices - put sleep or wait for network idle, but both
|
158
|
+
are bad. Sleep makes you wait longer or less than needed, network idle can
|
159
|
+
return earlier even before the whole page is started to reload. Here's the
|
160
|
+
rescue.
|
161
|
+
|
162
|
+
|
163
|
+
## Manipulating cookies
|
131
164
|
|
132
165
|
The following methods are used to inspect and manipulate cookies:
|
133
166
|
|
@@ -142,18 +175,22 @@ The following methods are used to inspect and manipulate cookies:
|
|
142
175
|
* `page.driver.remove_cookie(name)` - remove a cookie
|
143
176
|
* `page.driver.clear_cookies` - clear all cookies
|
144
177
|
|
145
|
-
|
178
|
+
|
179
|
+
## Screenshot
|
146
180
|
|
147
181
|
Besides capybara screenshot method you can get image as Base64:
|
148
182
|
|
149
183
|
* `page.driver.render_base64(format, options)`
|
150
184
|
|
151
|
-
|
185
|
+
|
186
|
+
## Authorization
|
152
187
|
|
153
188
|
* `page.driver.basic_authorize(user, password)`
|
154
189
|
* `page.driver.set_proxy(ip, port, type, user, password)`
|
155
190
|
|
156
|
-
|
191
|
+
|
192
|
+
## URL Blacklisting & Whitelisting
|
193
|
+
|
157
194
|
Cuprite supports URL blacklisting, which allows you to prevent scripts from
|
158
195
|
running on designated domains:
|
159
196
|
|
@@ -161,8 +198,8 @@ running on designated domains:
|
|
161
198
|
page.driver.browser.url_blacklist = ["http://www.example.com"]
|
162
199
|
```
|
163
200
|
|
164
|
-
and also URL whitelisting, which allows scripts to only run
|
165
|
-
|
201
|
+
and also URL whitelisting, which allows scripts to only run on designated
|
202
|
+
domains:
|
166
203
|
|
167
204
|
```ruby
|
168
205
|
page.driver.browser.url_whitelist = ["http://www.example.com"]
|
@@ -172,40 +209,7 @@ If you are experiencing slower run times, consider creating a URL whitelist of
|
|
172
209
|
domains that are essential or a blacklist of domains that are not essential,
|
173
210
|
such as ad networks or analytics, to your testing environment.
|
174
211
|
|
175
|
-
|
176
|
-
|
177
|
-
If you use the `inspector: true` option, remote debugging will be enabled. When
|
178
|
-
this option is enabled, you can insert `page.driver.debug` into your tests to
|
179
|
-
pause the test and launch a browser which gives you the Chrome inspector to view
|
180
|
-
all your open pages and inspect them.
|
181
|
-
|
182
|
-
You could set the inspector option via an environment variable:
|
183
|
-
|
184
|
-
```ruby
|
185
|
-
Capybara.register_driver :cuprite do |app|
|
186
|
-
Capybara::Cuprite::Driver.new(app, inspector: ENV['INSPECTOR'])
|
187
|
-
end
|
188
|
-
```
|
189
|
-
|
190
|
-
## License ##
|
191
|
-
|
192
|
-
Copyright 2018-2019 Machinio
|
193
|
-
|
194
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
195
|
-
a copy of this software and associated documentation files (the
|
196
|
-
"Software"), to deal in the Software without restriction, including
|
197
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
198
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
199
|
-
permit persons to whom the Software is furnished to do so, subject to
|
200
|
-
the following conditions:
|
201
|
-
|
202
|
-
The above copyright notice and this permission notice shall be
|
203
|
-
included in all copies or substantial portions of the Software.
|
212
|
+
## License
|
204
213
|
|
205
|
-
|
206
|
-
|
207
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
208
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
209
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
210
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
211
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
214
|
+
The gem is available as open source under the terms of the
|
215
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/lib/capybara/cuprite.rb
CHANGED
@@ -2,18 +2,12 @@
|
|
2
2
|
|
3
3
|
require "ferrum"
|
4
4
|
require "capybara"
|
5
|
-
|
6
|
-
module Capybara::Cuprite
|
7
|
-
end
|
8
|
-
|
9
5
|
require "capybara/cuprite/driver"
|
10
6
|
require "capybara/cuprite/browser"
|
11
7
|
require "capybara/cuprite/page"
|
12
8
|
require "capybara/cuprite/node"
|
13
9
|
require "capybara/cuprite/errors"
|
14
10
|
|
15
|
-
Ferrum::Page.prepend(Capybara::Cuprite::Page)
|
16
|
-
|
17
11
|
Capybara.register_driver(:cuprite) do |app|
|
18
12
|
Capybara::Cuprite::Driver.new(app)
|
19
13
|
end
|
@@ -23,12 +23,12 @@ module Capybara::Cuprite
|
|
23
23
|
|
24
24
|
def page
|
25
25
|
raise Ferrum::NoSuchPageError if @page.nil?
|
26
|
-
@page ||=
|
26
|
+
@page ||= attach_page
|
27
27
|
end
|
28
28
|
|
29
29
|
def reset
|
30
30
|
super
|
31
|
-
@page =
|
31
|
+
@page = attach_page
|
32
32
|
end
|
33
33
|
|
34
34
|
def quit
|
@@ -81,7 +81,7 @@ module Capybara::Cuprite
|
|
81
81
|
|
82
82
|
if Capybara::VERSION.to_f < 3.0
|
83
83
|
target_id = window_handles.find do |target_id|
|
84
|
-
page =
|
84
|
+
page = attach_page(target_id)
|
85
85
|
locator == page.frame_name
|
86
86
|
end
|
87
87
|
locator = target_id if target_id
|
@@ -100,13 +100,13 @@ module Capybara::Cuprite
|
|
100
100
|
def switch_to_window(target_id)
|
101
101
|
target = targets[target_id]
|
102
102
|
raise Ferrum::NoSuchPageError unless target
|
103
|
-
@page = target.
|
103
|
+
@page = attach_page(target.id)
|
104
104
|
end
|
105
105
|
|
106
106
|
def close_window(target_id)
|
107
107
|
target = targets[target_id]
|
108
108
|
raise Ferrum::NoSuchPageError unless target
|
109
|
-
@page = nil if @page == target.
|
109
|
+
@page = nil if @page.target_id == target.id
|
110
110
|
target.page.close
|
111
111
|
end
|
112
112
|
|
@@ -200,5 +200,15 @@ module Capybara::Cuprite
|
|
200
200
|
end
|
201
201
|
end
|
202
202
|
end
|
203
|
+
|
204
|
+
def attach_page(target_id = nil)
|
205
|
+
target = targets[target_id] if target_id
|
206
|
+
target ||= default_context.default_target
|
207
|
+
return target.page if target.attached?
|
208
|
+
|
209
|
+
target.maybe_sleep_if_new_window
|
210
|
+
target.page = Page.new(target.id, self)
|
211
|
+
target.page
|
212
|
+
end
|
203
213
|
end
|
204
214
|
end
|
@@ -26,6 +26,8 @@ module Capybara::Cuprite
|
|
26
26
|
@screen_size ||= DEFAULT_MAXIMIZE_SCREEN_SIZE
|
27
27
|
|
28
28
|
@options[:save_path] = Capybara.save_path.to_s if Capybara.save_path
|
29
|
+
|
30
|
+
ENV["FERRUM_DEBUG"] = "true" if ENV["CUPRITE_DEBUG"]
|
29
31
|
end
|
30
32
|
|
31
33
|
def needs_server?
|
@@ -129,7 +131,10 @@ module Capybara::Cuprite
|
|
129
131
|
end
|
130
132
|
|
131
133
|
def open_new_window
|
132
|
-
browser.
|
134
|
+
target = browser.default_context.create_target
|
135
|
+
target.maybe_sleep_if_new_window
|
136
|
+
target.page = Page.new(target.id, browser)
|
137
|
+
target.page
|
133
138
|
end
|
134
139
|
|
135
140
|
def switch_to_window(handle)
|
@@ -238,7 +243,9 @@ module Capybara::Cuprite
|
|
238
243
|
server = type ? "#{type}=#{ip}:#{port}" : "#{ip}:#{port}"
|
239
244
|
@options[:browser_options].merge!("proxy-server" => server)
|
240
245
|
@options[:browser_options].merge!("proxy-bypass-list" => bypass) if bypass
|
241
|
-
browser.network.authorize(type: :proxy, user: user, password: password)
|
246
|
+
browser.network.authorize(type: :proxy, user: user, password: password) do |request|
|
247
|
+
request.continue
|
248
|
+
end
|
242
249
|
end
|
243
250
|
|
244
251
|
def headers
|
@@ -282,22 +289,41 @@ module Capybara::Cuprite
|
|
282
289
|
browser.cookies.clear
|
283
290
|
end
|
284
291
|
|
292
|
+
def wait_for_network_idle(**options)
|
293
|
+
browser.network.wait_for_idle(**options)
|
294
|
+
end
|
295
|
+
|
285
296
|
def clear_memory_cache
|
286
297
|
browser.network.clear(:cache)
|
287
298
|
end
|
288
299
|
|
289
300
|
def basic_authorize(user, password)
|
290
|
-
browser.network.authorize(user: user, password: password)
|
301
|
+
browser.network.authorize(user: user, password: password) do |request|
|
302
|
+
request.continue
|
303
|
+
end
|
291
304
|
end
|
292
305
|
alias_method :authorize, :basic_authorize
|
293
306
|
|
294
|
-
def
|
307
|
+
def debug_url
|
308
|
+
"http://#{browser.process.host}:#{browser.process.port}"
|
309
|
+
end
|
310
|
+
|
311
|
+
def debug(binding = nil)
|
295
312
|
if @options[:inspector]
|
296
|
-
Process.spawn(browser.process.path,
|
297
|
-
|
313
|
+
Process.spawn(browser.process.path, debug_url)
|
314
|
+
|
315
|
+
if binding&.respond_to?(:pry)
|
316
|
+
Pry.start(binding)
|
317
|
+
elsif binding&.respond_to?(:irb)
|
318
|
+
binding.irb
|
319
|
+
else
|
320
|
+
pause
|
321
|
+
end
|
298
322
|
else
|
299
323
|
raise Error, "To use the remote debugging, you have to launch " \
|
300
|
-
"the driver with `inspector:
|
324
|
+
"the driver with `inspector: ENV['INSPECTOR']` " \
|
325
|
+
"configuration option and run your test suite passing " \
|
326
|
+
"env variable"
|
301
327
|
end
|
302
328
|
end
|
303
329
|
|
@@ -308,7 +334,7 @@ module Capybara::Cuprite
|
|
308
334
|
# In jRuby - STDIN returns immediately from select
|
309
335
|
# see https://github.com/jruby/jruby/issues/1783
|
310
336
|
read, write = IO.pipe
|
311
|
-
Thread.new { IO.copy_stream(STDIN, write); write.close }
|
337
|
+
thread = Thread.new { IO.copy_stream(STDIN, write); write.close }
|
312
338
|
|
313
339
|
STDERR.puts "Cuprite execution paused. Press enter (or run 'kill -CONT #{Process.pid}') to continue."
|
314
340
|
|
@@ -324,6 +350,8 @@ module Capybara::Cuprite
|
|
324
350
|
end
|
325
351
|
end
|
326
352
|
ensure
|
353
|
+
thread.kill
|
354
|
+
read.close
|
327
355
|
trap("SIGCONT", old_trap) # Restore the previous signal handler, if there was one.
|
328
356
|
STDERR.puts "Continuing"
|
329
357
|
end
|
@@ -335,7 +363,9 @@ module Capybara::Cuprite
|
|
335
363
|
def invalid_element_errors
|
336
364
|
[Capybara::Cuprite::ObsoleteNode,
|
337
365
|
Capybara::Cuprite::MouseEventFailed,
|
338
|
-
Ferrum::
|
366
|
+
Ferrum::CoordinatesNotFoundError,
|
367
|
+
Ferrum::NoExecutionContextError,
|
368
|
+
Ferrum::NodeNotFoundError]
|
339
369
|
end
|
340
370
|
|
341
371
|
def go_back
|
@@ -350,6 +380,10 @@ module Capybara::Cuprite
|
|
350
380
|
browser.refresh
|
351
381
|
end
|
352
382
|
|
383
|
+
def wait_for_reload(*args)
|
384
|
+
browser.wait_for_reload(*args)
|
385
|
+
end
|
386
|
+
|
353
387
|
def accept_modal(type, options = {})
|
354
388
|
case type
|
355
389
|
when :alert, :confirm
|
@@ -41,7 +41,7 @@ class Cuprite {
|
|
41
41
|
parents(node) {
|
42
42
|
let nodes = [];
|
43
43
|
let parent = node.parentNode;
|
44
|
-
while (parent != document) {
|
44
|
+
while (parent != document && parent !== null) {
|
45
45
|
nodes.push(parent);
|
46
46
|
parent = parent.parentNode;
|
47
47
|
}
|
@@ -97,7 +97,7 @@ class Cuprite {
|
|
97
97
|
path(node) {
|
98
98
|
let nodes = [node];
|
99
99
|
let parent = node.parentNode;
|
100
|
-
while (parent !== document) {
|
100
|
+
while (parent !== document && parent !== null) {
|
101
101
|
nodes.unshift(parent);
|
102
102
|
parent = parent.parentNode;
|
103
103
|
}
|
@@ -128,7 +128,7 @@ class Cuprite {
|
|
128
128
|
this.trigger(node, "focus");
|
129
129
|
this.setValue(node, "");
|
130
130
|
|
131
|
-
if (node.type == "number" || node.type == "date") {
|
131
|
+
if (node.type == "number" || node.type == "date" || node.type == "range") {
|
132
132
|
this.setValue(node, value);
|
133
133
|
this.input(node);
|
134
134
|
} else if (node.type == "time") {
|
@@ -104,6 +104,8 @@ module Capybara::Cuprite
|
|
104
104
|
when "file"
|
105
105
|
files = value.respond_to?(:to_ary) ? value.to_ary.map(&:to_s) : value.to_s
|
106
106
|
command(:select_file, files)
|
107
|
+
when "color"
|
108
|
+
node.evaluate("this.setAttribute('value', '#{value}')")
|
107
109
|
else
|
108
110
|
command(:set, value.to_s)
|
109
111
|
end
|
@@ -144,16 +146,16 @@ module Capybara::Cuprite
|
|
144
146
|
command(:disabled?)
|
145
147
|
end
|
146
148
|
|
147
|
-
def click(keys = [],
|
148
|
-
prepare_and_click(:left, __method__, keys,
|
149
|
+
def click(keys = [], **options)
|
150
|
+
prepare_and_click(:left, __method__, keys, options)
|
149
151
|
end
|
150
152
|
|
151
|
-
def right_click(keys = [],
|
152
|
-
prepare_and_click(:right, __method__, keys,
|
153
|
+
def right_click(keys = [], **options)
|
154
|
+
prepare_and_click(:right, __method__, keys, options)
|
153
155
|
end
|
154
156
|
|
155
|
-
def double_click(keys = [],
|
156
|
-
prepare_and_click(:double, __method__, keys,
|
157
|
+
def double_click(keys = [], **options)
|
158
|
+
prepare_and_click(:double, __method__, keys, options)
|
157
159
|
end
|
158
160
|
|
159
161
|
def hover
|
@@ -225,9 +227,12 @@ module Capybara::Cuprite
|
|
225
227
|
|
226
228
|
private
|
227
229
|
|
228
|
-
def prepare_and_click(mode, name, keys,
|
230
|
+
def prepare_and_click(mode, name, keys, options)
|
231
|
+
delay = options[:delay].to_i
|
232
|
+
x, y = options.values_at(:x, :y)
|
233
|
+
offset = { x: x, y: y, position: options[:offset] || :top }
|
229
234
|
command(:before_click, name, keys, offset)
|
230
|
-
node.click(mode: mode, keys: keys, offset: offset)
|
235
|
+
node.click(mode: mode, keys: keys, offset: offset, delay: delay)
|
231
236
|
end
|
232
237
|
|
233
238
|
def filter_text(text)
|
@@ -3,15 +3,14 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
5
|
module Capybara::Cuprite
|
6
|
-
|
6
|
+
class Page < Ferrum::Page
|
7
7
|
MODAL_WAIT = ENV.fetch("CUPRITE_MODAL_WAIT", 0.05).to_f
|
8
8
|
TRIGGER_CLICK_WAIT = ENV.fetch("CUPRITE_TRIGGER_CLICK_WAIT", 0.1).to_f
|
9
9
|
|
10
10
|
extend Forwardable
|
11
11
|
delegate %i[at_css at_xpath css xpath
|
12
|
-
current_url current_title body
|
13
|
-
|
14
|
-
|
12
|
+
current_url current_title body execution_id
|
13
|
+
evaluate evaluate_on evaluate_async execute] => :active_frame
|
15
14
|
|
16
15
|
def initialize(*args)
|
17
16
|
@frame_stack = []
|
@@ -95,7 +94,12 @@ module Capybara::Cuprite
|
|
95
94
|
|
96
95
|
def before_click(node, name, keys = [], offset = {})
|
97
96
|
evaluate_on(node: node, expression: "_cuprite.scrollIntoViewport(this)")
|
98
|
-
|
97
|
+
|
98
|
+
# If offset is given it may go outside of the element and likely error
|
99
|
+
# will be raised that we detected another element at this position.
|
100
|
+
return true if offset[:x] || offset[:y]
|
101
|
+
|
102
|
+
x, y = find_position(node, **offset)
|
99
103
|
evaluate_on(node: node, expression: "_cuprite.mouseEventTest(this, '#{name}', #{x}, #{y})")
|
100
104
|
true
|
101
105
|
rescue Ferrum::JavaScriptError => e
|
@@ -114,6 +118,10 @@ module Capybara::Cuprite
|
|
114
118
|
end
|
115
119
|
end
|
116
120
|
|
121
|
+
def frame_name
|
122
|
+
evaluate("window.name")
|
123
|
+
end
|
124
|
+
|
117
125
|
def title
|
118
126
|
active_frame.current_title
|
119
127
|
end
|
@@ -129,15 +137,15 @@ module Capybara::Cuprite
|
|
129
137
|
on(:request) do |request, index, total|
|
130
138
|
if @browser.url_blacklist && !@browser.url_blacklist.empty?
|
131
139
|
if @browser.url_blacklist.any? { |r| request.match?(r) }
|
132
|
-
request.abort and
|
140
|
+
request.abort and next
|
133
141
|
else
|
134
|
-
request.continue and
|
142
|
+
request.continue and next
|
135
143
|
end
|
136
144
|
elsif @browser.url_whitelist && !@browser.url_whitelist.empty?
|
137
145
|
if @browser.url_whitelist.any? { |r| request.match?(r) }
|
138
|
-
request.continue and
|
146
|
+
request.continue and next
|
139
147
|
else
|
140
|
-
request.abort and
|
148
|
+
request.abort and next
|
141
149
|
end
|
142
150
|
elsif index + 1 < total
|
143
151
|
# There are other callbacks that may handle this request
|
@@ -171,8 +179,8 @@ module Capybara::Cuprite
|
|
171
179
|
end
|
172
180
|
end
|
173
181
|
|
174
|
-
def find_position(node,
|
175
|
-
x, y = node.find_position(
|
182
|
+
def find_position(node, **options)
|
183
|
+
x, y = node.find_position(**options)
|
176
184
|
rescue Ferrum::BrowserError => e
|
177
185
|
if e.message == "Could not compute content quads."
|
178
186
|
raise MouseEventFailed.new("MouseEventFailed: click, none, 0, 0")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuprite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.13'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Vorotilin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.11.0
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 0.11.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: image_size
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -189,10 +189,14 @@ files:
|
|
189
189
|
- lib/capybara/cuprite/node.rb
|
190
190
|
- lib/capybara/cuprite/page.rb
|
191
191
|
- lib/capybara/cuprite/version.rb
|
192
|
-
homepage: https://github.com/
|
192
|
+
homepage: https://github.com/rubycdp/cuprite
|
193
193
|
licenses:
|
194
194
|
- MIT
|
195
|
-
metadata:
|
195
|
+
metadata:
|
196
|
+
homepage_uri: https://cuprite.rubycdp.com/
|
197
|
+
bug_tracker_uri: https://github.com/rubycdp/cuprite/issues
|
198
|
+
documentation_uri: https://github.com/rubycdp/cuprite/blob/master/README.md
|
199
|
+
source_code_uri: https://github.com/rubycdp/cuprite
|
196
200
|
post_install_message:
|
197
201
|
rdoc_options: []
|
198
202
|
require_paths:
|
@@ -208,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
212
|
- !ruby/object:Gem::Version
|
209
213
|
version: '0'
|
210
214
|
requirements: []
|
211
|
-
rubygems_version: 3.
|
215
|
+
rubygems_version: 3.1.2
|
212
216
|
signing_key:
|
213
217
|
specification_version: 4
|
214
218
|
summary: Headless Chrome driver for Capybara
|