puppeteer-ruby 0.0.13 → 0.0.18
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/.circleci/config.yml +2 -14
- data/.github/workflows/docs.yml +45 -0
- data/.github/workflows/reviewdog.yml +15 -0
- data/.rubocop.yml +39 -3
- data/README.md +54 -1
- data/lib/puppeteer.rb +10 -2
- data/lib/puppeteer/browser.rb +53 -34
- data/lib/puppeteer/browser_context.rb +35 -5
- data/lib/puppeteer/cdp_session.rb +3 -19
- data/lib/puppeteer/concurrent_ruby_utils.rb +6 -0
- data/lib/puppeteer/connection.rb +9 -16
- data/lib/puppeteer/debug_print.rb +1 -1
- data/lib/puppeteer/define_async_method.rb +23 -0
- data/lib/puppeteer/dom_world.rb +84 -73
- data/lib/puppeteer/element_handle.rb +46 -63
- data/lib/puppeteer/emulation_manager.rb +2 -6
- data/lib/puppeteer/env.rb +18 -0
- data/lib/puppeteer/execution_context.rb +1 -6
- data/lib/puppeteer/frame.rb +46 -46
- data/lib/puppeteer/frame_manager.rb +7 -25
- data/lib/puppeteer/js_handle.rb +39 -38
- data/lib/puppeteer/keyboard.rb +9 -29
- data/lib/puppeteer/mouse.rb +20 -24
- data/lib/puppeteer/network_manager.rb +163 -5
- data/lib/puppeteer/page.rb +221 -181
- data/lib/puppeteer/page/pdf_options.rb +166 -0
- data/lib/puppeteer/remote_object.rb +18 -5
- data/lib/puppeteer/request.rb +330 -0
- data/lib/puppeteer/response.rb +113 -0
- data/lib/puppeteer/touch_screen.rb +2 -7
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +3 -5
- data/lib/puppeteer/web_socket.rb +7 -0
- data/puppeteer-ruby.gemspec +2 -1
- metadata +25 -103
- data/docs/Puppeteer.html +0 -2338
- data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
- data/docs/Puppeteer/Browser.html +0 -2258
- data/docs/Puppeteer/BrowserContext.html +0 -809
- data/docs/Puppeteer/BrowserFetcher.html +0 -214
- data/docs/Puppeteer/BrowserRunner.html +0 -914
- data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
- data/docs/Puppeteer/CDPSession.html +0 -813
- data/docs/Puppeteer/CDPSession/Error.html +0 -124
- data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -438
- data/docs/Puppeteer/Connection.html +0 -964
- data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
- data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
- data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
- data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
- data/docs/Puppeteer/ConsoleMessage.html +0 -565
- data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
- data/docs/Puppeteer/DOMWorld.html +0 -2293
- data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
- data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
- data/docs/Puppeteer/DebugPrint.html +0 -233
- data/docs/Puppeteer/Device.html +0 -470
- data/docs/Puppeteer/Devices.html +0 -139
- data/docs/Puppeteer/ElementHandle.html +0 -2542
- data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
- data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
- data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
- data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
- data/docs/Puppeteer/ElementHandle/Point.html +0 -492
- data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
- data/docs/Puppeteer/EmulationManager.html +0 -454
- data/docs/Puppeteer/EventCallbackable.html +0 -499
- data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
- data/docs/Puppeteer/ExecutionContext.html +0 -998
- data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
- data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
- data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
- data/docs/Puppeteer/FileChooser.html +0 -455
- data/docs/Puppeteer/Frame.html +0 -3835
- data/docs/Puppeteer/FrameManager.html +0 -2410
- data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
- data/docs/Puppeteer/IfPresent.html +0 -222
- data/docs/Puppeteer/JSHandle.html +0 -1352
- data/docs/Puppeteer/Keyboard.html +0 -1557
- data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
- data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
- data/docs/Puppeteer/Launcher.html +0 -237
- data/docs/Puppeteer/Launcher/Base.html +0 -385
- data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
- data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
- data/docs/Puppeteer/Launcher/Chrome.html +0 -674
- data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
- data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
- data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
- data/docs/Puppeteer/LifecycleWatcher.html +0 -834
- data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
- data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
- data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
- data/docs/Puppeteer/Mouse.html +0 -1095
- data/docs/Puppeteer/Mouse/Button.html +0 -136
- data/docs/Puppeteer/NetworkManager.html +0 -901
- data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
- data/docs/Puppeteer/Page.html +0 -6173
- data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
- data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
- data/docs/Puppeteer/Page/ScriptTag.html +0 -555
- data/docs/Puppeteer/Page/StyleTag.html +0 -448
- data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
- data/docs/Puppeteer/RemoteObject.html +0 -1087
- data/docs/Puppeteer/Target.html +0 -1336
- data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
- data/docs/Puppeteer/Target/TargetInfo.html +0 -729
- data/docs/Puppeteer/TimeoutError.html +0 -135
- data/docs/Puppeteer/TimeoutSettings.html +0 -496
- data/docs/Puppeteer/TouchScreen.html +0 -464
- data/docs/Puppeteer/Viewport.html +0 -837
- data/docs/Puppeteer/WaitTask.html +0 -637
- data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
- data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
- data/docs/Puppeteer/WebSocket.html +0 -673
- data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
- data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
- data/docs/Puppeteer/WebSocketTransport.html +0 -600
- data/docs/Puppeteer/WebSocktTransportError.html +0 -124
- data/docs/_index.html +0 -816
- data/docs/class_list.html +0 -51
- data/docs/css/common.css +0 -1
- data/docs/css/full_list.css +0 -58
- data/docs/css/style.css +0 -496
- data/docs/file.README.html +0 -125
- data/docs/file_list.html +0 -56
- data/docs/frames.html +0 -17
- data/docs/index.html +0 -125
- data/docs/js/app.js +0 -314
- data/docs/js/full_list.js +0 -216
- data/docs/js/jquery.js +0 -4
- data/docs/method_list.html +0 -4123
- data/docs/top-level-namespace.html +0 -126
- data/lib/puppeteer/async_await_behavior.rb +0 -38
|
@@ -4,7 +4,7 @@ class Puppeteer::FrameManager
|
|
|
4
4
|
include Puppeteer::DebugPrint
|
|
5
5
|
include Puppeteer::IfPresent
|
|
6
6
|
include Puppeteer::EventCallbackable
|
|
7
|
-
using Puppeteer::
|
|
7
|
+
using Puppeteer::DefineAsyncMethod
|
|
8
8
|
|
|
9
9
|
UTILITY_WORLD_NAME = '__puppeteer_utility_world__'
|
|
10
10
|
|
|
@@ -23,7 +23,6 @@ class Puppeteer::FrameManager
|
|
|
23
23
|
|
|
24
24
|
# @type {!Map<number, !ExecutionContext>}
|
|
25
25
|
@context_id_to_context = {}
|
|
26
|
-
@context_id_created = {}
|
|
27
26
|
|
|
28
27
|
# @type {!Set<string>}
|
|
29
28
|
@isolated_worlds = Set.new
|
|
@@ -74,9 +73,7 @@ class Puppeteer::FrameManager
|
|
|
74
73
|
@network_manager.init
|
|
75
74
|
end
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
init
|
|
79
|
-
end
|
|
76
|
+
define_async_method :async_init
|
|
80
77
|
|
|
81
78
|
attr_reader :network_manager
|
|
82
79
|
|
|
@@ -281,7 +278,7 @@ class Puppeteer::FrameManager
|
|
|
281
278
|
# @param url [String]
|
|
282
279
|
def handle_frame_navigated_within_document(frame_id, url)
|
|
283
280
|
frame = @frames[frame_id]
|
|
284
|
-
return
|
|
281
|
+
return unless frame
|
|
285
282
|
frame.navigated_within_document(url)
|
|
286
283
|
emit_event 'Events.FrameManager.FrameNavigatedWithinDocument', frame
|
|
287
284
|
emit_event 'Events.FrameManager.FrameNavigated', frame
|
|
@@ -320,44 +317,29 @@ class Puppeteer::FrameManager
|
|
|
320
317
|
world.context = context
|
|
321
318
|
end
|
|
322
319
|
@context_id_to_context[context_payload['id']] = context
|
|
323
|
-
@context_id_created[context_payload['id']] = Time.now
|
|
324
320
|
end
|
|
325
321
|
|
|
326
322
|
# @param {number} executionContextId
|
|
327
323
|
def handle_execution_context_destroyed(execution_context_id)
|
|
328
324
|
context = @context_id_to_context[execution_context_id]
|
|
329
|
-
return
|
|
325
|
+
return unless context
|
|
330
326
|
@context_id_to_context.delete(execution_context_id)
|
|
331
|
-
@context_id_created.delete(execution_context_id)
|
|
332
327
|
if context.world
|
|
333
328
|
context.world.delete_context(execution_context_id)
|
|
334
329
|
end
|
|
335
330
|
end
|
|
336
331
|
|
|
337
332
|
def handle_execution_contexts_cleared
|
|
338
|
-
|
|
339
|
-
# D, [2020-04-06T01:47:03.101227 #13823] DEBUG -- : RECV << {"method"=>"Runtime.executionContextCreated", "params"=>{"context"=>{"id"=>5, "origin"=>"https://github.com", "name"=>"", "auxData"=>{"isDefault"=>true, "type"=>"default", "frameId"=>"71C347B70848B89DDDEFAA8AB5B0BC92"}}}, "sessionId"=>"53F088EED260C28001D26A019F95D9E3"}
|
|
340
|
-
# D, [2020-04-06T01:47:03.101439 #13823] DEBUG -- : RECV << {"method"=>"Page.frameNavigated", "params"=>{"frame"=>{"id"=>"71C347B70848B89DDDEFAA8AB5B0BC92", "loaderId"=>"80338225D035AC96BAE8F6D4E81C7D51", "url"=>"https://github.com/search?q=puppeteer", "securityOrigin"=>"https://github.com", "mimeType"=>"text/html"}}, "sessionId"=>"53F088EED260C28001D26A019F95D9E3"}
|
|
341
|
-
# D, [2020-04-06T01:47:03.101325 #13823] DEBUG -- : RECV << {"method"=>"Target.targetInfoChanged", "params"=>{"targetInfo"=>{"targetId"=>"71C347B70848B89DDDEFAA8AB5B0BC92", "type"=>"page", "title"=>"https://github.com/search?q=puppeteer", "url"=>"https://github.com/search?q=puppeteer", "attached"=>true, "browserContextId"=>"AF37BC660284CE1552B4ECB147BE9305"}}}
|
|
342
|
-
# D, [2020-04-06T01:47:03.101269 #13823] DEBUG -- : RECV << {"method"=>"Runtime.executionContextsCleared", "params"=>{}, "sessionId"=>"53F088EED260C28001D26A019F95D9E3"}
|
|
343
|
-
# it unexpectedly clears the created execution context.
|
|
344
|
-
# To avoid the problem, just skip recent created ids.
|
|
345
|
-
now = Time.now
|
|
346
|
-
context_ids_to_skip = @context_id_created.select { |k, v| now - v < 1 }.keys
|
|
347
|
-
@context_id_to_context.reject { |k, v| context_ids_to_skip.include?(k) }.each do |execution_context_id, context|
|
|
333
|
+
@context_id_to_context.each do |execution_context_id, context|
|
|
348
334
|
if context.world
|
|
349
335
|
context.world.delete_context(execution_context_id)
|
|
350
336
|
end
|
|
351
337
|
end
|
|
352
|
-
@context_id_to_context.
|
|
338
|
+
@context_id_to_context.clear
|
|
353
339
|
end
|
|
354
340
|
|
|
355
341
|
def execution_context_by_id(context_id)
|
|
356
|
-
context =
|
|
357
|
-
if !context
|
|
358
|
-
raise "INTERNAL ERROR: missing context with id = #{context_id}"
|
|
359
|
-
end
|
|
360
|
-
context
|
|
342
|
+
@context_id_to_context[context_id] or raise "INTERNAL ERROR: missing context with id = #{context_id}"
|
|
361
343
|
end
|
|
362
344
|
|
|
363
345
|
# @param {!Frame} frame
|
data/lib/puppeteer/js_handle.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
class Puppeteer::JSHandle
|
|
2
|
-
using Puppeteer::
|
|
2
|
+
using Puppeteer::DefineAsyncMethod
|
|
3
|
+
include Puppeteer::IfPresent
|
|
3
4
|
|
|
4
5
|
# @param context [Puppeteer::ExecutionContext]
|
|
5
6
|
# @param remote_object [Puppeteer::RemoteObject]
|
|
@@ -46,11 +47,7 @@ class Puppeteer::JSHandle
|
|
|
46
47
|
execution_context.evaluate(page_function, self, *args)
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
# @return [Future<Object>]
|
|
51
|
-
async def async_evaluate(page_function, *args)
|
|
52
|
-
evaluate(page_function, *args)
|
|
53
|
-
end
|
|
50
|
+
define_async_method :async_evaluate
|
|
54
51
|
|
|
55
52
|
# @param page_function [String]
|
|
56
53
|
# @param args {Array<*>}
|
|
@@ -59,28 +56,31 @@ class Puppeteer::JSHandle
|
|
|
59
56
|
execution_context.evaluate_handle(page_function, self, *args)
|
|
60
57
|
end
|
|
61
58
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
define_async_method :async_evaluate_handle
|
|
60
|
+
|
|
61
|
+
# getProperty(propertyName) in JavaScript
|
|
62
|
+
# @param name [String]
|
|
63
|
+
# @return [Puppeteer::JSHandle]
|
|
64
|
+
def property(name)
|
|
65
|
+
js = <<~JAVASCRIPT
|
|
66
|
+
(object, propertyName) => {
|
|
67
|
+
const result = {__proto__: null};
|
|
68
|
+
result[propertyName] = object[propertyName];
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
JAVASCRIPT
|
|
72
|
+
object_handle = evaluate_handle(js, name)
|
|
73
|
+
properties = object_handle.properties
|
|
74
|
+
result = properties[name]
|
|
75
|
+
object_handle.dispose
|
|
76
|
+
result
|
|
67
77
|
end
|
|
68
78
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# const objectHandle = await this.evaluateHandle((object, propertyName) => {
|
|
75
|
-
# const result = {__proto__: null};
|
|
76
|
-
# result[propertyName] = object[propertyName];
|
|
77
|
-
# return result;
|
|
78
|
-
# }, propertyName);
|
|
79
|
-
# const properties = await objectHandle.getProperties();
|
|
80
|
-
# const result = properties.get(propertyName) || null;
|
|
81
|
-
# await objectHandle.dispose();
|
|
82
|
-
# return result;
|
|
83
|
-
# }
|
|
79
|
+
# @param name [String]
|
|
80
|
+
# @return [Puppeteer::JSHandle]
|
|
81
|
+
def [](name)
|
|
82
|
+
property(name)
|
|
83
|
+
end
|
|
84
84
|
|
|
85
85
|
# getProperties in JavaScript.
|
|
86
86
|
# @return [Hash<String, JSHandle>]
|
|
@@ -110,7 +110,7 @@ class Puppeteer::JSHandle
|
|
|
110
110
|
#
|
|
111
111
|
# However it would be better that RemoteObject is responsible for
|
|
112
112
|
# the logic `if (this._remoteObject.objectId) { ... }`.
|
|
113
|
-
@remote_object.evaluate_self(@client) || @remote_object.value
|
|
113
|
+
@remote_object.evaluate_self(@client)&.value || @remote_object.value
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
def as_element
|
|
@@ -128,15 +128,16 @@ class Puppeteer::JSHandle
|
|
|
128
128
|
@disposed
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
def to_s
|
|
132
|
+
# original logic was:
|
|
133
|
+
# if (this._remoteObject.objectId) {
|
|
134
|
+
# const type = this._remoteObject.subtype || this._remoteObject.type;
|
|
135
|
+
# return 'JSHandle@' + type;
|
|
136
|
+
# }
|
|
137
|
+
# return 'JSHandle:' + helper.valueFromRemoteObject(this._remoteObject);
|
|
138
|
+
#
|
|
139
|
+
# However it would be better that RemoteObject is responsible for
|
|
140
|
+
# the logic `if (this._remoteObject.objectId) { ... }`.
|
|
141
|
+
if_present(@remote_object.type_str) { |type_str| "JSHandle@#{type_str}" } || "JSHandle:#{@remote_object.value || 'undefined'}"
|
|
142
|
+
end
|
|
142
143
|
end
|
data/lib/puppeteer/keyboard.rb
CHANGED
|
@@ -2,7 +2,7 @@ require_relative './keyboard/key_description'
|
|
|
2
2
|
require_relative './keyboard/us_keyboard_layout'
|
|
3
3
|
|
|
4
4
|
class Puppeteer::Keyboard
|
|
5
|
-
using Puppeteer::
|
|
5
|
+
using Puppeteer::DefineAsyncMethod
|
|
6
6
|
|
|
7
7
|
# @param {!Puppeteer.CDPSession} client
|
|
8
8
|
def initialize(client)
|
|
@@ -38,12 +38,7 @@ class Puppeteer::Keyboard
|
|
|
38
38
|
@client.send_message('Input.dispatchKeyEvent', params)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
# @param text [String]
|
|
43
|
-
# @return [Future]
|
|
44
|
-
async def async_down(key, text: nil)
|
|
45
|
-
down(key, text)
|
|
46
|
-
end
|
|
41
|
+
define_async_method :async_down
|
|
47
42
|
|
|
48
43
|
# @param {string} key
|
|
49
44
|
# @return {number}
|
|
@@ -127,22 +122,14 @@ class Puppeteer::Keyboard
|
|
|
127
122
|
)
|
|
128
123
|
end
|
|
129
124
|
|
|
130
|
-
|
|
131
|
-
# @return [Future]
|
|
132
|
-
async def async_up(key)
|
|
133
|
-
up(key)
|
|
134
|
-
end
|
|
125
|
+
define_async_method :async_up
|
|
135
126
|
|
|
136
127
|
# @param char [string]
|
|
137
128
|
def send_character(char)
|
|
138
129
|
@client.send_message('Input.insertText', text: char)
|
|
139
130
|
end
|
|
140
131
|
|
|
141
|
-
|
|
142
|
-
# @return [Future]
|
|
143
|
-
async def async_send_character(char)
|
|
144
|
-
send_character(char)
|
|
145
|
-
end
|
|
132
|
+
define_async_method :async_send_character
|
|
146
133
|
|
|
147
134
|
# @param text [String]
|
|
148
135
|
# @return [Future]
|
|
@@ -159,25 +146,18 @@ class Puppeteer::Keyboard
|
|
|
159
146
|
end
|
|
160
147
|
end
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
# @return [Future]
|
|
164
|
-
async def async_type_text(text, delay: nil)
|
|
165
|
-
type_text(text, delay)
|
|
166
|
-
end
|
|
149
|
+
define_async_method :async_type_text
|
|
167
150
|
|
|
168
151
|
# @param key [String]
|
|
152
|
+
# @param text [String]
|
|
169
153
|
# @return [Future]
|
|
170
|
-
def press(key, delay: nil)
|
|
171
|
-
down(key)
|
|
154
|
+
def press(key, delay: nil, text: nil)
|
|
155
|
+
down(key, text: text)
|
|
172
156
|
if delay
|
|
173
157
|
sleep(delay.to_i / 1000.0)
|
|
174
158
|
end
|
|
175
159
|
up(key)
|
|
176
160
|
end
|
|
177
161
|
|
|
178
|
-
|
|
179
|
-
# @return [Future]
|
|
180
|
-
async def async_press(key, delay: nil)
|
|
181
|
-
press(key, delay: delay)
|
|
182
|
-
end
|
|
162
|
+
define_async_method :async_press
|
|
183
163
|
end
|
data/lib/puppeteer/mouse.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class Puppeteer::Mouse
|
|
2
|
-
using Puppeteer::
|
|
2
|
+
using Puppeteer::DefineAsyncMethod
|
|
3
3
|
|
|
4
4
|
module Button
|
|
5
5
|
NONE = 'none'
|
|
@@ -44,13 +44,7 @@ class Puppeteer::Mouse
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
# @param y [number]
|
|
49
|
-
# @param steps [number]
|
|
50
|
-
# @return [Future]
|
|
51
|
-
async def async_move(x, y, steps: nil)
|
|
52
|
-
move(x, y, steps: steps)
|
|
53
|
-
end
|
|
47
|
+
define_async_method :async_move
|
|
54
48
|
|
|
55
49
|
# @param x [number]
|
|
56
50
|
# @param y [number]
|
|
@@ -70,13 +64,7 @@ class Puppeteer::Mouse
|
|
|
70
64
|
up(button: button, click_count: click_count)
|
|
71
65
|
end
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
# @param y [number]
|
|
75
|
-
# @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options
|
|
76
|
-
# @return [Future]
|
|
77
|
-
async def async_click(x, y, delay: nil, button: nil, click_count: nil)
|
|
78
|
-
click(x, y, delay: delay, button: button, click_count: click_count)
|
|
79
|
-
end
|
|
67
|
+
define_async_method :async_click
|
|
80
68
|
|
|
81
69
|
# @param {!{button?: "left"|"right"|"middle", clickCount?: number}=} options
|
|
82
70
|
def down(button: nil, click_count: nil)
|
|
@@ -91,11 +79,7 @@ class Puppeteer::Mouse
|
|
|
91
79
|
)
|
|
92
80
|
end
|
|
93
81
|
|
|
94
|
-
|
|
95
|
-
# @return [Future]
|
|
96
|
-
async def async_down(button: nil, click_count: nil)
|
|
97
|
-
down(button: button, click_count: click_count)
|
|
98
|
-
end
|
|
82
|
+
define_async_method :async_down
|
|
99
83
|
|
|
100
84
|
# @param {!{button?: "left"|"right"|"middle", clickCount?: number}=} options
|
|
101
85
|
def up(button: nil, click_count: nil)
|
|
@@ -110,9 +94,21 @@ class Puppeteer::Mouse
|
|
|
110
94
|
)
|
|
111
95
|
end
|
|
112
96
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
|
|
116
|
-
|
|
97
|
+
# Dispatches a `mousewheel` event.
|
|
98
|
+
#
|
|
99
|
+
# @param delta_x [Integer]
|
|
100
|
+
# @param delta_y [Integer]
|
|
101
|
+
def wheel(delta_x: 0, delta_y: 0)
|
|
102
|
+
@client.send_message('Input.dispatchMouseEvent',
|
|
103
|
+
type: 'mouseWheel',
|
|
104
|
+
x: @x,
|
|
105
|
+
y: @y,
|
|
106
|
+
deltaX: delta_x,
|
|
107
|
+
deltaY: delta_y,
|
|
108
|
+
modifiers: @keyboard.modifiers,
|
|
109
|
+
pointerType: 'mouse',
|
|
110
|
+
)
|
|
117
111
|
end
|
|
112
|
+
|
|
113
|
+
define_async_method :async_up
|
|
118
114
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
class Puppeteer::NetworkManager
|
|
2
|
+
include Puppeteer::DebugPrint
|
|
2
3
|
include Puppeteer::EventCallbackable
|
|
4
|
+
include Puppeteer::IfPresent
|
|
3
5
|
|
|
4
6
|
class Credentials
|
|
5
7
|
# @param username [String|NilClass]
|
|
@@ -23,19 +25,39 @@ class Puppeteer::NetworkManager
|
|
|
23
25
|
@request_id_to_request = {}
|
|
24
26
|
|
|
25
27
|
# @type {!Map<string, !Protocol.Network.requestWillBeSentPayload>}
|
|
26
|
-
@request_id_to_request_with_be_sent_event
|
|
28
|
+
@request_id_to_request_with_be_sent_event = {}
|
|
27
29
|
|
|
28
30
|
@extra_http_headers = {}
|
|
29
31
|
|
|
30
32
|
@offline = false
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
# this._attemptedAuthentications = new Set();
|
|
34
|
+
@attempted_authentications = Set.new
|
|
34
35
|
@user_request_interception_enabled = false
|
|
35
36
|
@protocol_request_interception_enabled = false
|
|
36
37
|
@user_cache_disabled = false
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
@request_id_to_interception_id = {}
|
|
39
|
+
|
|
40
|
+
@client.on_event('Fetch.requestPaused') do |event|
|
|
41
|
+
handle_request_paused(event)
|
|
42
|
+
end
|
|
43
|
+
@client.on_event('Fetch.authRequired') do |event|
|
|
44
|
+
handle_auth_required(event)
|
|
45
|
+
end
|
|
46
|
+
@client.on_event('Network.requestWillBeSent') do |event|
|
|
47
|
+
handle_request_will_be_sent(event)
|
|
48
|
+
end
|
|
49
|
+
@client.on_event('Network.requestServedFromCache') do |event|
|
|
50
|
+
handle_request_served_from_cache(event)
|
|
51
|
+
end
|
|
52
|
+
@client.on_event('Network.responseReceived') do |event|
|
|
53
|
+
handle_response_received(event)
|
|
54
|
+
end
|
|
55
|
+
@client.on_event('Network.loadingFinished') do |event|
|
|
56
|
+
handle_loading_finished(event)
|
|
57
|
+
end
|
|
58
|
+
@client.on_event('Network.loadingFailed') do |event|
|
|
59
|
+
handle_loading_failed(event)
|
|
60
|
+
end
|
|
39
61
|
end
|
|
40
62
|
|
|
41
63
|
def init
|
|
@@ -119,4 +141,140 @@ class Puppeteer::NetworkManager
|
|
|
119
141
|
cache_disabled = @user_cache_disabled || @protocol_request_interception_enabled
|
|
120
142
|
@client.send_message('Network.setCacheDisabled', cacheDisabled: cache_disabled)
|
|
121
143
|
end
|
|
144
|
+
|
|
145
|
+
private def handle_request_will_be_sent(event)
|
|
146
|
+
# Request interception doesn't happen for data URLs with Network Service.
|
|
147
|
+
if @protocol_request_interception_enabled && !event['request']['url'].start_with?('data:')
|
|
148
|
+
request_id = event['requestId']
|
|
149
|
+
interception_id = @request_id_to_interception_id.delete(request_id)
|
|
150
|
+
if interception_id
|
|
151
|
+
handle_request(event, interception_id)
|
|
152
|
+
else
|
|
153
|
+
@request_id_to_request_with_be_sent_event[request_id] = event
|
|
154
|
+
end
|
|
155
|
+
return
|
|
156
|
+
end
|
|
157
|
+
handle_request(event, nil)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private def handle_auth_required(event)
|
|
161
|
+
response = 'Default'
|
|
162
|
+
if @attempted_authentications.include?(event['requestId'])
|
|
163
|
+
response = 'CancelAuth'
|
|
164
|
+
elsif @credentials
|
|
165
|
+
response = 'ProvideCredentials'
|
|
166
|
+
@attempted_authentications << event['requestId']
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
username = @credentials&.username
|
|
170
|
+
password = @credentials&.password
|
|
171
|
+
|
|
172
|
+
begin
|
|
173
|
+
@client.send_message('Fetch.continueWithAuth',
|
|
174
|
+
requestId: event['requestId'],
|
|
175
|
+
authChallengeResponse: {
|
|
176
|
+
response: response,
|
|
177
|
+
username: username,
|
|
178
|
+
password: password,
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
rescue => err
|
|
182
|
+
debug_puts(err)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private def handle_request_paused(event)
|
|
187
|
+
if !@user_request_interception_enabled && @protocol_request_interception_enabled
|
|
188
|
+
begin
|
|
189
|
+
@client.send_message('Fetch.continueRequest', requestId: event['requestId'])
|
|
190
|
+
rescue => err
|
|
191
|
+
debug_puts(err)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
request_id = event['networkId']
|
|
196
|
+
interception_id = event['requestId']
|
|
197
|
+
if request_id && (request_will_be_sent_event = @request_id_to_request_with_be_sent_event.delete(request_id))
|
|
198
|
+
handle_request(request_will_be_sent_event, interception_id)
|
|
199
|
+
else
|
|
200
|
+
@request_id_to_interception_id[request_id] = interception_id
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
private def handle_request(event, interception_id)
|
|
205
|
+
redirect_chain = []
|
|
206
|
+
if event['redirectResponse']
|
|
207
|
+
if_present(@request_id_to_request[event['requestId']]) do |request|
|
|
208
|
+
handle_request_redirect(request, event['redirectResponse'])
|
|
209
|
+
redirect_chain = request.internal.redirect_chain
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) }
|
|
213
|
+
request = Puppeteer::Request.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
|
|
214
|
+
@request_id_to_request[event['requestId']] = request
|
|
215
|
+
emit_event 'Events.NetworkManager.Request', request
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private def handle_request_served_from_cache(event)
|
|
219
|
+
if_present(@request_id_to_request[event['requestId']]) do |request|
|
|
220
|
+
request.internal.from_memory_cache = true
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @param request [Puppeteer::Request]
|
|
225
|
+
# @param response_payload [Hash]
|
|
226
|
+
private def handle_request_redirect(request, response_payload)
|
|
227
|
+
response = Puppeteer::Response.new(@client, request, response_payload)
|
|
228
|
+
request.internal.response = response
|
|
229
|
+
request.internal.redirect_chain << request
|
|
230
|
+
response.internal.body_loaded_promise.reject(Puppeteer::Response::Redirected.new)
|
|
231
|
+
@request_id_to_request.delete(request.internal.request_id)
|
|
232
|
+
@attempted_authentications.delete(request.internal.interception_id)
|
|
233
|
+
emit_event 'Events.NetworkManager.Response', response
|
|
234
|
+
emit_event 'Events.NetworkManager.RequestFinished', request
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# @param event [Hash]
|
|
238
|
+
private def handle_response_received(event)
|
|
239
|
+
request = @request_id_to_request[event['requestId']]
|
|
240
|
+
# FileUpload sends a response without a matching request.
|
|
241
|
+
return unless request
|
|
242
|
+
|
|
243
|
+
response = Puppeteer::Response.new(@client, request, event['response'])
|
|
244
|
+
request.internal.response = response
|
|
245
|
+
emit_event 'Events.NetworkManager.Response', response
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
private def handle_loading_finished(event)
|
|
249
|
+
request = @request_id_to_request[event['requestId']]
|
|
250
|
+
# For certain requestIds we never receive requestWillBeSent event.
|
|
251
|
+
# @see https://crbug.com/750469
|
|
252
|
+
return unless request
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# Under certain conditions we never get the Network.responseReceived
|
|
256
|
+
# event from protocol. @see https://crbug.com/883475
|
|
257
|
+
if_present(request.response) do |response|
|
|
258
|
+
response.internal.body_loaded_promise.fulfill(nil)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
@request_id_to_request.delete(request.internal.request_id)
|
|
262
|
+
@attempted_authentications.delete(request.internal.interception_id)
|
|
263
|
+
emit_event 'Events.NetworkManager.RequestFinished', request
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
private def handle_loading_failed(event)
|
|
267
|
+
request = @request_id_to_request[event['requestId']]
|
|
268
|
+
# For certain requestIds we never receive requestWillBeSent event.
|
|
269
|
+
# @see https://crbug.com/750469
|
|
270
|
+
return unless request
|
|
271
|
+
|
|
272
|
+
request.internal.failure_text = event['errorText']
|
|
273
|
+
if_present(request.response) do |response|
|
|
274
|
+
response.internal.body_loaded_promise.fulfill(nil)
|
|
275
|
+
end
|
|
276
|
+
@request_id_to_request.delete(request.internal.request_id)
|
|
277
|
+
@attempted_authentications.delete(request.internal.interception_id)
|
|
278
|
+
emit_event 'Events.NetworkManager.RequestFailed', request
|
|
279
|
+
end
|
|
122
280
|
end
|