puppeteer-ruby 0.50.0.alpha5 → 0.50.0.alpha6
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/AGENTS.md +1 -0
- data/CLAUDE/porting_puppeteer.md +30 -0
- data/CLAUDE/spec_migration_plans.md +8 -10
- data/README.md +3 -2
- data/docs/api_coverage.md +20 -20
- data/lib/puppeteer/element_handle.rb +5 -0
- data/lib/puppeteer/frame.rb +15 -0
- data/lib/puppeteer/js_handle.rb +22 -3
- data/lib/puppeteer/locators.rb +733 -0
- data/lib/puppeteer/p_query_handler.rb +367 -0
- data/lib/puppeteer/p_selector_parser.rb +241 -0
- data/lib/puppeteer/page.rb +15 -0
- data/lib/puppeteer/query_handler_manager.rb +14 -60
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer.rb +3 -0
- data/sig/puppeteer/element_handle.rbs +3 -0
- data/sig/puppeteer/frame.rbs +7 -0
- data/sig/puppeteer/locators.rbs +222 -0
- data/sig/puppeteer/p_query_handler.rbs +73 -0
- data/sig/puppeteer/p_selector_parser.rbs +31 -0
- data/sig/puppeteer/page.rbs +7 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24705930799f6f57d44adea7741837c3e5af927f42990f43c1194e0c71a8b813
|
|
4
|
+
data.tar.gz: 68a01d815bc7d6fe2e7223d08a44c256274469bb5e665a98fb86da37ee202445
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c4fc76a84ee3da78f2bca282c0c7b799dffc1bc3160413c3fe32f7053bc007b614b42f4a0867db8e6a7fb10ffb9855d171c311d4a77d0127e7cc5a89737e247
|
|
7
|
+
data.tar.gz: 31602ed31b3710ba50b4f7b1594edc32ac3f18b1203448d8b4ed24424ff9c068d0d96a7578759d3419574416f7bcc7d9aef22b630f7f9d7e6baa3259c3479af0
|
data/AGENTS.md
CHANGED
|
@@ -155,6 +155,7 @@ See `CLAUDE/porting_puppeteer.md` for detailed examples.
|
|
|
155
155
|
- RxJS Observable flows are replaced with manual EventEmitter listeners + `Async::Promise` (no `fromEmitterEvent`/`merge`/`timeout`), so compose waits explicitly (e.g., `wait_for_navigation`, `set_content`).
|
|
156
156
|
- Use `AsyncUtils` (Barrier-based Promise.all/race + `async_timeout`) instead of RxJS `combineLatest`/`firstValueFrom`/`timeout`.
|
|
157
157
|
- `WaitTask`/`TaskManager` mirror Puppeteer's polling waits; no AbortSignal, use Async tasks + cancellation.
|
|
158
|
+
- **AbortSignal is NOT supported**: Do NOT port `signal` parameters from upstream Puppeteer. Ruby's concurrency model doesn't align with JavaScript's AbortController pattern.
|
|
158
159
|
- `ReactorRunner` runs a dedicated Async reactor thread and proxies sync calls into it (wrap/unwrap).
|
|
159
160
|
- Use `Core::EventEmitter` + symbols instead of RxJS event streams; clean up listeners explicitly.
|
|
160
161
|
- Disposable patterns: `Core::Disposable::DisposableStack`/`DisposableMixin` stand in for JS DisposableStack/AsyncDisposableStack.
|
data/CLAUDE/porting_puppeteer.md
CHANGED
|
@@ -197,6 +197,16 @@ Note: Some tests (e.g., `BrowserContext#override_permissions`) may be split into
|
|
|
197
197
|
4. **Preserve asset files** - Keep `spec/assets/` identical to upstream `test/assets/`
|
|
198
198
|
5. **Separate Ruby-specific tests** - Move Ruby-only features to `*_ext_spec.rb` files
|
|
199
199
|
|
|
200
|
+
## Fidelity Notes
|
|
201
|
+
|
|
202
|
+
- `JSHandle#json_value`: Node.js normalizes CDP errors like "Object reference chain is too long" and
|
|
203
|
+
"Object couldn't be returned by value" via `ExecutionContext#rewriteError` to `undefined`. The
|
|
204
|
+
Ruby port keeps the same behavior by rescuing in `JSHandle#json_value` and returning `nil`.
|
|
205
|
+
- PSelectors/PQueryHandler: The Ruby PSelector path relies on `PQueryHandler` with the same
|
|
206
|
+
`IDENT_TOKEN_START` regex behavior as upstream. Keep the CSS query selector JS in a single-quoted
|
|
207
|
+
heredoc so the regex survives Ruby parsing. `wait_for` should use `Frame#default_timeout` to match
|
|
208
|
+
Node's timeout settings.
|
|
209
|
+
|
|
200
210
|
### Ruby-Specific Tests (`*_ext_spec.rb`)
|
|
201
211
|
|
|
202
212
|
When porting tests, separate Ruby-only features into dedicated extension spec files:
|
|
@@ -410,6 +420,26 @@ diff spec/assets/input/keyboard.html <(curl -s https://raw.githubusercontent.com
|
|
|
410
420
|
|
|
411
421
|
### Common Gotchas
|
|
412
422
|
|
|
423
|
+
#### 0. AbortSignal Not Supported
|
|
424
|
+
|
|
425
|
+
**Do NOT port `signal` parameters from upstream Puppeteer.**
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
// TypeScript - has signal parameter
|
|
429
|
+
async click(options?: {signal?: AbortSignal}): Promise<void> {
|
|
430
|
+
// ...
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
```ruby
|
|
435
|
+
# Ruby - do NOT include signal parameter
|
|
436
|
+
def click(delay: nil, button: nil)
|
|
437
|
+
# ...
|
|
438
|
+
end
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Ruby's concurrency model doesn't align with JavaScript's AbortController/AbortSignal pattern. Use timeout parameters instead for cancellation.
|
|
442
|
+
|
|
413
443
|
#### 1. Event Type Differences
|
|
414
444
|
|
|
415
445
|
Upstream keyboard tests use `input` events, not `keypress`:
|
|
@@ -88,7 +88,7 @@ Tests must be **faithfully ported** from Node.js Puppeteer to Ruby RSpec:
|
|
|
88
88
|
| jshandle.spec.ts | js_handle_spec.rb | [x] Ported |
|
|
89
89
|
| keyboard.spec.ts | keyboard_spec.rb | [x] Ported |
|
|
90
90
|
| launcher.spec.ts | launcher_spec.rb | [x] Ported |
|
|
91
|
-
| locator.spec.ts |
|
|
91
|
+
| locator.spec.ts | locator_spec.rb | [x] Ported |
|
|
92
92
|
| mouse.spec.ts | mouse_spec.rb | [x] Ported |
|
|
93
93
|
| navigation.spec.ts | navigation_spec.rb | [x] Ported |
|
|
94
94
|
| network.spec.ts | network_spec.rb | [x] Ported |
|
|
@@ -137,7 +137,7 @@ Node.js tests include:
|
|
|
137
137
|
- `Locator.prototype.map/filter/wait/clone`
|
|
138
138
|
- `FunctionLocator`
|
|
139
139
|
|
|
140
|
-
**Ruby status:**
|
|
140
|
+
**Ruby status:** Implemented and ported to `spec/integration/locator_spec.rb`.
|
|
141
141
|
|
|
142
142
|
### 3. Navigation Tests (`navigation.spec.ts`)
|
|
143
143
|
**Priority: HIGH** - Core navigation functionality
|
|
@@ -191,7 +191,7 @@ Node.js tests:
|
|
|
191
191
|
- [x] Port missing `target.spec.ts` tests → Create `target_spec.rb` (AbortSignal pending)
|
|
192
192
|
|
|
193
193
|
### Phase 2: New APIs (High Priority)
|
|
194
|
-
- [
|
|
194
|
+
- [x] Implement Locator API and port `locator.spec.ts` tests
|
|
195
195
|
|
|
196
196
|
### Phase 3: Medium Priority
|
|
197
197
|
- [x] Port `download.spec.ts` tests
|
|
@@ -1000,17 +1000,16 @@ Most OOPIF tests are ported including:
|
|
|
1000
1000
|
|
|
1001
1001
|
### Spec Files Status Summary
|
|
1002
1002
|
|
|
1003
|
-
**Fully Ported (
|
|
1004
|
-
aria_query_handler, browser, browser_context, browser_context_cookies, click, connect (in launcher), cookies, coverage, defaultbrowsercontext (in browser_context), dialog, download, drag_and_drop, element_handle, emulation, evaluation, frame, idle_override, input, js_handle, keyboard, launcher, mouse, navigation, network, oopif, page, query_handler, query_selector, request_interception, request_interception_experimental, screenshot, touchscreen, tracing, waittask, worker
|
|
1003
|
+
**Fully Ported (36):**
|
|
1004
|
+
aria_query_handler, browser, browser_context, browser_context_cookies, click, connect (in launcher), cookies, coverage, defaultbrowsercontext (in browser_context), dialog, download, drag_and_drop, element_handle, emulation, evaluation, frame, idle_override, input, js_handle, keyboard, launcher, locator, mouse, navigation, network, oopif, page, query_handler, query_selector, request_interception, request_interception_experimental, screenshot, touchscreen, tracing, waittask, worker
|
|
1005
1005
|
|
|
1006
1006
|
**Partially Ported (1):**
|
|
1007
1007
|
- target.spec.ts → target_spec.rb (AbortSignal unsupported)
|
|
1008
1008
|
|
|
1009
|
-
**Missing - High Priority (
|
|
1009
|
+
**Missing - High Priority (3):**
|
|
1010
1010
|
1. **accessibility.spec.ts** - Accessibility API not implemented
|
|
1011
|
-
2. **
|
|
1012
|
-
3. **
|
|
1013
|
-
4. **autofill.spec.ts** - Autofill not implemented
|
|
1011
|
+
2. **proxy.spec.ts** - Proxy support not implemented
|
|
1012
|
+
3. **autofill.spec.ts** - Autofill not implemented
|
|
1014
1013
|
|
|
1015
1014
|
**Low Priority/N/A (11):**
|
|
1016
1015
|
acceptInsecureCerts, bluetooth-emulation, debugInfo, device-request-prompt, fixtures, headful, injected, stacktrace, webExtension, webgl
|
|
@@ -1019,7 +1018,6 @@ acceptInsecureCerts, bluetooth-emulation, debugInfo, device-request-prompt, fixt
|
|
|
1019
1018
|
|
|
1020
1019
|
#### High Priority (Core functionality gaps)
|
|
1021
1020
|
1. **Accessibility API** - Add `Page#accessibility` and port accessibility.spec.ts
|
|
1022
|
-
2. **Locator API** - Implement Locator class and port locator.spec.ts
|
|
1023
1021
|
|
|
1024
1022
|
#### Medium Priority
|
|
1025
1023
|
1. **proxy.spec.ts** - Proxy configuration support
|
data/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
[](https://badge.fury.io/rb/puppeteer-ruby)
|
|
2
2
|
|
|
3
3
|
> [!IMPORTANT]
|
|
4
|
-
>
|
|
5
|
-
>
|
|
4
|
+
> - This library now requires **Ruby 3.2 or later**.
|
|
5
|
+
> - Firefox support has been moved to [puppeteer-bidi](https://github.com/YusukeIwaki/puppeteer-bidi).
|
|
6
|
+
> - For older versions, please refer to the [ref-2025 tag](https://github.com/YusukeIwaki/puppeteer-ruby/tree/ref-2025).
|
|
6
7
|
|
|
7
8
|
# Puppeteer in Ruby
|
|
8
9
|
|
data/docs/api_coverage.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# API coverages
|
|
2
2
|
- Puppeteer version: v24.35.0
|
|
3
|
-
- puppeteer-ruby version: 0.50.0.
|
|
3
|
+
- puppeteer-ruby version: 0.50.0.alpha4
|
|
4
4
|
|
|
5
5
|
## Puppeteer
|
|
6
6
|
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
* $$ => `#query_selector_all`
|
|
124
124
|
* $$eval => `#eval_on_selector_all`
|
|
125
125
|
* $eval => `#eval_on_selector`
|
|
126
|
-
*
|
|
126
|
+
* asLocator => `#as_locator`
|
|
127
127
|
* ~~autofill~~
|
|
128
128
|
* ~~backendNodeId~~
|
|
129
129
|
* boundingBox => `#bounding_box`
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
* goto
|
|
194
194
|
* hover
|
|
195
195
|
* isDetached => `#detached?`
|
|
196
|
-
*
|
|
196
|
+
* locator
|
|
197
197
|
* name
|
|
198
198
|
* page
|
|
199
199
|
* parentFrame => `#parent_frame`
|
|
@@ -277,23 +277,23 @@
|
|
|
277
277
|
* type => `#type_text`
|
|
278
278
|
* up
|
|
279
279
|
|
|
280
|
-
##
|
|
280
|
+
## Locator
|
|
281
281
|
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
282
|
+
* click
|
|
283
|
+
* clone
|
|
284
|
+
* fill
|
|
285
|
+
* filter
|
|
286
|
+
* hover
|
|
287
|
+
* map
|
|
288
288
|
* ~~race~~
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
289
|
+
* scroll
|
|
290
|
+
* setEnsureElementIsInTheViewport => `#set_ensure_element_is_in_the_viewport`
|
|
291
|
+
* setTimeout => `#set_timeout`
|
|
292
|
+
* setVisibility => `#set_visibility`
|
|
293
|
+
* setWaitForEnabled => `#set_wait_for_enabled`
|
|
294
|
+
* setWaitForStableBoundingBox => `#set_wait_for_stable_bounding_box`
|
|
295
|
+
* wait
|
|
296
|
+
* waitHandle => `#wait_handle`
|
|
297
297
|
|
|
298
298
|
## Mouse
|
|
299
299
|
|
|
@@ -344,7 +344,7 @@
|
|
|
344
344
|
* focus
|
|
345
345
|
* frames
|
|
346
346
|
* ~~getDefaultNavigationTimeout~~
|
|
347
|
-
*
|
|
347
|
+
* getDefaultTimeout => `#default_timeout`
|
|
348
348
|
* goBack => `#go_back`
|
|
349
349
|
* goForward => `#go_forward`
|
|
350
350
|
* goto
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
* isDragInterceptionEnabled => `#drag_interception_enabled?`
|
|
354
354
|
* isJavaScriptEnabled => `#javascript_enabled?`
|
|
355
355
|
* isServiceWorkerBypassed => `#service_worker_bypassed?`
|
|
356
|
-
*
|
|
356
|
+
* locator
|
|
357
357
|
* mainFrame => `#main_frame`
|
|
358
358
|
* metrics
|
|
359
359
|
* ~~openDevTools~~
|
|
@@ -152,6 +152,11 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
152
152
|
self
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
# @rbs return: Puppeteer::Locator -- Locator for this element
|
|
156
|
+
def as_locator
|
|
157
|
+
Puppeteer::NodeLocator.create_from_handle(@frame, self)
|
|
158
|
+
end
|
|
159
|
+
|
|
155
160
|
# @rbs return: bool -- Whether element is visible
|
|
156
161
|
def visible?
|
|
157
162
|
check_visibility(true)
|
data/lib/puppeteer/frame.rb
CHANGED
|
@@ -51,6 +51,21 @@ class Puppeteer::Frame
|
|
|
51
51
|
@frame_manager.page
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
# @rbs return: Numeric -- Default timeout in milliseconds
|
|
55
|
+
def default_timeout
|
|
56
|
+
@frame_manager.timeout_settings.timeout
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @rbs selector_or_function: String -- Selector or JS function
|
|
60
|
+
# @rbs return: Puppeteer::Locator -- Locator for selector or function
|
|
61
|
+
def locator(selector_or_function)
|
|
62
|
+
if Puppeteer::Locator.function_string?(selector_or_function)
|
|
63
|
+
Puppeteer::FunctionLocator.create(self, selector_or_function)
|
|
64
|
+
else
|
|
65
|
+
Puppeteer::NodeLocator.create(self, selector_or_function)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
54
69
|
# @rbs return: bool -- Whether this is an OOPIF frame
|
|
55
70
|
def oop_frame?
|
|
56
71
|
@client != @frame_manager.client
|
data/lib/puppeteer/js_handle.rb
CHANGED
|
@@ -124,11 +124,30 @@ class Puppeteer::JSHandle
|
|
|
124
124
|
return Time.iso8601(iso_value) if iso_value
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
begin
|
|
128
|
+
result = @client.send_message('Runtime.callFunctionOn',
|
|
129
|
+
functionDeclaration: 'function() { return this; }',
|
|
130
|
+
objectId: @remote_object.object_id_value,
|
|
131
|
+
returnByValue: true,
|
|
132
|
+
awaitPromise: true,
|
|
133
|
+
userGesture: true,
|
|
134
|
+
)
|
|
135
|
+
rescue Puppeteer::Connection::ProtocolError => err
|
|
136
|
+
if err.message.include?('Object reference chain is too long') ||
|
|
137
|
+
err.message.include?("Object couldn't be returned by value")
|
|
138
|
+
return nil
|
|
139
|
+
end
|
|
140
|
+
raise
|
|
141
|
+
end
|
|
142
|
+
if result['exceptionDetails']
|
|
143
|
+
raise Puppeteer::ExecutionContext::EvaluationError.new("Evaluation failed: #{result['exceptionDetails']}")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
remote_object = Puppeteer::RemoteObject.new(result['result'])
|
|
147
|
+
if remote_object.type == 'undefined'
|
|
129
148
|
raise Puppeteer::Error.new('Could not serialize referenced object')
|
|
130
149
|
end
|
|
131
|
-
value
|
|
150
|
+
remote_object.value
|
|
132
151
|
end
|
|
133
152
|
|
|
134
153
|
def as_element
|