playwright-ruby-client 0.0.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +117 -5
  3. data/docs/api_coverage.md +359 -0
  4. data/lib/playwright.rb +6 -2
  5. data/lib/playwright/android_input_impl.rb +23 -0
  6. data/lib/playwright/api_implementation.rb +18 -0
  7. data/lib/playwright/channel.rb +7 -0
  8. data/lib/playwright/channel_owner.rb +6 -7
  9. data/lib/playwright/channel_owners/android.rb +10 -1
  10. data/lib/playwright/channel_owners/android_device.rb +163 -0
  11. data/lib/playwright/channel_owners/browser.rb +14 -14
  12. data/lib/playwright/channel_owners/browser_context.rb +10 -2
  13. data/lib/playwright/channel_owners/download.rb +27 -0
  14. data/lib/playwright/channel_owners/element_handle.rb +243 -1
  15. data/lib/playwright/channel_owners/frame.rb +269 -22
  16. data/lib/playwright/channel_owners/js_handle.rb +51 -0
  17. data/lib/playwright/channel_owners/page.rb +379 -34
  18. data/lib/playwright/channel_owners/request.rb +9 -1
  19. data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
  20. data/lib/playwright/connection.rb +9 -6
  21. data/lib/playwright/errors.rb +2 -2
  22. data/lib/playwright/event_emitter.rb +8 -1
  23. data/lib/playwright/event_emitter_proxy.rb +49 -0
  24. data/lib/playwright/file_chooser_impl.rb +23 -0
  25. data/lib/playwright/http_headers.rb +20 -0
  26. data/lib/playwright/input_files.rb +42 -0
  27. data/lib/playwright/javascript/expression.rb +15 -0
  28. data/lib/playwright/javascript/function.rb +15 -0
  29. data/lib/playwright/javascript/value_parser.rb +1 -1
  30. data/lib/playwright/javascript/value_serializer.rb +11 -11
  31. data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +6 -2
  32. data/lib/playwright/mouse_impl.rb +7 -0
  33. data/lib/playwright/playwright_api.rb +66 -19
  34. data/lib/playwright/select_option_values.rb +42 -0
  35. data/lib/playwright/timeout_settings.rb +1 -1
  36. data/lib/playwright/touchscreen_impl.rb +7 -0
  37. data/lib/playwright/utils.rb +18 -0
  38. data/lib/playwright/version.rb +1 -1
  39. data/lib/playwright/wait_helper.rb +1 -1
  40. data/lib/playwright_api/android.rb +32 -0
  41. data/lib/playwright_api/android_device.rb +77 -0
  42. data/lib/playwright_api/android_input.rb +25 -0
  43. data/lib/playwright_api/binding_call.rb +10 -6
  44. data/lib/playwright_api/browser.rb +22 -22
  45. data/lib/playwright_api/browser_context.rb +31 -22
  46. data/lib/playwright_api/browser_type.rb +16 -56
  47. data/lib/playwright_api/chromium_browser_context.rb +10 -8
  48. data/lib/playwright_api/console_message.rb +9 -10
  49. data/lib/playwright_api/dialog.rb +7 -3
  50. data/lib/playwright_api/download.rb +28 -11
  51. data/lib/playwright_api/element_handle.rb +139 -127
  52. data/lib/playwright_api/file_chooser.rb +17 -9
  53. data/lib/playwright_api/frame.rb +148 -148
  54. data/lib/playwright_api/js_handle.rb +26 -22
  55. data/lib/playwright_api/keyboard.rb +6 -6
  56. data/lib/playwright_api/page.rb +215 -179
  57. data/lib/playwright_api/playwright.rb +34 -46
  58. data/lib/playwright_api/request.rb +7 -8
  59. data/lib/playwright_api/response.rb +10 -6
  60. data/lib/playwright_api/selectors.rb +13 -9
  61. data/lib/playwright_api/web_socket.rb +10 -1
  62. data/lib/playwright_api/worker.rb +13 -13
  63. data/playwright.gemspec +1 -0
  64. metadata +32 -6
  65. data/lib/playwright/input_type.rb +0 -19
  66. data/lib/playwright/input_types/mouse.rb +0 -4
  67. data/lib/playwright/input_types/touchscreen.rb +0 -4
@@ -1,7 +1,7 @@
1
1
  module Playwright
2
2
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_frame.py
3
3
  define_channel_owner :Frame do
4
- def after_initialize
4
+ private def after_initialize
5
5
  if @initializer['parentFrame']
6
6
  @parent_frame = ChannelOwners::Frame.from(@initializer['parentFrame'])
7
7
  @parent_frame.send(:append_child_frame_from_child, self)
@@ -62,7 +62,7 @@ module Playwright
62
62
  end
63
63
  end
64
64
 
65
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
65
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
66
66
  option_wait_until = waitUntil || 'load'
67
67
  option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
68
68
  time_start = Time.now
