playwright-ruby-client 0.0.7 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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.