cuprite 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +21 -15
- data/lib/capybara/cuprite/browser.rb +58 -31
- data/lib/capybara/cuprite/browser/input.rb +12 -3
- data/lib/capybara/cuprite/browser/javascripts/index.js +10 -1
- data/lib/capybara/cuprite/browser/page.rb +25 -5
- data/lib/capybara/cuprite/browser/process.rb +30 -16
- data/lib/capybara/cuprite/browser/runtime.rb +13 -2
- data/lib/capybara/cuprite/browser/targets.rb +8 -1
- data/lib/capybara/cuprite/driver.rb +13 -4
- data/lib/capybara/cuprite/node.rb +69 -1
- data/lib/capybara/cuprite/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d183c86ecad6aaaf681364bda5ee919e5952a2b3a8d55cad40b3a6cec57ff26f
|
4
|
+
data.tar.gz: cccf18bb4e24c66262a0a6302ea7611e3aa1897c9b2442c24cfbc0feedfb46b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '056827d707f4e8388aa2350b53791d060f7c30872d5930311606d750822483a667b5d74093e03217cfa3a342c4fe8cd5d5b766fd3155de9c5ff0c6da6b335a17'
|
7
|
+
data.tar.gz: 389f981e6ae4b3a06cc3babbb70b942b0e2a8844bee690fc508af111bab65b333777f7b330554d2ae0f43abae918e3395ff1ae306b17df015efe94eaebd8c0e8
|
data/README.md
CHANGED
@@ -5,8 +5,7 @@
|
|
5
5
|
Cuprite is a pure Ruby driver (read as _no_ Java/Selenium/WebDriver/ChromeDriver
|
6
6
|
requirement) for [Capybara](https://github.com/teamcapybara/capybara). It allows
|
7
7
|
you to run your Capybara tests on a headless [Chrome](https://www.google.com/chrome/)
|
8
|
-
or [Chromium](https://www.chromium.org/) browser
|
9
|
-
for now because we work with tip-of-tree [protocol](https://chromedevtools.github.io/devtools-protocol/).
|
8
|
+
or [Chromium](https://www.chromium.org/) browser by [CDP protocol](https://chromedevtools.github.io/devtools-protocol/).
|
10
9
|
|
11
10
|
The emphasis was made on raw CDP protocol because Headless Chrome allows you to
|
12
11
|
do so many cool things that are barely supported by WebDriver because it should
|
@@ -21,8 +20,8 @@ Poltergest/PhantomJS:
|
|
21
20
|
|
22
21
|
```
|
23
22
|
cuprite:
|
24
|
-
Finished in 8 minutes
|
25
|
-
|
23
|
+
Finished in 8 minutes 58 seconds (files took 0.89959 seconds to load)
|
24
|
+
1555 examples, 0 failures, 27 pending
|
26
25
|
|
27
26
|
selenium headless chrome:
|
28
27
|
Finished in 9 minutes 13 seconds (files took 0.97749 seconds to load)
|
@@ -39,11 +38,6 @@ Finished in 11 minutes 49 seconds (files took 0.54019 seconds to load)
|
|
39
38
|
gem "cuprite"
|
40
39
|
```
|
41
40
|
|
42
|
-
Though we recommend using github until we release 1.0:
|
43
|
-
``` ruby
|
44
|
-
gem "cuprite", github: "machinio/cuprite"
|
45
|
-
```
|
46
|
-
|
47
41
|
and run `bundle install`.
|
48
42
|
|
49
43
|
In your test setup add:
|
@@ -137,13 +131,25 @@ end
|
|
137
131
|
|
138
132
|
`options` is a hash of options. The following options are supported:
|
139
133
|
|
140
|
-
* `:
|
141
|
-
|
142
|
-
|
143
|
-
|
134
|
+
* `:browser_path` (String) - Path to chrome binary, you can also set ENV
|
135
|
+
variable as `BROWSER_PATH=some/path/chrome bundle exec rspec`.
|
136
|
+
* `:headless` (Boolean) - Set browser as headless or not, `true` by default.
|
137
|
+
* `:logger` (Object responding to `puts`) - When present, debug output is
|
138
|
+
written to this object.
|
139
|
+
* `:timeout` (Numeric) - The number of seconds we'll wait for a response when
|
140
|
+
communicating with browser. Default is 30.
|
141
|
+
* `:js_errors` (Boolean) - When true, JavaScript errors get re-raised in Ruby.
|
142
|
+
* `:window_size` (Array) - The dimensions of the browser window in which to
|
144
143
|
test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
145
|
-
|
146
|
-
|
144
|
+
* `:browser_options` (Hash) - Additional command line options,
|
145
|
+
[see them all](https://peter.sh/experiments/chromium-command-line-switches/)
|
146
|
+
e.g. `{ "ignore-certificate-errors" => nil }`
|
147
|
+
* `:extensions` (Array) - An array of JS files to be preloaded into the browser
|
148
|
+
* `:port` (Integer) - Remote debugging port for headless Chrome
|
149
|
+
* `:host` (String) - Remote debugging address for headless Chrome
|
150
|
+
* `:url_blacklist` (Array) - array of strings to match against requested URLs
|
151
|
+
* `:url_whitelist` (Array) - array of strings to match against requested URLs
|
152
|
+
|
147
153
|
|
148
154
|
### URL Blacklisting & Whitelisting ###
|
149
155
|
Cuprite supports URL blacklisting, which allows you to prevent scripts from
|
@@ -34,12 +34,13 @@ module Capybara::Cuprite
|
|
34
34
|
go_back go_forward find_modal accept_confirm dismiss_confirm
|
35
35
|
accept_prompt dismiss_prompt reset_modals) => :page
|
36
36
|
|
37
|
-
attr_reader :process, :logger
|
37
|
+
attr_reader :process, :logger, :js_errors
|
38
38
|
attr_writer :timeout
|
39
39
|
|
40
40
|
def initialize(options = nil)
|
41
41
|
@options = Hash(options)
|
42
42
|
@logger, @timeout = @options.values_at(:logger, :timeout)
|
43
|
+
@js_errors = @options.fetch(:js_errors, false)
|
43
44
|
|
44
45
|
if ENV["CUPRITE_DEBUG"]
|
45
46
|
STDOUT.sync = true
|
@@ -79,16 +80,7 @@ module Capybara::Cuprite
|
|
79
80
|
end
|
80
81
|
|
81
82
|
def visible_text(node)
|
82
|
-
|
83
|
-
evaluate_on(node: node, expr: "_cuprite.visibleText(this)")
|
84
|
-
rescue BrowserError => e
|
85
|
-
# FIXME: ObsoleteNode first arg is node, so it should be in node class
|
86
|
-
if e.message == "No node with given id found"
|
87
|
-
raise ObsoleteNode.new(self, e.response)
|
88
|
-
end
|
89
|
-
|
90
|
-
raise
|
91
|
-
end
|
83
|
+
evaluate_on(node: node, expr: "_cuprite.visibleText(this)")
|
92
84
|
end
|
93
85
|
|
94
86
|
def delete_text(node)
|
@@ -96,32 +88,36 @@ module Capybara::Cuprite
|
|
96
88
|
end
|
97
89
|
|
98
90
|
def select_file(node, value)
|
99
|
-
|
91
|
+
page.command("DOM.setFileInputFiles", nodeId: node["nodeId"], files: Array(value))
|
100
92
|
end
|
101
93
|
|
102
|
-
def render(path,
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
File.open(path.to_s, "wb") { |f| f.write(
|
94
|
+
def render(path, options = {})
|
95
|
+
format = options.delete(:format)
|
96
|
+
options = options.merge(path: path)
|
97
|
+
bin = Base64.decode64(render_base64(format, options))
|
98
|
+
File.open(path.to_s, "wb") { |f| f.write(bin) }
|
107
99
|
end
|
108
100
|
|
109
|
-
def render_base64(format
|
110
|
-
|
111
|
-
|
112
|
-
|
101
|
+
def render_base64(format, options = {})
|
102
|
+
options = render_options(format, options)
|
103
|
+
|
104
|
+
if options[:format].to_s == "pdf"
|
105
|
+
options = {}
|
106
|
+
options[:paperWidth] = @paper_size[:width].to_f if @paper_size
|
107
|
+
options[:paperHeight] = @paper_size[:height].to_f if @paper_size
|
108
|
+
options[:scale] = @zoom_factor if @zoom_factor
|
109
|
+
page.command("Page.printToPDF", **options)
|
110
|
+
else
|
111
|
+
page.command("Page.captureScreenshot", **options)
|
112
|
+
end.fetch("data")
|
113
113
|
end
|
114
114
|
|
115
115
|
def set_zoom_factor(zoom_factor)
|
116
|
-
|
116
|
+
@zoom_factor = zoom_factor.to_f
|
117
117
|
end
|
118
118
|
|
119
119
|
def set_paper_size(size)
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
def set_proxy(ip, port, type, user, password)
|
124
|
-
raise NotImplementedError
|
120
|
+
@paper_size = size
|
125
121
|
end
|
126
122
|
|
127
123
|
def headers=(headers)
|
@@ -198,6 +194,7 @@ module Capybara::Cuprite
|
|
198
194
|
|
199
195
|
def reset
|
200
196
|
@headers = {}
|
197
|
+
@zoom_factor = nil
|
201
198
|
targets.reset
|
202
199
|
end
|
203
200
|
|
@@ -216,6 +213,10 @@ module Capybara::Cuprite
|
|
216
213
|
command("Browser.crash")
|
217
214
|
end
|
218
215
|
|
216
|
+
def browser_error
|
217
|
+
page.evaluate("_cuprite.browserError()")
|
218
|
+
end
|
219
|
+
|
219
220
|
def command(*args)
|
220
221
|
id = @client.command(*args)
|
221
222
|
@client.wait(id: id)
|
@@ -236,10 +237,36 @@ module Capybara::Cuprite
|
|
236
237
|
@client = Client.new(self, @process.ws_url)
|
237
238
|
end
|
238
239
|
|
239
|
-
def
|
240
|
-
|
241
|
-
|
242
|
-
|
240
|
+
def render_options(format, opts)
|
241
|
+
options = {}
|
242
|
+
|
243
|
+
format ||= File.extname(opts[:path]).delete(".") || "png"
|
244
|
+
format = "jpeg" if format == "jpg"
|
245
|
+
raise "Not supported format: #{format}. jpeg | png | pdf" if format !~ /jpeg|png|pdf/i
|
246
|
+
options.merge!(format: format)
|
247
|
+
|
248
|
+
options.merge!(quality: opts[:quality] ? opts[:quality] : 75) if format == "jpeg"
|
249
|
+
|
250
|
+
warn "Ignoring :selector in #render since full: true was given at #{caller(1..1).first}" if !!opts[:full] && opts[:selector]
|
251
|
+
|
252
|
+
if !!opts[:full]
|
253
|
+
width, height = page.evaluate("[document.documentElement.offsetWidth, document.documentElement.offsetHeight]")
|
254
|
+
options.merge!(clip: { x: 0, y: 0, width: width, height: height, scale: @zoom_factor || 1.0 }) if width > 0 && height > 0
|
255
|
+
elsif opts[:selector]
|
256
|
+
rect = page.evaluate("document.querySelector('#{opts[:selector]}').getBoundingClientRect()")
|
257
|
+
options.merge!(clip: { x: rect["x"], y: rect["y"], width: rect["width"], height: rect["height"], scale: @zoom_factor || 1.0 })
|
258
|
+
end
|
259
|
+
|
260
|
+
if @zoom_factor
|
261
|
+
if !options[:clip]
|
262
|
+
width, height = page.evaluate("[document.documentElement.clientWidth, document.documentElement.clientHeight]")
|
263
|
+
options[:clip] = { x: 0, y: 0, width: width, height: height }
|
264
|
+
end
|
265
|
+
|
266
|
+
options[:clip].merge!(scale: @zoom_factor)
|
267
|
+
end
|
268
|
+
|
269
|
+
options
|
243
270
|
end
|
244
271
|
|
245
272
|
def find_all(method, selector, within = nil)
|
@@ -75,8 +75,8 @@ module Capybara::Cuprite
|
|
75
75
|
evaluate_on(node: node, expr: %(_cuprite.trigger(this, "#{event}")), **options)
|
76
76
|
end
|
77
77
|
|
78
|
-
def scroll_to(
|
79
|
-
|
78
|
+
def scroll_to(top, left)
|
79
|
+
execute("window.scrollTo(#{top}, #{left})")
|
80
80
|
end
|
81
81
|
|
82
82
|
def send_keys(node, keys)
|
@@ -171,7 +171,16 @@ module Capybara::Cuprite
|
|
171
171
|
end
|
172
172
|
|
173
173
|
def get_content_quads(node)
|
174
|
-
|
174
|
+
begin
|
175
|
+
result = command("DOM.getContentQuads", nodeId: node["nodeId"])
|
176
|
+
rescue BrowserError => e
|
177
|
+
if e.message == "Could not compute content quads."
|
178
|
+
raise MouseEventFailed.new("MouseEventFailed: click, none, 0, 0")
|
179
|
+
else
|
180
|
+
raise
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
175
184
|
raise "Node is either not visible or not an HTMLElement" if result["quads"].size == 0
|
176
185
|
|
177
186
|
# FIXME: Case when a few quads returned
|
@@ -24,7 +24,7 @@ class Cuprite {
|
|
24
24
|
results.push(xpath.snapshotItem(i));
|
25
25
|
}
|
26
26
|
} else {
|
27
|
-
results = within.querySelectorAll(selector);
|
27
|
+
results = Array.from(within.querySelectorAll(selector));
|
28
28
|
}
|
29
29
|
|
30
30
|
return results;
|
@@ -441,6 +441,10 @@ class Cuprite {
|
|
441
441
|
}
|
442
442
|
|
443
443
|
isCyclic(object) {
|
444
|
+
if (Array.isArray(object) && object.every(n => n instanceof Node)) {
|
445
|
+
return false;
|
446
|
+
}
|
447
|
+
|
444
448
|
try {
|
445
449
|
this._json.stringify(object);
|
446
450
|
return false;
|
@@ -448,6 +452,11 @@ class Cuprite {
|
|
448
452
|
return true;
|
449
453
|
}
|
450
454
|
}
|
455
|
+
|
456
|
+
// This command is purely for testing error handling
|
457
|
+
browserError() {
|
458
|
+
throw new Error("zomg");
|
459
|
+
}
|
451
460
|
}
|
452
461
|
|
453
462
|
window._cuprite = new Cuprite;
|
@@ -90,11 +90,17 @@ module Capybara::Cuprite
|
|
90
90
|
@client.close
|
91
91
|
end
|
92
92
|
|
93
|
-
def resize(width, height)
|
93
|
+
def resize(width: nil, height: nil, fullscreen: false)
|
94
94
|
result = @browser.command("Browser.getWindowForTarget", targetId: @target_id)
|
95
95
|
@window_id, @bounds = result.values_at("windowId", "bounds")
|
96
|
-
|
97
|
-
|
96
|
+
|
97
|
+
if fullscreen
|
98
|
+
@browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { windowState: "fullscreen" })
|
99
|
+
else
|
100
|
+
@browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { windowState: "normal" })
|
101
|
+
@browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { width: width, height: height, windowState: "normal" })
|
102
|
+
command("Emulation.setDeviceMetricsOverride", width: width, height: height, deviceScaleFactor: 1, mobile: false)
|
103
|
+
end
|
98
104
|
end
|
99
105
|
|
100
106
|
def refresh
|
@@ -182,7 +188,7 @@ module Capybara::Cuprite
|
|
182
188
|
@wait = 0
|
183
189
|
end
|
184
190
|
|
185
|
-
|
191
|
+
@client.wait(id: id)
|
186
192
|
end
|
187
193
|
|
188
194
|
private
|
@@ -196,16 +202,27 @@ module Capybara::Cuprite
|
|
196
202
|
end
|
197
203
|
end
|
198
204
|
|
205
|
+
if @browser.js_errors
|
206
|
+
@client.subscribe("Runtime.exceptionThrown") do |params|
|
207
|
+
Thread.main.raise JavaScriptError.new(params.dig("exceptionDetails", "exception"))
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
199
211
|
@client.subscribe("Page.javascriptDialogOpening") do |params|
|
200
212
|
accept_modal = @accept_modal.last
|
201
213
|
if accept_modal == true || accept_modal == false
|
202
214
|
@accept_modal.pop
|
203
215
|
@modal_messages << params["message"]
|
204
216
|
options = { accept: accept_modal }
|
205
|
-
default = params["defaultPrompt"]
|
206
217
|
response = @modal_response || params["defaultPrompt"]
|
207
218
|
options.merge!(promptText: response) if response
|
208
219
|
@client.command("Page.handleJavaScriptDialog", **options)
|
220
|
+
else
|
221
|
+
warn "Modal window has been opened, but you didn't wrap your code into (`accept_prompt` | `dismiss_prompt` | `accept_confirm` | `dismiss_confirm` | `accept_alert`), accepting by default"
|
222
|
+
options = { accept: true }
|
223
|
+
response = params["defaultPrompt"]
|
224
|
+
options.merge!(promptText: response) if response
|
225
|
+
@client.command("Page.handleJavaScriptDialog", **options)
|
209
226
|
end
|
210
227
|
end
|
211
228
|
|
@@ -280,6 +297,9 @@ module Capybara::Cuprite
|
|
280
297
|
command("Runtime.enable")
|
281
298
|
command("Log.enable")
|
282
299
|
command("Network.enable")
|
300
|
+
if Capybara.save_path
|
301
|
+
command("Page.setDownloadBehavior", behavior: "allow", downloadPath: Capybara.save_path)
|
302
|
+
end
|
283
303
|
|
284
304
|
@browser.extensions.each do |extension|
|
285
305
|
@client.command("Page.addScriptToEvaluateOnNewDocument", source: extension)
|
@@ -53,20 +53,27 @@ module Capybara::Cuprite
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def initialize(options)
|
56
|
-
@options =
|
56
|
+
@options = {}
|
57
57
|
|
58
|
-
detect_browser_path
|
58
|
+
detect_browser_path(options)
|
59
59
|
|
60
60
|
window_size = options.fetch(:window_size, [1024, 768])
|
61
|
-
@options
|
61
|
+
@options.merge!("window-size" => window_size.join(","))
|
62
62
|
|
63
63
|
port = options.fetch(:port, BROWSER_PORT)
|
64
|
-
@options
|
64
|
+
@options.merge!("remote-debugging-port" => port)
|
65
65
|
|
66
66
|
host = options.fetch(:host, BROWSER_HOST)
|
67
|
-
@options
|
67
|
+
@options.merge!("remote-debugging-address" => host)
|
68
68
|
|
69
69
|
@options = DEFAULT_OPTIONS.merge(@options)
|
70
|
+
|
71
|
+
unless options.fetch(:headless, true)
|
72
|
+
@options.delete("headless")
|
73
|
+
@options.delete("disable-gpu")
|
74
|
+
end
|
75
|
+
|
76
|
+
@options.merge!(options.fetch(:browser_options, {}))
|
70
77
|
end
|
71
78
|
|
72
79
|
def start
|
@@ -99,15 +106,24 @@ module Capybara::Cuprite
|
|
99
106
|
start
|
100
107
|
end
|
101
108
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
private
|
110
|
+
|
111
|
+
def detect_browser_path(options)
|
112
|
+
@path =
|
113
|
+
options[:browser_path] ||
|
114
|
+
BROWSER_PATH || (
|
115
|
+
if RUBY_PLATFORM.include?('darwin')
|
116
|
+
[
|
117
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
118
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
119
|
+
].find { |path| File.exist?(path) }
|
120
|
+
else
|
121
|
+
%w[chromium google-chrome-unstable google-chrome-beta google-chrome chrome].reduce(nil) do |path, exe|
|
122
|
+
path = Cliver.detect(exe)
|
123
|
+
break path if path
|
124
|
+
end
|
125
|
+
end
|
126
|
+
)
|
111
127
|
|
112
128
|
unless @path
|
113
129
|
message = "Could not find an executable `#{exe}`. Try to make it " \
|
@@ -117,8 +133,6 @@ module Capybara::Cuprite
|
|
117
133
|
end
|
118
134
|
end
|
119
135
|
|
120
|
-
private
|
121
|
-
|
122
136
|
def redirect_stdout(write_io)
|
123
137
|
if Capybara::Cuprite.mri?
|
124
138
|
yield
|
@@ -76,8 +76,19 @@ module Capybara::Cuprite
|
|
76
76
|
options = options.merge(executionContextId: execution_context_id)
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
|
-
|
79
|
+
begin
|
80
|
+
attempts ||= 1
|
81
|
+
response = command("Runtime.callFunctionOn", **options)
|
82
|
+
response.dig("result").tap { |r| handle_error(r) }
|
83
|
+
rescue BrowserError => e
|
84
|
+
case e.message
|
85
|
+
when "No node with given id found", "Could not find node with given id", "Cannot find context with specified id"
|
86
|
+
sleep 0.1
|
87
|
+
attempts += 1
|
88
|
+
options = options.merge(executionContextId: execution_context_id)
|
89
|
+
retry if attempts <= 3
|
90
|
+
end
|
91
|
+
end
|
81
92
|
end
|
82
93
|
|
83
94
|
# FIXME: We should have a central place to handle all type of errors
|
@@ -107,7 +107,14 @@ module Capybara::Cuprite
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def targets
|
110
|
-
|
110
|
+
attempts ||= 1
|
111
|
+
# Targets cannot be empty the must be at least one default target.
|
112
|
+
targets = @browser.command("Target.getTargets")["targetInfos"]
|
113
|
+
raise TypeError if targets.empty?
|
114
|
+
targets
|
115
|
+
rescue TypeError
|
116
|
+
attempts += 1
|
117
|
+
retry if attempts < 3
|
111
118
|
end
|
112
119
|
|
113
120
|
def default?(target)
|
@@ -14,7 +14,7 @@ module Capybara::Cuprite
|
|
14
14
|
|
15
15
|
def initialize(app, options = {})
|
16
16
|
@app = app
|
17
|
-
@options = options
|
17
|
+
@options = options
|
18
18
|
@started = false
|
19
19
|
end
|
20
20
|
|
@@ -152,7 +152,7 @@ module Capybara::Cuprite
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def resize(width, height)
|
155
|
-
browser.resize(width, height)
|
155
|
+
browser.resize(width: width, height: height)
|
156
156
|
end
|
157
157
|
alias_method :resize_window, :resize
|
158
158
|
|
@@ -172,6 +172,12 @@ module Capybara::Cuprite
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
+
def fullscreen_window(handle)
|
176
|
+
within_window(handle) do
|
177
|
+
browser.resize(fullscreen: true)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
175
181
|
def scroll_to(left, top)
|
176
182
|
browser.scroll_to(left, top)
|
177
183
|
end
|
@@ -184,8 +190,11 @@ module Capybara::Cuprite
|
|
184
190
|
browser.clear_network_traffic
|
185
191
|
end
|
186
192
|
|
187
|
-
|
188
|
-
|
193
|
+
# FIXME: check user/pass proxy auth
|
194
|
+
def set_proxy(ip, port, type = "http", user = nil, password = nil, bypass = nil)
|
195
|
+
@options[:browser] ||= {}
|
196
|
+
@options[:browser].merge!("proxy-server" => "#{type}=#{ip}:#{port}")
|
197
|
+
@options[:browser].merge!("proxy-bypass-list" => bypass) if bypass
|
189
198
|
end
|
190
199
|
|
191
200
|
def headers
|
@@ -17,7 +17,7 @@ module Capybara::Cuprite
|
|
17
17
|
browser.send(name, @node, *args)
|
18
18
|
rescue BrowserError => e
|
19
19
|
case e.message
|
20
|
-
when "
|
20
|
+
when "No node with given id found"
|
21
21
|
raise ObsoleteNode.new(self, e.response)
|
22
22
|
when "Cuprite.MouseEventFailed"
|
23
23
|
raise MouseEventFailed.new(self, e.response)
|
@@ -168,6 +168,29 @@ module Capybara::Cuprite
|
|
168
168
|
command(:trigger, event)
|
169
169
|
end
|
170
170
|
|
171
|
+
def scroll_to(element, location, position = nil)
|
172
|
+
if element.is_a?(Node)
|
173
|
+
scroll_element_to_location(element, location)
|
174
|
+
elsif location.is_a?(Symbol)
|
175
|
+
scroll_to_location(location)
|
176
|
+
else
|
177
|
+
scroll_to_coords(*position)
|
178
|
+
end
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
def scroll_by(x, y)
|
183
|
+
driver.execute_script <<~JS, self, x, y
|
184
|
+
var el = arguments[0];
|
185
|
+
if (el.scrollBy){
|
186
|
+
el.scrollBy(arguments[1], arguments[2]);
|
187
|
+
} else {
|
188
|
+
el.scrollTop = el.scrollTop + arguments[2];
|
189
|
+
el.scrollLeft = el.scrollLeft + arguments[1];
|
190
|
+
}
|
191
|
+
JS
|
192
|
+
end
|
193
|
+
|
171
194
|
def ==(other)
|
172
195
|
# We compare backendNodeId because once nodeId is sent to frontend backend
|
173
196
|
# never returns same nodeId sending 0. In other words frontend is
|
@@ -212,5 +235,50 @@ module Capybara::Cuprite
|
|
212
235
|
.tr("\u00a0", " ")
|
213
236
|
end
|
214
237
|
end
|
238
|
+
|
239
|
+
def scroll_element_to_location(element, location)
|
240
|
+
scroll_opts = case location
|
241
|
+
when :top
|
242
|
+
'true'
|
243
|
+
when :bottom
|
244
|
+
'false'
|
245
|
+
when :center
|
246
|
+
"{behavior: 'instant', block: 'center'}"
|
247
|
+
else
|
248
|
+
raise ArgumentError, "Invalid scroll_to location: #{location}"
|
249
|
+
end
|
250
|
+
driver.execute_script <<~JS, element
|
251
|
+
arguments[0].scrollIntoView(#{scroll_opts})
|
252
|
+
JS
|
253
|
+
end
|
254
|
+
|
255
|
+
def scroll_to_location(location)
|
256
|
+
scroll_y = case location
|
257
|
+
when :top
|
258
|
+
'0'
|
259
|
+
when :bottom
|
260
|
+
'arguments[0].scrollHeight'
|
261
|
+
when :center
|
262
|
+
'(arguments[0].scrollHeight - arguments[0].clientHeight)/2'
|
263
|
+
end
|
264
|
+
driver.execute_script <<~JS, self
|
265
|
+
if (arguments[0].scrollTo){
|
266
|
+
arguments[0].scrollTo(0, #{scroll_y});
|
267
|
+
} else {
|
268
|
+
arguments[0].scrollTop = #{scroll_y};
|
269
|
+
}
|
270
|
+
JS
|
271
|
+
end
|
272
|
+
|
273
|
+
def scroll_to_coords(x, y)
|
274
|
+
driver.execute_script <<~JS, self, x, y
|
275
|
+
if (arguments[0].scrollTo){
|
276
|
+
arguments[0].scrollTo(arguments[1], arguments[2]);
|
277
|
+
} else {
|
278
|
+
arguments[0].scrollTop = arguments[2];
|
279
|
+
arguments[0].scrollLeft = arguments[1];
|
280
|
+
}
|
281
|
+
JS
|
282
|
+
end
|
215
283
|
end
|
216
284
|
end
|
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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Vorotilin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -176,6 +176,20 @@ dependencies:
|
|
176
176
|
- - "~>"
|
177
177
|
- !ruby/object:Gem::Version
|
178
178
|
version: '3.0'
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: chunky_png
|
181
|
+
requirement: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - "~>"
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '1.3'
|
186
|
+
type: :development
|
187
|
+
prerelease: false
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - "~>"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '1.3'
|
179
193
|
description: Cuprite is a driver for Capybara that allows you to run your tests on
|
180
194
|
a headless Chrome browser
|
181
195
|
email:
|