cuprite 0.15 → 0.15.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/README.md +4 -7
- data/lib/capybara/cuprite/browser.rb +44 -24
- data/lib/capybara/cuprite/driver.rb +21 -3
- data/lib/capybara/cuprite/javascripts/index.js +21 -7
- data/lib/capybara/cuprite/node.rb +2 -2
- data/lib/capybara/cuprite/options.rb +14 -0
- data/lib/capybara/cuprite/page.rb +20 -7
- data/lib/capybara/cuprite/version.rb +1 -1
- data/lib/capybara/cuprite.rb +3 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78b7dde58d02147e2985473da0a7527d338ff086e4a4aaf0fd9302e5faf3ee11
|
4
|
+
data.tar.gz: 777726c6161975950df923a305b0bdb9da54b5531b7a5339ed0d4beaf264beb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04e88a47d9d2d2df68ad11dca8224f6d24001340b1743f538e6fdb64e818381037da7987b9db25284336b469c986d9d9e883192743749c4c6cad6c43adc160a1
|
7
|
+
data.tar.gz: a059dae9790af13c8a56999d6d76d5920e863e217b346a721a4051f0cc786e295a35c0e574c00e425b87e2d0c7a8b140c991183ab3246d1678566318745c9ecf
|
data/README.md
CHANGED
@@ -4,9 +4,7 @@ Cuprite is a pure Ruby driver (read as _no_ Selenium/WebDriver/ChromeDriver
|
|
4
4
|
dependency) for [Capybara](https://github.com/teamcapybara/capybara). It allows
|
5
5
|
you to run Capybara tests on a headless Chrome or Chromium. Under the hood it
|
6
6
|
uses [Ferrum](https://github.com/rubycdp/ferrum#index) which is high-level API
|
7
|
-
to the browser by CDP protocol.
|
8
|
-
[Poltergeist](https://github.com/teampoltergeist/poltergeist) as possible though
|
9
|
-
it's not a goal.
|
7
|
+
to the browser by CDP protocol.
|
10
8
|
|
11
9
|
|
12
10
|
## Install
|
@@ -43,8 +41,7 @@ browser = page.driver.browser
|
|
43
41
|
browser.mouse.move(x: 123, y: 456).down.up
|
44
42
|
```
|
45
43
|
|
46
|
-
|
47
|
-
Selenium you better check your code for `manage` calls because it works
|
44
|
+
For Selenium you better check your code for `manage` calls because it works
|
48
45
|
differently in Cuprite, see the documentation below.
|
49
46
|
|
50
47
|
|
@@ -64,8 +61,8 @@ end
|
|
64
61
|
`Cuprite`-specific options are:
|
65
62
|
|
66
63
|
* options `Hash`
|
67
|
-
* `:url_blacklist` (Array) - array of
|
68
|
-
* `:url_whitelist` (Array) - array of
|
64
|
+
* `:url_blacklist` (Array) - array of regexes to match against requested URLs
|
65
|
+
* `:url_whitelist` (Array) - array of regexes to match against requested URLs
|
69
66
|
|
70
67
|
|
71
68
|
## Debugging
|
@@ -11,50 +11,63 @@ module Capybara
|
|
11
11
|
find_modal accept_confirm dismiss_confirm accept_prompt
|
12
12
|
dismiss_prompt reset_modals] => :page
|
13
13
|
|
14
|
-
attr_reader :url_blacklist, :url_whitelist
|
15
|
-
alias url_blocklist url_blacklist
|
16
|
-
alias url_allowlist url_whitelist
|
17
|
-
|
18
14
|
def initialize(options = nil)
|
19
|
-
options ||= {}
|
20
|
-
@client = nil
|
21
|
-
self.url_blacklist = options[:url_blacklist]
|
22
|
-
self.url_whitelist = options[:url_whitelist]
|
23
|
-
|
24
15
|
super
|
25
|
-
|
16
|
+
|
17
|
+
@options.url_blacklist = prepare_wildcards(options&.dig(:url_blacklist))
|
18
|
+
@options.url_whitelist = prepare_wildcards(options&.dig(:url_whitelist))
|
19
|
+
|
20
|
+
@page = nil
|
26
21
|
end
|
27
22
|
|
28
|
-
def
|
23
|
+
def command(...)
|
29
24
|
super
|
30
|
-
|
25
|
+
rescue Ferrum::DeadBrowserError
|
26
|
+
restart
|
27
|
+
raise
|
31
28
|
end
|
32
29
|
|
33
30
|
def page
|
34
|
-
raise Ferrum::NoSuchPageError if @page
|
31
|
+
raise Ferrum::NoSuchPageError if @page&.closed?
|
35
32
|
|
36
33
|
@page ||= attach_page
|
37
34
|
end
|
38
35
|
|
39
36
|
def reset
|
40
37
|
super
|
41
|
-
@
|
38
|
+
@options.reset_window_size
|
39
|
+
@page = nil
|
42
40
|
end
|
43
41
|
|
44
42
|
def quit
|
45
43
|
super
|
46
|
-
@page =
|
44
|
+
@page = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def resize(**options)
|
48
|
+
@options.window_size = [options[:width], options[:height]]
|
49
|
+
super
|
47
50
|
end
|
48
51
|
|
52
|
+
def url_whitelist
|
53
|
+
@options.url_whitelist
|
54
|
+
end
|
55
|
+
alias url_allowlist url_whitelist
|
56
|
+
|
49
57
|
def url_whitelist=(patterns)
|
50
|
-
@url_whitelist = prepare_wildcards(patterns)
|
51
|
-
page.network.whitelist = @url_whitelist if @client && @url_whitelist.any?
|
58
|
+
@options.url_whitelist = prepare_wildcards(patterns)
|
59
|
+
page.network.whitelist = @options.url_whitelist if @client && @options.url_whitelist.any?
|
52
60
|
end
|
53
61
|
alias url_allowlist= url_whitelist=
|
54
62
|
|
63
|
+
def url_blacklist
|
64
|
+
@options.url_blacklist
|
65
|
+
end
|
66
|
+
alias url_blocklist url_blacklist
|
67
|
+
|
55
68
|
def url_blacklist=(patterns)
|
56
|
-
@url_blacklist = prepare_wildcards(patterns)
|
57
|
-
page.network.blacklist = @url_blacklist if @client && @url_blacklist.any?
|
69
|
+
@options.url_blacklist = prepare_wildcards(patterns)
|
70
|
+
page.network.blacklist = @options.url_blacklist if @client && @options.url_blacklist.any?
|
58
71
|
end
|
59
72
|
alias url_blocklist= url_blacklist=
|
60
73
|
|
@@ -109,8 +122,13 @@ module Capybara
|
|
109
122
|
target = targets[target_id]
|
110
123
|
raise Ferrum::NoSuchPageError unless target
|
111
124
|
|
112
|
-
@page =
|
125
|
+
@page = ClosedPage.new if @page.target_id == target.id
|
113
126
|
target.page.close
|
127
|
+
targets.delete(target_id) # page.close is async, delete target asap
|
128
|
+
end
|
129
|
+
|
130
|
+
def active_element
|
131
|
+
evaluate("document.activeElement")
|
114
132
|
end
|
115
133
|
|
116
134
|
def browser_error
|
@@ -121,23 +139,25 @@ module Capybara
|
|
121
139
|
raise NotImplementedError
|
122
140
|
end
|
123
141
|
|
124
|
-
def drag(node, other, steps)
|
142
|
+
def drag(node, other, steps, delay = nil)
|
125
143
|
x1, y1 = node.find_position
|
126
144
|
x2, y2 = other.find_position
|
127
145
|
|
128
146
|
mouse.move(x: x1, y: y1)
|
129
147
|
mouse.down
|
148
|
+
sleep delay if delay
|
130
149
|
mouse.move(x: x2, y: y2, steps: steps)
|
131
150
|
mouse.up
|
132
151
|
end
|
133
152
|
|
134
|
-
def drag_by(node, x, y, steps)
|
153
|
+
def drag_by(node, x, y, steps, delay = nil)
|
135
154
|
x1, y1 = node.find_position
|
136
155
|
x2 = x1 + x
|
137
156
|
y2 = y1 + y
|
138
157
|
|
139
158
|
mouse.move(x: x1, y: y1)
|
140
159
|
mouse.down
|
160
|
+
sleep delay if delay
|
141
161
|
mouse.move(x: x2, y: y2, steps: steps)
|
142
162
|
mouse.up
|
143
163
|
end
|
@@ -224,10 +244,10 @@ module Capybara
|
|
224
244
|
def attach_page(target_id = nil)
|
225
245
|
target = targets[target_id] if target_id
|
226
246
|
target ||= default_context.default_target
|
227
|
-
return target.page if target.
|
247
|
+
return target.page if target.connected?
|
228
248
|
|
229
249
|
target.maybe_sleep_if_new_window
|
230
|
-
target.page = Page.new(target.
|
250
|
+
target.page = Page.new(target.client, context_id: target.context_id, target_id: target.id)
|
231
251
|
target.page
|
232
252
|
end
|
233
253
|
end
|
@@ -15,6 +15,7 @@ module Capybara
|
|
15
15
|
delegate %i[restart quit status_code timeout timeout= current_url title body
|
16
16
|
window_handles close_window switch_to_window within_window window_handle
|
17
17
|
back forward refresh wait_for_reload viewport_size device_pixel_ratio] => :browser
|
18
|
+
delegate %i[send_keys] => :active_element
|
18
19
|
alias html body
|
19
20
|
alias current_window_handle window_handle
|
20
21
|
alias go_back back
|
@@ -34,7 +35,11 @@ module Capybara
|
|
34
35
|
@screen_size ||= DEFAULT_MAXIMIZE_SCREEN_SIZE
|
35
36
|
@options[:save_path] ||= File.expand_path(Capybara.save_path) if Capybara.save_path
|
36
37
|
|
37
|
-
|
38
|
+
# It's set for debug() to make devtools tab open correctly.
|
39
|
+
@options[:browser_options] ||= {}
|
40
|
+
unless @options[:browser_options][:"remote-allow-origins"]
|
41
|
+
@options[:browser_options].merge!("remote-allow-origins": "*")
|
42
|
+
end
|
38
43
|
|
39
44
|
super()
|
40
45
|
end
|
@@ -64,6 +69,10 @@ module Capybara
|
|
64
69
|
evaluate_script("document.title")
|
65
70
|
end
|
66
71
|
|
72
|
+
def active_element
|
73
|
+
Node.new(self, browser.active_element)
|
74
|
+
end
|
75
|
+
|
67
76
|
def find_xpath(selector)
|
68
77
|
find(:xpath, selector)
|
69
78
|
end
|
@@ -109,7 +118,7 @@ module Capybara
|
|
109
118
|
def open_new_window
|
110
119
|
target = browser.default_context.create_target
|
111
120
|
target.maybe_sleep_if_new_window
|
112
|
-
target.page = Page.new(target.
|
121
|
+
target.page = Page.new(target.client, context_id: target.context_id, target_id: target.id)
|
113
122
|
target.page
|
114
123
|
end
|
115
124
|
|
@@ -265,7 +274,12 @@ module Capybara
|
|
265
274
|
alias authorize basic_authorize
|
266
275
|
|
267
276
|
def debug_url
|
268
|
-
|
277
|
+
response = JSON.parse(Net::HTTP.get(URI(build_remote_debug_url(path: "/json"))))
|
278
|
+
|
279
|
+
devtools_frontend_path = response[0]&.[]("devtoolsFrontendUrl")
|
280
|
+
raise "Could not generate debug url for remote debugging session" unless devtools_frontend_path
|
281
|
+
|
282
|
+
build_remote_debug_url(path: devtools_frontend_path)
|
269
283
|
end
|
270
284
|
|
271
285
|
def debug(binding = nil)
|
@@ -363,6 +377,10 @@ module Capybara
|
|
363
377
|
|
364
378
|
private
|
365
379
|
|
380
|
+
def build_remote_debug_url(path:)
|
381
|
+
"http://#{browser.process.host}:#{browser.process.port}#{path}"
|
382
|
+
end
|
383
|
+
|
366
384
|
def default_domain
|
367
385
|
if @started
|
368
386
|
URI.parse(browser.current_url).host
|
@@ -84,7 +84,6 @@ class Cuprite {
|
|
84
84
|
return true;
|
85
85
|
}
|
86
86
|
|
87
|
-
|
88
87
|
isDisabled(node) {
|
89
88
|
let xpath = "parent::optgroup[@disabled] | \
|
90
89
|
ancestor::select[@disabled] | \
|
@@ -344,10 +343,24 @@ class Cuprite {
|
|
344
343
|
|
345
344
|
_isInViewport(node) {
|
346
345
|
let rect = node.getBoundingClientRect();
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
346
|
+
|
347
|
+
let inViewport = rect.top >= 0 &&
|
348
|
+
rect.left >= 0 &&
|
349
|
+
rect.bottom <= window.innerHeight &&
|
350
|
+
rect.right <= window.innerWidth;
|
351
|
+
|
352
|
+
if (inViewport) {
|
353
|
+
// check if obscured by another element
|
354
|
+
let x = rect.width/2;
|
355
|
+
let y = rect.height/2 ;
|
356
|
+
|
357
|
+
let px = rect.left + x,
|
358
|
+
py = rect.top + y,
|
359
|
+
e = document.elementFromPoint(px, py);
|
360
|
+
return node == e;
|
361
|
+
}
|
362
|
+
|
363
|
+
return false;
|
351
364
|
}
|
352
365
|
|
353
366
|
select(node, value) {
|
@@ -356,12 +369,13 @@ class Cuprite {
|
|
356
369
|
} else if (value == false && !node.parentNode.multiple) {
|
357
370
|
return false;
|
358
371
|
} else {
|
359
|
-
|
372
|
+
let parentNode = node.parentNode;
|
373
|
+
this.trigger(parentNode, "focus");
|
360
374
|
|
361
375
|
node.selected = value;
|
362
376
|
this.changed(node);
|
363
377
|
|
364
|
-
this.trigger(
|
378
|
+
this.trigger(parentNode, "blur");
|
365
379
|
return true;
|
366
380
|
}
|
367
381
|
}
|
@@ -162,13 +162,13 @@ module Capybara
|
|
162
162
|
def drag_to(other, **options)
|
163
163
|
options[:steps] ||= 1
|
164
164
|
|
165
|
-
command(:drag, other.node, options[:steps])
|
165
|
+
command(:drag, other.node, options[:steps], options[:delay])
|
166
166
|
end
|
167
167
|
|
168
168
|
def drag_by(x, y, **options)
|
169
169
|
options[:steps] ||= 1
|
170
170
|
|
171
|
-
command(:drag_by, x, y, options[:steps])
|
171
|
+
command(:drag_by, x, y, options[:steps], options[:delay])
|
172
172
|
end
|
173
173
|
|
174
174
|
def trigger(event)
|
@@ -4,6 +4,12 @@ require "forwardable"
|
|
4
4
|
|
5
5
|
module Capybara
|
6
6
|
module Cuprite
|
7
|
+
class ClosedPage
|
8
|
+
def closed?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
7
13
|
class Page < Ferrum::Page
|
8
14
|
MODAL_WAIT = ENV.fetch("CUPRITE_MODAL_WAIT", 0.05).to_f
|
9
15
|
TRIGGER_CLICK_WAIT = ENV.fetch("CUPRITE_TRIGGER_CLICK_WAIT", 0.1).to_f
|
@@ -13,7 +19,7 @@ module Capybara
|
|
13
19
|
current_url current_title body execution_id execution_id!
|
14
20
|
evaluate evaluate_on evaluate_async execute] => :active_frame
|
15
21
|
|
16
|
-
def initialize(
|
22
|
+
def initialize(...)
|
17
23
|
@frame_stack = []
|
18
24
|
@accept_modal = []
|
19
25
|
@modal_messages = []
|
@@ -70,17 +76,17 @@ module Capybara
|
|
70
76
|
|
71
77
|
def find_modal(options)
|
72
78
|
start = Ferrum::Utils::ElapsedTime.monotonic_time
|
73
|
-
timeout = options.fetch(:wait, browser.timeout)
|
74
79
|
expect_text = options[:text]
|
75
80
|
expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
|
76
81
|
not_found_msg = "Unable to find modal dialog"
|
77
82
|
not_found_msg += " with #{expect_text}" if expect_text
|
83
|
+
wait = options.fetch(:wait, timeout)
|
78
84
|
|
79
85
|
begin
|
80
86
|
modal_text = @modal_messages.shift
|
81
87
|
raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
|
82
88
|
rescue Capybara::ModalNotFound => e
|
83
|
-
raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start,
|
89
|
+
raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start, wait)
|
84
90
|
|
85
91
|
sleep(MODAL_WAIT)
|
86
92
|
retry
|
@@ -129,15 +135,22 @@ module Capybara
|
|
129
135
|
active_frame.current_title
|
130
136
|
end
|
131
137
|
|
138
|
+
def closed?
|
139
|
+
false
|
140
|
+
end
|
141
|
+
|
132
142
|
private
|
133
143
|
|
134
144
|
def prepare_page
|
135
145
|
super
|
136
146
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
147
|
+
width, height = @options.window_size
|
148
|
+
resize(width: width, height: height)
|
149
|
+
|
150
|
+
if @options.url_blacklist.any?
|
151
|
+
network.blacklist = @options.url_blacklist
|
152
|
+
elsif @options.url_whitelist.any?
|
153
|
+
network.whitelist = @options.url_whitelist
|
141
154
|
end
|
142
155
|
|
143
156
|
on("Page.javascriptDialogOpening") do |params|
|
data/lib/capybara/cuprite.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
ENV["FERRUM_DEBUG"] = "true" if ENV["CUPRITE_DEBUG"]
|
4
|
+
|
3
5
|
require "ferrum"
|
4
6
|
require "capybara"
|
5
7
|
require "capybara/cuprite/driver"
|
6
8
|
require "capybara/cuprite/browser"
|
7
9
|
require "capybara/cuprite/page"
|
10
|
+
require "capybara/cuprite/options"
|
8
11
|
require "capybara/cuprite/node"
|
9
12
|
require "capybara/cuprite/errors"
|
10
13
|
|
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:
|
4
|
+
version: 0.15.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:
|
11
|
+
date: 2024-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.15.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.15.0
|
41
41
|
description: Cuprite is a driver for Capybara that allows you to run your tests on
|
42
42
|
a headless Chrome browser
|
43
43
|
email:
|
@@ -55,6 +55,7 @@ files:
|
|
55
55
|
- lib/capybara/cuprite/errors.rb
|
56
56
|
- lib/capybara/cuprite/javascripts/index.js
|
57
57
|
- lib/capybara/cuprite/node.rb
|
58
|
+
- lib/capybara/cuprite/options.rb
|
58
59
|
- lib/capybara/cuprite/page.rb
|
59
60
|
- lib/capybara/cuprite/version.rb
|
60
61
|
homepage: https://github.com/rubycdp/cuprite
|
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
82
|
- !ruby/object:Gem::Version
|
82
83
|
version: '0'
|
83
84
|
requirements: []
|
84
|
-
rubygems_version: 3.
|
85
|
+
rubygems_version: 3.5.11
|
85
86
|
signing_key:
|
86
87
|
specification_version: 4
|
87
88
|
summary: Headless Chrome driver for Capybara
|