@@ -100,6 +100,7 @@ module Playwright
100
100
 
101
101
  def wait_for_load_state(state: nil, timeout: nil)
102
102
  option_state = state || 'load'
103
+ option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
103
104
  unless %w(load domcontentloaded networkidle).include?(option_state)
104
105
  raise ArgumentError.new('state: expected one of (load|domcontentloaded|networkidle)')
105
106
  end
@@ -107,7 +108,7 @@ module Playwright
107
108
  return
108
109
  end
109
110
 
110
- wait_helper = setup_navigation_wait_helper(timeout: timeout)
111
+ wait_helper = setup_navigation_wait_helper(timeout: option_timeout)
111
112
 
112
113
  predicate = ->(state) { state == option_state }
113
114
  wait_helper.wait_for_event(@event_emitter, 'loadstate', predicate: predicate)
@@ -143,6 +144,55 @@ module Playwright
143
144
  end
144
145
  end
145
146
 
147
+ def wait_for_selector(selector, state: nil, timeout: nil)
148
+ params = { selector: selector, state: state, timeout: timeout }.compact
149
+ resp = @channel.send_message_to_server('waitForSelector', params)
150
+
151
+ ChannelOwners::ElementHandle.from_nullable(resp)
152
+ end
153
+
154
+ def checked?(selector, timeout: nil)
155
+ params = { selector: selector, timeout: timeout }.compact
156
+ @channel.send_message_to_server('isChecked', params)
157
+ end
158
+
159
+ def disabled?(selector, timeout: nil)
160
+ params = { selector: selector, timeout: timeout }.compact
161
+ @channel.send_message_to_server('isDisabled', params)
162
+ end
163
+
164
+ def editable?(selector, timeout: nil)
165
+ params = { selector: selector, timeout: timeout }.compact
166
+ @channel.send_message_to_server('isEditable', params)
167
+ end
168
+
169
+ def enabled?(selector, timeout: nil)
170
+ params = { selector: selector, timeout: timeout }.compact
171
+ @channel.send_message_to_server('isEnabled', params)
172
+ end
173
+
174
+ def hidden?(selector, timeout: nil)
175
+ params = { selector: selector, timeout: timeout }.compact
176
+ @channel.send_message_to_server('isHidden', params)
177
+ end
178
+
179
+ def visible?(selector, timeout: nil)
180
+ params = { selector: selector, timeout: timeout }.compact
181
+ @channel.send_message_to_server('isVisible', params)
182
+ end
183
+
184
+ def dispatch_event(selector, type, eventInit: nil, timeout: nil)
185
+ params = {
186
+ selector: selector,
187
+ type: type,
188
+ eventInit: JavaScript::ValueSerializer.new(eventInit).serialize,
189
+ timeout: timeout,
190
+ }.compact
191
+ @channel.send_message_to_server('dispatchEvent', params)
192
+
193
+ nil
194
+ end
195
+
146
196
  def eval_on_selector(selector, pageFunction, arg: nil)
147
197
  if JavaScript.function?(pageFunction)
148
198
  JavaScript::Function.new(pageFunction, arg).eval_on_selector(@channel, selector)
@@ -175,6 +225,47 @@ module Playwright
175
225
  nil
176
226
  end
177
227
 
