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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b3d43410a4b7875e111108b5ef1b53bf07589f833925ea3a9e336d725d99b95
4
- data.tar.gz: 6cea0c2abdef1b5d8f8b6468f2924dac1cbbe5b51f1a4b6ce74bb980a86278ab
3
+ metadata.gz: 2931562eb83d217b25c93d8449b3a5e3c401e2ad64689a7b60c1de9b6abb8b5b
4
+ data.tar.gz: 5701e966d47d9dc45450b47dbb51ed56cd0ba94abe904573a2fc54bc04042210
5
5
  SHA512:
6
- metadata.gz: cd77da4241673d610343e552245f5e0421ee6fe8613cc437bd53d0e8bd3d63be8b422a4abf36fcfedf35d79bbed0b7db5fe26250e5b86f737ac4479c6e02281e
7
- data.tar.gz: cd86413a1b47478e4b0545c28c5ba0ea54a592d889ef0420547d2192bfdac7bece55e9557d88d48cca0720a8d86562dbe281b0988e1234fc55a25d7fc44484c1
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.
@@ -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.
@@ -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
- raise NotImplementedError
94
+ evaluate_on(node: node, expr: "_cuprite.deleteText(this)")
95
95
  end
96
96
 
97
97
  def select_file(node, value)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "timeout"
4
- require "cuprite/browser/web_socket"
4
+ require "capybara/cuprite/browser/web_socket"
5
5
 
6
6
  module Capybara::Cuprite
7
7
  class Browser
@@ -59,20 +59,19 @@ module Capybara::Cuprite
59
59
  end
60
60
 
61
61
  def send_keys(node, keys)
62
- # value.each_char do |char|
63
- # # Check puppeteer Input.js and USKeyboardLayout.js
64
- # # also send_keys and modifiers from capybara API and unify all that.
65
- # if /\n/.match?(char)
66
- # command("Input.insertText", text: char)
67
- # # command("Input.dispatchKeyEvent", type: "keyDown", code: "Enter", key: "Enter", text: "\r")
68
- # # command("Input.dispatchKeyEvent", type: "keyUp", code: "Enter", key: "Enter")
69
- # else
70
- # command("Input.dispatchKeyEvent", type: "keyDown", text: char)
71
- # command("Input.dispatchKeyEvent", type: "keyUp", text: char)
72
- # end
73
- # end
74
- # command "send_keys", node, normalize_keys(keys)
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Cuprite
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.1"
6
6
  end
7
7
  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.2.0
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-15 00:00:00.000000000 Z
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/capybara
216
+ - lib
215
217
  required_ruby_version: !ruby/object:Gem::Requirement
216
218
  requirements:
217
219
  - - ">="
218
220
  - !ruby/object:Gem::Version
219
- version: '0'
221
+ version: 2.3.0
220
222
  required_rubygems_version: !ruby/object:Gem::Requirement
221
223
  requirements:
222
224
  - - ">="