puppeteer-bidi 0.0.1 → 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 +4 -4
- data/API_COVERAGE.md +9 -23
- data/CLAUDE/expose_function_implementation.md +271 -0
- data/CLAUDE.md +1 -0
- data/development/generate_api_coverage.rb +6 -5
- data/lib/puppeteer/bidi/async_utils.rb +25 -9
- data/lib/puppeteer/bidi/browser.rb +2 -1
- data/lib/puppeteer/bidi/core/browser.rb +3 -0
- data/lib/puppeteer/bidi/core/session.rb +1 -0
- data/lib/puppeteer/bidi/exposed_function.rb +390 -0
- data/lib/puppeteer/bidi/frame.rb +82 -9
- data/lib/puppeteer/bidi/page.rb +200 -291
- data/lib/puppeteer/bidi/timeout_settings.rb +23 -6
- data/lib/puppeteer/bidi/version.rb +1 -1
- data/lib/puppeteer/bidi.rb +1 -0
- data/sig/puppeteer/bidi/exposed_function.rbs +127 -0
- data/sig/puppeteer/bidi/frame.rbs +21 -4
- data/sig/puppeteer/bidi/page.rbs +81 -50
- data/sig/puppeteer/bidi/timeout_settings.rbs +16 -4
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7242d594b90af9ed2739ef56e234d3d26805cf19d688212e9b0b68ad823a96c2
|
|
4
|
+
data.tar.gz: 6bca1fe1f82165851376466367cee72ec59f10fabb6b2970a70bcffde5ef42b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c7f73fa6f5351d1e1e12a87388e56c05faa11286bf724e400ec97e19092a81a6e22c6718970c028305717afdaf560ddd16dbfa6f499b5dbc28313b8b55d3347
|
|
7
|
+
data.tar.gz: ad2cc2f58a6da1d6bff87bde5eab283536f46aa160bbc3ac197c6574f9fd5f35950ca47331c9363feea4a93eaa8af76322f38b123e31d9212206d01e01d2d9d4
|
data/API_COVERAGE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
- Puppeteer commit: `7d750c25cb29764f2fb31cb90b750a8eec350199`
|
|
4
4
|
- Generated by: `development/generate_api_coverage.rb`
|
|
5
|
-
- Coverage: `
|
|
5
|
+
- Coverage: `182/265` (`68.68%`)
|
|
6
6
|
|
|
7
7
|
## Browser (Puppeteer::Bidi::Browser)
|
|
8
8
|
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
| `Frame.addStyleTag` | `Puppeteer::Bidi::Frame#add_style_tag` | ❌ |
|
|
112
112
|
| `Frame.childFrames` | `Puppeteer::Bidi::Frame#child_frames` | ✅ |
|
|
113
113
|
| `Frame.click` | `Puppeteer::Bidi::Frame#click` | ✅ |
|
|
114
|
-
| `Frame.content` | `Puppeteer::Bidi::Frame#content` |
|
|
114
|
+
| `Frame.content` | `Puppeteer::Bidi::Frame#content` | ✅ |
|
|
115
115
|
| `Frame.evaluate` | `Puppeteer::Bidi::Frame#evaluate` | ✅ |
|
|
116
116
|
| `Frame.evaluateHandle` | `Puppeteer::Bidi::Frame#evaluate_handle` | ✅ |
|
|
117
117
|
| `Frame.focus` | `Puppeteer::Bidi::Frame#focus` | ❌ |
|
|
@@ -254,12 +254,12 @@
|
|
|
254
254
|
| `Page.emulateVisionDeficiency` | `Puppeteer::Bidi::Page#emulate_vision_deficiency` | ❌ |
|
|
255
255
|
| `Page.evaluate` | `Puppeteer::Bidi::Page#evaluate` | ✅ |
|
|
256
256
|
| `Page.evaluateHandle` | `Puppeteer::Bidi::Page#evaluate_handle` | ✅ |
|
|
257
|
-
| `Page.evaluateOnNewDocument` | `Puppeteer::Bidi::Page#evaluate_on_new_document` |
|
|
258
|
-
| `Page.exposeFunction` | `Puppeteer::Bidi::Page#expose_function` |
|
|
257
|
+
| `Page.evaluateOnNewDocument` | `Puppeteer::Bidi::Page#evaluate_on_new_document` | ✅ |
|
|
258
|
+
| `Page.exposeFunction` | `Puppeteer::Bidi::Page#expose_function` | ✅ |
|
|
259
259
|
| `Page.focus` | `Puppeteer::Bidi::Page#focus` | ✅ |
|
|
260
260
|
| `Page.frames` | `Puppeteer::Bidi::Page#frames` | ✅ |
|
|
261
|
-
| `Page.getDefaultNavigationTimeout` | `Puppeteer::Bidi::Page#get_default_navigation_timeout` |
|
|
262
|
-
| `Page.getDefaultTimeout` | `Puppeteer::Bidi::Page#get_default_timeout` |
|
|
261
|
+
| `Page.getDefaultNavigationTimeout` | `Puppeteer::Bidi::Page#get_default_navigation_timeout` | ✅ |
|
|
262
|
+
| `Page.getDefaultTimeout` | `Puppeteer::Bidi::Page#get_default_timeout` | ✅ |
|
|
263
263
|
| `Page.goBack` | `Puppeteer::Bidi::Page#go_back` | ✅ |
|
|
264
264
|
| `Page.goForward` | `Puppeteer::Bidi::Page#go_forward` | ✅ |
|
|
265
265
|
| `Page.goto` | `Puppeteer::Bidi::Page#goto` | ✅ |
|
|
@@ -275,8 +275,8 @@
|
|
|
275
275
|
| `Page.pdf` | `Puppeteer::Bidi::Page#pdf` | ❌ |
|
|
276
276
|
| `Page.queryObjects` | `Puppeteer::Bidi::Page#query_objects` | ❌ |
|
|
277
277
|
| `Page.reload` | `Puppeteer::Bidi::Page#reload` | ✅ |
|
|
278
|
-
| `Page.removeExposedFunction` | `Puppeteer::Bidi::Page#remove_exposed_function` |
|
|
279
|
-
| `Page.removeScriptToEvaluateOnNewDocument` | `Puppeteer::Bidi::Page#remove_script_to_evaluate_on_new_document` |
|
|
278
|
+
| `Page.removeExposedFunction` | `Puppeteer::Bidi::Page#remove_exposed_function` | ✅ |
|
|
279
|
+
| `Page.removeScriptToEvaluateOnNewDocument` | `Puppeteer::Bidi::Page#remove_script_to_evaluate_on_new_document` | ✅ |
|
|
280
280
|
| `Page.resize` | `Puppeteer::Bidi::Page#resize` | ❌ |
|
|
281
281
|
| `Page.screencast` | `Puppeteer::Bidi::Page#screencast` | ❌ |
|
|
282
282
|
| `Page.screenshot` | `Puppeteer::Bidi::Page#screenshot` | ✅ |
|
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
| `Page.setCacheEnabled` | `Puppeteer::Bidi::Page#set_cache_enabled` | ✅ |
|
|
287
287
|
| `Page.setContent` | `Puppeteer::Bidi::Page#set_content` | ✅ |
|
|
288
288
|
| `Page.setCookie` | `Puppeteer::Bidi::Page#set_cookie` | ✅ |
|
|
289
|
-
| `Page.setDefaultNavigationTimeout` | `Puppeteer::Bidi::Page#set_default_navigation_timeout` |
|
|
289
|
+
| `Page.setDefaultNavigationTimeout` | `Puppeteer::Bidi::Page#set_default_navigation_timeout` | ✅ |
|
|
290
290
|
| `Page.setDefaultTimeout` | `Puppeteer::Bidi::Page#set_default_timeout` | ✅ |
|
|
291
291
|
| `Page.setDragInterception` | `Puppeteer::Bidi::Page#set_drag_interception` | ❌ |
|
|
292
292
|
| `Page.setExtraHTTPHeaders` | `Puppeteer::Bidi::Page#set_extra_http_headers` | ✅ |
|
|
@@ -329,17 +329,3 @@
|
|
|
329
329
|
| `PuppeteerNode.trimCache` | `Puppeteer::Bidi.trim_cache` | ❌ |
|
|
330
330
|
| `Puppeteer.unregisterCustomQueryHandler` | `Puppeteer::Bidi.unregister_custom_query_handler` | ❌ |
|
|
331
331
|
|
|
332
|
-
## Target (Puppeteer::Bidi::Target)
|
|
333
|
-
|
|
334
|
-
| Node.js | Ruby | Supported |
|
|
335
|
-
| --- | --- | :---: |
|
|
336
|
-
| `Target.asPage` | `Puppeteer::Bidi::Target#as_page` | ❌ |
|
|
337
|
-
| `Target.browser` | `Puppeteer::Bidi::Target#browser` | ❌ |
|
|
338
|
-
| `Target.browserContext` | `Puppeteer::Bidi::Target#browser_context` | ❌ |
|
|
339
|
-
| `Target.createCDPSession` | `Puppeteer::Bidi::Target#create_cdp_session` | ❌ |
|
|
340
|
-
| `Target.opener` | `Puppeteer::Bidi::Target#opener` | ❌ |
|
|
341
|
-
| `Target.page` | `Puppeteer::Bidi::Target#page` | ❌ |
|
|
342
|
-
| `Target.type` | `Puppeteer::Bidi::Target#type` | ❌ |
|
|
343
|
-
| `Target.url` | `Puppeteer::Bidi::Target#url` | ❌ |
|
|
344
|
-
| `Target.worker` | `Puppeteer::Bidi::Target#worker` | ❌ |
|
|
345
|
-
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# ExposeFunction and EvaluateOnNewDocument Implementation
|
|
2
|
+
|
|
3
|
+
This document details the implementation of `Page.evaluateOnNewDocument` and `Page.exposeFunction`, which use BiDi preload scripts and `script.message` channel for communication.
|
|
4
|
+
|
|
5
|
+
## Page.evaluateOnNewDocument
|
|
6
|
+
|
|
7
|
+
Injects JavaScript to be evaluated before any page scripts run.
|
|
8
|
+
|
|
9
|
+
### BiDi Implementation
|
|
10
|
+
|
|
11
|
+
Uses `script.addPreloadScript` command:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
def evaluate_on_new_document(page_function, *args)
|
|
15
|
+
expression = build_evaluation_expression(page_function, *args)
|
|
16
|
+
script_id = @browsing_context.add_preload_script(expression).wait
|
|
17
|
+
NewDocumentScriptEvaluation.new(script_id)
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Key Points
|
|
22
|
+
|
|
23
|
+
1. **Preload Scripts Persist**: Scripts added via `addPreloadScript` run on every navigation
|
|
24
|
+
2. **Argument Serialization**: Arguments are serialized into the script as JSON literals
|
|
25
|
+
3. **Return Value**: Returns a `NewDocumentScriptEvaluation` with the script ID for later removal
|
|
26
|
+
|
|
27
|
+
### Example
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
# Inject code that runs before any page scripts
|
|
31
|
+
script = page.evaluate_on_new_document("window.injected = 123")
|
|
32
|
+
page.goto(server.empty_page)
|
|
33
|
+
result = page.evaluate("window.injected") # => 123
|
|
34
|
+
|
|
35
|
+
# Remove when done
|
|
36
|
+
page.remove_script_to_evaluate_on_new_document(script.identifier)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Page.exposeFunction
|
|
40
|
+
|
|
41
|
+
Exposes a Ruby callable as a JavaScript function on the page.
|
|
42
|
+
|
|
43
|
+
### BiDi Implementation
|
|
44
|
+
|
|
45
|
+
Uses `script.message` channel for bidirectional communication:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Page (JS) Ruby (ExposedFunction)
|
|
49
|
+
| |
|
|
50
|
+
|-- callback([resolve,reject,args]) -->|
|
|
51
|
+
| |
|
|
52
|
+
|<-- resolve(result) or reject(error) -|
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Key Components
|
|
56
|
+
|
|
57
|
+
#### 1. Channel Argument Pattern
|
|
58
|
+
|
|
59
|
+
BiDi uses a special `channel` argument type:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
def channel_argument
|
|
63
|
+
{
|
|
64
|
+
type: "channel",
|
|
65
|
+
value: {
|
|
66
|
+
channel: @channel, # Unique channel ID
|
|
67
|
+
ownership: "root" # Keep handles alive
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### 2. Function Declaration
|
|
74
|
+
|
|
75
|
+
The exposed function creates a Promise that waits for the Ruby callback:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
(callback) => {
|
|
79
|
+
Object.assign(globalThis, {
|
|
80
|
+
[name]: function (...args) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
callback([resolve, reject, args]);
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### 3. Message Handling
|
|
90
|
+
|
|
91
|
+
Ruby listens for `script.message` events and processes calls:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
def handle_message(params)
|
|
95
|
+
return unless params["channel"] == @channel
|
|
96
|
+
|
|
97
|
+
# Extract data handle with [resolve, reject, args]
|
|
98
|
+
data_handle = JSHandle.from(params["data"], realm.core_realm)
|
|
99
|
+
|
|
100
|
+
# Call Ruby function and send result back
|
|
101
|
+
result = @apply.call(*args)
|
|
102
|
+
send_result(data_handle, result)
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Session Event Subscription
|
|
107
|
+
|
|
108
|
+
**Important**: `script.message` must be subscribed in the session:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# In Core::Session
|
|
112
|
+
def subscribe_to_events
|
|
113
|
+
subscribe([
|
|
114
|
+
"browsingContext.load",
|
|
115
|
+
"browsingContext.domContentLoaded",
|
|
116
|
+
# ... other events
|
|
117
|
+
"script.message", # Required for exposeFunction
|
|
118
|
+
]).wait
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Frame Handling
|
|
123
|
+
|
|
124
|
+
ExposedFunction handles dynamic frames by:
|
|
125
|
+
|
|
126
|
+
1. **Listening to frameattached**: Injects into new frames
|
|
127
|
+
2. **Using preload scripts**: For top-level browsing contexts (not iframes)
|
|
128
|
+
3. **Using callFunction**: For immediate injection into current context
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
def inject_into_frame(frame)
|
|
132
|
+
# Add preload script for top-level contexts only
|
|
133
|
+
if frame.browsing_context.parent.nil?
|
|
134
|
+
script_id = frame.browsing_context.add_preload_script(
|
|
135
|
+
function_declaration,
|
|
136
|
+
arguments: [channel]
|
|
137
|
+
).wait
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Always call function for immediate availability
|
|
141
|
+
realm.core_realm.call_function(
|
|
142
|
+
function_declaration,
|
|
143
|
+
false,
|
|
144
|
+
arguments: [channel]
|
|
145
|
+
).wait
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Error Handling
|
|
150
|
+
|
|
151
|
+
#### Standard Errors
|
|
152
|
+
|
|
153
|
+
Errors are serialized with name, message, and stack trace:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
def send_error(data_handle, error)
|
|
157
|
+
name = error.class.name
|
|
158
|
+
message = error.message
|
|
159
|
+
stack = error.backtrace&.join("\n")
|
|
160
|
+
|
|
161
|
+
data_handle.evaluate(<<~JS, name, message, stack)
|
|
162
|
+
([, reject], name, message, stack) => {
|
|
163
|
+
const error = new Error(message);
|
|
164
|
+
error.name = name;
|
|
165
|
+
if (stack) { error.stack = stack; }
|
|
166
|
+
reject(error);
|
|
167
|
+
}
|
|
168
|
+
JS
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### Non-Error Values (ThrownValue)
|
|
173
|
+
|
|
174
|
+
Ruby doesn't support `throw "string"` syntax. Use `ThrownValue`:
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
class ThrownValue < StandardError
|
|
178
|
+
attr_reader :value
|
|
179
|
+
|
|
180
|
+
def initialize(value)
|
|
181
|
+
@value = value
|
|
182
|
+
super("Thrown value")
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Usage
|
|
187
|
+
page.expose_function("throwValue") do |value|
|
|
188
|
+
raise ExposedFunction::ThrownValue.new(value)
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Cleanup
|
|
193
|
+
|
|
194
|
+
Disposal removes the function from all frames and cleans up resources:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
def dispose
|
|
198
|
+
session.off("script.message", &@listener)
|
|
199
|
+
page.off(:frameattached, &@frame_listener)
|
|
200
|
+
|
|
201
|
+
# Remove from globalThis
|
|
202
|
+
remove_binding_from_frame(@frame)
|
|
203
|
+
|
|
204
|
+
# Remove preload scripts
|
|
205
|
+
@scripts.each do |frame, script_id|
|
|
206
|
+
frame.browsing_context.remove_preload_script(script_id).wait
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Testing Considerations
|
|
212
|
+
|
|
213
|
+
### CSP Headers
|
|
214
|
+
|
|
215
|
+
Some tests require Content-Security-Policy headers. Use `TestServer#set_csp`:
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
server.set_csp("/empty.html", "script-src 'self'")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Test Asset
|
|
222
|
+
|
|
223
|
+
`spec/assets/tamperable.html` captures `window.injected` before page scripts run:
|
|
224
|
+
|
|
225
|
+
```html
|
|
226
|
+
<script>
|
|
227
|
+
window.result = window.injected;
|
|
228
|
+
</script>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Common Pitfalls
|
|
232
|
+
|
|
233
|
+
### 1. Missing script.message Subscription
|
|
234
|
+
|
|
235
|
+
**Problem**: `exposeFunction` doesn't receive callbacks
|
|
236
|
+
|
|
237
|
+
**Solution**: Ensure `script.message` is in session event subscriptions
|
|
238
|
+
|
|
239
|
+
### 2. Ownership: "root" Required
|
|
240
|
+
|
|
241
|
+
**Problem**: JSHandle becomes invalid before processing
|
|
242
|
+
|
|
243
|
+
**Solution**: Use `ownership: "root"` in channel argument to keep handles alive
|
|
244
|
+
|
|
245
|
+
### 3. Preload Scripts for Iframes
|
|
246
|
+
|
|
247
|
+
**Problem**: `addPreloadScript` not supported for iframe contexts
|
|
248
|
+
|
|
249
|
+
**Solution**: Only use preload scripts for top-level contexts; use `callFunction` for iframes
|
|
250
|
+
|
|
251
|
+
### 4. TypeError on raise nil
|
|
252
|
+
|
|
253
|
+
**Problem**: Ruby's `raise nil` throws `TypeError: exception class/object expected`
|
|
254
|
+
|
|
255
|
+
**Solution**: Catch and convert to `send_thrown_value`:
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
rescue TypeError => e
|
|
259
|
+
if e.message.include?("exception class/object expected")
|
|
260
|
+
send_thrown_value(data_handle, nil)
|
|
261
|
+
else
|
|
262
|
+
send_error(data_handle, e)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## References
|
|
268
|
+
|
|
269
|
+
- [WebDriver BiDi script.message](https://w3c.github.io/webdriver-bidi/#event-script-message)
|
|
270
|
+
- [WebDriver BiDi addPreloadScript](https://w3c.github.io/webdriver-bidi/#command-script-addPreloadScript)
|
|
271
|
+
- [Puppeteer ExposedFunction.ts](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/bidi/ExposedFunction.ts)
|
data/CLAUDE.md
CHANGED
|
@@ -201,6 +201,7 @@ See the [CLAUDE/](CLAUDE/) directory for detailed implementation guides:
|
|
|
201
201
|
- **[Navigation Waiting](CLAUDE/navigation_waiting.md)** - waitForNavigation patterns
|
|
202
202
|
- **[Frame Architecture](CLAUDE/frame_architecture.md)** - Parent-based frame hierarchy
|
|
203
203
|
- **[FileChooser](CLAUDE/file_chooser.md)** - File upload and dialog handling (requires Firefox Nightly)
|
|
204
|
+
- **[ExposeFunction](CLAUDE/expose_function_implementation.md)** - `exposeFunction` and `evaluateOnNewDocument` using BiDi script.message
|
|
204
205
|
- **[Error Handling](CLAUDE/error_handling.md)** - Custom exception types
|
|
205
206
|
|
|
206
207
|
### Testing
|
|
@@ -211,9 +211,9 @@ NODE_OWNER_ALIASES = {
|
|
|
211
211
|
"HTTPResponse" => "HTTPResponse",
|
|
212
212
|
"filechooser" => "FileChooser",
|
|
213
213
|
"fileChooser" => "FileChooser",
|
|
214
|
-
"FileChooser" => "FileChooser"
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
"FileChooser" => "FileChooser"
|
|
215
|
+
# Note: Target is excluded from coverage tracking due to significant
|
|
216
|
+
# implementation differences between Node.js and Ruby versions.
|
|
217
217
|
}.freeze
|
|
218
218
|
|
|
219
219
|
def canonical_node_owner(owner)
|
|
@@ -232,8 +232,9 @@ RUBY_OWNER_CONSTANTS = {
|
|
|
232
232
|
"Mouse" => "Puppeteer::Bidi::Mouse",
|
|
233
233
|
"HTTPRequest" => "Puppeteer::Bidi::HTTPRequest",
|
|
234
234
|
"HTTPResponse" => "Puppeteer::Bidi::HTTPResponse",
|
|
235
|
-
"FileChooser" => "Puppeteer::Bidi::FileChooser"
|
|
236
|
-
|
|
235
|
+
"FileChooser" => "Puppeteer::Bidi::FileChooser"
|
|
236
|
+
# Note: Target is excluded from coverage tracking due to significant
|
|
237
|
+
# implementation differences between Node.js and Ruby versions.
|
|
237
238
|
}.freeze
|
|
238
239
|
|
|
239
240
|
def safe_constantize(name)
|
|
@@ -28,29 +28,45 @@ module Puppeteer
|
|
|
28
28
|
# @yield [async_task] Execute a task within the timeout, optionally receiving Async::Task
|
|
29
29
|
# @return [Async::Task] Async task that resolves/rejects once the operation completes
|
|
30
30
|
def async_timeout(timeout_ms, task = nil, &block)
|
|
31
|
-
timeout_seconds = timeout_ms / 1000.0
|
|
32
|
-
|
|
33
31
|
if task
|
|
34
|
-
Async do |async_task|
|
|
35
|
-
|
|
32
|
+
return Async do |async_task|
|
|
33
|
+
if timeout_ms == 0
|
|
36
34
|
if task.is_a?(Proc)
|
|
37
35
|
args = task.arity.positive? ? [async_task] : []
|
|
38
36
|
task.call(*args)
|
|
39
37
|
else
|
|
40
38
|
await(task)
|
|
41
39
|
end
|
|
40
|
+
else
|
|
41
|
+
timeout_seconds = timeout_ms / 1000.0
|
|
42
|
+
async_task.with_timeout(timeout_seconds) do
|
|
43
|
+
if task.is_a?(Proc)
|
|
44
|
+
args = task.arity.positive? ? [async_task] : []
|
|
45
|
+
task.call(*args)
|
|
46
|
+
else
|
|
47
|
+
await(task)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
end
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if block
|
|
55
|
+
return Async do |async_task|
|
|
56
|
+
if timeout_ms == 0
|
|
47
57
|
args = block.arity.positive? ? [async_task] : []
|
|
48
58
|
await(block.call(*args))
|
|
59
|
+
else
|
|
60
|
+
timeout_seconds = timeout_ms / 1000.0
|
|
61
|
+
async_task.with_timeout(timeout_seconds) do
|
|
62
|
+
args = block.arity.positive? ? [async_task] : []
|
|
63
|
+
await(block.call(*args))
|
|
64
|
+
end
|
|
49
65
|
end
|
|
50
66
|
end
|
|
51
|
-
else
|
|
52
|
-
raise ArgumentError, 'AsyncUtils.async_timeout requires a task or block'
|
|
53
67
|
end
|
|
68
|
+
|
|
69
|
+
raise ArgumentError, 'AsyncUtils.async_timeout requires a task or block'
|
|
54
70
|
end
|
|
55
71
|
|
|
56
72
|
def promise_all(*tasks)
|
|
@@ -91,7 +91,8 @@ module Puppeteer
|
|
|
91
91
|
|
|
92
92
|
# Start transport connection in background thread with Sync reactor
|
|
93
93
|
# Sync is the preferred way to run async code at the top level
|
|
94
|
-
|
|
94
|
+
timeout_ms = ((timeout || 30) * 1000).to_i
|
|
95
|
+
AsyncUtils.async_timeout(timeout_ms, transport.connect).wait
|
|
95
96
|
|
|
96
97
|
connection = Connection.new(transport)
|
|
97
98
|
|
|
@@ -81,6 +81,9 @@ module Puppeteer
|
|
|
81
81
|
if options[:contexts]
|
|
82
82
|
params[:contexts] = options[:contexts].map(&:id)
|
|
83
83
|
end
|
|
84
|
+
if options.key?(:arguments) || options.key?("arguments")
|
|
85
|
+
params[:arguments] = options[:arguments] || options["arguments"]
|
|
86
|
+
end
|
|
84
87
|
params[:sandbox] = options[:sandbox] if options[:sandbox]
|
|
85
88
|
|
|
86
89
|
Async do
|