228
+ def name
229
+ @name || ''
230
+ end
231
+
232
+ def url
233
+ @url || ''
234
+ end
235
+
236
+ def child_frames
237
+ @child_frames.to_a
238
+ end
239
+
240
+ def detached?
241
+ @detached
242
+ end
243
+
244
+ def add_script_tag(content: nil, path: nil, type: nil, url: nil)
245
+ params = {
246
+ content: content,
247
+ type: type,
248
+ url: url,
249
+ }.compact
250
+ if path
251
+ params[:content] = "#{File.read(path)}\n//# sourceURL=#{path}"
252
+ end
253
+ resp = @channel.send_message_to_server('addScriptTag', params)
254
+ ChannelOwners::ElementHandle.from(resp)
255
+ end
256
+
257
+ def add_style_tag(content: nil, path: nil, url: nil)
258
+ params = {
259
+ content: content,
260
+ url: url,
261
+ }.compact
262
+ if path
263
+ params[:content] = "#{File.read(path)}\n/*# sourceURL=#{path}*/"
264
+ end
265
+ resp = @channel.send_message_to_server('addStyleTag', params)
266
+ ChannelOwners::ElementHandle.from(resp)
267
+ end
268
+
178
269
  def click(
179
270
  selector,
180
271
  button: nil,
@@ -202,18 +293,145 @@ module Playwright
202
293
  nil
203
294
  end
204
295
 
296
+ def dblclick(
297
+ selector,
298
+ button: nil,
299
+ delay: nil,
300
+ force: nil,
301
+ modifiers: nil,
302
+ noWaitAfter: nil,
303
+ position: nil,
304
+ timeout: nil)
305
+
306
+ params = {
307
+ selector: selector,
308
+ button: button,
309
+ delay: delay,
310
+ force: force,
311
+ modifiers: modifiers,
312
+ noWaitAfter: noWaitAfter,
313
+ position: position,
314
+ timeout: timeout,
315
+ }.compact
316
+ @channel.send_message_to_server('dblclick', params)
317
+
318
+ nil
319
+ end
320
+
321
+ def tap_point(
322
+ selector,
323
+ force: nil,
324
+ modifiers: nil,
325
+ noWaitAfter: nil,
326
+ position: nil,
327
+ timeout: nil)
328
+ params = {
329
+ selector: selector,
330
+ force: force,
331
+ modifiers: modifiers,
332
+ noWaitAfter: noWaitAfter,
333
+ position: position,
334
+ timeout: timeout,
335
+ }.compact
336
+ @channel.send_message_to_server('tap', params)
337
+
338
+ nil
339
+ end
340
+
341
+ def fill(selector, value, noWaitAfter: nil, timeout: nil)
342
+ params = {
343
+ selector: selector,
344
+ value: value,
345
+ noWaitAfter: noWaitAfter,
346
+ timeout: timeout,
347
+ }.compact
348
+ @channel.send_message_to_server('fill', params)
349
+
350
+ nil
351
+ end
352
+
205
353
  def focus(selector, timeout: nil)
206
354
  params = { selector: selector, timeout: timeout }.compact
207
355
  @channel.send_message_to_server('focus', params)
208
356
  nil
209
357
  end
210
358
 
211
- def type_text(
212
- selector,
213
- text,
214
- delay: nil,
215
- noWaitAfter: nil,
216
- timeout: nil)
359
+ def text_content(selector, timeout: nil)
360
+ params = { selector: selector, timeout: timeout }.compact
361
+ @channel.send_message_to_server('textContent', params)
362
+ end
363
+
364
+ def inner_text(selector, timeout: nil)
365
+ params = { selector: selector, timeout: timeout }.compact
366
+ @channel.send_message_to_server('innerText', params)
367
+ end
368
+
369
+ def inner_html(selector, timeout: nil)
370
+ params = { selector: selector, timeout: timeout }.compact
371
+ @channel.send_message_to_server('innerHTML', params)
372
+ end
373
+
374
+ def get_attribute(selector, name, timeout: nil)
375
+ params = {
376
+ selector: selector,
377
+ name: name,
378
+ timeout: timeout,
379
+ }.compact
380
+ @channel.send_message_to_server('getAttribute', params)
381
+ end
382
+
383
+ def hover(
384
+ selector,
385
+ force: nil,
386
+ modifiers: nil,
387
+ position: nil,
388
+ timeout: nil)
389
+ params = {
390
+ selector: selector,
391
+ force: force,
392
+ modifiers: modifiers,
393
+ position: position,
394
+ timeout: timeout,
395
+ }.compact
396
+ @channel.send_message_to_server('hover', params)
397
+
398
+ nil
399
+ end
400
+
401
+ def select_option(
402
+ selector,
403
+ element: nil,
404
+ index: nil,
405
+ value: nil,
406
+ label: nil,
407
+ noWaitAfter: nil,
408
+ timeout: nil)
409
+ base_params = SelectOptionValues.new(
410
+ element: element,
411
+ index: index,
412
+ value: value,
413
+ label: label,
414
+ ).as_params
415
+ params = base_params + { selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
416
+ @channel.send_message_to_server('selectOption', params)
417
+
418
+ nil
419
+ end
420
+
421
+ def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
422
+ file_payloads = InputFiles.new(files).as_params
423
+ params = { files: file_payloads, selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
424
+ @channel.send_message_to_server('setInputFiles', params)
425
+
426
+ nil
427
+ end
428
+
429
+ def type(
430
+ selector,
431
+ text,
432
+ delay: nil,
433
+ noWaitAfter: nil,
434
+ timeout: nil)
217
435
 
218
436
  params = {
219
437
  selector: selector,
@@ -222,16 +440,17 @@ module Playwright
222
440
  noWaitAfter: noWaitAfter,
223
441
  timeout: timeout,
224
442
  }.compact
225
-
226
443
  @channel.send_message_to_server('type', params)
444
+
445
+ nil
227
446
  end
228
447
 
229
448
  def press(
230
- selector,
231
- key,
232
- delay: nil,
233
- noWaitAfter: nil,
234
- timeout: nil)
449
+ selector,
450
+ key,
451
+ delay: nil,
452
+ noWaitAfter: nil,
453
+ timeout: nil)
235
454
 
236
455
  params = {
237
456
  selector: selector,
@@ -240,20 +459,48 @@ module Playwright
240
459
  noWaitAfter: noWaitAfter,
241
460
  timeout: timeout,
242
461
  }.compact
243
-
244
462
  @channel.send_message_to_server('press', params)
463
+
464
+ nil
245
465
  end
246
466
 
247
- def name
248
- @name || ''
467
+ def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
468
+ params = {
469
+ selector: selector,
470
+ force: force,
471
+ noWaitAfter: noWaitAfter,
472
+ timeout: timeout,
473
+ }.compact
474
+ @channel.send_message_to_server('check', params)
475
+
476
+ nil
249
477
  end
250
478
 
251
- def url
252
- @url || ''
479
+ def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
480
+ params = {
481
+ selector: selector,
482
+ force: force,
483
+ noWaitAfter: noWaitAfter,
484
+ timeout: timeout,
485
+ }.compact
486
+ @channel.send_message_to_server('uncheck', params)
487
+
488
+ nil
253
489
  end
254
490
 
255
- def child_frames
256
- @child_frames.to_a
491
+ def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
492
+ if polling.is_a?(String) && polling != 'raf'
493
+ raise ArgumentError.new("Unknown polling option: #{polling}")
494
+ end
495
+
496
+ function_or_expression =
497
+ if JavaScript.function?(pageFunction)
498
+ JavaScript::Function.new(pageFunction, arg)
499
+ else
500
+ JavaScript::Expression.new(pageFunction)
501
+ end
502
+
503
+ function_or_expression.wait_for_function(@channel, polling: polling, timeout: timeout)
257
504
  end
258
505
 
259
506
  def title
@@ -1,4 +1,55 @@
1
1
  module Playwright
2
2
  define_channel_owner :JSHandle do
3
+ private def after_initialize
4
+ @preview = @initializer['preview']
5
+ @channel.on('previewUpdated', method(:on_preview_updated))
6
+ end
7
+
8
+ def to_s
9
+ @preview
10
+ end
11
+
12
+ private def on_preview_updated(preview)
13
+ @preview = preview
14
+ end
15
+
16
+ def evaluate(pageFunction, arg: nil)
17
+ if JavaScript.function?(pageFunction)
18
+ JavaScript::Function.new(pageFunction, arg).evaluate(@channel)
19
+ else
20
+ JavaScript::Expression.new(pageFunction).evaluate(@channel)
21
+ end
22
+ end
23
+
24
+ def evaluate_handle(pageFunction, arg: nil)
25
+ if JavaScript.function?(pageFunction)
26
+ JavaScript::Function.new(pageFunction, arg).evaluate_handle(@channel)
27
+ else
28
+ JavaScript::Expression.new(pageFunction).evaluate_handle(@channel)
29
+ end
30
+ end
31
+
32
+ def get_properties
33
+ resp = @channel.send_message_to_server('getPropertyList')
34
+ resp.map { |prop| [prop['name'], ChannelOwner.from(prop['value'])] }.to_h
35
+ end
36
+
37
+ def get_property(name)
38
+ resp = @channel.send_message_to_server('getProperty', name: name)
39
+ ChannelOwner.from(resp)
40
+ end
41
+
42
+ def as_element
43
+ nil
44
+ end
45
+
46
+ def dispose
47
+ @channel.send_message_to_server('dispose')
48
+ end
49
+
50
+ def json_value
51
+ value = @channel.send_message_to_server('jsonValue')
52
+ JavaScript::ValueParser.new(value).parse
53
+ end
3
54
  end
4
55
  end
@@ -6,13 +6,13 @@ module Playwright
6
6
  include Utils::Errors::SafeCloseError
7
7
  attr_writer :owned_context
8
8
 
9
- def after_initialize
9
+ private def after_initialize
10
10
  @browser_context = @parent
11
11
  @timeout_settings = TimeoutSettings.new(@browser_context.send(:_timeout_settings))
12
12
  @accessibility = Accessibility.new(@channel)
13
- @keyboard = InputTypes::Keyboard.new(@channel)
14
- @mouse = InputTypes::Mouse.new(@channel)
15
- @touchscreen = InputTypes::Touchscreen.new(@channel)
13
+ @keyboard = KeyboardImpl.new(@channel)
14
+ @mouse = MouseImpl.new(@channel)
15
+ @touchscreen = TouchscreenImpl.new(@channel)
16
16
 
17
17
  @viewport_size = @initializer['viewportSize']
18
18
  @closed = false
@@ -26,7 +26,19 @@ module Playwright
26
26
  console_message = ChannelOwners::ConsoleMessage.from(params['message'])
27
27
  emit(Events::Page::Console, console_message)
28
28
  })
