cuprite 0.18 → 0.20
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/README.md +69 -37
- data/lib/capybara/cuprite/browser/deprecations.rb +26 -0
- data/lib/capybara/cuprite/browser/extensions.rb +59 -0
- data/lib/capybara/cuprite/browser.rb +28 -231
- data/lib/capybara/cuprite/deprecation.rb +13 -0
- data/lib/capybara/cuprite/devices.rb +188 -0
- data/lib/capybara/cuprite/driver/deprecations.rb +198 -0
- data/lib/capybara/cuprite/driver/extensions.rb +13 -0
- data/lib/capybara/cuprite/driver.rb +68 -201
- data/lib/capybara/cuprite/finder.rb +22 -0
- data/lib/capybara/cuprite/javascripts/drag.js +100 -103
- data/lib/capybara/cuprite/javascripts/index.js +511 -489
- data/lib/capybara/cuprite/node/deprecations.rb +43 -0
- data/lib/capybara/cuprite/node/extensions.rb +27 -0
- data/lib/capybara/cuprite/node.rb +140 -116
- data/lib/capybara/cuprite/options.rb +19 -0
- data/lib/capybara/cuprite/page/frames.rb +47 -0
- data/lib/capybara/cuprite/page/modals.rb +118 -0
- data/lib/capybara/cuprite/page.rb +9 -207
- data/lib/capybara/cuprite/version.rb +1 -1
- data/lib/capybara/cuprite.rb +1 -0
- metadata +16 -6
- data/lib/capybara/cuprite/cookie.rb +0 -47
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 159c7e6289accaf81577a8549e3e1447ea90e0f99694b91547704fef206b8c56
|
|
4
|
+
data.tar.gz: 1b70f9e72fbdd0a089d45229ecb12604d655a782ca2a10b358220b66865e5d09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dac1cb17193f518ce4e276c2580d02118e9a1cce86737c8e0b501c2747a438b89dfda2ed2eb5b66b23e4a92fa7d30c53cbb991ae172358fbbb12531fd441a777
|
|
7
|
+
data.tar.gz: f9758427a804d2dc3ecda09610598fa2a22389f520789800fc5b71bf60f5cef9be01a48a464610a1200914ab4f005ca71634557f9b113586c594097a0c592884
|
data/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Cuprite - Headless Chrome driver for Capybara
|
|
2
2
|
|
|
3
|
+
## [Documentation](https://docs.rubycdp.com/docs/cuprite/introduction)
|
|
4
|
+
|
|
5
|
+
<img align="right"
|
|
6
|
+
width="160" height="160"
|
|
7
|
+
alt="Cuprite logo"
|
|
8
|
+
src="https://raw.githubusercontent.com/rubycdp/cuprite/main/logo.svg?sanitize=true">
|
|
9
|
+
|
|
3
10
|
Cuprite is a pure Ruby driver (read as _no_ Selenium/WebDriver/ChromeDriver
|
|
4
11
|
dependency) for [Capybara](https://github.com/teamcapybara/capybara). It allows
|
|
5
12
|
you to run Capybara tests on a headless Chrome or Chromium. Under the hood it
|
|
@@ -7,6 +14,8 @@ uses [Ferrum](https://github.com/rubycdp/ferrum#index) which is high-level API
|
|
|
7
14
|
to the browser by CDP protocol.
|
|
8
15
|
|
|
9
16
|
|
|
17
|
+
<br clear="right">
|
|
18
|
+
|
|
10
19
|
## Install
|
|
11
20
|
|
|
12
21
|
Add this to your `Gemfile` and run `bundle install`.
|
|
@@ -49,7 +58,8 @@ because Docker is involved. Prefer running the browser as a non-root user with
|
|
|
49
58
|
a working sandbox when possible.
|
|
50
59
|
|
|
51
60
|
Since Cuprite uses [Ferrum](https://github.com/rubycdp/ferrum#examples) there
|
|
52
|
-
are many useful methods you can call even using this driver
|
|
61
|
+
are many useful methods you can call even using this driver.
|
|
62
|
+
`page.driver.browser` is a `Ferrum::Browser`:
|
|
53
63
|
|
|
54
64
|
```ruby
|
|
55
65
|
browser = page.driver.browser
|
|
@@ -84,7 +94,18 @@ end
|
|
|
84
94
|
timer) only surfaces on whatever command runs next.
|
|
85
95
|
* `:url_blacklist` (Array) - array of regexes to match against requested URLs
|
|
86
96
|
* `:url_whitelist` (Array) - array of regexes to match against requested URLs
|
|
97
|
+
* `:emulate` (Symbol) - device from Chrome DevTools' list to emulate, e.g. `:iphone_16`, `:pixel_9`, `:ipad_mini`
|
|
98
|
+
* `:mobile` (Boolean) - emulate a mobile device: viewport meta tag and touch events
|
|
99
|
+
* `:scale_factor` (Numeric) - device scale factor to emulate
|
|
87
100
|
|
|
101
|
+
`emulate:` sets the device's `:window_size`, `:scale_factor`, `:mobile` and user agent, options passed explicitly
|
|
102
|
+
take precedence:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
Capybara.register_driver(:cuprite) do |app|
|
|
106
|
+
Capybara::Cuprite::Driver.new(app, emulate: :iphone_14)
|
|
107
|
+
end
|
|
108
|
+
```
|
|
88
109
|
|
|
89
110
|
## Debugging
|
|
90
111
|
|
|
@@ -109,35 +130,35 @@ opened where you can further experiment with the test.
|
|
|
109
130
|
|
|
110
131
|
## Clicking/Scrolling
|
|
111
132
|
|
|
112
|
-
* `page.driver.click(x
|
|
113
|
-
* `page.
|
|
133
|
+
* `page.driver.browser.mouse.click(x:, y:)` Click a very specific area of the screen.
|
|
134
|
+
* `page.scroll_to(left, top)` Scroll to a given position.
|
|
114
135
|
* `element.send_keys(*keys)` Send keys to a given node.
|
|
115
136
|
|
|
116
137
|
|
|
117
138
|
## Request headers
|
|
118
139
|
|
|
119
|
-
Manipulate HTTP request headers
|
|
140
|
+
Manipulate HTTP request headers with Ferrum:
|
|
120
141
|
|
|
121
142
|
``` ruby
|
|
122
|
-
page.driver.headers # => {}
|
|
123
|
-
page.driver.headers
|
|
124
|
-
page.driver.
|
|
125
|
-
page.driver.headers # => { "User-Agent" => "Cuprite", "Referer" => "https://example.com" }
|
|
143
|
+
page.driver.browser.headers.get # => {}
|
|
144
|
+
page.driver.browser.headers.set("User-Agent" => "Cuprite")
|
|
145
|
+
page.driver.browser.headers.add({ "Referer" => "https://example.com" })
|
|
146
|
+
page.driver.browser.headers.get # => { "User-Agent" => "Cuprite", "Referer" => "https://example.com" }
|
|
126
147
|
```
|
|
127
148
|
|
|
128
|
-
Notice that `
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
Notice that `set` will overwrite already set headers. You should use `add` if
|
|
150
|
+
you want to add a few more. These headers will apply to all subsequent HTTP
|
|
151
|
+
requests (including requests for assets, AJAX, etc). They will be automatically
|
|
152
|
+
cleared at the end of the test.
|
|
132
153
|
|
|
133
154
|
|
|
134
155
|
## Network traffic
|
|
135
156
|
|
|
136
|
-
* `page.driver.
|
|
157
|
+
* `page.driver.browser.network.traffic` allows you to inspect network traffic (i.e., loaded resources) on the current page. It returns an array of `Ferrum::Network::Exchange` objects, each representing a network request/response exchange. You can query both the request and response details of each exchange.
|
|
137
158
|
|
|
138
159
|
```ruby
|
|
139
160
|
# Retrieve all network exchanges
|
|
140
|
-
network_traffic = page.driver.
|
|
161
|
+
network_traffic = page.driver.browser.network.traffic
|
|
141
162
|
|
|
142
163
|
# Access the first exchange
|
|
143
164
|
first_exchange = network_traffic.first
|
|
@@ -146,22 +167,22 @@ first_exchange = network_traffic.first
|
|
|
146
167
|
response = first_exchange.response
|
|
147
168
|
```
|
|
148
169
|
|
|
149
|
-
* `page.driver.
|
|
150
|
-
there are
|
|
151
|
-
the same options as
|
|
170
|
+
* `page.driver.browser.network.wait_for_idle` Natively waits for network idle
|
|
171
|
+
and returns `false` if there are still active connections after timeout.
|
|
172
|
+
Accepts the same options as
|
|
152
173
|
[`wait_for_idle`](https://github.com/rubycdp/ferrum#wait_for_idleoptions)
|
|
153
174
|
|
|
154
175
|
```ruby
|
|
155
|
-
page.driver.
|
|
176
|
+
page.driver.browser.network.wait_for_idle
|
|
156
177
|
page.driver.refresh
|
|
157
178
|
```
|
|
158
179
|
|
|
159
180
|
Please note that network traffic is not cleared when you visit new page. You can
|
|
160
|
-
manually clear the network traffic by calling
|
|
161
|
-
or `page.driver.reset
|
|
181
|
+
manually clear the network traffic by calling
|
|
182
|
+
`page.driver.browser.network.clear(:traffic)` or `page.driver.reset!`
|
|
162
183
|
|
|
163
|
-
* `page.driver.wait_for_reload` unlike `
|
|
164
|
-
the whole page is reloaded or
|
|
184
|
+
* `page.driver.browser.wait_for_reload` unlike `network.wait_for_idle` will wait until
|
|
185
|
+
the whole page is reloaded or the timeout passes. It's useful when you know
|
|
165
186
|
that for example after clicking autocomplete suggestion you expect page to be
|
|
166
187
|
reloaded, you have a few choices - put sleep or wait for network idle, but both
|
|
167
188
|
are bad. Sleep makes you wait longer or less than needed, network idle can
|
|
@@ -171,34 +192,45 @@ rescue.
|
|
|
171
192
|
|
|
172
193
|
## Manipulating cookies
|
|
173
194
|
|
|
174
|
-
|
|
195
|
+
Use Ferrum's cookies to inspect and manipulate cookies:
|
|
175
196
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
* `page.driver.remove_cookie(name)` - remove a cookie
|
|
185
|
-
* `page.driver.clear_cookies` - clear all cookies
|
|
197
|
+
```ruby
|
|
198
|
+
cookies = page.driver.browser.cookies
|
|
199
|
+
cookies.set(name: "stealth", value: "omg")
|
|
200
|
+
cookies["stealth"].value # => "omg"
|
|
201
|
+
cookies.all # => { "stealth" => #<Ferrum::Cookies::Cookie ...> }
|
|
202
|
+
cookies.remove(name: "stealth")
|
|
203
|
+
cookies.clear
|
|
204
|
+
```
|
|
186
205
|
|
|
187
206
|
|
|
188
207
|
## Screenshot
|
|
189
208
|
|
|
190
|
-
Besides capybara screenshot method you can get image as Base64:
|
|
209
|
+
Besides capybara screenshot method you can get image or PDF as Base64 with Ferrum:
|
|
191
210
|
|
|
192
|
-
|
|
211
|
+
```ruby
|
|
212
|
+
page.driver.browser.screenshot(format: :jpeg, full: true)
|
|
213
|
+
page.driver.browser.pdf(paper_width: 6, paper_height: 12)
|
|
214
|
+
```
|
|
193
215
|
|
|
194
216
|
|
|
195
217
|
## Authorization
|
|
196
218
|
|
|
197
|
-
* `page.driver.
|
|
219
|
+
* `page.driver.browser.network.authorize(user:, password:) { |request, _index, _total| request.continue }`
|
|
198
220
|
|
|
199
221
|
## Proxy
|
|
200
222
|
|
|
201
|
-
|
|
223
|
+
```ruby
|
|
224
|
+
Capybara::Cuprite::Driver.new(app, proxy: { host: "127.0.0.1", port: 8080, user: "user", password: "password" })
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The proxy is passed to Chrome as a command-line flag when the browser starts.
|
|
228
|
+
|
|
229
|
+
When connecting to a remote browser with the `:url` option (browserless, Selenoid, etc.), Cuprite doesn't launch
|
|
230
|
+
Chrome and the proxy flag is never applied, so configure the proxy on the remote browser itself. The `user` and
|
|
231
|
+
`password` are still used to answer the proxy's authentication challenge.
|
|
232
|
+
|
|
233
|
+
The `bypass` option is a list of hosts that skip the proxy, so don't pass the host you want to go through it.
|
|
202
234
|
|
|
203
235
|
|
|
204
236
|
## URL Blocklisting & Allowlisting
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "capybara/cuprite/deprecation"
|
|
4
|
+
|
|
5
|
+
module Capybara
|
|
6
|
+
module Cuprite
|
|
7
|
+
class Browser < Ferrum::Browser
|
|
8
|
+
module Deprecations
|
|
9
|
+
def visit(*args)
|
|
10
|
+
Cuprite.deprecation_warning("#{self.class}#visit", "use #goto")
|
|
11
|
+
goto(*args)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def status_code
|
|
15
|
+
Cuprite.deprecation_warning("#{self.class}#status_code", "use #network.status")
|
|
16
|
+
network.status
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def window_handle
|
|
20
|
+
Cuprite.deprecation_warning("#{self.class}#window_handle", "use #current_window_handle")
|
|
21
|
+
current_window_handle
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
module Cuprite
|
|
5
|
+
class Browser < Ferrum::Browser
|
|
6
|
+
module Extensions
|
|
7
|
+
def raise_on_unhandled_modal
|
|
8
|
+
@options.raise_on_unhandled_modal
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def raise_on_unhandled_modal=(value)
|
|
12
|
+
@options.raise_on_unhandled_modal = value
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def url_whitelist
|
|
16
|
+
@options.url_whitelist
|
|
17
|
+
end
|
|
18
|
+
alias url_allowlist url_whitelist
|
|
19
|
+
|
|
20
|
+
def url_whitelist=(patterns)
|
|
21
|
+
@options.url_whitelist = prepare_wildcards(patterns)
|
|
22
|
+
page.network.whitelist = @options.url_whitelist if @client && @options.url_whitelist.any?
|
|
23
|
+
end
|
|
24
|
+
alias url_allowlist= url_whitelist=
|
|
25
|
+
|
|
26
|
+
def url_blacklist
|
|
27
|
+
@options.url_blacklist
|
|
28
|
+
end
|
|
29
|
+
alias url_blocklist url_blacklist
|
|
30
|
+
|
|
31
|
+
def url_blacklist=(patterns)
|
|
32
|
+
@options.url_blacklist = prepare_wildcards(patterns)
|
|
33
|
+
page.network.blacklist = @options.url_blacklist if @client && @options.url_blacklist.any?
|
|
34
|
+
end
|
|
35
|
+
alias url_blocklist= url_blacklist=
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def prepare_wildcards(patterns)
|
|
40
|
+
string_passed = false
|
|
41
|
+
|
|
42
|
+
Array(patterns).map do |pattern|
|
|
43
|
+
if pattern.is_a?(Regexp)
|
|
44
|
+
pattern
|
|
45
|
+
else
|
|
46
|
+
string_passed = true
|
|
47
|
+
pattern = pattern.gsub("*", ".*")
|
|
48
|
+
Regexp.new(pattern, Regexp::IGNORECASE)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
ensure
|
|
52
|
+
if string_passed
|
|
53
|
+
warn "Passing strings to blacklist/whitelist is deprecated, pass regexp at #{caller(4..4).first}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "capybara/cuprite/browser/deprecations"
|
|
4
|
+
require "capybara/cuprite/browser/extensions"
|
|
4
5
|
|
|
5
6
|
module Capybara
|
|
6
7
|
module Cuprite
|
|
7
8
|
class Browser < Ferrum::Browser
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
DRAG_HTML5_JS = File.read(File.expand_path("javascripts/drag.js", __dir__))
|
|
11
|
-
|
|
12
|
-
delegate %i[send_keys select set hover trigger before_click switch_to_frame
|
|
13
|
-
find_modal accept_confirm dismiss_confirm accept_prompt
|
|
14
|
-
dismiss_prompt reset_modals] => :page
|
|
9
|
+
include Deprecations
|
|
10
|
+
include Extensions
|
|
15
11
|
|
|
16
12
|
def initialize(options = nil)
|
|
13
|
+
device = options&.dig(:emulate)
|
|
14
|
+
options = Devices.fetch(device).except(:user_agent).merge(options) if device
|
|
17
15
|
super
|
|
18
16
|
|
|
19
17
|
@options.raise_on_unhandled_modal = options&.dig(:raise_on_unhandled_modal)
|
|
@@ -31,20 +29,21 @@ module Capybara
|
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
def page
|
|
34
|
-
raise Ferrum::NoSuchPageError if @
|
|
32
|
+
raise Ferrum::NoSuchPageError if @page_closed
|
|
35
33
|
|
|
36
34
|
@page ||= attach_page
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
def reset
|
|
40
38
|
super
|
|
39
|
+
ensure
|
|
41
40
|
@options.reset_window_size
|
|
42
|
-
|
|
41
|
+
forget_page
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
def quit
|
|
46
45
|
super
|
|
47
|
-
|
|
46
|
+
forget_page
|
|
48
47
|
end
|
|
49
48
|
|
|
50
49
|
def resize(**options)
|
|
@@ -52,249 +51,47 @@ module Capybara
|
|
|
52
51
|
super
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
def
|
|
56
|
-
@options.raise_on_unhandled_modal
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def raise_on_unhandled_modal=(value)
|
|
60
|
-
@options.raise_on_unhandled_modal = value
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def url_whitelist
|
|
64
|
-
@options.url_whitelist
|
|
65
|
-
end
|
|
66
|
-
alias url_allowlist url_whitelist
|
|
67
|
-
|
|
68
|
-
def url_whitelist=(patterns)
|
|
69
|
-
@options.url_whitelist = prepare_wildcards(patterns)
|
|
70
|
-
page.network.whitelist = @options.url_whitelist if @client && @options.url_whitelist.any?
|
|
71
|
-
end
|
|
72
|
-
alias url_allowlist= url_whitelist=
|
|
73
|
-
|
|
74
|
-
def url_blacklist
|
|
75
|
-
@options.url_blacklist
|
|
76
|
-
end
|
|
77
|
-
alias url_blocklist url_blacklist
|
|
78
|
-
|
|
79
|
-
def url_blacklist=(patterns)
|
|
80
|
-
@options.url_blacklist = prepare_wildcards(patterns)
|
|
81
|
-
page.network.blacklist = @options.url_blacklist if @client && @options.url_blacklist.any?
|
|
82
|
-
end
|
|
83
|
-
alias url_blocklist= url_blacklist=
|
|
84
|
-
|
|
85
|
-
def visit(*args)
|
|
86
|
-
goto(*args)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def status_code
|
|
90
|
-
network.status
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def find(method, selector)
|
|
94
|
-
find_all(method, selector)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def property(node, name)
|
|
98
|
-
node.property(name)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def find_within(node, method, selector)
|
|
102
|
-
resolved = page.command("DOM.resolveNode", nodeId: node.node_id)
|
|
103
|
-
object_id = resolved.dig("object", "objectId")
|
|
104
|
-
find_all(method, selector, { "objectId" => object_id })
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def window_handle
|
|
54
|
+
def current_window_handle
|
|
108
55
|
page.target_id
|
|
109
56
|
end
|
|
110
57
|
|
|
111
58
|
def window_handles
|
|
112
|
-
targets.
|
|
59
|
+
targets.values.select(&:page?).map(&:id)
|
|
113
60
|
end
|
|
114
61
|
|
|
115
|
-
def
|
|
116
|
-
|
|
117
|
-
raise Ferrum::NoSuchPageError unless window_handles.include?(locator)
|
|
118
|
-
|
|
119
|
-
switch_to_window(locator)
|
|
120
|
-
yield
|
|
121
|
-
ensure
|
|
122
|
-
switch_to_window(original)
|
|
62
|
+
def open_new_window
|
|
63
|
+
attach_page(default_context.create_target.id)
|
|
123
64
|
end
|
|
124
65
|
|
|
125
66
|
def switch_to_window(target_id)
|
|
126
|
-
target =
|
|
127
|
-
|
|
128
|
-
|
|
67
|
+
target = window_target(target_id)
|
|
68
|
+
forget_page
|
|
129
69
|
@page = attach_page(target.id)
|
|
130
70
|
@page.activate
|
|
131
71
|
end
|
|
132
72
|
|
|
133
73
|
def close_window(target_id)
|
|
134
|
-
target =
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
74
|
+
target = window_target(target_id)
|
|
75
|
+
if @page&.target_id == target.id
|
|
76
|
+
forget_page
|
|
77
|
+
@page_closed = true
|
|
78
|
+
end
|
|
138
79
|
target.page.close
|
|
139
80
|
targets.delete(target_id) # page.close is async, delete target asap
|
|
140
81
|
end
|
|
141
82
|
|
|
142
|
-
def active_element
|
|
143
|
-
evaluate("document.activeElement")
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def browser_error
|
|
147
|
-
evaluate("_cuprite.browserError()")
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def source
|
|
151
|
-
raise NotImplementedError
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def drag(node, other, drop_modifiers, options = {})
|
|
155
|
-
steps = options.fetch(:steps, 1)
|
|
156
|
-
delay = options[:delay]
|
|
157
|
-
scroll = options.fetch(:scroll, true)
|
|
158
|
-
html5 = options[:html5]
|
|
159
|
-
|
|
160
|
-
execute("_cuprite.dragMousedownTracker()")
|
|
161
|
-
|
|
162
|
-
node.scroll_into_view if scroll
|
|
163
|
-
x1, y1 = node.find_position
|
|
164
|
-
|
|
165
|
-
mouse.move(x: x1, y: y1)
|
|
166
|
-
mouse.down
|
|
167
|
-
sleep delay if delay
|
|
168
|
-
|
|
169
|
-
html5 = !evaluate_on(node: node, expression: "_cuprite.legacyDragCheck(this)") if html5.nil?
|
|
170
|
-
|
|
171
|
-
if html5
|
|
172
|
-
drag_html5(node, other, drop_modifiers, delay)
|
|
173
|
-
else
|
|
174
|
-
modifiers = keyboard.modifiers(drop_modifiers)
|
|
175
|
-
|
|
176
|
-
other.scroll_into_view if scroll
|
|
177
|
-
x2, y2 = other.find_position
|
|
178
|
-
mouse.move(x: x2, y: y2, steps: steps)
|
|
179
|
-
|
|
180
|
-
mouse.up(modifiers: modifiers)
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def drag_html5(node, other, drop_modifiers, delay)
|
|
185
|
-
keys = drop_modifiers.map(&:to_s)
|
|
186
|
-
evaluate_async(DRAG_HTML5_JS, timeout, node, other, (delay || 0.05) * 1000, keys)
|
|
187
|
-
mouse.up
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def drag_by(node, dx, dy, steps, delay = nil, scroll = true)
|
|
191
|
-
x1, y1 = node.find_position
|
|
192
|
-
|
|
193
|
-
mouse.move(x: x1, y: y1)
|
|
194
|
-
mouse.down
|
|
195
|
-
|
|
196
|
-
sleep delay if delay
|
|
197
|
-
|
|
198
|
-
evaluate("window.scrollBy(#{dx}, #{dy})") if scroll # should be extracted to Mouse#scroll_by in ferrum
|
|
199
|
-
|
|
200
|
-
x2, y2 = node.find_position
|
|
201
|
-
mouse.move(x: x2 + dx, y: y2 + dy, steps: steps)
|
|
202
|
-
mouse.up
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def drop(node, *args)
|
|
206
|
-
if args[0].is_a?(String)
|
|
207
|
-
execute("_cuprite.attachDropInput()")
|
|
208
|
-
input = find(:css, "#_cuprite_drop_file").first
|
|
209
|
-
select_file(input, args)
|
|
210
|
-
evaluate_on(node: node, expression: "_cuprite.dropFile(this)")
|
|
211
|
-
else
|
|
212
|
-
strings = args.flat_map { |arg| arg.map { |type, data| { "type" => type, "data" => data } } }
|
|
213
|
-
evaluate_on(node: node, expression: "_cuprite.dropString(#{strings.to_json}, this)")
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def select_file(node, value)
|
|
218
|
-
node.select_file(value)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def parents(node)
|
|
222
|
-
evaluate_on(node: node, expression: "_cuprite.parents(this)", by_value: false)
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def visible_text(node)
|
|
226
|
-
evaluate_on(node: node, expression: "_cuprite.visibleText(this)")
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def delete_text(node)
|
|
230
|
-
evaluate_on(node: node, expression: "_cuprite.deleteText(this)")
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def attributes(node)
|
|
234
|
-
value = evaluate_on(node: node, expression: "_cuprite.getAttributes(this)")
|
|
235
|
-
JSON.parse(value)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
def attribute(node, name)
|
|
239
|
-
evaluate_on(node: node, expression: %(_cuprite.getAttribute(this, "#{name}")))
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def value(node)
|
|
243
|
-
evaluate_on(node: node, expression: "_cuprite.value(this)")
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def visible?(node)
|
|
247
|
-
evaluate_on(node: node, expression: "_cuprite.isVisible(this)")
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def disabled?(node)
|
|
251
|
-
evaluate_on(node: node, expression: "_cuprite.isDisabled(this)")
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def path(node)
|
|
255
|
-
evaluate_on(node: node, expression: "_cuprite.path(this)")
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def obscured?(node)
|
|
259
|
-
evaluate_on(node: node, expression: "_cuprite.isObscured(this)")
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def all_text(node)
|
|
263
|
-
node.text
|
|
264
|
-
end
|
|
265
|
-
|
|
266
83
|
private
|
|
267
84
|
|
|
268
|
-
def
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
else
|
|
272
|
-
evaluate("_cuprite.find(arguments[0], arguments[1])", method, selector)
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
nodes.select(&:node?)
|
|
276
|
-
rescue Ferrum::JavaScriptError => e
|
|
277
|
-
raise InvalidSelector.new(e.response, method, selector) if e.class_name == "InvalidSelector"
|
|
278
|
-
|
|
279
|
-
raise
|
|
85
|
+
def forget_page
|
|
86
|
+
@page = nil
|
|
87
|
+
@page_closed = false
|
|
280
88
|
end
|
|
281
89
|
|
|
282
|
-
def
|
|
283
|
-
|
|
90
|
+
def window_target(target_id)
|
|
91
|
+
target = targets[target_id]
|
|
92
|
+
raise Ferrum::NoSuchPageError unless target&.page?
|
|
284
93
|
|
|
285
|
-
|
|
286
|
-
if pattern.is_a?(Regexp)
|
|
287
|
-
pattern
|
|
288
|
-
else
|
|
289
|
-
string_passed = true
|
|
290
|
-
pattern = pattern.gsub("*", ".*")
|
|
291
|
-
Regexp.new(pattern, Regexp::IGNORECASE)
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
ensure
|
|
295
|
-
if string_passed
|
|
296
|
-
warn "Passing strings to blacklist/whitelist is deprecated, pass regexp at #{caller(4..4).first}"
|
|
297
|
-
end
|
|
94
|
+
target
|
|
298
95
|
end
|
|
299
96
|
|
|
300
97
|
def attach_page(target_id = nil)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Capybara
|
|
4
|
+
module Cuprite
|
|
5
|
+
REMOVE_DEPRECATED_IN = "0.21"
|
|
6
|
+
|
|
7
|
+
def self.deprecation_warning(method, advice = nil)
|
|
8
|
+
message = "#{method} is deprecated and will be removed in #{REMOVE_DEPRECATED_IN}"
|
|
9
|
+
message += ", #{advice} instead" if advice
|
|
10
|
+
warn message, uplevel: 2
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|