puppeteer-bidi 0.0.3.beta1 → 0.0.3.beta2

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.
@@ -1,262 +0,0 @@
1
- # RSpec: pending vs skip
2
-
3
- ## Overview
4
-
5
- RSpec provides two mechanisms for handling tests that cannot or should not run: `pending` and `skip`. Understanding when to use each is critical for documenting browser limitations and future work.
6
-
7
- ## Difference
8
-
9
- ### skip
10
-
11
- **Completely skips the test** - does not run any code:
12
-
13
- ```ruby
14
- it 'should work' do
15
- skip 'feature not implemented'
16
-
17
- # This code NEVER runs
18
- page.do_something
19
- expect(result).to be_truthy
20
- end
21
- ```
22
-
23
- **Output**: Test marked as skipped, no execution, no error trace.
24
-
25
- ### pending
26
-
27
- **Runs the test** and expects it to fail:
28
-
29
- ```ruby
30
- it 'should work' do
31
- pending 'feature not implemented'
32
-
33
- # This code RUNS and is expected to fail
34
- page.do_something # Raises error
35
- expect(result).to be_truthy
36
- end
37
- ```
38
-
39
- **Output**: Test marked as pending with full error trace showing exactly what failed.
40
-
41
- ## When to Use Each
42
-
43
- ### Use `pending` for:
44
-
45
- 1. **Browser limitations** - Features not yet supported by Firefox BiDi
46
- 2. **Known failures** - Code exists but fails due to external issues
47
- 3. **Documentation** - Want to show error trace to document what's missing
48
-
49
- ### Use `skip` for:
50
-
51
- 1. **Unimplemented features** - Code doesn't exist yet
52
- 2. **Environment issues** - Test requires specific setup not available
53
- 3. **Temporary exclusion** - Test is broken and needs fixing
54
-
55
- ## Firefox BiDi Limitations
56
-
57
- For features that exist in BiDi spec but not yet implemented in Firefox, use `pending`:
58
-
59
- ```ruby
60
- describe 'Page.setJavaScriptEnabled' do
61
- it 'should work' do
62
- # Pending: Firefox does not yet support emulation.setScriptingEnabled BiDi command
63
- pending 'emulation.setScriptingEnabled not supported by Firefox yet'
64
-
65
- with_test_state do |page:, **|
66
- page.set_javascript_enabled(false)
67
- expect(page.javascript_enabled?).to be false
68
-
69
- page.goto('data:text/html, <script>var something = "forbidden"</script>')
70
-
71
- error = nil
72
- begin
73
- page.evaluate('something')
74
- rescue => e
75
- error = e
76
- end
77
-
78
- expect(error).not_to be_nil
79
- expect(error.message).to include('something is not defined')
80
- end
81
- end
82
- end
83
- ```
84
-
85
- **Why pending, not skip**:
86
- - Code path exists (`page.set_javascript_enabled`)
87
- - BiDi command exists in spec (`emulation.setScriptingEnabled`)
88
- - Firefox just hasn't implemented it yet
89
- - Running the test shows exactly what error Firefox returns
90
-
91
- ## Output Comparison
92
-
93
- ### With `skip`
94
-
95
- ```
96
- Page
97
- Page.setJavaScriptEnabled
98
- should work (SKIPPED)
99
- ```
100
-
101
- No error information, no way to know what's missing.
102
-
103
- ### With `pending`
104
-
105
- ```
106
- Page
107
- Page.setJavaScriptEnabled
108
- should work (PENDING: emulation.setScriptingEnabled not supported by Firefox yet)
109
-
110
- Pending: (Failures listed here are expected and do not affect your suite's status)
111
-
112
- 1) Page Page.setJavaScriptEnabled should work
113
- # emulation.setScriptingEnabled not supported by Firefox yet
114
- Failure/Error: raise ProtocolError, "BiDi error (#{method}): #{result['error']['message']}"
115
-
116
- Puppeteer::Bidi::Connection::ProtocolError:
117
- BiDi error (emulation.setScriptingEnabled):
118
- # ./lib/puppeteer/bidi/connection.rb:71:in 'send_command'
119
- # ./lib/puppeteer/bidi/core/browsing_context.rb:331:in 'set_javascript_enabled'
120
- # ./lib/puppeteer/bidi/page.rb:313:in 'set_javascript_enabled'
121
- ```
122
-
123
- Full error trace shows:
124
- - Which BiDi command failed
125
- - Error message from Firefox
126
- - Complete stack trace
127
- - Where in our code it failed
128
-
129
- ## Implementation Pattern
130
-
131
- ### Before (Incorrect - Using skip in before block)
132
-
133
- ```ruby
134
- describe 'Page.setJavaScriptEnabled' do
135
- before do
136
- skip 'emulation.setScriptingEnabled not supported by Firefox yet'
137
- end
138
-
139
- it 'should work' do
140
- # Never runs
141
- end
142
-
143
- it 'setInterval should pause' do
144
- # Never runs
145
- end
146
- end
147
- ```
148
-
149
- **Problems**:
150
- - Tests don't run at all
151
- - No error information
152
- - Not clear which BiDi command is missing
153
-
154
- ### After (Correct - Using pending in individual tests)
155
-
156
- ```ruby
157
- describe 'Page.setJavaScriptEnabled' do
158
- it 'should work' do
159
- pending 'emulation.setScriptingEnabled not supported by Firefox yet'
160
-
161
- with_test_state do |page:, **|
162
- # Test code runs and fails with proper error trace
163
- end
164
- end
165
-
166
- it 'setInterval should pause' do
167
- pending 'emulation.setScriptingEnabled not supported by Firefox yet'
168
-
169
- with_test_state do |page:, **|
170
- # Test code runs and fails with proper error trace
171
- end
172
- end
173
- end
174
- ```
175
-
176
- **Benefits**:
177
- - Tests run and document exact failure
178
- - Each test can have specific pending message
179
- - Easy to identify when Firefox adds support (test will pass)
180
- - Full error trace available for debugging
181
-
182
- ## Best Practices
183
-
184
- ### 1. Be Specific in Pending Messages
185
-
186
- ```ruby
187
- # Good
188
- pending 'emulation.setScriptingEnabled not supported by Firefox yet'
189
-
190
- # Bad
191
- pending 'not supported'
192
- ```
193
-
194
- ### 2. Include BiDi Command Name
195
-
196
- ```ruby
197
- # Good
198
- pending 'browsingContext.setViewport not implemented'
199
-
200
- # Bad
201
- pending 'viewport not working'
202
- ```
203
-
204
- ### 3. Document When to Re-check
205
-
206
- ```ruby
207
- # Good
208
- pending 'network.addIntercept requires Firefox 120+, current: 119'
209
-
210
- # Bad
211
- pending 'network interception broken'
212
- ```
213
-
214
- ### 4. Remove Pending When Fixed
215
-
216
- When Firefox adds support, the test will fail with:
217
- ```
218
- Expected example to fail but it passed
219
- ```
220
-
221
- This is your signal to remove the `pending` line!
222
-
223
- ## Firefox BiDi Limitations (Current)
224
-
225
- As of this implementation, the following BiDi commands are not supported by Firefox:
226
-
227
- 1. `emulation.setScriptingEnabled` - Control JavaScript execution
228
- - Tests: `spec/integration/page_spec.rb` (2 tests)
229
- - Tests: `spec/integration/click_spec.rb` (1 test)
230
-
231
- ## Files Changed
232
-
233
- - `spec/integration/click_spec.rb`: Changed `skip` to `pending` (line 71)
234
- - `spec/integration/page_spec.rb`: Moved `skip` from before block to individual tests as `pending` (lines 19, 48)
235
-
236
- ## Test Results
237
-
238
- ```bash
239
- bundle exec rspec spec/integration/
240
- # 108 examples, 0 failures, 4 pending
241
- ```
242
-
243
- All pending tests show proper error traces documenting Firefox limitations.
244
-
245
- ## Key Takeaways
246
-
247
- 1. **Use `pending` for browser limitations** - Shows what's missing with error trace
248
- 2. **Use `skip` for unimplemented features** - Our code doesn't exist yet
249
- 3. **Be specific in messages** - Include BiDi command name and reason
250
- 4. **Pending in test body, not before block** - Each test should be explicit
251
- 5. **Pending tests run code** - They document exact failure mode
252
- 6. **Remove pending when fixed** - Test will fail with "expected to fail but passed"
253
-
254
- ## References
255
-
256
- - [RSpec Documentation: Pending and Skipped Examples](https://rspec.info/features/3-12/rspec-core/pending-and-skipped-examples/)
257
- - [WebDriver BiDi Spec](https://w3c.github.io/webdriver-bidi/) - Check which commands are standardized
258
- - [Firefox BiDi Implementation Status](https://wiki.mozilla.org/WebDriver/RemoteProtocol/WebDriver_BiDi) - Check Firefox support
259
-
260
- ## Commit Reference
261
-
262
- See commit: "test: Use pending instead of skip for Firefox unsupported features"
@@ -1,198 +0,0 @@
1
- # Selector Evaluation Methods Implementation
2
-
3
- This document explains the implementation of `eval_on_selector` and `eval_on_selector_all` methods, including delegation patterns, handle lifecycle, and performance considerations.
4
-
5
- ### Overview
6
-
7
- The `eval_on_selector` and `eval_on_selector_all` methods provide convenient shortcuts for querying elements and evaluating JavaScript functions on them, equivalent to Puppeteer's `$eval` and `$$eval`.
8
-
9
- ### API Design
10
-
11
- #### Method Naming Convention
12
-
13
- Ruby cannot use `$` in method names, so we use descriptive alternatives:
14
-
15
- | Puppeteer | Ruby | Description |
16
- |-----------|------|-------------|
17
- | `$eval` | `eval_on_selector` | Evaluate on first matching element |
18
- | `$$eval` | `eval_on_selector_all` | Evaluate on all matching elements |
19
-
20
- #### Implementation Hierarchy
21
-
22
- Following Puppeteer's delegation pattern:
23
-
24
- ```
25
- Page#eval_on_selector(_all)
26
- ↓ delegates to
27
- Frame#eval_on_selector(_all)
28
- ↓ delegates to
29
- ElementHandle#eval_on_selector(_all) (on document)
30
- ↓ implementation
31
- 1. query_selector(_all) - Find element(s)
32
- 2. Validate results
33
- 3. evaluate() - Execute function
34
- 4. dispose - Clean up handles
35
- ```
36
-
37
- ### Implementation Details
38
-
39
- #### Page and Frame Methods
40
-
41
- ```ruby
42
- # lib/puppeteer/bidi/page.rb
43
- def eval_on_selector(selector, page_function, *args)
44
- main_frame.eval_on_selector(selector, page_function, *args)
45
- end
46
-
47
- # lib/puppeteer/bidi/frame.rb
48
- def eval_on_selector(selector, page_function, *args)
49
- document.eval_on_selector(selector, page_function, *args)
50
- end
51
- ```
52
-
53
- **Design rationale**: Page and Frame act as thin wrappers, delegating to the document element handle.
54
-
55
- #### ElementHandle#eval_on_selector
56
-
57
- ```ruby
58
- def eval_on_selector(selector, page_function, *args)
59
- assert_not_disposed
60
-
61
- element_handle = query_selector(selector)
62
- raise SelectorNotFoundError, selector unless element_handle
63
-
64
- begin
65
- element_handle.evaluate(page_function, *args)
66
- ensure
67
- element_handle.dispose
68
- end
69
- end
70
- ```
71
-
72
- **Key points**:
73
- - Throws `SelectorNotFoundError` if no element found (matches Puppeteer behavior)
74
- - Uses `begin/ensure` to guarantee handle disposal
75
- - Searches within element's subtree (not page-wide)
76
-
77
- #### ElementHandle#eval_on_selector_all
78
-
79
- ```ruby
80
- def eval_on_selector_all(selector, page_function, *args)
81
- assert_not_disposed
82
-
83
- element_handles = query_selector_all(selector)
84
-
85
- begin
86
- # Create array handle in browser context
87
- array_handle = @realm.call_function(
88
- '(...elements) => elements',
89
- false,
90
- arguments: element_handles.map(&:remote_value)
91
- )
92
-
93
- array_js_handle = JSHandle.from(array_handle['result'], @realm)
94
-
95
- begin
96
- array_js_handle.evaluate(page_function, *args)
97
- ensure
98
- array_js_handle.dispose
99
- end
100
- ensure
101
- element_handles.each(&:dispose)
102
- end
103
- end
104
- ```
105
-
106
- **Key points**:
107
- - Returns result for empty array without error (differs from `eval_on_selector`)
108
- - Creates array handle using spread operator trick: `(...elements) => elements`
109
- - Nested `ensure` blocks for proper resource cleanup
110
- - Disposes both individual element handles and array handle
111
-
112
- ### Error Handling Differences
113
-
114
- | Method | Behavior when no elements found |
115
- |--------|--------------------------------|
116
- | `eval_on_selector` | Throws `SelectorNotFoundError` |
117
- | `eval_on_selector_all` | Returns evaluation result (e.g., `0` for `divs => divs.length`) |
118
-
119
- This matches Puppeteer's behavior:
120
- - `$eval`: Must find exactly one element
121
- - `$$eval`: Works with zero or more elements
122
-
123
- ### Usage Examples
124
-
125
- ```ruby
126
- # Basic usage
127
- page.set_content('<section id="test">Hello</section>')
128
- id = page.eval_on_selector('section', 'e => e.id')
129
- # => "test"
130
-
131
- # With arguments
132
- text = page.eval_on_selector('section', '(e, suffix) => e.textContent + suffix', '!')
133
- # => "Hello!"
134
-
135
- # ElementHandle arguments
136
- div = page.query_selector('div')
137
- result = page.eval_on_selector('section', '(e, div) => e.textContent + div.textContent', div)
138
-
139
- # eval_on_selector_all with multiple elements
140
- page.set_content('<div>A</div><div>B</div><div>C</div>')
141
- count = page.eval_on_selector_all('div', 'divs => divs.length')
142
- # => 3
143
-
144
- # Subtree search with ElementHandle
145
- tweet = page.query_selector('.tweet')
146
- likes = tweet.eval_on_selector('.like', 'node => node.innerText')
147
- # Only searches within .tweet element
148
- ```
149
-
150
- ### Test Coverage
151
-
152
- **Total**: 13 integration tests
153
-
154
- **Page.eval_on_selector** (4 tests):
155
- - Basic functionality (property access)
156
- - Argument passing
157
- - ElementHandle arguments
158
- - Error on missing selector
159
-
160
- **ElementHandle.eval_on_selector** (3 tests):
161
- - Basic functionality
162
- - Subtree isolation
163
- - Error on missing selector
164
-
165
- **Page.eval_on_selector_all** (4 tests):
166
- - Basic functionality (array length)
167
- - Extra arguments
168
- - ElementHandle arguments
169
- - Large element count (1001 elements)
170
-
171
- **ElementHandle.eval_on_selector_all** (2 tests):
172
- - Subtree retrieval
173
- - Empty result handling
174
-
175
- ### Performance Considerations
176
-
177
- #### Handle Lifecycle
178
-
179
- - **eval_on_selector**: Creates 1 temporary handle per call
180
- - **eval_on_selector_all**: Creates N+1 handles (N elements + 1 array)
181
- - All handles automatically disposed after evaluation
182
-
183
- #### Large Element Sets
184
-
185
- Tested with 1001 elements without issues. The implementation efficiently:
186
- 1. Queries all elements at once
187
- 2. Creates single array handle
188
- 3. Evaluates function in single round-trip
189
- 4. Disposes all handles in parallel
190
-
191
- ### Reference Implementation
192
-
193
- Based on Puppeteer's implementation:
194
- - [Page.$eval](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/api/Page.ts)
195
- - [Frame.$eval](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/api/Frame.ts)
196
- - [ElementHandle.$eval](https://github.com/puppeteer/puppeteer/blob/main/packages/puppeteer-core/src/api/ElementHandle.ts)
197
- - [Test specs](https://github.com/puppeteer/puppeteer/blob/main/test/src/queryselector.spec.ts)
198
-