29
+ @channel.on('crash', ->(_) { emit(Events::Page::Crash) })
30
+ @channel.on('dialog', method(:on_dialog))
29
31
  @channel.on('domcontentloaded', ->(_) { emit(Events::Page::DOMContentLoaded) })
32
+ @channel.on('download', ->(params) {
33
+ emit(Events::Page::Download, ChannelOwners::Download.from(params['download']))
34
+ })
35
+ @channel.on('fileChooser', ->(params) {
36
+ chooser = FileChooserImpl.new(
37
+ page: self,
38
+ element_handle: ChannelOwners::ElementHandle.from(params['element']),
39
+ is_multiple: params['isMultiple'])
40
+ emit(Events::Page::FileChooser, chooser)
41
+ })
30
42
  @channel.on('frameAttached', ->(params) {
31
43
  on_frame_attached(ChannelOwners::Frame.from(params['frame']))
32
44
  })
@@ -34,9 +46,43 @@ module Playwright
34
46
  on_frame_detached(ChannelOwners::Frame.from(params['frame']))
35
47
  })
36
48
  @channel.on('load', ->(_) { emit(Events::Page::Load) })
49
+ @channel.on('pageError', ->(params) {
50
+ emit(Events::Page::PageError, Error.parse(params['error']['error']))
51
+ })
37
52
  @channel.on('popup', ->(params) {
38
53
  emit(Events::Page::Popup, ChannelOwners::Page.from(params['page']))
39
54
  })
