playwright-ruby-client 0.0.7 → 0.2.1

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -3
  3. data/docs/api_coverage.md +89 -84
  4. data/lib/playwright.rb +4 -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 +3 -5
  9. data/lib/playwright/channel_owners/android.rb +1 -1
  10. data/lib/playwright/channel_owners/android_device.rb +83 -13
  11. data/lib/playwright/channel_owners/browser.rb +1 -1
  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 +15 -4
  15. data/lib/playwright/channel_owners/frame.rb +228 -19
  16. data/lib/playwright/channel_owners/js_handle.rb +1 -1
  17. data/lib/playwright/channel_owners/page.rb +350 -27
  18. data/lib/playwright/channel_owners/request.rb +9 -1
  19. data/lib/playwright/errors.rb +1 -1
  20. data/lib/playwright/event_emitter.rb +8 -1
  21. data/lib/playwright/event_emitter_proxy.rb +49 -0
  22. data/lib/playwright/file_chooser_impl.rb +23 -0
  23. data/lib/playwright/http_headers.rb +20 -0
  24. data/lib/playwright/input_files.rb +1 -1
  25. data/lib/playwright/javascript/expression.rb +15 -0
  26. data/lib/playwright/javascript/function.rb +15 -0
  27. data/lib/playwright/javascript/value_parser.rb +1 -1
  28. data/lib/playwright/javascript/value_serializer.rb +1 -1
  29. data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +5 -1
  30. data/lib/playwright/mouse_impl.rb +7 -0
  31. data/lib/playwright/playwright_api.rb +59 -20
  32. data/lib/playwright/select_option_values.rb +14 -4
  33. data/lib/playwright/timeout_settings.rb +1 -1
  34. data/lib/playwright/touchscreen_impl.rb +7 -0
  35. data/lib/playwright/utils.rb +3 -3
  36. data/lib/playwright/version.rb +1 -1
  37. data/lib/playwright/wait_helper.rb +1 -1
  38. data/lib/playwright_api/android.rb +9 -10
  39. data/lib/playwright_api/android_device.rb +43 -14
  40. data/lib/playwright_api/android_input.rb +25 -0
  41. data/lib/playwright_api/binding_call.rb +10 -6
  42. data/lib/playwright_api/browser.rb +20 -21
  43. data/lib/playwright_api/browser_context.rb +29 -20
  44. data/lib/playwright_api/browser_type.rb +16 -56
  45. data/lib/playwright_api/chromium_browser_context.rb +10 -8
  46. data/lib/playwright_api/console_message.rb +10 -6
  47. data/lib/playwright_api/dialog.rb +5 -1
  48. data/lib/playwright_api/download.rb +28 -11
  49. data/lib/playwright_api/element_handle.rb +107 -96
  50. data/lib/playwright_api/file_chooser.rb +17 -9
  51. data/lib/playwright_api/frame.rb +136 -132
  52. data/lib/playwright_api/js_handle.rb +18 -20
  53. data/lib/playwright_api/keyboard.rb +5 -5
  54. data/lib/playwright_api/page.rb +204 -149
  55. data/lib/playwright_api/playwright.rb +32 -44
  56. data/lib/playwright_api/request.rb +7 -8
  57. data/lib/playwright_api/response.rb +10 -6
  58. data/lib/playwright_api/selectors.rb +13 -9
  59. data/lib/playwright_api/web_socket.rb +10 -1
  60. data/lib/playwright_api/worker.rb +13 -13
  61. metadata +12 -6
  62. data/lib/playwright/input_type.rb +0 -19
  63. data/lib/playwright/input_types/mouse.rb +0 -4
  64. data/lib/playwright/input_types/touchscreen.rb +0 -4
@@ -1,6 +1,6 @@
1
1
  module Playwright
2
2
  define_channel_owner :JSHandle do
3
- def after_initialize
3
+ private def after_initialize
4
4
  @preview = @initializer['preview']
5
5
  @channel.on('previewUpdated', method(:on_preview_updated))
6
6
  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
@@ -156,12 +311,53 @@ module Playwright
156
311
  @main_frame.wait_for_load_state(state: state, timeout: timeout)
