puppeteer-ruby 0.0.20 → 0.0.26
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/.rubocop.yml +37 -0
- data/CHANGELOG.md +62 -0
- data/README.md +15 -0
- data/lib/puppeteer.rb +9 -2
- data/lib/puppeteer/browser.rb +19 -28
- data/lib/puppeteer/browser_context.rb +48 -49
- data/lib/puppeteer/browser_runner.rb +19 -5
- data/lib/puppeteer/cdp_session.rb +11 -7
- data/lib/puppeteer/concurrent_ruby_utils.rb +22 -6
- data/lib/puppeteer/connection.rb +30 -11
- data/lib/puppeteer/devices.rb +998 -849
- data/lib/puppeteer/dom_world.rb +2 -2
- data/lib/puppeteer/event_callbackable.rb +4 -0
- data/lib/puppeteer/events.rb +184 -0
- data/lib/puppeteer/exception_details.rb +38 -0
- data/lib/puppeteer/frame_manager.rb +20 -16
- data/lib/puppeteer/geolocation.rb +24 -0
- data/lib/puppeteer/keyboard/us_keyboard_layout.rb +2 -2
- data/lib/puppeteer/launcher.rb +0 -1
- data/lib/puppeteer/launcher/browser_options.rb +2 -1
- data/lib/puppeteer/launcher/chrome.rb +4 -8
- data/lib/puppeteer/launcher/firefox.rb +8 -15
- data/lib/puppeteer/lifecycle_watcher.rb +6 -6
- data/lib/puppeteer/network_manager.rb +6 -6
- data/lib/puppeteer/page.rb +119 -141
- data/lib/puppeteer/page/screenshot_options.rb +2 -2
- data/lib/puppeteer/page/screenshot_task_queue.rb +13 -0
- data/lib/puppeteer/target.rb +4 -6
- data/lib/puppeteer/version.rb +1 -1
- data/puppeteer-ruby.gemspec +1 -0
- metadata +21 -2
@@ -12,9 +12,9 @@ module Puppeteer::Launcher
|
|
12
12
|
|
13
13
|
firefox_arguments =
|
14
14
|
if !@launch_options.ignore_default_args
|
15
|
-
default_args.to_a
|
15
|
+
default_args(options).to_a
|
16
16
|
elsif @launch_options.ignore_default_args.is_a?(Enumerable)
|
17
|
-
default_args.reject do |arg|
|
17
|
+
default_args(options).reject do |arg|
|
18
18
|
@launch_options.ignore_default_args.include?(arg)
|
19
19
|
end.to_a
|
20
20
|
else
|
@@ -127,7 +127,7 @@ module Puppeteer::Launcher
|
|
127
127
|
resolve_executable_path
|
128
128
|
end
|
129
129
|
|
130
|
-
|
130
|
+
def product
|
131
131
|
'firefox'
|
132
132
|
end
|
133
133
|
|
@@ -173,11 +173,7 @@ module Puppeteer::Launcher
|
|
173
173
|
|
174
174
|
# @return [DefaultArgs]
|
175
175
|
def default_args(options = nil)
|
176
|
-
|
177
|
-
@default_args ||= DefaultArgs.new(@chrome_arg_options)
|
178
|
-
else
|
179
|
-
DefaultArgs.new(ChromeArgOptions.new(options))
|
180
|
-
end
|
176
|
+
DefaultArgs.new(ChromeArgOptions.new(options || {}))
|
181
177
|
end
|
182
178
|
|
183
179
|
private def create_profile(extra_prefs = {})
|
@@ -203,7 +199,7 @@ module Puppeteer::Launcher
|
|
203
199
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
|
204
200
|
'browser.dom.window.dump.enabled': true,
|
205
201
|
# Disable topstories
|
206
|
-
'browser.newtabpage.activity-stream.feeds.
|
202
|
+
'browser.newtabpage.activity-stream.feeds.system.topstories': false,
|
207
203
|
# Always display a blank page
|
208
204
|
'browser.newtabpage.enabled': false,
|
209
205
|
# Background thumbnails in particular cause grief: and disabling
|
@@ -250,16 +246,15 @@ module Puppeteer::Launcher
|
|
250
246
|
# Do not warn on quitting Firefox
|
251
247
|
'browser.warnOnQuit': false,
|
252
248
|
|
253
|
-
#
|
254
|
-
# interfere with tests
|
255
|
-
'datareporting.healthreport.about.reportUrl': "http://#{server}/dummy/abouthealthreport/",
|
249
|
+
# Defensively disable data reporting systems
|
256
250
|
'datareporting.healthreport.documentServerURI': "http://#{server}/dummy/healthreport/",
|
257
251
|
'datareporting.healthreport.logging.consoleEnabled': false,
|
258
252
|
'datareporting.healthreport.service.enabled': false,
|
259
253
|
'datareporting.healthreport.service.firstRun': false,
|
260
254
|
'datareporting.healthreport.uploadEnabled': false,
|
255
|
+
|
256
|
+
# Do not show datareporting policy notifications which can interfere with tests
|
261
257
|
'datareporting.policy.dataSubmissionEnabled': false,
|
262
|
-
'datareporting.policy.dataSubmissionPolicyAccepted': false,
|
263
258
|
'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
|
264
259
|
|
265
260
|
# DevTools JSONViewer sometimes fails to load dependencies with its require.js.
|
@@ -372,8 +367,6 @@ module Puppeteer::Launcher
|
|
372
367
|
# Disable browser animations (tabs, fullscreen, sliding alerts)
|
373
368
|
'toolkit.cosmeticAnimations.enabled': false,
|
374
369
|
|
375
|
-
# We want to collect telemetry, but we don't want to send in the results
|
376
|
-
'toolkit.telemetry.server': "https://#{server}/dummy/telemetry/",
|
377
370
|
# Prevent starting into safe mode after application crashes
|
378
371
|
'toolkit.startup.max_resumed_crashes': -1,
|
379
372
|
}
|
@@ -69,17 +69,17 @@ class Puppeteer::LifecycleWatcher
|
|
69
69
|
@timeout = timeout
|
70
70
|
|
71
71
|
@listener_ids = {}
|
72
|
-
@listener_ids['client'] = @frame_manager.client.add_event_listener(
|
72
|
+
@listener_ids['client'] = @frame_manager.client.add_event_listener(CDPSessionEmittedEvents::Disconnected) do
|
73
73
|
terminate(TerminatedError.new('Navigation failed because browser has disconnected!'))
|
74
74
|
end
|
75
75
|
@listener_ids['frame_manager'] = [
|
76
|
-
@frame_manager.add_event_listener(
|
76
|
+
@frame_manager.add_event_listener(FrameManagerEmittedEvents::LifecycleEvent) do |_|
|
77
77
|
check_lifecycle_complete
|
78
78
|
end,
|
79
|
-
@frame_manager.add_event_listener(
|
80
|
-
@frame_manager.add_event_listener(
|
79
|
+
@frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameNavigatedWithinDocument, &method(:navigated_within_document)),
|
80
|
+
@frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameDetached, &method(:handle_frame_detached)),
|
81
81
|
]
|
82
|
-
@listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener(
|
82
|
+
@listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener(NetworkManagerEmittedEvents::Request, &method(:handle_request))
|
83
83
|
|
84
84
|
@same_document_navigation_promise = resolvable_future
|
85
85
|
@lifecycle_promise = resolvable_future
|
@@ -128,7 +128,7 @@ class Puppeteer::LifecycleWatcher
|
|
128
128
|
@termination_promise.value!
|
129
129
|
end
|
130
130
|
rescue Timeout::Error
|
131
|
-
raise Puppeteer::
|
131
|
+
raise Puppeteer::TimeoutError.new("Navigation timeout of #{@timeout}ms exceeded")
|
132
132
|
end
|
133
133
|
else
|
134
134
|
@termination_promise
|
@@ -212,7 +212,7 @@ class Puppeteer::NetworkManager
|
|
212
212
|
frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) }
|
213
213
|
request = Puppeteer::Request.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
|
214
214
|
@request_id_to_request[event['requestId']] = request
|
215
|
-
emit_event
|
215
|
+
emit_event(NetworkManagerEmittedEvents::Request, request)
|
216
216
|
end
|
217
217
|
|
218
218
|
private def handle_request_served_from_cache(event)
|
@@ -230,8 +230,8 @@ class Puppeteer::NetworkManager
|
|
230
230
|
response.internal.body_loaded_promise.reject(Puppeteer::Response::Redirected.new)
|
231
231
|
@request_id_to_request.delete(request.internal.request_id)
|
232
232
|
@attempted_authentications.delete(request.internal.interception_id)
|
233
|
-
emit_event
|
234
|
-
emit_event
|
233
|
+
emit_event(NetworkManagerEmittedEvents::Response, response)
|
234
|
+
emit_event(NetworkManagerEmittedEvents::RequestFinished, request)
|
235
235
|
end
|
236
236
|
|
237
237
|
# @param event [Hash]
|
@@ -242,7 +242,7 @@ class Puppeteer::NetworkManager
|
|
242
242
|
|
243
243
|
response = Puppeteer::Response.new(@client, request, event['response'])
|
244
244
|
request.internal.response = response
|
245
|
-
emit_event
|
245
|
+
emit_event(NetworkManagerEmittedEvents::Response, response)
|
246
246
|
end
|
247
247
|
|
248
248
|
private def handle_loading_finished(event)
|
@@ -260,7 +260,7 @@ class Puppeteer::NetworkManager
|
|
260
260
|
|
261
261
|
@request_id_to_request.delete(request.internal.request_id)
|
262
262
|
@attempted_authentications.delete(request.internal.interception_id)
|
263
|
-
emit_event
|
263
|
+
emit_event(NetworkManagerEmittedEvents::RequestFinished, request)
|
264
264
|
end
|
265
265
|
|
266
266
|
private def handle_loading_failed(event)
|
@@ -275,6 +275,6 @@ class Puppeteer::NetworkManager
|
|
275
275
|
end
|
276
276
|
@request_id_to_request.delete(request.internal.request_id)
|
277
277
|
@attempted_authentications.delete(request.internal.interception_id)
|
278
|
-
emit_event
|
278
|
+
emit_event(NetworkManagerEmittedEvents::RequestFailed, request)
|
279
279
|
end
|
280
280
|
end
|
data/lib/puppeteer/page.rb
CHANGED
@@ -3,6 +3,7 @@ require "stringio"
|
|
3
3
|
|
4
4
|
require_relative './page/pdf_options'
|
5
5
|
require_relative './page/screenshot_options'
|
6
|
+
require_relative './page/screenshot_task_queue'
|
6
7
|
|
7
8
|
class Puppeteer::Page
|
8
9
|
include Puppeteer::EventCallbackable
|
@@ -13,10 +14,9 @@ class Puppeteer::Page
|
|
13
14
|
# @param {!Puppeteer.Target} target
|
14
15
|
# @param {boolean} ignoreHTTPSErrors
|
15
16
|
# @param {?Puppeteer.Viewport} defaultViewport
|
16
|
-
# @param {!Puppeteer.TaskQueue} screenshotTaskQueue
|
17
17
|
# @return {!Promise<!Page>}
|
18
|
-
def self.create(client, target, ignore_https_errors, default_viewport
|
19
|
-
page = Puppeteer::Page.new(client, target, ignore_https_errors
|
18
|
+
def self.create(client, target, ignore_https_errors, default_viewport)
|
19
|
+
page = Puppeteer::Page.new(client, target, ignore_https_errors)
|
20
20
|
page.init
|
21
21
|
if default_viewport
|
22
22
|
page.viewport = default_viewport
|
@@ -27,8 +27,7 @@ class Puppeteer::Page
|
|
27
27
|
# @param {!Puppeteer.CDPSession} client
|
28
28
|
# @param {!Puppeteer.Target} target
|
29
29
|
# @param {boolean} ignoreHTTPSErrors
|
30
|
-
|
31
|
-
def initialize(client, target, ignore_https_errors, screenshot_task_queue)
|
30
|
+
def initialize(client, target, ignore_https_errors)
|
32
31
|
@closed = false
|
33
32
|
@client = client
|
34
33
|
@target = target
|
@@ -43,10 +42,10 @@ class Puppeteer::Page
|
|
43
42
|
@page_bindings = {}
|
44
43
|
# @coverage = Coverage.new(client)
|
45
44
|
@javascript_enabled = true
|
46
|
-
@screenshot_task_queue =
|
45
|
+
@screenshot_task_queue = ScreenshotTaskQueue.new
|
47
46
|
|
48
47
|
@workers = {}
|
49
|
-
@client.on_event
|
48
|
+
@client.on_event('Target.attachedToTarget') do |event|
|
50
49
|
if event['targetInfo']['type'] != 'worker'
|
51
50
|
# If we don't detach from service workers, they will never die.
|
52
51
|
await @client.send_message('Target.detachFromTarget', sessionId: event['sessionId'])
|
@@ -56,65 +55,69 @@ class Puppeteer::Page
|
|
56
55
|
session = Puppeteer::Connection.from_session(@client).session(event['sessionId']) # rubocop:disable Lint/UselessAssignment
|
57
56
|
# const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
|
58
57
|
# this._workers.set(event.sessionId, worker);
|
59
|
-
# this.emit(
|
58
|
+
# this.emit(PageEmittedEvents::WorkerCreated, worker);
|
60
59
|
end
|
61
|
-
@client.on_event
|
60
|
+
@client.on_event('Target.detachedFromTarget') do |event|
|
62
61
|
session_id = event['sessionId']
|
63
62
|
worker = @workers[session_id]
|
64
63
|
next unless worker
|
65
64
|
|
66
|
-
emit_event(
|
65
|
+
emit_event(PageEmittedEvents::WorkerDestroyed, worker)
|
67
66
|
@workers.delete(session_id)
|
68
67
|
end
|
69
68
|
|
70
|
-
@frame_manager.on_event
|
71
|
-
emit_event
|
69
|
+
@frame_manager.on_event(FrameManagerEmittedEvents::FrameAttached) do |event|
|
70
|
+
emit_event(PageEmittedEvents::FrameAttached, event)
|
72
71
|
end
|
73
|
-
@frame_manager.on_event
|
74
|
-
emit_event
|
72
|
+
@frame_manager.on_event(FrameManagerEmittedEvents::FrameDetached) do |event|
|
73
|
+
emit_event(PageEmittedEvents::FrameDetached, event)
|
75
74
|
end
|
76
|
-
@frame_manager.on_event
|
77
|
-
emit_event
|
75
|
+
@frame_manager.on_event(FrameManagerEmittedEvents::FrameNavigated) do |event|
|
76
|
+
emit_event(PageEmittedEvents::FrameNavigated, event)
|
78
77
|
end
|
79
78
|
|
80
79
|
network_manager = @frame_manager.network_manager
|
81
|
-
network_manager.on_event
|
82
|
-
emit_event
|
80
|
+
network_manager.on_event(NetworkManagerEmittedEvents::Request) do |event|
|
81
|
+
emit_event(PageEmittedEvents::Request, event)
|
83
82
|
end
|
84
|
-
network_manager.on_event
|
85
|
-
emit_event
|
83
|
+
network_manager.on_event(NetworkManagerEmittedEvents::Response) do |event|
|
84
|
+
emit_event(PageEmittedEvents::Response, event)
|
86
85
|
end
|
87
|
-
network_manager.on_event
|
88
|
-
emit_event
|
86
|
+
network_manager.on_event(NetworkManagerEmittedEvents::RequestFailed) do |event|
|
87
|
+
emit_event(PageEmittedEvents::RequestFailed, event)
|
89
88
|
end
|
90
|
-
network_manager.on_event
|
91
|
-
emit_event
|
89
|
+
network_manager.on_event(NetworkManagerEmittedEvents::RequestFinished) do |event|
|
90
|
+
emit_event(PageEmittedEvents::RequestFinished, event)
|
92
91
|
end
|
93
92
|
@file_chooser_interception_is_disabled = false
|
94
93
|
@file_chooser_interceptors = Set.new
|
95
94
|
|
96
|
-
@client.on_event
|
97
|
-
emit_event
|
95
|
+
@client.on_event('Page.domContentEventFired') do |event|
|
96
|
+
emit_event(PageEmittedEvents::DOMContentLoaded)
|
98
97
|
end
|
99
|
-
@client.on_event
|
100
|
-
emit_event
|
98
|
+
@client.on_event('Page.loadEventFired') do |event|
|
99
|
+
emit_event(PageEmittedEvents::Load)
|
101
100
|
end
|
102
101
|
# client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
103
102
|
# client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
|
104
|
-
@client.on_event
|
103
|
+
@client.on_event('Page.javascriptDialogOpening') do |event|
|
105
104
|
handle_dialog_opening(event)
|
106
105
|
end
|
107
|
-
|
108
|
-
|
106
|
+
@client.on_event('Runtime.exceptionThrown') do |exception|
|
107
|
+
handle_exception(exception['exceptionDetails'])
|
108
|
+
end
|
109
|
+
@client.on_event('Inspector.targetCrashed') do |event|
|
110
|
+
handle_target_crashed
|
111
|
+
end
|
109
112
|
# client.on('Performance.metrics', event => this._emitMetrics(event));
|
110
|
-
@client.on_event
|
113
|
+
@client.on_event('Log.entryAdded') do |event|
|
111
114
|
handle_log_entry_added(event)
|
112
115
|
end
|
113
|
-
@client.on_event
|
116
|
+
@client.on_event('Page.fileChooserOpened') do |event|
|
114
117
|
handle_file_chooser(event)
|
115
118
|
end
|
116
119
|
@target.is_closed_promise.then do
|
117
|
-
emit_event
|
120
|
+
emit_event(PageEmittedEvents::Close)
|
118
121
|
@closed = true
|
119
122
|
end
|
120
123
|
end
|
@@ -128,43 +131,22 @@ class Puppeteer::Page
|
|
128
131
|
)
|
129
132
|
end
|
130
133
|
|
131
|
-
EVENT_MAPPINGS = {
|
132
|
-
close: 'Events.Page.Close',
|
133
|
-
# console: 'Events.Page.Console',
|
134
|
-
dialog: 'Events.Page.Dialog',
|
135
|
-
domcontentloaded: 'Events.Page.DOMContentLoaded',
|
136
|
-
# error:
|
137
|
-
frameattached: 'Events.Page.FrameAttached',
|
138
|
-
framedetached: 'Events.Page.FrameDetached',
|
139
|
-
framenavigated: 'Events.Page.FrameNavigated',
|
140
|
-
load: 'Events.Page.Load',
|
141
|
-
# metrics: 'Events.Page.Metrics',
|
142
|
-
# pageerror: 'Events.Page.PageError',
|
143
|
-
popup: 'Events.Page.Popup',
|
144
|
-
request: 'Events.Page.Request',
|
145
|
-
requestfailed: 'Events.Page.RequestFailed',
|
146
|
-
requestfinished: 'Events.Page.RequestFinished',
|
147
|
-
response: 'Events.Page.Response',
|
148
|
-
# workercreated: 'Events.Page.WorkerCreated',
|
149
|
-
# workerdestroyed: 'Events.Page.WorkerDestroyed',
|
150
|
-
}
|
151
|
-
|
152
134
|
# @param event_name [Symbol]
|
153
135
|
def on(event_name, &block)
|
154
|
-
unless
|
155
|
-
raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{
|
136
|
+
unless PageEmittedEvents.values.include?(event_name.to_s)
|
137
|
+
raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
|
156
138
|
end
|
157
139
|
|
158
|
-
|
140
|
+
super(event_name.to_s, &block)
|
159
141
|
end
|
160
142
|
|
161
143
|
# @param event_name [Symbol]
|
162
144
|
def once(event_name, &block)
|
163
|
-
unless
|
164
|
-
raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{
|
145
|
+
unless PageEmittedEvents.values.include?(event_name.to_s)
|
146
|
+
raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
|
165
147
|
end
|
166
148
|
|
167
|
-
|
149
|
+
super(event_name.to_s, &block)
|
168
150
|
end
|
169
151
|
|
170
152
|
def handle_file_chooser(event)
|
@@ -211,19 +193,10 @@ class Puppeteer::Page
|
|
211
193
|
|
212
194
|
define_async_method :async_wait_for_file_chooser
|
213
195
|
|
214
|
-
#
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
# const { longitude, latitude, accuracy = 0} = options;
|
219
|
-
# if (longitude < -180 || longitude > 180)
|
220
|
-
# throw new Error(`Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.`);
|
221
|
-
# if (latitude < -90 || latitude > 90)
|
222
|
-
# throw new Error(`Invalid latitude "${latitude}": precondition -90 <= LATITUDE <= 90 failed.`);
|
223
|
-
# if (accuracy < 0)
|
224
|
-
# throw new Error(`Invalid accuracy "${accuracy}": precondition 0 <= ACCURACY failed.`);
|
225
|
-
# await this._client.send('Emulation.setGeolocationOverride', {longitude, latitude, accuracy});
|
226
|
-
# }
|
196
|
+
# @param [Puppeteer::Geolocation]
|
197
|
+
def geolocation=(geolocation)
|
198
|
+
@client.send_message('Emulation.setGeolocationOverride', geolocation.to_h)
|
199
|
+
end
|
227
200
|
|
228
201
|
attr_reader :javascript_enabled, :target
|
229
202
|
|
@@ -238,7 +211,7 @@ class Puppeteer::Page
|
|
238
211
|
class TargetCrashedError < StandardError; end
|
239
212
|
|
240
213
|
private def handle_target_crashed
|
241
|
-
emit_event
|
214
|
+
emit_event(PageEmittedEvents::Error, TargetCrashedError.new('Page crashed!'))
|
242
215
|
end
|
243
216
|
|
244
217
|
private def handle_log_entry_added(event)
|
@@ -259,7 +232,7 @@ class Puppeteer::Page
|
|
259
232
|
url: url,
|
260
233
|
line_number: line_number,
|
261
234
|
)
|
262
|
-
emit_event(
|
235
|
+
emit_event(PageEmittedEvents::Console,
|
263
236
|
Puppeteer::ConsoleMessage.new(level, text, [], console_message_location))
|
264
237
|
end
|
265
238
|
end
|
@@ -367,47 +340,34 @@ class Puppeteer::Page
|
|
367
340
|
|
368
341
|
define_async_method :async_Sx
|
369
342
|
|
370
|
-
#
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
# async cookies(...urls) {
|
375
|
-
# return (await this._client.send('Network.getCookies', {
|
376
|
-
# urls: urls.length ? urls : [this.url()]
|
377
|
-
# })).cookies;
|
378
|
-
# }
|
343
|
+
# @return [Array<Hash>]
|
344
|
+
def cookies(*urls)
|
345
|
+
@client.send_message('Network.getCookies', urls: (urls.empty? ? [url] : urls))['cookies']
|
346
|
+
end
|
379
347
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
# item.url = pageURL;
|
389
|
-
# await this._client.send('Network.deleteCookies', item);
|
390
|
-
# }
|
391
|
-
# }
|
348
|
+
def delete_cookie(*cookies)
|
349
|
+
page_url = url
|
350
|
+
starts_with_http = page_url.start_with?("http")
|
351
|
+
cookies.each do |cookie|
|
352
|
+
item = (starts_with_http ? { url: page_url } : {}).merge(cookie)
|
353
|
+
@client.send_message("Network.deleteCookies", item)
|
354
|
+
end
|
355
|
+
end
|
392
356
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
# await this.deleteCookie(...items);
|
408
|
-
# if (items.length)
|
409
|
-
# await this._client.send('Network.setCookies', { cookies: items });
|
410
|
-
# }
|
357
|
+
def set_cookie(*cookies)
|
358
|
+
page_url = url
|
359
|
+
starts_with_http = page_url.start_with?("http")
|
360
|
+
items = cookies.map do |cookie|
|
361
|
+
(starts_with_http ? { url: page_url } : {}).merge(cookie).tap do |item|
|
362
|
+
raise ArgumentError.new("Blank page can not have cookie \"#{item[:name]}\"") if item[:url] == "about:blank"
|
363
|
+
raise ArgumetnError.new("Data URL page can not have cookie \"#{item[:name]}\"") if item[:url]&.start_with?("data:")
|
364
|
+
end
|
365
|
+
end
|
366
|
+
delete_cookie(*items)
|
367
|
+
unless items.empty?
|
368
|
+
@client.send_message("Network.setCookies", cookies: items)
|
369
|
+
end
|
370
|
+
end
|
411
371
|
|
412
372
|
class ScriptTag
|
413
373
|
# @param {!{content?: string, path?: string, type?: string, url?: string}} options
|
@@ -502,7 +462,7 @@ class Puppeteer::Page
|
|
502
462
|
# * @param {!Protocol.Performance.metricsPayload} event
|
503
463
|
# */
|
504
464
|
# _emitMetrics(event) {
|
505
|
-
# this.emit(
|
465
|
+
# this.emit(PageEmittedEvents::Metrics, {
|
506
466
|
# title: event.title,
|
507
467
|
# metrics: this._buildMetricsObject(event.metrics)
|
508
468
|
# });
|
@@ -521,15 +481,14 @@ class Puppeteer::Page
|
|
521
481
|
# return result;
|
522
482
|
# }
|
523
483
|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
# }
|
484
|
+
class PageError < StandardError ; end
|
485
|
+
|
486
|
+
private def handle_exception(exception_details)
|
487
|
+
message = Puppeteer::ExceptionDetails.new(exception_details).message
|
488
|
+
err = PageError.new(message)
|
489
|
+
# err.stack = ''; // Don't report clientside error with a node stack attached
|
490
|
+
emit_event(PageEmittedEvents::PageError, err)
|
491
|
+
end
|
533
492
|
|
534
493
|
# /**
|
535
494
|
# * @param {!Protocol.Runtime.consoleAPICalledPayload} event
|
@@ -613,7 +572,7 @@ class Puppeteer::Page
|
|
613
572
|
# * @param {Protocol.Runtime.StackTrace=} stackTrace
|
614
573
|
# */
|
615
574
|
# _addConsoleMessage(type, args, stackTrace) {
|
616
|
-
# if (!this.listenerCount(
|
575
|
+
# if (!this.listenerCount(PageEmittedEvents::Console)) {
|
617
576
|
# args.forEach(arg => arg.dispose());
|
618
577
|
# return;
|
619
578
|
# }
|
@@ -631,7 +590,7 @@ class Puppeteer::Page
|
|
631
590
|
# columnNumber: stackTrace.callFrames[0].columnNumber,
|
632
591
|
# } : {};
|
633
592
|
# const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
|
634
|
-
# this.emit(
|
593
|
+
# this.emit(PageEmittedEvents::Console, message);
|
635
594
|
# }
|
636
595
|
|
637
596
|
private def handle_dialog_opening(event)
|
@@ -643,7 +602,7 @@ class Puppeteer::Page
|
|
643
602
|
type: dialog_type,
|
644
603
|
message: event['message'],
|
645
604
|
default_value: event['defaultPrompt'])
|
646
|
-
emit_event(
|
605
|
+
emit_event(PageEmittedEvents::Dialog, dialog)
|
647
606
|
end
|
648
607
|
|
649
608
|
# @return [String]
|
@@ -726,7 +685,7 @@ class Puppeteer::Page
|
|
726
685
|
|
727
686
|
private def session_close_promise
|
728
687
|
@disconnect_promise ||= resolvable_future do |future|
|
729
|
-
@client.observe_first(
|
688
|
+
@client.observe_first(CDPSessionEmittedEvents::Disconnected) do
|
730
689
|
future.reject(Puppeteer::CDPSession::Error.new('Target Closed'))
|
731
690
|
end
|
732
691
|
end
|
@@ -746,7 +705,7 @@ class Puppeteer::Page
|
|
746
705
|
-> (request) { predicate.call(request) }
|
747
706
|
end
|
748
707
|
|
749
|
-
wait_for_network_manager_event(
|
708
|
+
wait_for_network_manager_event(NetworkManagerEmittedEvents::Request,
|
750
709
|
predicate: request_predicate,
|
751
710
|
timeout: timeout,
|
752
711
|
)
|
@@ -780,7 +739,7 @@ class Puppeteer::Page
|
|
780
739
|
-> (response) { predicate.call(response) }
|
781
740
|
end
|
782
741
|
|
783
|
-
wait_for_network_manager_event(
|
742
|
+
wait_for_network_manager_event(NetworkManagerEmittedEvents::Response,
|
784
743
|
predicate: response_predicate,
|
785
744
|
timeout: timeout,
|
786
745
|
)
|
@@ -907,15 +866,28 @@ class Puppeteer::Page
|
|
907
866
|
main_frame.title
|
908
867
|
end
|
909
868
|
|
910
|
-
#
|
911
|
-
#
|
912
|
-
#
|
913
|
-
#
|
914
|
-
|
869
|
+
# @param type [String] "png"|"jpeg"
|
870
|
+
# @param path [String]
|
871
|
+
# @param full_page [Boolean]
|
872
|
+
# @param clip [Hash]
|
873
|
+
# @param quality [Integer]
|
874
|
+
# @param omit_background [Boolean]
|
875
|
+
# @param encoding [String]
|
876
|
+
def screenshot(type: nil, path: nil, full_page: nil, clip: nil, quality: nil, omit_background: nil, encoding: nil)
|
877
|
+
options = {
|
878
|
+
type: type,
|
879
|
+
path: path,
|
880
|
+
full_page: full_page,
|
881
|
+
clip: clip,
|
882
|
+
quality: quality,
|
883
|
+
omit_background: omit_background,
|
884
|
+
encoding: encoding,
|
885
|
+
}.compact
|
915
886
|
screenshot_options = ScreenshotOptions.new(options)
|
916
887
|
|
917
|
-
|
918
|
-
|
888
|
+
@screenshot_task_queue.post_task do
|
889
|
+
screenshot_task(screenshot_options.type, screenshot_options)
|
890
|
+
end
|
919
891
|
end
|
920
892
|
|
921
893
|
# @param {"png"|"jpeg"} format
|
@@ -939,16 +911,16 @@ class Puppeteer::Page
|
|
939
911
|
clip = { x: 0, y: 0, width: width, height: height, scale: 1 }
|
940
912
|
|
941
913
|
screen_orientation =
|
942
|
-
if @viewport
|
914
|
+
if @viewport&.landscape?
|
943
915
|
{ angle: 90, type: 'landscapePrimary' }
|
944
916
|
else
|
945
917
|
{ angle: 0, type: 'portraitPrimary' }
|
946
918
|
end
|
947
919
|
@client.send_message('Emulation.setDeviceMetricsOverride',
|
948
|
-
mobile: @viewport
|
920
|
+
mobile: @viewport&.mobile? || false,
|
949
921
|
width: width,
|
950
922
|
height: height,
|
951
|
-
deviceScaleFactor: @viewport
|
923
|
+
deviceScaleFactor: @viewport&.device_scale_factor || 1,
|
952
924
|
screenOrientation: screen_orientation)
|
953
925
|
end
|
954
926
|
|
@@ -1043,6 +1015,12 @@ class Puppeteer::Page
|
|
1043
1015
|
else
|
1044
1016
|
@client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
|
1045
1017
|
await @target.is_closed_promise
|
1018
|
+
|
1019
|
+
# @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
|
1020
|
+
25.times do
|
1021
|
+
break if @closed
|
1022
|
+
sleep 0.004
|
1023
|
+
end
|
1046
1024
|
end
|
1047
1025
|
end
|
1048
1026
|
|