cuprite 0.2.0 → 0.2.1
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 +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
|
- - ">="
|