cuprite 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +180 -0
- data/lib/capybara/cuprite.rb +5 -5
- data/lib/capybara/cuprite/browser.rb +5 -5
- data/lib/capybara/cuprite/browser/client.rb +1 -1
- data/lib/capybara/cuprite/browser/input.rb +13 -14
- data/lib/capybara/cuprite/browser/javascripts/index.js +35 -2
- data/lib/capybara/cuprite/browser/page.rb +8 -8
- data/lib/capybara/cuprite/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2931562eb83d217b25c93d8449b3a5e3c401e2ad64689a7b60c1de9b6abb8b5b
|
4
|
+
data.tar.gz: 5701e966d47d9dc45450b47dbb51ed56cd0ba94abe904573a2fc54bc04042210
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a348c4d493896c9ba2ba729a83741fd4ff8f52a6bead2486654a6c8ad90408780fec57ea2adcdeb7bc359516e4c768fb67b15fa0bdd862cbb314af4e6c462401
|
7
|
+
data.tar.gz: 6639dc96f4da906ce8f69657043e28de6d98f28e5cf0d7a71b8e0a3af7eca2ed94f3b931c539910b46ffabc147e54c8c0a847d8499df2efef30b4863e16ec93f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Machinio
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# Cuprite - Headless Chrome driver for Capybara #
|
2
|
+
|
3
|
+
Cuprite is a pure Ruby driver (read as _no_ Java/Selenium/WebDriver/ChromeDriver
|
4
|
+
requirement) for [Capybara](https://github.com/teamcapybara/capybara). It allows
|
5
|
+
you to run your Capybara tests on a headless [Chrome](https://www.google.com/chrome/)
|
6
|
+
or [Chromium](https://www.chromium.org/) browser while the latter is prefered
|
7
|
+
for now because we work with tip-of-tree [protocol](https://chromedevtools.github.io/devtools-protocol/).
|
8
|
+
|
9
|
+
The emphasis was made on raw CDP protocol because Headless Chrome allows you to
|
10
|
+
do so many cool things that are barely supported by WebDriver because it should
|
11
|
+
have consistent design with other browsers. The design of the driver will be as
|
12
|
+
close to [Poltergeist](https://github.com/teampoltergeist/poltergeist) as
|
13
|
+
possible but it's not a goal.
|
14
|
+
|
15
|
+
## Speed comparison and missing features ##
|
16
|
+
|
17
|
+
Almost all capybara tests are passing with quite good speed in comparison with
|
18
|
+
Poltergest/PhantomJS:
|
19
|
+
|
20
|
+
```
|
21
|
+
cuprite:
|
22
|
+
Finished in 4 minutes 15 seconds (files took 1.23 seconds to load)
|
23
|
+
1533 examples, 0 failures, 148 pending
|
24
|
+
|
25
|
+
poltergeist:
|
26
|
+
Finished in 7 minutes 6 seconds (files took 0.59349 seconds to load)
|
27
|
+
1560 examples, 0 failures, 6 pending
|
28
|
+
|
29
|
+
selenium headless chrome:
|
30
|
+
Finished in 9 minutes 3 seconds (files took 5.98 seconds to load)
|
31
|
+
1445 examples, 0 failures, 3 pending
|
32
|
+
```
|
33
|
+
|
34
|
+
## Installation ##
|
35
|
+
|
36
|
+
``` ruby
|
37
|
+
gem "cuprite"
|
38
|
+
```
|
39
|
+
and run `bundle install`.
|
40
|
+
|
41
|
+
In your test setup add:
|
42
|
+
|
43
|
+
``` ruby
|
44
|
+
require "capybara/cuprite"
|
45
|
+
Capybara.javascript_driver = :cuprite
|
46
|
+
```
|
47
|
+
|
48
|
+
If you were previously using the `:rack_test` driver, be aware that
|
49
|
+
your app will now run in a separate thread and this can have
|
50
|
+
consequences for transactional tests. [See the Capybara README for more detail](https://github.com/jnicklas/capybara/blob/master/README.md#transactions-and-database-setup).
|
51
|
+
|
52
|
+
## Installing Chromium ##
|
53
|
+
|
54
|
+
As Chromium is stopped being built as a package for Linux don't even try to
|
55
|
+
install it this way because it will either be outdated or unofficial package.
|
56
|
+
Both are bad. Download it from official [source](https://www.chromium.org/getting-involved/download-chromium).
|
57
|
+
|
58
|
+
## Supported features ##
|
59
|
+
|
60
|
+
All the mandatory capybara features plus optional ones:
|
61
|
+
|
62
|
+
* `page.evaluate_script` and `page.execute_script`
|
63
|
+
* `page.within_frame`
|
64
|
+
* `page.status_code`
|
65
|
+
* `page.response_headers`
|
66
|
+
* `page.save_screenshot`
|
67
|
+
* `page.driver.render_base64(format, options)`
|
68
|
+
* window API
|
69
|
+
* cookie handling
|
70
|
+
|
71
|
+
### Clicking coordinates ###
|
72
|
+
|
73
|
+
Sometimes its desirable to click a very specific area of the screen. You can
|
74
|
+
accomplish this with `page.driver.click(x, y)`, where x and y are the screen
|
75
|
+
coordinates.
|
76
|
+
|
77
|
+
### Manipulating request headers ###
|
78
|
+
|
79
|
+
Manipulate HTTP request headers like a boss:
|
80
|
+
|
81
|
+
``` ruby
|
82
|
+
page.driver.headers # => {}
|
83
|
+
page.driver.headers = { "User-Agent" => "Cuprite" }
|
84
|
+
page.driver.add_headers("Referer" => "https://example.com")
|
85
|
+
page.driver.headers # => { "User-Agent" => "Cuprite", "Referer" => "https://example.com" }
|
86
|
+
```
|
87
|
+
|
88
|
+
Notice that `headers=` will overwrite already set headers. You should use
|
89
|
+
`add_headers` if you want to add a few more. These headers will apply to all
|
90
|
+
subsequent HTTP requests (including requests for assets, AJAX, etc). They will
|
91
|
+
be automatically cleared at the end of the test.
|
92
|
+
|
93
|
+
### Inspecting network traffic ###
|
94
|
+
|
95
|
+
You can inspect the network traffic (i.e. what resources have been loaded) on
|
96
|
+
the current page by calling `page.driver.network_traffic`. This returns an array
|
97
|
+
of request objects. A request object has a `response` method containing data
|
98
|
+
about the response.
|
99
|
+
|
100
|
+
Please note that network traffic is not cleared when you visit new page. You can
|
101
|
+
manually clear the network traffic by calling `page.driver.clear_network_traffic`
|
102
|
+
or `page.driver.reset`
|
103
|
+
|
104
|
+
### Manipulating cookies ###
|
105
|
+
|
106
|
+
The following methods are used to inspect and manipulate cookies:
|
107
|
+
|
108
|
+
* `page.driver.cookies` - a hash of cookies accessible to the current
|
109
|
+
page. The keys are cookie names. The values are `Cookie` objects, with
|
110
|
+
the following methods: `name`, `value`, `domain`, `path`, `size`, `secure?`,
|
111
|
+
`httponly?`, `session?`, `expires`.
|
112
|
+
* `page.driver.set_cookie(name, value, options = {})` - set a cookie.
|
113
|
+
The options hash can take the following keys: `:domain`, `:path`,
|
114
|
+
`:secure`, `:httponly`, `:expires`. `:expires` should be a
|
115
|
+
`Time` object.
|
116
|
+
* `page.driver.remove_cookie(name)` - remove a cookie
|
117
|
+
* `page.driver.clear_cookies` - clear all cookies
|
118
|
+
|
119
|
+
## Customization ##
|
120
|
+
|
121
|
+
You can customize the way that Capybara sets up Cuprite via the following code
|
122
|
+
in your test setup:
|
123
|
+
|
124
|
+
``` ruby
|
125
|
+
Capybara.register_driver :cuprite do |app|
|
126
|
+
Capybara::Cuprite::Driver.new(app, options)
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
`options` is a hash of options. The following options are supported:
|
131
|
+
|
132
|
+
* `:browser` (Hash) - Hash of options to be passed to chrome process:
|
133
|
+
* `:path` (String) - Path to chrome binary, you can also set ENV variable as
|
134
|
+
`BROWSER_PATH=some/path/chrome bundle exec rspec`
|
135
|
+
* `:window_size` (Array) - The dimensions of the browser window in which to
|
136
|
+
test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
137
|
+
* `:port` (Integer) - Remote debugging port for headless Chrome
|
138
|
+
* `:host` (String) - Remote debugging address for headless Chrome
|
139
|
+
|
140
|
+
### URL Blacklisting & Whitelisting ###
|
141
|
+
Cuprite supports URL blacklisting, which allows you to prevent scripts from
|
142
|
+
running on designated domains:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
page.driver.browser.url_blacklist = ['http://www.example.com']
|
146
|
+
```
|
147
|
+
|
148
|
+
and also URL whitelisting, which allows scripts to only run
|
149
|
+
on designated domains:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
page.driver.browser.url_whitelist = ['http://www.example.com']
|
153
|
+
```
|
154
|
+
|
155
|
+
If you are experiencing slower run times, consider creating a URL whitelist of
|
156
|
+
domains that are essential or a blacklist of domains that are not essential,
|
157
|
+
such as ad networks or analytics, to your testing environment.
|
158
|
+
|
159
|
+
## License ##
|
160
|
+
|
161
|
+
Copyright 2018-2019 Machinio
|
162
|
+
|
163
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
164
|
+
a copy of this software and associated documentation files (the
|
165
|
+
"Software"), to deal in the Software without restriction, including
|
166
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
167
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
168
|
+
permit persons to whom the Software is furnished to do so, subject to
|
169
|
+
the following conditions:
|
170
|
+
|
171
|
+
The above copyright notice and this permission notice shall be
|
172
|
+
included in all copies or substantial portions of the Software.
|
173
|
+
|
174
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
175
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
176
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
177
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
178
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
179
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
180
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/capybara/cuprite.rb
CHANGED
@@ -6,11 +6,11 @@ Thread.abort_on_exception = true
|
|
6
6
|
Thread.report_on_exception = true
|
7
7
|
|
8
8
|
module Capybara::Cuprite
|
9
|
-
require "cuprite/driver"
|
10
|
-
require "cuprite/browser"
|
11
|
-
require "cuprite/node"
|
12
|
-
require "cuprite/errors"
|
13
|
-
require "cuprite/cookie"
|
9
|
+
require "capybara/cuprite/driver"
|
10
|
+
require "capybara/cuprite/browser"
|
11
|
+
require "capybara/cuprite/node"
|
12
|
+
require "capybara/cuprite/errors"
|
13
|
+
require "capybara/cuprite/cookie"
|
14
14
|
|
15
15
|
class << self
|
16
16
|
def windows?
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require "base64"
|
4
4
|
require "forwardable"
|
5
|
-
require "cuprite/browser/targets"
|
6
|
-
require "cuprite/browser/process"
|
7
|
-
require "cuprite/browser/client"
|
8
|
-
require "cuprite/browser/page"
|
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
9
|
|
10
10
|
module Capybara::Cuprite
|
11
11
|
class Browser
|
@@ -91,7 +91,7 @@ module Capybara::Cuprite
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def delete_text(node)
|
94
|
-
|
94
|
+
evaluate_on(node: node, expr: "_cuprite.deleteText(this)")
|
95
95
|
end
|
96
96
|
|
97
97
|
def select_file(node, value)
|
@@ -59,20 +59,19 @@ module Capybara::Cuprite
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def send_keys(node, keys)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
raise NotImplementedError
|
62
|
+
click(node) if !evaluate_on(node: node, expr: %(_cuprite.containsSelection(this)))
|
63
|
+
|
64
|
+
keys.first.each_char do |char|
|
65
|
+
# Check puppeteer Input.js and USKeyboardLayout.js also send_keys and modifiers from poltergeist.
|
66
|
+
if /\n/.match?(char)
|
67
|
+
command("Input.insertText", text: char)
|
68
|
+
# command("Input.dispatchKeyEvent", type: "keyDown", code: "Enter", key: "Enter", text: "\r")
|
69
|
+
# command("Input.dispatchKeyEvent", type: "keyUp", code: "Enter", key: "Enter")
|
70
|
+
else
|
71
|
+
command("Input.dispatchKeyEvent", type: "keyDown", text: char)
|
72
|
+
command("Input.dispatchKeyEvent", type: "keyUp", text: char)
|
73
|
+
end
|
74
|
+
end
|
76
75
|
end
|
77
76
|
|
78
77
|
private
|
@@ -122,8 +122,19 @@ class Cuprite {
|
|
122
122
|
this.trigger(node, "focus");
|
123
123
|
node.value = "";
|
124
124
|
|
125
|
-
if (node.type == "number") {
|
126
|
-
node.value = value
|
125
|
+
if (node.type == "number" || node.type == "date") {
|
126
|
+
node.value = value;
|
127
|
+
} else if (node.type == "time") {
|
128
|
+
node.value = new Date(value).toTimeString().split(" ")[0];
|
129
|
+
} else if (node.type == "datetime-local") {
|
130
|
+
value = new Date(value);
|
131
|
+
let year = value.getFullYear();
|
132
|
+
let month = ("0" + (value.getMonth() + 1)).slice(-2);
|
133
|
+
let date = ("0" + value.getDate()).slice(-2);
|
134
|
+
let hour = ("0" + value.getHours()).slice(-2);
|
135
|
+
let min = ("0" + value.getMinutes()).slice(-2);
|
136
|
+
let sec = ("0" + value.getSeconds()).slice(-2);
|
137
|
+
node.value = `${year}-${month}-${date}T${hour}:${min}:${sec}`;
|
127
138
|
} else {
|
128
139
|
for (let i = 0; i < value.length; i++) {
|
129
140
|
let char = value[i];
|
@@ -402,6 +413,28 @@ class Cuprite {
|
|
402
413
|
return node.value;
|
403
414
|
}
|
404
415
|
}
|
416
|
+
|
417
|
+
deleteText(node) {
|
418
|
+
let range = document.createRange();
|
419
|
+
range.selectNodeContents(node);
|
420
|
+
window.getSelection().removeAllRanges();
|
421
|
+
window.getSelection().addRange(range);
|
422
|
+
window.getSelection().deleteFromDocument();
|
423
|
+
}
|
424
|
+
|
425
|
+
containsSelection(node) {
|
426
|
+
let selectedNode = document.getSelection().focusNode;
|
427
|
+
|
428
|
+
if (!selectedNode) {
|
429
|
+
return false;
|
430
|
+
}
|
431
|
+
|
432
|
+
if (selectedNode.nodeType == 3) {
|
433
|
+
selectedNode = selectedNode.parentNode;
|
434
|
+
}
|
435
|
+
|
436
|
+
return node.contains(selectedNode);
|
437
|
+
}
|
405
438
|
}
|
406
439
|
|
407
440
|
window._cuprite = new Cuprite;
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "cuprite/browser/dom"
|
4
|
-
require "cuprite/browser/input"
|
5
|
-
require "cuprite/browser/runtime"
|
6
|
-
require "cuprite/browser/frame"
|
7
|
-
require "cuprite/browser/client"
|
8
|
-
require "cuprite/network/error"
|
9
|
-
require "cuprite/network/request"
|
10
|
-
require "cuprite/network/response"
|
3
|
+
require "capybara/cuprite/browser/dom"
|
4
|
+
require "capybara/cuprite/browser/input"
|
5
|
+
require "capybara/cuprite/browser/runtime"
|
6
|
+
require "capybara/cuprite/browser/frame"
|
7
|
+
require "capybara/cuprite/browser/client"
|
8
|
+
require "capybara/cuprite/network/error"
|
9
|
+
require "capybara/cuprite/network/request"
|
10
|
+
require "capybara/cuprite/network/response"
|
11
11
|
|
12
12
|
# RemoteObjectId is from a JavaScript world, and corresponds to any JavaScript
|
13
13
|
# object, including JS wrappers for DOM nodes. There is a way to convert between
|
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.2.
|
4
|
+
version: 0.2.1
|
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-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -184,6 +184,8 @@ executables: []
|
|
184
184
|
extensions: []
|
185
185
|
extra_rdoc_files: []
|
186
186
|
files:
|
187
|
+
- LICENSE
|
188
|
+
- README.md
|
187
189
|
- lib/capybara/cuprite.rb
|
188
190
|
- lib/capybara/cuprite/browser.rb
|
189
191
|
- lib/capybara/cuprite/browser/client.rb
|
@@ -211,12 +213,12 @@ metadata: {}
|
|
211
213
|
post_install_message:
|
212
214
|
rdoc_options: []
|
213
215
|
require_paths:
|
214
|
-
- lib
|
216
|
+
- lib
|
215
217
|
required_ruby_version: !ruby/object:Gem::Requirement
|
216
218
|
requirements:
|
217
219
|
- - ">="
|
218
220
|
- !ruby/object:Gem::Version
|
219
|
-
version:
|
221
|
+
version: 2.3.0
|
220
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
223
|
requirements:
|
222
224
|
- - ">="
|