cuprite 0.6.0 → 0.7.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 +103 -67
- data/lib/capybara/cuprite.rb +8 -21
- data/lib/capybara/cuprite/browser.rb +66 -224
- data/lib/capybara/cuprite/driver.rb +87 -44
- data/lib/capybara/cuprite/errors.rb +1 -64
- data/lib/capybara/cuprite/{browser/javascripts → javascripts}/index.js +26 -20
- data/lib/capybara/cuprite/node.rb +37 -31
- data/lib/capybara/cuprite/page.rb +166 -0
- data/lib/capybara/cuprite/version.rb +1 -1
- metadata +8 -42
- data/lib/capybara/cuprite/browser/client.rb +0 -74
- data/lib/capybara/cuprite/browser/dom.rb +0 -50
- data/lib/capybara/cuprite/browser/frame.rb +0 -115
- data/lib/capybara/cuprite/browser/input.json +0 -1341
- data/lib/capybara/cuprite/browser/input.rb +0 -200
- data/lib/capybara/cuprite/browser/net.rb +0 -90
- data/lib/capybara/cuprite/browser/page.rb +0 -378
- data/lib/capybara/cuprite/browser/process.rb +0 -223
- data/lib/capybara/cuprite/browser/runtime.rb +0 -182
- data/lib/capybara/cuprite/browser/targets.rb +0 -129
- data/lib/capybara/cuprite/browser/web_socket.rb +0 -69
- data/lib/capybara/cuprite/network/error.rb +0 -25
- data/lib/capybara/cuprite/network/request.rb +0 -33
- data/lib/capybara/cuprite/network/response.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07b0203f3647868b796a4649f28e2ed0a549412156e08a3ef50e83625acaca11
|
4
|
+
data.tar.gz: 9854d6126698f53691c30b04c9a8677f24091c76720227ceb474101dab06a475
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fe300cdefbb2a2c7d09d37329ab7a31dcf2d7cda9177ffafc91bdec2923fabf24c933f6894e5e959bdb6218e03ac9211afedb7ae588ae97f87d7142fb249e7c
|
7
|
+
data.tar.gz: ede07bd3d885c5e711a80a6698d10ad28d855d7b6917f10ebc2cfe0153fde5af261ef553cdee62ad3a6cabdacfee659e12d13b95ebc8c2470d4d4b33772ad5be
|
data/README.md
CHANGED
@@ -5,59 +5,97 @@
|
|
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/)
|
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.
|
9
11
|
|
10
12
|
The emphasis was made on raw CDP protocol because Headless Chrome allows you to
|
11
|
-
do so many
|
12
|
-
|
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
|
13
15
|
close to [Poltergeist](https://github.com/teampoltergeist/poltergeist) as
|
14
|
-
possible
|
16
|
+
possible though it's not a goal.
|
15
17
|
|
16
|
-
##
|
18
|
+
## Install ##
|
19
|
+
|
20
|
+
Add these lines to your `Gemfile` and run `bundle install`.
|
17
21
|
|
18
22
|
``` ruby
|
19
|
-
gem "cuprite"
|
23
|
+
gem "cuprite", group: :test
|
20
24
|
```
|
21
25
|
|
22
|
-
and run `bundle install`.
|
23
|
-
|
24
26
|
In your test setup add:
|
25
27
|
|
26
28
|
``` ruby
|
27
29
|
require "capybara/cuprite"
|
28
30
|
Capybara.javascript_driver = :cuprite
|
31
|
+
Capybara.register_driver(:cuprite) do |app|
|
32
|
+
Capybara::Cuprite::Driver.new(app, window_size: [1200, 800])
|
33
|
+
end
|
29
34
|
```
|
30
35
|
|
31
|
-
|
36
|
+
If you already had tests on Poltergeist then it should simply work, for Selenium
|
37
|
+
you better check your code for `.manage` calls because things are much easier
|
38
|
+
with Cuprite, see the documentation below.
|
32
39
|
|
33
|
-
|
34
|
-
install it this way because it will either be outdated or unofficial package.
|
35
|
-
Both are bad. Download it from official [source](https://www.chromium.org/getting-involved/download-chromium).
|
40
|
+
## Install Chrome ##
|
36
41
|
|
37
|
-
|
42
|
+
There's no official Chrome or Chromium package for Linux don't install it this
|
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
|
38
47
|
|
39
|
-
|
48
|
+
## Customization ##
|
40
49
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
* `page.driver.basic_authorize(user, password)`
|
49
|
-
* `element.send_keys(*keys)`
|
50
|
-
* `page.driver.set_proxy(ip, port, type, user, password)`
|
51
|
-
* window API
|
52
|
-
* cookie handling
|
50
|
+
You can customize options with the following code in your test setup:
|
51
|
+
|
52
|
+
``` ruby
|
53
|
+
Capybara.register_driver(:cuprite) do |app|
|
54
|
+
Capybara::Cuprite::Driver.new(app, options)
|
55
|
+
end
|
56
|
+
```
|
53
57
|
|
54
|
-
|
58
|
+
#### Running in Docker ####
|
55
59
|
|
56
|
-
|
57
|
-
accomplish this with `page.driver.click(x, y)`, where x and y are the screen
|
58
|
-
coordinates.
|
60
|
+
In docker as root you must pass the no-sandbox browser option:
|
59
61
|
|
60
|
-
|
62
|
+
```ruby
|
63
|
+
Capybara::Cuprite::Driver.new(app, browser_options: { 'no-sandbox': nil })
|
64
|
+
```
|
65
|
+
|
66
|
+
* options `Hash`
|
67
|
+
* `:browser_path` (String) - Path to chrome binary, you can also set ENV
|
68
|
+
variable as `BROWSER_PATH=some/path/chrome bundle exec rspec`.
|
69
|
+
* `:headless` (Boolean) - Set browser as headless or not, `true` by default.
|
70
|
+
* `:slowmo` (Integer | Float) - Set a delay to wait before sending command.
|
71
|
+
Usefull companion of headless option, so that you have time to see changes.
|
72
|
+
* `:logger` (Object responding to `puts`) - When present, debug output is
|
73
|
+
written to this object.
|
74
|
+
* `:timeout` (Numeric) - The number of seconds we'll wait for a response when
|
75
|
+
communicating with browser. Default is 5.
|
76
|
+
* `:js_errors` (Boolean) - When true, JavaScript errors get re-raised in Ruby.
|
77
|
+
* `:window_size` (Array) - The dimensions of the browser window in which to
|
78
|
+
test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
79
|
+
* `:browser_options` (Hash) - Additional command line options,
|
80
|
+
[see them all](https://peter.sh/experiments/chromium-command-line-switches/)
|
81
|
+
e.g. `{ "ignore-certificate-errors" => nil }`
|
82
|
+
* `:extensions` (Array) - An array of JS files to be preloaded into the browser
|
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
|
91
|
+
|
92
|
+
### Clicking/Scrolling ###
|
93
|
+
|
94
|
+
* `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.
|
97
|
+
|
98
|
+
### Request headers ###
|
61
99
|
|
62
100
|
Manipulate HTTP request headers like a boss:
|
63
101
|
|
@@ -73,12 +111,17 @@ Notice that `headers=` will overwrite already set headers. You should use
|
|
73
111
|
subsequent HTTP requests (including requests for assets, AJAX, etc). They will
|
74
112
|
be automatically cleared at the end of the test.
|
75
113
|
|
76
|
-
###
|
114
|
+
### Network traffic ###
|
115
|
+
|
116
|
+
* `page.driver.network_traffic` Inspect network traffic (resources have been
|
117
|
+
loaded) on the current page. This returns an array of request objects.
|
77
118
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
page.driver.network_traffic # => [Request, ...]
|
122
|
+
request = page.driver.network_traffic.first
|
123
|
+
request.response
|
124
|
+
```
|
82
125
|
|
83
126
|
Please note that network traffic is not cleared when you visit new page. You can
|
84
127
|
manually clear the network traffic by calling `page.driver.clear_network_traffic`
|
@@ -99,41 +142,16 @@ The following methods are used to inspect and manipulate cookies:
|
|
99
142
|
* `page.driver.remove_cookie(name)` - remove a cookie
|
100
143
|
* `page.driver.clear_cookies` - clear all cookies
|
101
144
|
|
102
|
-
|
145
|
+
### Screenshot ###
|
103
146
|
|
104
|
-
|
105
|
-
in your test setup:
|
147
|
+
Besides capybara screenshot method you can get image as Base64:
|
106
148
|
|
107
|
-
|
108
|
-
Capybara.register_driver :cuprite do |app|
|
109
|
-
Capybara::Cuprite::Driver.new(app, options)
|
110
|
-
end
|
111
|
-
```
|
149
|
+
* `page.driver.render_base64(format, options)`
|
112
150
|
|
113
|
-
|
114
|
-
|
115
|
-
* `:browser_path` (String) - Path to chrome binary, you can also set ENV
|
116
|
-
variable as `BROWSER_PATH=some/path/chrome bundle exec rspec`.
|
117
|
-
* `:headless` (Boolean) - Set browser as headless or not, `true` by default.
|
118
|
-
* `:slowmo` (Integer | Float) - Set a delay to wait before sending command.
|
119
|
-
Usefull companion of headless option, so that you have time to see changes.
|
120
|
-
* `:logger` (Object responding to `puts`) - When present, debug output is
|
121
|
-
written to this object.
|
122
|
-
* `:timeout` (Numeric) - The number of seconds we'll wait for a response when
|
123
|
-
communicating with browser. Default is 30.
|
124
|
-
* `:js_errors` (Boolean) - When true, JavaScript errors get re-raised in Ruby.
|
125
|
-
* `:window_size` (Array) - The dimensions of the browser window in which to
|
126
|
-
test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
127
|
-
* `:browser_options` (Hash) - Additional command line options,
|
128
|
-
[see them all](https://peter.sh/experiments/chromium-command-line-switches/)
|
129
|
-
e.g. `{ "ignore-certificate-errors" => nil }`
|
130
|
-
* `:extensions` (Array) - An array of JS files to be preloaded into the browser
|
131
|
-
* `:port` (Integer) - Remote debugging port for headless Chrome
|
132
|
-
* `:host` (String) - Remote debugging address for headless Chrome
|
133
|
-
* `:url_blacklist` (Array) - array of strings to match against requested URLs
|
134
|
-
* `:url_whitelist` (Array) - array of strings to match against requested URLs
|
135
|
-
* `:process_timeout` (Integer) - How long to wait for the Chrome process to respond on startup
|
151
|
+
### Authorization ###
|
136
152
|
|
153
|
+
* `page.driver.basic_authorize(user, password)`
|
154
|
+
* `page.driver.set_proxy(ip, port, type, user, password)`
|
137
155
|
|
138
156
|
### URL Blacklisting & Whitelisting ###
|
139
157
|
Cuprite supports URL blacklisting, which allows you to prevent scripts from
|
@@ -154,6 +172,24 @@ If you are experiencing slower run times, consider creating a URL whitelist of
|
|
154
172
|
domains that are essential or a blacklist of domains that are not essential,
|
155
173
|
such as ad networks or analytics, to your testing environment.
|
156
174
|
|
175
|
+
### Remote debugging ###
|
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 can register this debugger driver with a different name and set it
|
183
|
+
as the current javascript driver. By example, in your helper file:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
Capybara.register_driver :cuprite_debug do |app|
|
187
|
+
Capybara::Cuprite::Driver.new(app, inspector: true)
|
188
|
+
end
|
189
|
+
|
190
|
+
Capybara.javascript_driver = :cuprite_debug
|
191
|
+
```
|
192
|
+
|
157
193
|
## License ##
|
158
194
|
|
159
195
|
Copyright 2018-2019 Machinio
|
data/lib/capybara/cuprite.rb
CHANGED
@@ -1,31 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ferrum"
|
3
4
|
require "capybara"
|
4
5
|
|
5
|
-
Thread.abort_on_exception = true
|
6
|
-
Thread.report_on_exception = true if Thread.respond_to?(:report_on_exception=)
|
7
|
-
|
8
6
|
module Capybara::Cuprite
|
9
|
-
|
10
|
-
require "capybara/cuprite/browser"
|
11
|
-
require "capybara/cuprite/node"
|
12
|
-
require "capybara/cuprite/errors"
|
13
|
-
require "capybara/cuprite/cookie"
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def windows?
|
17
|
-
RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/
|
18
|
-
end
|
7
|
+
end
|
19
8
|
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
require "capybara/cuprite/driver"
|
10
|
+
require "capybara/cuprite/browser"
|
11
|
+
require "capybara/cuprite/page"
|
12
|
+
require "capybara/cuprite/node"
|
13
|
+
require "capybara/cuprite/errors"
|
23
14
|
|
24
|
-
|
25
|
-
defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
15
|
+
Ferrum::Page.prepend(Capybara::Cuprite::Page)
|
29
16
|
|
30
17
|
Capybara.register_driver(:cuprite) do |app|
|
31
18
|
Capybara::Cuprite::Driver.new(app)
|
@@ -1,301 +1,143 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "base64"
|
4
3
|
require "forwardable"
|
5
|
-
require "capybara/cuprite/browser/targets"
|
6
|
-
require "capybara/cuprite/browser/process"
|
7
|
-
require "capybara/cuprite/browser/client"
|
8
|
-
require "capybara/cuprite/browser/page"
|
9
4
|
|
10
5
|
module Capybara::Cuprite
|
11
|
-
class Browser
|
12
|
-
TIMEOUT = 5
|
13
|
-
WINDOW_SIZE = [1024, 768].freeze
|
14
|
-
EXTENSIONS = [
|
15
|
-
File.expand_path("browser/javascripts/index.js", __dir__)
|
16
|
-
].freeze
|
17
|
-
|
6
|
+
class Browser < Ferrum::Browser
|
18
7
|
extend Forwardable
|
19
8
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
9
|
+
delegate %i[find_or_create_page] => :targets
|
10
|
+
delegate %i[send_keys select set hover trigger before_click switch_to_frame
|
11
|
+
find_modal accept_confirm dismiss_confirm accept_prompt
|
12
|
+
dismiss_prompt reset_modals] => :page
|
25
13
|
|
26
|
-
|
27
|
-
delegate %i(window_handle window_handles switch_to_window open_new_window
|
28
|
-
close_window within_window page) => :targets
|
29
|
-
delegate %i(visit status_code body all_text property attributes attribute
|
30
|
-
value visible? disabled? network_traffic clear_network_traffic
|
31
|
-
path response_headers refresh click right_click double_click
|
32
|
-
hover set click_coordinates drag drag_by select trigger
|
33
|
-
scroll_to send_keys evaluate evaluate_on evaluate_async execute
|
34
|
-
frame_url frame_title switch_to_frame current_url title go_back
|
35
|
-
go_forward find_modal accept_confirm dismiss_confirm
|
36
|
-
accept_prompt dismiss_prompt reset_modals authorize
|
37
|
-
proxy_authorize) => :page
|
38
|
-
|
39
|
-
attr_reader :process, :logger, :js_errors, :slowmo,
|
40
|
-
:url_blacklist, :url_whitelist
|
41
|
-
attr_writer :timeout
|
14
|
+
attr_reader :url_blacklist, :url_whitelist
|
42
15
|
|
43
16
|
def initialize(options = nil)
|
44
|
-
# Doesn't work on MacOS, so we need to set it by CDP as well
|
45
17
|
options ||= {}
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@options = Hash(options.merge(window_size: @window_size))
|
50
|
-
@logger, @timeout = @options.values_at(:logger, :timeout)
|
51
|
-
@js_errors = @options.fetch(:js_errors, false)
|
52
|
-
@slowmo = @options[:slowmo]
|
53
|
-
|
54
|
-
self.url_blacklist = @options[:url_blacklist]
|
55
|
-
self.url_whitelist = @options[:url_whitelist]
|
56
|
-
|
57
|
-
if ENV["CUPRITE_DEBUG"] && !@logger
|
58
|
-
STDOUT.sync = true
|
59
|
-
@logger = STDOUT
|
60
|
-
@options[:logger] = @logger
|
61
|
-
end
|
62
|
-
|
63
|
-
@options.freeze
|
18
|
+
self.url_blacklist = options[:url_blacklist]
|
19
|
+
self.url_whitelist = options[:url_whitelist]
|
64
20
|
|
65
|
-
|
21
|
+
super
|
66
22
|
end
|
67
23
|
|
68
|
-
def
|
69
|
-
@
|
70
|
-
|
71
|
-
(EXTENSIONS + exts).map { |p| File.read(p) }
|
72
|
-
end
|
24
|
+
def url_whitelist=(patterns)
|
25
|
+
@url_whitelist = prepare_wildcards(patterns)
|
26
|
+
page.intercept_request if @client && !@url_whitelist.empty?
|
73
27
|
end
|
74
28
|
|
75
|
-
def
|
76
|
-
@
|
29
|
+
def url_blacklist=(patterns)
|
30
|
+
@url_blacklist = prepare_wildcards(patterns)
|
31
|
+
page.intercept_request if @client && !@url_blacklist.empty?
|
77
32
|
end
|
78
33
|
|
79
|
-
def
|
80
|
-
|
34
|
+
def visit(*args)
|
35
|
+
goto(*args)
|
81
36
|
end
|
82
37
|
|
83
|
-
def
|
84
|
-
|
38
|
+
def status_code
|
39
|
+
status
|
85
40
|
end
|
86
41
|
|
87
42
|
def find(method, selector)
|
88
43
|
find_all(method, selector)
|
89
44
|
end
|
90
45
|
|
46
|
+
def property(node, name)
|
47
|
+
node.property(name)
|
48
|
+
end
|
49
|
+
|
91
50
|
def find_within(node, method, selector)
|
92
|
-
resolved = page.command("DOM.resolveNode", nodeId: node
|
51
|
+
resolved = page.command("DOM.resolveNode", nodeId: node.node_id)
|
93
52
|
object_id = resolved.dig("object", "objectId")
|
94
53
|
find_all(method, selector, { "objectId" => object_id })
|
95
54
|
end
|
96
55
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
def select_file(node, value)
|
106
|
-
page.command("DOM.setFileInputFiles", nodeId: node["nodeId"], files: Array(value))
|
107
|
-
end
|
108
|
-
|
109
|
-
def render(path, options = {})
|
110
|
-
format = options.delete(:format)
|
111
|
-
options = options.merge(path: path)
|
112
|
-
bin = Base64.decode64(render_base64(format, options))
|
113
|
-
File.open(path.to_s, "wb") { |f| f.write(bin) }
|
114
|
-
end
|
115
|
-
|
116
|
-
def render_base64(format, options = {})
|
117
|
-
options = render_options(format, options)
|
118
|
-
|
119
|
-
if options[:format].to_s == "pdf"
|
120
|
-
options = {}
|
121
|
-
options[:paperWidth] = @paper_size[:width].to_f if @paper_size
|
122
|
-
options[:paperHeight] = @paper_size[:height].to_f if @paper_size
|
123
|
-
options[:scale] = @zoom_factor if @zoom_factor
|
124
|
-
page.command("Page.printToPDF", **options)
|
125
|
-
else
|
126
|
-
page.command("Page.captureScreenshot", **options)
|
127
|
-
end.fetch("data")
|
128
|
-
end
|
129
|
-
|
130
|
-
def set_zoom_factor(zoom_factor)
|
131
|
-
@zoom_factor = zoom_factor.to_f
|
132
|
-
end
|
133
|
-
|
134
|
-
def set_paper_size(size)
|
135
|
-
@paper_size = size
|
136
|
-
end
|
137
|
-
|
138
|
-
def headers=(headers)
|
139
|
-
@headers = {}
|
140
|
-
add_headers(headers)
|
141
|
-
end
|
142
|
-
|
143
|
-
def add_headers(headers, permanent: true)
|
144
|
-
if headers["Referer"]
|
145
|
-
page.referrer = headers["Referer"]
|
146
|
-
headers.delete("Referer") unless permanent
|
56
|
+
def within_window(locator = nil, &block)
|
57
|
+
if Capybara::VERSION.to_f < 3.0
|
58
|
+
target_id = window_handles.find do |target_id|
|
59
|
+
page = find_or_create_page(target_id)
|
60
|
+
locator == page.frame_name
|
61
|
+
end
|
62
|
+
locator = target_id if target_id
|
147
63
|
end
|
148
64
|
|
149
|
-
|
150
|
-
user_agent = @headers["User-Agent"]
|
151
|
-
accept_language = @headers["Accept-Language"]
|
152
|
-
|
153
|
-
set_overrides(user_agent: user_agent, accept_language: accept_language)
|
154
|
-
page.command("Network.setExtraHTTPHeaders", headers: @headers)
|
155
|
-
end
|
156
|
-
|
157
|
-
def add_header(header, permanent: true)
|
158
|
-
add_headers(header, permanent: permanent)
|
159
|
-
end
|
160
|
-
|
161
|
-
def set_overrides(user_agent: nil, accept_language: nil, platform: nil)
|
162
|
-
options = Hash.new
|
163
|
-
options[:userAgent] = user_agent if user_agent
|
164
|
-
options[:acceptLanguage] = accept_language if accept_language
|
165
|
-
options[:platform] if platform
|
166
|
-
|
167
|
-
page.command("Network.setUserAgentOverride", **options) if !options.empty?
|
65
|
+
targets.within_window(locator, &block)
|
168
66
|
end
|
169
67
|
|
170
|
-
def
|
171
|
-
|
172
|
-
cookies.map { |c| [c["name"], Cookie.new(c)] }.to_h
|
68
|
+
def browser_error
|
69
|
+
evaluate("_cuprite.browserError()")
|
173
70
|
end
|
174
71
|
|
175
|
-
def
|
176
|
-
|
72
|
+
def source
|
73
|
+
raise NotImplementedError
|
177
74
|
end
|
178
75
|
|
179
|
-
def
|
180
|
-
|
76
|
+
def drag(node, other)
|
77
|
+
raise NotImplementedError
|
181
78
|
end
|
182
79
|
|
183
|
-
def
|
184
|
-
|
80
|
+
def drag_by(node, x, y)
|
81
|
+
raise NotImplementedError
|
185
82
|
end
|
186
83
|
|
187
|
-
def
|
188
|
-
|
189
|
-
page.intercept_request("*") if @client && !@url_whitelist.empty?
|
84
|
+
def select_file(node, value)
|
85
|
+
node.select_file(value)
|
190
86
|
end
|
191
87
|
|
192
|
-
def
|
193
|
-
|
194
|
-
page.intercept_request("*") if @client && !@url_blacklist.empty?
|
88
|
+
def parents(node)
|
89
|
+
evaluate_on(node: node, expression: "_cuprite.parents(this)", by_value: false)
|
195
90
|
end
|
196
91
|
|
197
|
-
def
|
198
|
-
|
92
|
+
def visible_text(node)
|
93
|
+
evaluate_on(node: node, expression: "_cuprite.visibleText(this)")
|
199
94
|
end
|
200
95
|
|
201
|
-
def
|
202
|
-
|
203
|
-
@zoom_factor = nil
|
204
|
-
@window_size = @original_window_size
|
205
|
-
targets.reset
|
96
|
+
def delete_text(node)
|
97
|
+
evaluate_on(node: node, expression: "_cuprite.deleteText(this)")
|
206
98
|
end
|
207
99
|
|
208
|
-
def
|
209
|
-
|
210
|
-
|
100
|
+
def attributes(node)
|
101
|
+
value = evaluate_on(node: node, expression: "_cuprite.getAttributes(this)")
|
102
|
+
JSON.parse(value)
|
211
103
|
end
|
212
104
|
|
213
|
-
def
|
214
|
-
|
215
|
-
@process.stop
|
216
|
-
@client = @process = @targets = nil
|
105
|
+
def attribute(node, name)
|
106
|
+
evaluate_on(node: node, expression: %Q(_cuprite.getAttribute(this, "#{name}")))
|
217
107
|
end
|
218
108
|
|
219
|
-
def
|
220
|
-
|
109
|
+
def value(node)
|
110
|
+
evaluate_on(node: node, expression: "_cuprite.value(this)")
|
221
111
|
end
|
222
112
|
|
223
|
-
def
|
224
|
-
|
113
|
+
def visible?(node)
|
114
|
+
evaluate_on(node: node, expression: "_cuprite.isVisible(this)")
|
225
115
|
end
|
226
116
|
|
227
|
-
def
|
228
|
-
|
229
|
-
page.resize(**options)
|
117
|
+
def disabled?(node)
|
118
|
+
evaluate_on(node: node, expression: "_cuprite.isDisabled(this)")
|
230
119
|
end
|
231
120
|
|
232
|
-
def
|
233
|
-
|
234
|
-
@client.wait(id: id)
|
235
|
-
rescue DeadBrowser
|
236
|
-
restart
|
237
|
-
raise
|
121
|
+
def path(node)
|
122
|
+
evaluate_on(node: node, expression: "_cuprite.path(this)")
|
238
123
|
end
|
239
124
|
|
240
|
-
def
|
241
|
-
|
125
|
+
def all_text(node)
|
126
|
+
node.text
|
242
127
|
end
|
243
128
|
|
244
129
|
private
|
245
130
|
|
246
|
-
def start
|
247
|
-
@headers = {}
|
248
|
-
@process = Process.start(@options)
|
249
|
-
@client = Client.new(self, @process.ws_url, false)
|
250
|
-
end
|
251
|
-
|
252
|
-
def render_options(format, opts)
|
253
|
-
options = {}
|
254
|
-
|
255
|
-
format ||= File.extname(opts[:path]).delete(".") || "png"
|
256
|
-
format = "jpeg" if format == "jpg"
|
257
|
-
raise "Not supported format: #{format}. jpeg | png | pdf" if format !~ /jpeg|png|pdf/i
|
258
|
-
options.merge!(format: format)
|
259
|
-
|
260
|
-
options.merge!(quality: opts[:quality] ? opts[:quality] : 75) if format == "jpeg"
|
261
|
-
|
262
|
-
warn "Ignoring :selector in #render since full: true was given at #{caller(1..1).first}" if !!opts[:full] && opts[:selector]
|
263
|
-
|
264
|
-
if !!opts[:full]
|
265
|
-
width, height = page.evaluate("[document.documentElement.offsetWidth, document.documentElement.offsetHeight]")
|
266
|
-
options.merge!(clip: { x: 0, y: 0, width: width, height: height, scale: @zoom_factor || 1.0 }) if width > 0 && height > 0
|
267
|
-
elsif opts[:selector]
|
268
|
-
rect = page.evaluate("document.querySelector('#{opts[:selector]}').getBoundingClientRect()")
|
269
|
-
options.merge!(clip: { x: rect["x"], y: rect["y"], width: rect["width"], height: rect["height"], scale: @zoom_factor || 1.0 })
|
270
|
-
end
|
271
|
-
|
272
|
-
if @zoom_factor
|
273
|
-
if !options[:clip]
|
274
|
-
width, height = page.evaluate("[document.documentElement.clientWidth, document.documentElement.clientHeight]")
|
275
|
-
options[:clip] = { x: 0, y: 0, width: width, height: height }
|
276
|
-
end
|
277
|
-
|
278
|
-
options[:clip].merge!(scale: @zoom_factor)
|
279
|
-
end
|
280
|
-
|
281
|
-
options
|
282
|
-
end
|
283
|
-
|
284
131
|
def find_all(method, selector, within = nil)
|
285
132
|
begin
|
286
|
-
|
133
|
+
nodes = if within
|
287
134
|
evaluate("_cuprite.find(arguments[0], arguments[1], arguments[2])", method, selector, within)
|
288
135
|
else
|
289
136
|
evaluate("_cuprite.find(arguments[0], arguments[1])", method, selector)
|
290
137
|
end
|
291
138
|
|
292
|
-
|
293
|
-
|
294
|
-
target_id, node = element.values_at("target_id", "node")
|
295
|
-
next if node["nodeType"] != 1
|
296
|
-
within ? node : [target_id, node]
|
297
|
-
end.compact
|
298
|
-
rescue JavaScriptError => e
|
139
|
+
nodes.map { |n| n.node? ? n : next }.compact
|
140
|
+
rescue Ferrum::JavaScriptError => e
|
299
141
|
if e.class_name == "InvalidSelector"
|
300
142
|
raise InvalidSelector.new(e.response, method, selector)
|
301
143
|
end
|