55
+ @channel.on('request', ->(params) {
56
+ emit(Events::Page::Request, ChannelOwners::Request.from(params['request']))
57
+ })
58
+ @channel.on('requestFailed', ->(params) {
59
+ on_request_failed(
60
+ ChannelOwners::Request.from(params['request']),
61
+ params['responseEndTiming'],
62
+ params['failureText'],
63
+ )
64
+ })
65
+ @channel.on('requestFinished', ->(params) {
66
+ on_request_finished(
67
+ ChannelOwners::Request.from(params['request']),
68
+ params['responseEndTiming'],
69
+ )
70
+ })
71
+ @channel.on('response', ->(params) {
72
+ emit(Events::Page::Response, ChannelOwners::Response.from(params['response']))
73
+ })
74
+ @channel.on('route', ->(params) {
75
+ on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
76
+ })
77
+ @channel.on('video', ->(params) {
78
+ video.send(:update_relative_path, params['relativePath'])
79
+ })
80
+ @channel.on('webSocket', ->(params) {
81
+ emit(Events::Page::WebSocket, ChannelOwners::WebSocket.from(params['webSocket']))
82
+ })
83
+ @channel.on('worker', ->(params) {
84
+ on_worker(ChannelOwners::Worker.from(params['worker']))
85
+ })
40
86
  end
41
87
 
42
88
  attr_reader \
@@ -47,6 +93,17 @@ module Playwright
47
93
  :viewport_size,
48
94
  :main_frame
49
95
 
96
+ private def on_request_failed(request, response_end_timing, failure_text)
97
+ request.send(:update_failure_text, failure_text)
98
+ request.send(:update_response_end_timing, response_end_timing)
99
+ emit(Events::Page::RequestFailed)
100
+ end
101
+
102
+ private def on_request_finished(request, response_end_timing)
103
+ request.send(:update_response_end_timing, response_end_timing)
104
+ emit(Events::Page::RequestFinished)
105
+ end
106
+
50
107
  private def on_frame_attached(frame)
51
108
  frame.send(:update_page_from_page, self)
52
109
  @frames << frame
@@ -59,12 +116,48 @@ module Playwright
59
116
  emit(Events::Page::FrameDetached, frame)
60
117
  end
61
118
 
119
+ private def on_route(route, request)
120
+ # @routes.each ...
121
+ @browser_context.send(:on_route, route, request)
122
+ end
123
+
62
124
  private def on_close
63
125
  @closed = true
64
126
  @browser_context.send(:remove_page, self)
65
127
  emit(Events::Page::Close)
66
128
  end
67
129
 
130
+ private def on_dialog(params)
131
+ dialog = ChannelOwners::Dialog.from(params['dialog'])
132
+ unless emit(Events::Page::Dialog, dialog)
133
+ dialog.dismiss # FIXME: this should be asynchronous
134
+ end
135
+ end
136
+
137
+ # @override
138
+ def on(event, callback)
139
+ if event == Events::Page::FileChooser && listener_count(event) == 0
140
+ @channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: true)
141
+ end
142
+ super
143
+ end
144
+
145
+ # @override
146
+ def once(event, callback)
147
+ if event == Events::Page::FileChooser && listener_count(event) == 0
148
+ @channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: true)
149
+ end
150
+ super
151
+ end
152
+
153
+ # @override
154
+ def off(event, callback)
155
+ super
156
+ if event == Events::Page::FileChooser && listener_count(event) == 0
157
+ @channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: false)
158
+ end
159
+ end
160
+
68
161
  def context
69
162
  @browser_context
70
163
  end
@@ -74,14 +167,7 @@ module Playwright
74
167
  ChannelOwners::Page.from(resp)
75
168
  end
76
169
 
77
- def frame(frameSelector)
78
- name, url =
79
- if frameSelector.is_a?(Hash)
80
- [frameSelector[:name], frameSelector[:url]]
81
- else
82
- [frameSelector, nil]
83
- end
84
-
170
+ def frame(name: nil, url: nil)
85
171
  if name
