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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a20cad1d3b0ad0947041ff8086f0336e381d783f1f6edb1aee45263054f5b40
4
- data.tar.gz: 70c27f24141dc2326762a419cd32c780fcb9c1b5474246e2dd339dd5246b2090
3
+ metadata.gz: 24705930799f6f57d44adea7741837c3e5af927f42990f43c1194e0c71a8b813
4
+ data.tar.gz: 68a01d815bc7d6fe2e7223d08a44c256274469bb5e665a98fb86da37ee202445
5
5
  SHA512:
6
- metadata.gz: 89f6ed85a37682ced989ece6cddbac7ad9489bd6a1a31fb98f557f96527a8d298b572c078a6438d7030bd6e8c14d3b5a92042d4c1fd5caad1fc1a031335381a1
7
- data.tar.gz: fe22e70a18f3319fcb7face324b2de32944f2ebfc0d594a8b33ad2bc95ceb2a0bd8a75bf63fa81369cd892fb8a125edf5c4221e0650476c618fef8455c794d0a
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.
@@ -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 | - | **[MISSING]** Locator API not ported |
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:** Not implemented. This is a significant new API addition.
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
- - [ ] Implement Locator API and port `locator.spec.ts` tests
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 (35):**
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 (4):**
1009
+ **Missing - High Priority (3):**
1010
1010
  1. **accessibility.spec.ts** - Accessibility API not implemented
1011
- 2. **locator.spec.ts** - Locator API not implemented
1012
- 3. **proxy.spec.ts** - Proxy support not implemented
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
  [![Gem Version](https://badge.fury.io/rb/puppeteer-ruby.svg)](https://badge.fury.io/rb/puppeteer-ruby)
2
2
 
3
3
  > [!IMPORTANT]
4
- > The `main` branch is currently under **HEAVY DEVELOPMENT** for increased stability.
5
- > If you need the latest stable release, please refer to the [ref-2025 tag](https://github.com/YusukeIwaki/puppeteer-ruby/tree/ref-2025).
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.alpha5
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
- * ~~asLocator~~
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
- * ~~locator~~
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
- ## ~~Locator~~
280
+ ## Locator
281
281
 
282
- * ~~click~~
283
- * ~~clone~~
284
- * ~~fill~~
285
- * ~~filter~~
286
- * ~~hover~~
287
- * ~~map~~
282
+ * click
283
+ * clone
284
+ * fill
285
+ * filter
286
+ * hover
287
+ * map
288
288
  * ~~race~~
289
- * ~~scroll~~
290
- * ~~setEnsureElementIsInTheViewport~~
291
- * ~~setTimeout~~
292
- * ~~setVisibility~~
293
- * ~~setWaitForEnabled~~
294
- * ~~setWaitForStableBoundingBox~~
295
- * ~~wait~~
296
- * ~~waitHandle~~
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
- * ~~getDefaultTimeout~~
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
- * ~~locator~~
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)
@@ -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
@@ -124,11 +124,30 @@ class Puppeteer::JSHandle
124
124
  return Time.iso8601(iso_value) if iso_value
125
125
  end
126
126
 
127
- value = evaluate('(object) => object')
128
- if value.nil?
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