puppeteer-ruby 0.0.2
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +7 -0
- data/Dockerfile +6 -0
- data/Gemfile +6 -0
- data/README.md +41 -0
- data/Rakefile +1 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +15 -0
- data/example.rb +7 -0
- data/lib/puppeteer.rb +192 -0
- data/lib/puppeteer/async_await_behavior.rb +34 -0
- data/lib/puppeteer/browser.rb +240 -0
- data/lib/puppeteer/browser_context.rb +90 -0
- data/lib/puppeteer/browser_fetcher.rb +6 -0
- data/lib/puppeteer/browser_runner.rb +142 -0
- data/lib/puppeteer/cdp_session.rb +78 -0
- data/lib/puppeteer/concurrent_ruby_utils.rb +37 -0
- data/lib/puppeteer/connection.rb +254 -0
- data/lib/puppeteer/console_message.rb +24 -0
- data/lib/puppeteer/debug_print.rb +20 -0
- data/lib/puppeteer/device.rb +12 -0
- data/lib/puppeteer/devices.rb +885 -0
- data/lib/puppeteer/dom_world.rb +447 -0
- data/lib/puppeteer/element_handle.rb +433 -0
- data/lib/puppeteer/emulation_manager.rb +46 -0
- data/lib/puppeteer/errors.rb +4 -0
- data/lib/puppeteer/event_callbackable.rb +88 -0
- data/lib/puppeteer/execution_context.rb +230 -0
- data/lib/puppeteer/frame.rb +278 -0
- data/lib/puppeteer/frame_manager.rb +380 -0
- data/lib/puppeteer/if_present.rb +18 -0
- data/lib/puppeteer/js_handle.rb +142 -0
- data/lib/puppeteer/keyboard.rb +183 -0
- data/lib/puppeteer/keyboard/key_description.rb +19 -0
- data/lib/puppeteer/keyboard/us_keyboard_layout.rb +283 -0
- data/lib/puppeteer/launcher.rb +26 -0
- data/lib/puppeteer/launcher/base.rb +48 -0
- data/lib/puppeteer/launcher/browser_options.rb +41 -0
- data/lib/puppeteer/launcher/chrome.rb +165 -0
- data/lib/puppeteer/launcher/chrome_arg_options.rb +49 -0
- data/lib/puppeteer/launcher/launch_options.rb +68 -0
- data/lib/puppeteer/lifecycle_watcher.rb +168 -0
- data/lib/puppeteer/mouse.rb +120 -0
- data/lib/puppeteer/network_manager.rb +122 -0
- data/lib/puppeteer/page.rb +1001 -0
- data/lib/puppeteer/page/screenshot_options.rb +78 -0
- data/lib/puppeteer/remote_object.rb +124 -0
- data/lib/puppeteer/target.rb +150 -0
- data/lib/puppeteer/timeout_settings.rb +15 -0
- data/lib/puppeteer/touch_screen.rb +43 -0
- data/lib/puppeteer/version.rb +3 -0
- data/lib/puppeteer/viewport.rb +36 -0
- data/lib/puppeteer/wait_task.rb +6 -0
- data/lib/puppeteer/web_socket.rb +117 -0
- data/lib/puppeteer/web_socket_transport.rb +49 -0
- data/puppeteer-ruby.gemspec +29 -0
- metadata +213 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
class Puppeteer::EmulationManager
|
2
|
+
using Puppeteer::AsyncAwaitBehavior
|
3
|
+
|
4
|
+
# @param {!Puppeteer.CDPSession} client
|
5
|
+
def initialize(client)
|
6
|
+
@client = client
|
7
|
+
@emulating_mobile = false
|
8
|
+
@has_touch = false
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param viewport [Puppeteer::Viewport]
|
12
|
+
# @return [true|false]
|
13
|
+
def emulate_viewport(viewport)
|
14
|
+
mobile = viewport.mobile?
|
15
|
+
width = viewport.width
|
16
|
+
height = viewport.height
|
17
|
+
device_scale_factor = viewport.device_scale_factor
|
18
|
+
# /** @type {Protocol.Emulation.ScreenOrientation} */
|
19
|
+
# const screenOrientation = viewport.isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' };
|
20
|
+
has_touch = viewport.has_touch?
|
21
|
+
|
22
|
+
await_all(
|
23
|
+
@client.async_send_message('Emulation.setDeviceMetricsOverride',
|
24
|
+
mobile: mobile,
|
25
|
+
width: width,
|
26
|
+
height: height,
|
27
|
+
deviceScaleFactor: device_scale_factor,
|
28
|
+
# screenOrientation: screen_orientation,
|
29
|
+
),
|
30
|
+
@client.async_send_message('Emulation.setTouchEmulationEnabled',
|
31
|
+
enabled: has_touch,
|
32
|
+
),
|
33
|
+
)
|
34
|
+
|
35
|
+
reload_needed = @emulating_mobile != mobile || @hasTouch != has_touch;
|
36
|
+
@emulating_mobile = mobile
|
37
|
+
@has_touch = has_touch
|
38
|
+
return reload_needed
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param viewport [Puppeteer::Viewport]
|
42
|
+
# @return [Future<true|false>]
|
43
|
+
async def async_emulate_viewport(viewport)
|
44
|
+
emulate_viewport(viewport)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Puppeteer::EventCallbackable
|
4
|
+
class EventListeners
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@listeners = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String] Listener ID
|
12
|
+
def add(&block)
|
13
|
+
id = SecureRandom.hex(8)
|
14
|
+
@listeners[id] = block
|
15
|
+
id
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param id [String] Listener ID returned on #add
|
19
|
+
def delete(id)
|
20
|
+
@listeners.delete(id)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @implement Enumerable#each
|
24
|
+
def each(&block)
|
25
|
+
@listeners.values.each(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_event_listener(event_name, &block)
|
30
|
+
@event_listeners ||= {}
|
31
|
+
(@event_listeners[event_name] ||= EventListeners.new).add(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_event_listener(*id_args)
|
35
|
+
(@event_listeners ||= {}).each do |event_name, listeners|
|
36
|
+
id_args.each do |id|
|
37
|
+
listeners.delete(id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_event(event_name, &block)
|
43
|
+
@event_callbackable_handlers ||= {}
|
44
|
+
@event_callbackable_handlers[event_name] = block
|
45
|
+
end
|
46
|
+
|
47
|
+
def emit_event(event_name, *args, **kwargs)
|
48
|
+
@event_callbackable_handlers ||= {}
|
49
|
+
@event_listeners ||= {}
|
50
|
+
|
51
|
+
if kwargs.empty?
|
52
|
+
# In Ruby's specification (version < 2.7),
|
53
|
+
# `method(:x).call(*args, **kwargs)` is equivalent to `x(*args, {})`
|
54
|
+
# It often causes unexpected ArgumentError.
|
55
|
+
#
|
56
|
+
# ----------------
|
57
|
+
# def greet
|
58
|
+
# puts 'Hello!'
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# def call_me(*args, **kwargs)
|
62
|
+
# greet(*args, **kwargs) # => 'Hello!'
|
63
|
+
#
|
64
|
+
# method(:greet).call(*args, **kwargs) # => `greet': wrong number of arguments (given 1, expected 0) (ArgumentError)
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# call_me
|
68
|
+
# ----------------
|
69
|
+
#
|
70
|
+
# This behavior is really annoying, and should be avoided, because we often want to set event handler as below:
|
71
|
+
#
|
72
|
+
# `on_event 'Some.Event.awesome', &method(:handle_awesome_event)`
|
73
|
+
#
|
74
|
+
# So Let's avoid it by checking kwargs.
|
75
|
+
@event_callbackable_handlers[event_name]&.call(*args)
|
76
|
+
@event_listeners[event_name]&.each do |proc|
|
77
|
+
proc.call(*args)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
@event_callbackable_handlers[event_name]&.call(*args, **kwargs)
|
81
|
+
@event_listeners[event_name]&.each do |proc|
|
82
|
+
proc.call(*args, **kwargs)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
event_name
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
class Puppeteer::ExecutionContext
|
2
|
+
include Puppeteer::IfPresent
|
3
|
+
using Puppeteer::AsyncAwaitBehavior
|
4
|
+
|
5
|
+
EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__'
|
6
|
+
SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m
|
7
|
+
|
8
|
+
# @param client [Puppeteer::CDPSession]
|
9
|
+
# @param context_payload [Hash]
|
10
|
+
# @param world [Puppeteer::DOMWorld?]
|
11
|
+
def initialize(client, context_payload, world)
|
12
|
+
@client = client
|
13
|
+
@world = world
|
14
|
+
@context_id = context_payload['id']
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :client, :world
|
18
|
+
|
19
|
+
# @return [Puppeteer::Frame]
|
20
|
+
def frame
|
21
|
+
if_present(@world) do |world|
|
22
|
+
world.frame
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param page_function [String]
|
27
|
+
# @return [Object]
|
28
|
+
def evaluate(page_function, *args)
|
29
|
+
evaluate_internal(true, page_function, *args)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param page_function [String]
|
33
|
+
# @return [Puppeteer::JSHandle]
|
34
|
+
def evaluate_handle(page_function, *args)
|
35
|
+
evaluate_internal(false, page_function, *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
class JavaScriptExpression
|
39
|
+
def initialize(execution_context, expression, return_by_value)
|
40
|
+
@execution_context = execution_context
|
41
|
+
@expression = expression
|
42
|
+
@return_by_value = return_by_value
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param client [Puppeteer::CDPSession]
|
46
|
+
# @param context_id [String]
|
47
|
+
# @return [Object|JSHandle]
|
48
|
+
def evaluate_with(client:, context_id:)
|
49
|
+
result = client.send_message('Runtime.evaluate',
|
50
|
+
expression: expression_with_source_url,
|
51
|
+
contextId: context_id,
|
52
|
+
returnByValue: @return_by_value,
|
53
|
+
awaitPromise: true,
|
54
|
+
userGesture: true,
|
55
|
+
)
|
56
|
+
# }).catch(rewriteError);
|
57
|
+
|
58
|
+
exception_details = result["exceptionDetails"]
|
59
|
+
if exception_details
|
60
|
+
raise EvaluationError.new("Evaluation failed: #{exception_details}")
|
61
|
+
end
|
62
|
+
|
63
|
+
remote_object = Puppeteer::RemoteObject.new(result['result'])
|
64
|
+
if @return_by_value
|
65
|
+
remote_object.value
|
66
|
+
else
|
67
|
+
Puppeteer::JSHandle.create(
|
68
|
+
context: @execution_context,
|
69
|
+
remote_object: remote_object,
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private def suffix
|
75
|
+
"//# sourceURL=#{EVALUATION_SCRIPT_URL}"
|
76
|
+
end
|
77
|
+
|
78
|
+
private def expression_with_source_url
|
79
|
+
if SOURCE_URL_REGEX.match?(@expression)
|
80
|
+
@expression
|
81
|
+
else
|
82
|
+
"#{@expression}\n#{suffix}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class JavaScriptFunction
|
88
|
+
include Puppeteer::IfPresent
|
89
|
+
|
90
|
+
def initialize(execution_context, expression, args, return_by_value)
|
91
|
+
@execution_context = execution_context
|
92
|
+
@expression = expression
|
93
|
+
@return_by_value = return_by_value
|
94
|
+
@args = args
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param client [Puppeteer::CDPSession]
|
98
|
+
# @param context_id [String]
|
99
|
+
# @return [Object|JSHandle]
|
100
|
+
def evaluate_with(client:, context_id:)
|
101
|
+
# `function` can be omitted in JS after ES2015.
|
102
|
+
# https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
103
|
+
#
|
104
|
+
# Original puppeteer implementation take it into consideration.
|
105
|
+
# But we don't support the syntax here.
|
106
|
+
|
107
|
+
result = client.send_message('Runtime.callFunctionOn',
|
108
|
+
functionDeclaration: "#{@expression}\n#{suffix}\n",
|
109
|
+
executionContextId: context_id,
|
110
|
+
arguments: converted_args,
|
111
|
+
returnByValue: @return_by_value,
|
112
|
+
awaitPromise: true,
|
113
|
+
userGesture: true,
|
114
|
+
) #.catch(rewriteError);
|
115
|
+
|
116
|
+
exception_details = result["exceptionDetails"]
|
117
|
+
remote_object = Puppeteer::RemoteObject.new(result["result"])
|
118
|
+
|
119
|
+
if exception_details
|
120
|
+
raise EvaluationError.new("Evaluation failed: #{exceptionDetails}")
|
121
|
+
end
|
122
|
+
|
123
|
+
if @return_by_value
|
124
|
+
remote_object.value
|
125
|
+
else
|
126
|
+
Puppeteer::JSHandle.create(
|
127
|
+
context: @execution_context,
|
128
|
+
remote_object: remote_object,
|
129
|
+
)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private def converted_args
|
134
|
+
# if (typeof arg === 'bigint') // eslint-disable-line valid-typeof
|
135
|
+
# return { unserializableValue: `${arg.toString()}n` };
|
136
|
+
# if (Object.is(arg, -0))
|
137
|
+
# return { unserializableValue: '-0' };
|
138
|
+
# if (Object.is(arg, Infinity))
|
139
|
+
# return { unserializableValue: 'Infinity' };
|
140
|
+
# if (Object.is(arg, -Infinity))
|
141
|
+
# return { unserializableValue: '-Infinity' };
|
142
|
+
# if (Object.is(arg, NaN))
|
143
|
+
# return { unserializableValue: 'NaN' };
|
144
|
+
@args.map do |arg|
|
145
|
+
if arg && arg.is_a?(Puppeteer::JSHandle)
|
146
|
+
if arg.context != @execution_context
|
147
|
+
raise EvaluationError.new('JSHandles can be evaluated only in the context they were created!')
|
148
|
+
elsif arg.disposed?
|
149
|
+
raise EvaluationError.new('JSHandles is disposed!')
|
150
|
+
end
|
151
|
+
|
152
|
+
arg.remote_object.converted_arg
|
153
|
+
else
|
154
|
+
{ value: arg }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# /**
|
160
|
+
# * @param {!Error} error
|
161
|
+
# * @return {!Protocol.Runtime.evaluateReturnValue}
|
162
|
+
# */
|
163
|
+
# function rewriteError(error) {
|
164
|
+
# if (error.message.includes('Object reference chain is too long'))
|
165
|
+
# return {result: {type: 'undefined'}};
|
166
|
+
# if (error.message.includes('Object couldn\'t be returned by value'))
|
167
|
+
# return {result: {type: 'undefined'}};
|
168
|
+
|
169
|
+
# if (error.message.endsWith('Cannot find context with specified id') || error.message.endsWith('Inspected target navigated or closed'))
|
170
|
+
# throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
171
|
+
# throw error;
|
172
|
+
# }
|
173
|
+
|
174
|
+
private def suffix
|
175
|
+
"//# sourceURL=#{EVALUATION_SCRIPT_URL}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class EvaluationError < StandardError ; end
|
180
|
+
|
181
|
+
# @param return_by_value [Boolean]
|
182
|
+
# @param page_function [String]
|
183
|
+
# @return [Object|Puppeteer::JSHandle]
|
184
|
+
private def evaluate_internal(return_by_value, page_function, *args)
|
185
|
+
# `function` can be omitted in JS after ES2015.
|
186
|
+
# https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
187
|
+
# But we don't support the syntax here.
|
188
|
+
js_object =
|
189
|
+
if ["=>", "async", "function"].any? { |keyword| page_function.include?(keyword) }
|
190
|
+
JavaScriptFunction.new(self, page_function, args, return_by_value)
|
191
|
+
else
|
192
|
+
JavaScriptExpression.new(self, page_function, return_by_value)
|
193
|
+
end
|
194
|
+
|
195
|
+
js_object.evaluate_with(
|
196
|
+
client: @client,
|
197
|
+
context_id: @context_id,
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
# /**
|
202
|
+
# * @param {!JSHandle} prototypeHandle
|
203
|
+
# * @return {!Promise<!JSHandle>}
|
204
|
+
# */
|
205
|
+
# async queryObjects(prototypeHandle) {
|
206
|
+
# assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
|
207
|
+
# assert(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
|
208
|
+
# const response = await this._client.send('Runtime.queryObjects', {
|
209
|
+
# prototypeObjectId: prototypeHandle._remoteObject.objectId
|
210
|
+
# });
|
211
|
+
# return createJSHandle(this, response.objects);
|
212
|
+
# }
|
213
|
+
|
214
|
+
# /**
|
215
|
+
# * @param {Puppeteer.ElementHandle} elementHandle
|
216
|
+
# * @return {Promise<Puppeteer.ElementHandle>}
|
217
|
+
# */
|
218
|
+
# async _adoptElementHandle(elementHandle) {
|
219
|
+
# assert(elementHandle.executionContext() !== this, 'Cannot adopt handle that already belongs to this execution context');
|
220
|
+
# assert(this._world, 'Cannot adopt handle without DOMWorld');
|
221
|
+
# const nodeInfo = await this._client.send('DOM.describeNode', {
|
222
|
+
# objectId: elementHandle._remoteObject.objectId,
|
223
|
+
# });
|
224
|
+
# const {object} = await this._client.send('DOM.resolveNode', {
|
225
|
+
# backendNodeId: nodeInfo.node.backendNodeId,
|
226
|
+
# executionContextId: this._contextId,
|
227
|
+
# });
|
228
|
+
# return /** @type {Puppeteer.ElementHandle}*/(createJSHandle(this, object));
|
229
|
+
# }
|
230
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
class Puppeteer::Frame
|
2
|
+
# @param {!FrameManager} frameManager
|
3
|
+
# @param {!Puppeteer.CDPSession} client
|
4
|
+
# @param {?Frame} parentFrame
|
5
|
+
# @param {string} frameId
|
6
|
+
def initialize(frame_manager, client, parent_frame, frame_id)
|
7
|
+
@frame_manager = frame_manager
|
8
|
+
@client = client
|
9
|
+
@parent_frame = parent_frame
|
10
|
+
@id = frame_id
|
11
|
+
@detached = false
|
12
|
+
|
13
|
+
@loader_id = ''
|
14
|
+
@lifecycle_events = Set.new
|
15
|
+
@main_world = Puppeteer::DOMWorld.new(frame_manager, self, frame_manager.timeout_settings)
|
16
|
+
@secondary_world = Puppeteer::DOMWorld.new(frame_manager, self, frame_manager.timeout_settings)
|
17
|
+
@child_frames = Set.new
|
18
|
+
if parent_frame
|
19
|
+
parent_frame._child_frames << self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :frame_manager, :id, :loader_id, :lifecycle_events, :main_world, :secondary_world
|
24
|
+
|
25
|
+
# @param url [String]
|
26
|
+
# @param rederer [String]
|
27
|
+
# @param timeout [number|nil]
|
28
|
+
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
29
|
+
# @return [Puppeteer::Response]
|
30
|
+
def goto(url, referer: nil, timeout: nil, wait_until: nil)
|
31
|
+
@frame_manager.navigate_frame(self, url, referer: referer, timeout: timeout, wait_until: wait_until)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param timeout [number|nil]
|
35
|
+
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
36
|
+
def wait_for_navigation(timeout: nil, wait_until: nil)
|
37
|
+
@frame_manager.wait_for_frame_navigation(self, timeout: timeout, wait_until: wait_until)
|
38
|
+
end
|
39
|
+
|
40
|
+
def execution_context
|
41
|
+
@main_world.execution_context
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param {Function|string} pageFunction
|
45
|
+
# @return {!Promise<!Puppeteer.JSHandle>}
|
46
|
+
def evaluate_handle(page_function, *args)
|
47
|
+
@main_world.evaluate_handle(page_function, *args)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param {Function|string} pageFunction
|
51
|
+
# @param {!Array<*>} args
|
52
|
+
def evaluate(page_function, *args)
|
53
|
+
@main_world.evaluate(page_function, *args)
|
54
|
+
end
|
55
|
+
|
56
|
+
# `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
57
|
+
# @param {string} selector
|
58
|
+
# @return {!Promise<?Puppeteer.ElementHandle>}
|
59
|
+
def S(selector)
|
60
|
+
@main_world.S(selector)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
65
|
+
# @param {string} expression
|
66
|
+
# @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
67
|
+
def Sx(expression)
|
68
|
+
@main_world.Sx(expression)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
73
|
+
# @param {string} selector
|
74
|
+
# @param {Function|string} pageFunction
|
75
|
+
# @param {!Array<*>} args
|
76
|
+
# @return {!Promise<(!Object|undefined)>}
|
77
|
+
def Seval(selector, page_function, *args)
|
78
|
+
@main_world.Seval(selector, page_function, *args)
|
79
|
+
end
|
80
|
+
|
81
|
+
# `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
82
|
+
# @param {string} selector
|
83
|
+
# @param {Function|string} pageFunction
|
84
|
+
# @param {!Array<*>} args
|
85
|
+
# @return {!Promise<(!Object|undefined)>}
|
86
|
+
def SSeval(selector, page_function, *args)
|
87
|
+
@main_world.SSeval(selector, page_function, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
# `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
91
|
+
# @param {string} selector
|
92
|
+
# @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
93
|
+
def SS(selector)
|
94
|
+
@main_world.SS(selector)
|
95
|
+
end
|
96
|
+
|
97
|
+
def content
|
98
|
+
@secondary_world.content
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param {string} html
|
102
|
+
# @param {!{timeout?: number, waitUntil?: string|!Array<string>}=} options
|
103
|
+
def set_content(html, timeout: nil, wait_until: nil)
|
104
|
+
@secondary_world.set_content(html, timeout: timeout, wait_until: wait_until)
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [String]
|
108
|
+
def name
|
109
|
+
@name || ''
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [String]
|
113
|
+
def url
|
114
|
+
@url
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Frame?]
|
118
|
+
def parent_frame
|
119
|
+
@parent_frame
|
120
|
+
end
|
121
|
+
|
122
|
+
protected def _child_frames
|
123
|
+
@child_frames
|
124
|
+
end
|
125
|
+
|
126
|
+
def child_frames
|
127
|
+
@child_frames.dup
|
128
|
+
end
|
129
|
+
|
130
|
+
def detached?
|
131
|
+
@detached
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param style_tag [Puppeteer::Page::ScriptTag]
|
135
|
+
# @return {!Promise<!ElementHandle>}
|
136
|
+
def add_script_tag(script_tag)
|
137
|
+
@main_world.add_script_tag(script_tag)
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param style_tag [Puppeteer::Page::StyleTag]
|
141
|
+
# @return {!Promise<!ElementHandle>}
|
142
|
+
def add_style_tag(style_tag)
|
143
|
+
@main_world.add_style_tag(style_tag)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @param {string} selector
|
147
|
+
# @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options
|
148
|
+
def click(selector, delay: nil, button: nil, click_count: nil)
|
149
|
+
@secondary_world.click(selector, delay: delay, button: button, click_count: click_count)
|
150
|
+
end
|
151
|
+
|
152
|
+
# @param {string} selector
|
153
|
+
def focus(selector)
|
154
|
+
@secondary_world.focus(selector)
|
155
|
+
end
|
156
|
+
|
157
|
+
# @param {string} selector
|
158
|
+
def hover(selector)
|
159
|
+
@secondary_world.hover(selector)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @param {string} selector
|
163
|
+
# @param {!Array<string>} values
|
164
|
+
# @return {!Promise<!Array<string>>}
|
165
|
+
def select(selector, *values)
|
166
|
+
@secondary_world.select(selector, *values)
|
167
|
+
end
|
168
|
+
|
169
|
+
# @param {string} selector
|
170
|
+
def tap(selector)
|
171
|
+
@secondary_world.tap(selector)
|
172
|
+
end
|
173
|
+
|
174
|
+
# @param {string} selector
|
175
|
+
# @param {string} text
|
176
|
+
# @param {{delay: (number|undefined)}=} options
|
177
|
+
def type(selector, text, delay: nil)
|
178
|
+
@main_world.type(selector, text, delay: delay)
|
179
|
+
end
|
180
|
+
|
181
|
+
# /**
|
182
|
+
# * @param {(string|number|Function)} selectorOrFunctionOrTimeout
|
183
|
+
# * @param {!Object=} options
|
184
|
+
# * @param {!Array<*>} args
|
185
|
+
# * @return {!Promise<?Puppeteer.JSHandle>}
|
186
|
+
# */
|
187
|
+
# waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) {
|
188
|
+
# const xPathPattern = '//';
|
189
|
+
|
190
|
+
# if (helper.isString(selectorOrFunctionOrTimeout)) {
|
191
|
+
# const string = /** @type {string} */ (selectorOrFunctionOrTimeout);
|
192
|
+
# if (string.startsWith(xPathPattern))
|
193
|
+
# return this.waitForXPath(string, options);
|
194
|
+
# return this.waitForSelector(string, options);
|
195
|
+
# }
|
196
|
+
# if (helper.isNumber(selectorOrFunctionOrTimeout))
|
197
|
+
# return new Promise(fulfill => setTimeout(fulfill, /** @type {number} */ (selectorOrFunctionOrTimeout)));
|
198
|
+
# if (typeof selectorOrFunctionOrTimeout === 'function')
|
199
|
+
# return this.waitForFunction(selectorOrFunctionOrTimeout, options, ...args);
|
200
|
+
# return Promise.reject(new Error('Unsupported target type: ' + (typeof selectorOrFunctionOrTimeout)));
|
201
|
+
# }
|
202
|
+
|
203
|
+
# @param {string} selector
|
204
|
+
# @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
205
|
+
# @return {!Promise<?Puppeteer.ElementHandle>}
|
206
|
+
def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
|
207
|
+
handle = @secondary_world.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout)
|
208
|
+
if !handle
|
209
|
+
return nil
|
210
|
+
end
|
211
|
+
main_execution_context = @main_world.execution_context
|
212
|
+
result = main_execution_context.adopt_element_handle(handle)
|
213
|
+
handle.dispose
|
214
|
+
return result
|
215
|
+
end
|
216
|
+
|
217
|
+
# @param {string} xpath
|
218
|
+
# @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
219
|
+
# @return {!Promise<?Puppeteer.ElementHandle>}
|
220
|
+
def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil)
|
221
|
+
handle = @secondary_world.wait_for_xpath(xpath, visible: visible, hidden: hidden, timeout: timeout)
|
222
|
+
if !handle
|
223
|
+
return nil
|
224
|
+
end
|
225
|
+
main_execution_context = @main_world.execution_context
|
226
|
+
result = main_execution_context.adopt_element_handle(handle)
|
227
|
+
handle.dispose
|
228
|
+
return result
|
229
|
+
end
|
230
|
+
|
231
|
+
# @param {Function|string} pageFunction
|
232
|
+
# @param {!{polling?: string|number, timeout?: number}=} options
|
233
|
+
# @param {!Array<*>} args
|
234
|
+
# @return {!Promise<!Puppeteer.JSHandle>}
|
235
|
+
def wait_for_function(page_function, options = {}, *args)
|
236
|
+
@main_world.wait_for_function(page_function, options, *args)
|
237
|
+
end
|
238
|
+
|
239
|
+
def title
|
240
|
+
@secondary_world.title
|
241
|
+
end
|
242
|
+
|
243
|
+
# @param frame_payload [Hash]
|
244
|
+
def navigated(frame_payload)
|
245
|
+
@name = frame_payload['name']
|
246
|
+
# TODO(lushnikov): remove this once requestInterception has loaderId exposed.
|
247
|
+
@navigation_url = frame_payload['url']
|
248
|
+
@url = frame_payload['url']
|
249
|
+
end
|
250
|
+
|
251
|
+
# @param url [String]
|
252
|
+
def navigated_within_document(url)
|
253
|
+
@url = url
|
254
|
+
end
|
255
|
+
|
256
|
+
def handle_lifecycle_event(loader_id, name)
|
257
|
+
if name == 'init'
|
258
|
+
@loader_id = loader_id
|
259
|
+
@lifecycle_events.clear
|
260
|
+
end
|
261
|
+
@lifecycle_events << name
|
262
|
+
end
|
263
|
+
|
264
|
+
def handle_loading_stopped
|
265
|
+
@lifecycle_events << 'DOMContentLoaded'
|
266
|
+
@lifecycle_events << 'load'
|
267
|
+
end
|
268
|
+
|
269
|
+
def detach
|
270
|
+
@detached = true
|
271
|
+
# this._mainWorld._detach();
|
272
|
+
# this._secondaryWorld._detach();
|
273
|
+
if @parent_frame
|
274
|
+
@parent_frame._child_frames.delete(self)
|
275
|
+
end
|
276
|
+
@parent_frame = nil
|
277
|
+
end
|
278
|
+
end
|