86
172
  @frames.find { |f| f.name == name }
87
173
  elsif url
@@ -103,6 +189,16 @@ module Playwright
103
189
  @frames.to_a
104
190
  end
105
191
 
192
+ def set_default_navigation_timeout(timeout)
193
+ @timeout_settings.default_navigation_timeout = timeout
194
+ @channel.send_message_to_server('setDefaultNavigationTimeoutNoReply', timeout: timeout)
195
+ end
196
+
197
+ def set_default_timeout(timeout)
198
+ @timeout_settings.default_timeout = timeout
199
+ @channel.send_message_to_server('setDefaultTimeoutNoReply', timeout: timeout)
200
+ end
201
+
106
202
  def query_selector(selector)
107
203
  @main_frame.query_selector(selector)
108
204
  end
@@ -111,6 +207,38 @@ module Playwright
111
207
  @main_frame.query_selector_all(selector)
112
208
  end
113
209
 
210
+ def wait_for_selector(selector, state: nil, timeout: nil)
211
+ @main_frame.wait_for_selector(selector, state: state, timeout: timeout)
212
+ end
213
+
214
+ def checked?(selector, timeout: nil)
215
+ @main_frame.checked?(selector, timeout: timeout)
216
+ end
217
+
218
+ def disabled?(selector, timeout: nil)
219
+ @main_frame.disabled?(selector, timeout: timeout)
220
+ end
221
+
222
+ def editable?(selector, timeout: nil)
223
+ @main_frame.editable?(selector, timeout: timeout)
224
+ end
225
+
226
+ def enabled?(selector, timeout: nil)
227
+ @main_frame.enabled?(selector, timeout: timeout)
228
+ end
229
+
230
+ def hidden?(selector, timeout: nil)
231
+ @main_frame.hidden?(selector, timeout: timeout)
232
+ end
233
+
234
+ def visible?(selector, timeout: nil)
235
+ @main_frame.visible?(selector, timeout: timeout)
236
+ end
237
+
238
+ def dispatch_event(selector, type, eventInit: nil, timeout: nil)
239
+ @main_frame.dispatch_event(selector, type, eventInit: eventInit, timeout: timeout)
240
+ end
241
+
114
242
  def evaluate(pageFunction, arg: nil)
115
243
  @main_frame.evaluate(pageFunction, arg: arg)
116
244
  end
@@ -127,6 +255,33 @@ module Playwright
127
255
  @main_frame.eval_on_selector_all(selector, pageFunction, arg: arg)
128
256
  end
129
257
 
258
+ def add_script_tag(content: nil, path: nil, type: nil, url: nil)
259
+ @main_frame.add_script_tag(content: content, path: path, type: type, url: url)
260
+ end
261
+
262
+ def add_style_tag(content: nil, path: nil, url: nil)
263
+ @main_frame.add_style_tag(content: content, path: path, url: url)
264
+ end
265
+
266
+ def expose_function(name, callback)
267
+ @channel.send_message_to_server('exposeBinding', name: name)
268
+ @bindings[name] = ->(_source, *args) { callback.call(*args) }
269
+ end
270
+
271
+ def expose_binding(name, callback, handle: nil)
272
+ params = {
273
+ name: name,
274
+ needsHandle: handle,
275
+ }.compact
276
+ @channel.send_message_to_server('exposeBinding', params)
277
+ @bindings[name] = callback
278
+ end
279
+
280
+ def set_extra_http_headers(headers)
281
+ serialized_headers = HttpHeaders.new(headers).as_serialized
282
+ @channel.send_message_to_server('setExtraHTTPHeaders', headers: serialized_headers)
283
+ end
284
+
130
285
  def url
131
286
  @main_frame.url
132
287
  end
@@ -143,12 +298,66 @@ module Playwright
143
298
  @main_frame.goto(url, timeout: timeout, waitUntil: waitUntil, referer: referer)
144
299
  end
145
300
 
301
+ def reload(timeout: nil, waitUntil: nil)
302
+ params = {
303
+ timeout: timeout,
304
+ waitUntil: waitUntil,
305
+ }.compact
306
+ resp = @channel.send_message_to_server('reoad', params)
307
+ ChannelOwners::Response.from_nullable(resp)
308
+ end
309
+
310
+ def wait_for_load_state(state: nil, timeout: nil)
311
+ @main_frame.wait_for_load_state(state: state, timeout: timeout)
312
+ end
313
+
314
+ def go_back(timeout: nil, waitUntil: nil)
315
+ params = { timeout: timeout, waitUntil: waitUntil }.compact
316
+ resp = @channel.send_message_to_server('goBack', params)
317
+ ChannelOwners::Response.from_nullable(resp)
318
+ end
319
+
320
+ def go_forward(timeout: nil, waitUntil: nil)
321
+ params = { timeout: timeout, waitUntil: waitUntil }.compact
322
+ resp = @channel.send_message_to_server('goForward', params)
323
+ ChannelOwners::Response.from_nullable(resp)
324
+ end
325
+
326
+ def emulate_media(colorScheme: nil, media: nil)
327
+ params = {
328
+ colorScheme: colorScheme,
329
+ media: media,
330
+ }.compact
331
+ @channel.send_message_to_server('emulateMedia', params)
332
+
333
+ nil
334
+ end
335
+
146
336
  def set_viewport_size(viewportSize)