157
312
  end
158
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
+
159
336
  def set_viewport_size(viewportSize)
160
337
  @viewport_size = viewportSize
161
338
  @channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
162
339
  nil
163
340
  end
164
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
+
165
361
  def screenshot(
166
362
  path: nil,
167
363
  type: nil,
@@ -251,6 +447,23 @@ module Playwright
251
447
  )
252
448
  end
253
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
+
254
467
  def fill(selector, value, noWaitAfter: nil, timeout: nil)
255
468
  @main_frame.fill(selector, value, noWaitAfter: noWaitAfter, timeout: timeout)
256
469
  end
@@ -259,6 +472,60 @@ module Playwright
259
472
  @main_frame.focus(selector, timeout: timeout)
260
473
  end
261
474
 
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
+
262
529
  def type(
263
530
  selector,
264
531
  text,
@@ -279,6 +546,57 @@ module Playwright
279
546
  @main_frame.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
280
547
  end
281
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
+
282
600
  class CrashedError < StandardError
283
601
  def initialize
284
602
  super('Page crashed')
@@ -297,20 +615,9 @@ module Playwright
297
615
  end
298
616
  end
299
617
 
300
- def expect_event(event, optionsOrPredicate: nil, &block)
301
- predicate, timeout =
302
- case optionsOrPredicate
303
- when Proc
304
- [optionsOrPredicate, nil]
305
- when Hash
306
- [optionsOrPredicate[:predicate], optionsOrPredicate[:timeout]]
307
- else
308
- [nil, nil]
309
- end
310
- timeout ||= @timeout_settings.timeout
311
-
618
+ def expect_event(event, predicate: nil, timeout: nil, &block)
312
619
  wait_helper = WaitHelper.new
313
- 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}\"")
314
621
 
315
622
  unless event == Events::Page::Crash
316
623
  wait_helper.reject_on_event(self, Events::Page::Crash, CrashedError.new)
@@ -327,6 +634,18 @@ module Playwright
327
634
  wait_helper.promise.value!
328
635
  end
329
636
 
637
+ def expect_console_message(predicate: nil, timeout: nil, &block)
638
+ expect_event(Events::Page::Console, predicate: predicate, timeout: timeout, &block)
639
+ end
640
+
641
+ def expect_download(predicate: nil, timeout: nil, &block)
642
+ expect_event(Events::Page::Download, predicate: predicate, timeout: timeout, &block)
643
+ end
644
+
645
+ def expect_file_chooser(predicate: nil, timeout: nil, &block)
646
+ expect_event(Events::Page::FileChooser, predicate: predicate, timeout: timeout, &block)
647
+ end
648
+
330
649
  def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
331
650
  @main_frame.expect_navigation(
332
651
  timeout: timeout,
@@ -335,6 +654,10 @@ module Playwright
335
654
  &block)
336
655
  end
337
656
 
657
+ def expect_popup(predicate: nil, timeout: nil, &block)
658
+ expect_event(Events::Page::Popup, predicate: predicate, timeout: timeout, &block)
659
+ end
660
+
338
661
  def expect_request(urlOrPredicate, timeout: nil)
339
662
  predicate =
340
663
  case urlOrPredicate
@@ -347,7 +670,7 @@ module Playwright
347
670
  -> (_) { true }
348
671
  end
349
672
 
350
- expect_event(Events::Page::Request, optionsOrPredicate: { predicate: predicate, timeout: timeout})
673
+ expect_event(Events::Page::Request, predicate: predicate, timeout: timeout)
351
674
  end
352
675
 
353
676
  def expect_response(urlOrPredicate, timeout: nil)
@@ -362,7 +685,7 @@ module Playwright
362
685
  -> (_) { true }
363
686
  end
364
687
 
365
- expect_event(Events::Page::Response, optionsOrPredicate: { predicate: predicate, timeout: timeout})
688
+ expect_event(Events::Page::Response, predicate: predicate, timeout: timeout)
366
689
  end
367
690
 
368
691
  # called from BrowserContext#on_page with send(:update_browser_context, page), so keep private.