147
337
  @viewport_size = viewportSize
148
338
  @channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
149
339
  nil
150
340
  end
151
341
 
342
+ def bring_to_front
343
+ @channel.send_message_to_server('bringToFront')
344
+ nil
345
+ end
346
+
347
+ def add_init_script(path: nil, script: nil)
348
+ source =
349
+ if path
350
+ File.read(path, 'r')
351
+ elsif script
352
+ script
353
+ else
354
+ raise ArgumentError.new('Either path or script parameter must be specified')
355
+ end
356
+
357
+ @channel.send_message_to_server('addInitScript', source: script)
358
+ nil
359
+ end
360
+
152
361
  def screenshot(
153
362
  path: nil,
154
363
  type: nil,
@@ -167,7 +376,7 @@ module Playwright
167
376
  timeout: timeout,
168
377
  }.compact
169
378
  encoded_binary = @channel.send_message_to_server('screenshot', params)
170
- decoded_binary = Base64.decode64(encoded_binary)
379
+ decoded_binary = Base64.strict_decode64(encoded_binary)
171
380
  if path
172
381
  File.open(path, 'wb') do |f|
173
382
  f.write(decoded_binary)
@@ -217,18 +426,114 @@ module Playwright
217
426
  )
218
427
  end
219
428
 
429
+ def dblclick(
430
+ selector,
431
+ button: nil,
432
+ delay: nil,
433
+ force: nil,
434
+ modifiers: nil,
435
+ noWaitAfter: nil,
436
+ position: nil,
437
+ timeout: nil)
438
+ @main_frame.dblclick(
439
+ selector,
440
+ button: button,
441
+ delay: delay,
442
+ force: force,
443
+ modifiers: modifiers,
444
+ noWaitAfter: noWaitAfter,
445
+ position: position,
446
+ timeout: timeout,
447
+ )
448
+ end
449
+
450
+ def tap_point(
451
+ selector,
452
+ force: nil,
453
+ modifiers: nil,
454
+ noWaitAfter: nil,
455
+ position: nil,
456
+ timeout: nil)
457
+ @main_frame.tap_point(
458
+ selector,
459
+ force: force,
460
+ modifiers: modifiers,
461
+ noWaitAfter: noWaitAfter,
462
+ position: position,
463
+ timeout: timeout,
464
+ )
465
+ end
466
+
467
+ def fill(selector, value, noWaitAfter: nil, timeout: nil)
468
+ @main_frame.fill(selector, value, noWaitAfter: noWaitAfter, timeout: timeout)
469
+ end
470
+
220
471
  def focus(selector, timeout: nil)
221
472
  @main_frame.focus(selector, timeout: timeout)
222
473
  end
223
474
 
224
- def type_text(
475
+ def text_content(selector, timeout: nil)
476
+ @main_frame.text_content(selector, timeout: timeout)
477
+ end
478
+
479
+ def inner_text(selector, timeout: nil)
480
+ @main_frame.inner_text(selector, timeout: timeout)
481
+ end
482
+
483
+ def inner_html(selector, timeout: nil)
484
+ @main_frame.inner_html(selector, timeout: timeout)
485
+ end
486
+
487
+ def get_attribute(selector, name, timeout: nil)
488
+ @main_frame.get_attribute(selector, name, timeout: timeout)
489
+ end
490
+
491
+ def hover(
492
+ selector,
493
+ force: nil,
494
+ modifiers: nil,
495
+ position: nil,
496
+ timeout: nil)
497
+ @main_frame.hover(
498
+ selector,
499
+ force: force,
500
+ modifiers: modifiers,
501
+ position: position,
502
+ timeout: timeout,
503
+ )
504
+ end
505
+
506
+ def select_option(
507
+ selector,
508
+ element: nil,
509
+ index: nil,
510
+ value: nil,
511
+ label: nil,
512
+ noWaitAfter: nil,
513
+ timeout: nil)
514
+ @main_frame.select_option(
515
+ selector,
516
+ element: element,
517
+ index: index,
518
+ value: value,
519
+ label: label,
520
+ noWaitAfter: noWaitAfter,
521
+ timeout: timeout,
522
+ )
523
+ end
524
+
525
+ def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
526
+ @main_frame.set_input_files(selector, files, noWaitAfter: noWaitAfter, timeout: timeout)
527
+ end
528
+
529
+ def type(
225
530
  selector,
226
531
  text,
227
532
  delay: nil,
228
533
  noWaitAfter: nil,
229
534
  timeout: nil)
230
535
 
231
- @main_frame.type_text(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
536
+ @main_frame.type(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
232
537
  end
233
538
 
234
539
  def press(
@@ -241,6 +546,57 @@ module Playwright
241
546
  @main_frame.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
242
547
  end
243
548
 
549
+ def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
550
+ @main_frame.check(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
551
+ end
552
+
553
+ def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
554
+ @main_frame.uncheck(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
555
+ end
556
+
557
+ def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
558
+ @main_frame.wait_for_function(pageFunction, arg: arg, polling: polling, timeout: timeout)
559
+ end
560
+
561
+ def pdf(
562
+ displayHeaderFooter: nil,
563
+ footerTemplate: nil,
564
+ format: nil,
565
+ headerTemplate: nil,
566
+ height: nil,
567
+ landscape: nil,
568
+ margin: nil,
569
+ pageRanges: nil,
570
+ path: nil,
571
+ preferCSSPageSize: nil,
572
+ printBackground: nil,
573
+ scale: nil,
574
+ width: nil)
575
+
576
+ params = {
577
+ displayHeaderFooter: displayHeaderFooter,
578
+ footerTemplate: footerTemplate,
579
+ format: format,
580
+ headerTemplate: headerTemplate,
581
+ height: height,
582
+ landscape: landscape,
583
+ margin: margin,
584
+ pageRanges: pageRanges,
585
+ preferCSSPageSize: preferCSSPageSize,
586
+ printBackground: printBackground,
587
+ scale: scale,
588
+ width: width,
589
+ }.compact
590
+ encoded_binary = @channel.send_message_to_server('pdf', params)
591
+ decoded_binary = Base64.strict_decode64(encoded_binary)
592
+ if path
593
+ File.open(path, 'wb') do |f|
594
+ f.write(decoded_binary)
595
+ end
596
+ end
597
+ decoded_binary
598
+ end
599
+
244
600
  class CrashedError < StandardError
245
601
  def initialize
246
602
  super('Page crashed')
@@ -259,20 +615,9 @@ module Playwright
259
615
  end
260
616
  end
261
617
 
262
- def wait_for_event(event, optionsOrPredicate: nil, &block)
263
- predicate, timeout =
264
- case optionsOrPredicate
265
- when Proc
266
- [optionsOrPredicate, nil]
267
- when Hash
268
- [optionsOrPredicate[:predicate], optionsOrPredicate[:timeout]]
269
- else
270
- [nil, nil]
271
- end
272
- timeout ||= @timeout_settings.timeout
273
-
618
+ def expect_event(event, predicate: nil, timeout: nil, &block)
274
619
  wait_helper = WaitHelper.new
275
- wait_helper.reject_on_timeout(timeout, "Timeout while waiting for event \"#{event}\"")
620
+ wait_helper.reject_on_timeout(timeout || @timeout_settings.timeout, "Timeout while waiting for event \"#{event}\"")
276
621
 
277
622
  unless event == Events::Page::Crash
278
623
  wait_helper.reject_on_event(self, Events::Page::Crash, CrashedError.new)
@@ -289,15 +634,15 @@ module Playwright
289
634
  wait_helper.promise.value!
290
635
  end
291
636
 
292
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
293
- @main_frame.wait_for_navigation(
637
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
638
+ @main_frame.expect_navigation(
294
639
  timeout: timeout,
295
640
  url: url,
296
641
  waitUntil: waitUntil,
297
642
  &block)
298
643
  end
299
644
 
300
- def wait_for_request(urlOrPredicate, timeout: nil)
645
+ def expect_request(urlOrPredicate, timeout: nil)
301
646
  predicate =
302
647
  case urlOrPredicate
303
648
  when String, Regexp
@@ -309,10 +654,10 @@ module Playwright
309
654
  -> (_) { true }
310
655
  end
311
656
 
312
- wait_for_event(Events::Page::Request, optionsOrPredicate: { predicate: predicate, timeout: timeout})
657
+ expect_event(Events::Page::Request, predicate: predicate, timeout: timeout)
313
658
  end
314
659
 
315
- def wait_for_response(urlOrPredicate, timeout: nil)
660
+ def expect_response(urlOrPredicate, timeout: nil)
316
661
  predicate =
317
662
  case urlOrPredicate
318
663
  when String, Regexp
@@ -324,7 +669,7 @@ module Playwright
324
669
  -> (_) { true }
325
670
  end
326
671
 
327
- wait_for_event(Events::Page::Response, optionsOrPredicate: { predicate: predicate, timeout: timeout})
672
+ expect_event(Events::Page::Response, predicate: predicate, timeout: timeout)
328
673
  end
329
674
 
330
675
  # called from BrowserContext#on_page with send(:update_browser_context, page), so keep private.