playwright-ruby-client 0.3.0 → 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -5
- data/docs/api_coverage.md +14 -25
- data/lib/playwright.rb +47 -9
- data/lib/playwright/channel.rb +19 -9
- data/lib/playwright/channel_owners/artifact.rb +30 -0
- data/lib/playwright/channel_owners/browser.rb +21 -0
- data/lib/playwright/channel_owners/browser_context.rb +5 -0
- data/lib/playwright/channel_owners/browser_type.rb +28 -0
- data/lib/playwright/channel_owners/element_handle.rb +7 -7
- data/lib/playwright/channel_owners/frame.rb +26 -5
- data/lib/playwright/channel_owners/js_handle.rb +2 -2
- data/lib/playwright/channel_owners/page.rb +78 -15
- data/lib/playwright/channel_owners/playwright.rb +22 -29
- data/lib/playwright/channel_owners/stream.rb +15 -0
- data/lib/playwright/connection.rb +11 -32
- data/lib/playwright/download.rb +27 -0
- data/lib/playwright/errors.rb +6 -0
- data/lib/playwright/events.rb +2 -5
- data/lib/playwright/keyboard_impl.rb +1 -1
- data/lib/playwright/mouse_impl.rb +41 -0
- data/lib/playwright/playwright_api.rb +5 -3
- data/lib/playwright/route_handler_entry.rb +1 -9
- data/lib/playwright/select_option_values.rb +31 -22
- data/lib/playwright/transport.rb +29 -7
- data/lib/playwright/url_matcher.rb +1 -1
- data/lib/playwright/utils.rb +8 -0
- data/lib/playwright/version.rb +1 -1
- data/lib/playwright/video.rb +51 -0
- data/lib/playwright/wait_helper.rb +2 -2
- data/lib/playwright_api/accessibility.rb +39 -1
- data/lib/playwright_api/android.rb +10 -10
- data/lib/playwright_api/android_device.rb +10 -9
- data/lib/playwright_api/browser.rb +83 -8
- data/lib/playwright_api/browser_context.rb +157 -9
- data/lib/playwright_api/browser_type.rb +35 -4
- data/lib/playwright_api/console_message.rb +6 -6
- data/lib/playwright_api/dialog.rb +28 -8
- data/lib/playwright_api/element_handle.rb +111 -37
- data/lib/playwright_api/file_chooser.rb +5 -0
- data/lib/playwright_api/frame.rb +228 -37
- data/lib/playwright_api/js_handle.rb +26 -3
- data/lib/playwright_api/keyboard.rb +48 -1
- data/lib/playwright_api/mouse.rb +26 -5
- data/lib/playwright_api/page.rb +454 -46
- data/lib/playwright_api/playwright.rb +26 -9
- data/lib/playwright_api/request.rb +34 -6
- data/lib/playwright_api/response.rb +6 -6
- data/lib/playwright_api/route.rb +30 -6
- data/lib/playwright_api/selectors.rb +32 -6
- data/lib/playwright_api/touchscreen.rb +1 -1
- data/lib/playwright_api/worker.rb +25 -1
- data/playwright.gemspec +4 -2
- metadata +37 -14
- data/lib/playwright/channel_owners/chromium_browser.rb +0 -8
- data/lib/playwright/channel_owners/chromium_browser_context.rb +0 -8
- data/lib/playwright/channel_owners/download.rb +0 -27
- data/lib/playwright/channel_owners/firefox_browser.rb +0 -8
- data/lib/playwright/channel_owners/webkit_browser.rb +0 -8
- data/lib/playwright_api/binding_call.rb +0 -32
- data/lib/playwright_api/chromium_browser_context.rb +0 -59
- data/lib/playwright_api/download.rb +0 -95
- data/lib/playwright_api/video.rb +0 -24
@@ -98,6 +98,15 @@ module Playwright
|
|
98
98
|
request&.response
|
99
99
|
end
|
100
100
|
|
101
|
+
def wait_for_url(url, timeout: nil, waitUntil: nil)
|
102
|
+
matcher = UrlMatcher.new(url)
|
103
|
+
if matcher.match?(@url)
|
104
|
+
wait_for_load_state(state: waitUntil, timeout: timeout)
|
105
|
+
else
|
106
|
+
expect_navigation(timeout: timeout, url: url, waitUntil: waitUntil)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
101
110
|
def wait_for_load_state(state: nil, timeout: nil)
|
102
111
|
option_state = state || 'load'
|
103
112
|
option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
|
@@ -412,10 +421,8 @@ module Playwright
|
|
412
421
|
value: value,
|
413
422
|
label: label,
|
414
423
|
).as_params
|
415
|
-
params = base_params
|
424
|
+
params = base_params.merge({ selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact)
|
416
425
|
@channel.send_message_to_server('selectOption', params)
|
417
|
-
|
418
|
-
nil
|
419
426
|
end
|
420
427
|
|
421
428
|
def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
|
@@ -464,11 +471,18 @@ module Playwright
|
|
464
471
|
nil
|
465
472
|
end
|
466
473
|
|
467
|
-
def check(
|
474
|
+
def check(
|
475
|
+
selector,
|
476
|
+
force: nil,
|
477
|
+
noWaitAfter: nil,
|
478
|
+
position: nil,
|
479
|
+
timeout: nil)
|
480
|
+
|
468
481
|
params = {
|
469
482
|
selector: selector,
|
470
483
|
force: force,
|
471
484
|
noWaitAfter: noWaitAfter,
|
485
|
+
position: position,
|
472
486
|
timeout: timeout,
|
473
487
|
}.compact
|
474
488
|
@channel.send_message_to_server('check', params)
|
@@ -476,11 +490,18 @@ module Playwright
|
|
476
490
|
nil
|
477
491
|
end
|
478
492
|
|
479
|
-
def uncheck(
|
493
|
+
def uncheck(
|
494
|
+
selector,
|
495
|
+
force: nil,
|
496
|
+
noWaitAfter: nil,
|
497
|
+
position: nil,
|
498
|
+
timeout: nil)
|
499
|
+
|
480
500
|
params = {
|
481
501
|
selector: selector,
|
482
502
|
force: force,
|
483
503
|
noWaitAfter: noWaitAfter,
|
504
|
+
position: position,
|
484
505
|
timeout: timeout,
|
485
506
|
}.compact
|
486
507
|
@channel.send_message_to_server('uncheck', params)
|
@@ -28,6 +28,7 @@ module Playwright
|
|
28
28
|
@main_frame.send(:update_page_from_page, self)
|
29
29
|
@frames = Set.new
|
30
30
|
@frames << @main_frame
|
31
|
+
@opener = ChannelOwners::Page.from_nullable(@initializer['opener'])
|
31
32
|
|
32
33
|
@channel.once('close', ->(_) { on_close })
|
33
34
|
@channel.on('console', ->(params) {
|
@@ -37,9 +38,7 @@ module Playwright
|
|
37
38
|
@channel.on('crash', ->(_) { emit(Events::Page::Crash) })
|
38
39
|
@channel.on('dialog', method(:on_dialog))
|
39
40
|
@channel.on('domcontentloaded', ->(_) { emit(Events::Page::DOMContentLoaded) })
|
40
|
-
@channel.on('download',
|
41
|
-
emit(Events::Page::Download, ChannelOwners::Download.from(params['download']))
|
42
|
-
})
|
41
|
+
@channel.on('download', method(:on_download))
|
43
42
|
@channel.on('fileChooser', ->(params) {
|
44
43
|
chooser = FileChooserImpl.new(
|
45
44
|
page: self,
|
@@ -57,9 +56,6 @@ module Playwright
|
|
57
56
|
@channel.on('pageError', ->(params) {
|
58
57
|
emit(Events::Page::PageError, Error.parse(params['error']['error']))
|
59
58
|
})
|
60
|
-
@channel.on('popup', ->(params) {
|
61
|
-
emit(Events::Page::Popup, ChannelOwners::Page.from(params['page']))
|
62
|
-
})
|
63
59
|
@channel.on('request', ->(params) {
|
64
60
|
emit(Events::Page::Request, ChannelOwners::Request.from(params['request']))
|
65
61
|
})
|
@@ -82,9 +78,7 @@ module Playwright
|
|
82
78
|
@channel.on('route', ->(params) {
|
83
79
|
on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
|
84
80
|
})
|
85
|
-
@channel.on('video',
|
86
|
-
video.send(:update_relative_path, params['relativePath'])
|
87
|
-
})
|
81
|
+
@channel.on('video', method(:on_video))
|
88
82
|
@channel.on('webSocket', ->(params) {
|
89
83
|
emit(Events::Page::WebSocket, ChannelOwners::WebSocket.from(params['webSocket']))
|
90
84
|
})
|
@@ -149,6 +143,20 @@ module Playwright
|
|
149
143
|
end
|
150
144
|
end
|
151
145
|
|
146
|
+
private def on_download(params)
|
147
|
+
download = Download.new(
|
148
|
+
url: params['url'],
|
149
|
+
suggested_filename: params['suggestedFilename'],
|
150
|
+
artifact: ChannelOwners::Artifact.from(params['artifact']),
|
151
|
+
)
|
152
|
+
emit(Events::Page::Download, download)
|
153
|
+
end
|
154
|
+
|
155
|
+
private def on_video(params)
|
156
|
+
artifact = ChannelOwners::Artifact.from(params['artifact'])
|
157
|
+
video.send(:set_artifact, artifact)
|
158
|
+
end
|
159
|
+
|
152
160
|
# @override
|
153
161
|
def on(event, callback)
|
154
162
|
if event == Events::Page::FileChooser && listener_count(event) == 0
|
@@ -178,8 +186,17 @@ module Playwright
|
|
178
186
|
end
|
179
187
|
|
180
188
|
def opener
|
181
|
-
|
182
|
-
|
189
|
+
if @opener&.closed?
|
190
|
+
nil
|
191
|
+
else
|
192
|
+
@opener
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
private def emit_popup_event_from_browser_context
|
197
|
+
if @opener && !@opener.closed?
|
198
|
+
@opener.emit(Events::Page::Popup, self)
|
199
|
+
end
|
183
200
|
end
|
184
201
|
|
185
202
|
def frame(name: nil, url: nil)
|
@@ -326,6 +343,10 @@ module Playwright
|
|
326
343
|
@main_frame.wait_for_load_state(state: state, timeout: timeout)
|
327
344
|
end
|
328
345
|
|
346
|
+
def wait_for_url(url, timeout: nil, waitUntil: nil)
|
347
|
+
@main_frame.wait_for_url(url, timeout: timeout, waitUntil: waitUntil)
|
348
|
+
end
|
349
|
+
|
329
350
|
def go_back(timeout: nil, waitUntil: nil)
|
330
351
|
params = { timeout: timeout, waitUntil: waitUntil }.compact
|
331
352
|
resp = @channel.send_message_to_server('goBack', params)
|
@@ -578,12 +599,24 @@ module Playwright
|
|
578
599
|
@main_frame.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
|
579
600
|
end
|
580
601
|
|
581
|
-
def check(
|
582
|
-
|
602
|
+
def check(
|
603
|
+
selector,
|
604
|
+
force: nil,
|
605
|
+
noWaitAfter: nil,
|
606
|
+
position: nil,
|
607
|
+
timeout: nil)
|
608
|
+
|
609
|
+
@main_frame.check(selector, force: force, noWaitAfter: noWaitAfter, position: position, timeout: timeout)
|
583
610
|
end
|
584
611
|
|
585
|
-
def uncheck(
|
586
|
-
|
612
|
+
def uncheck(
|
613
|
+
selector,
|
614
|
+
force: nil,
|
615
|
+
noWaitAfter: nil,
|
616
|
+
position: nil,
|
617
|
+
timeout: nil)
|
618
|
+
|
619
|
+
@main_frame.uncheck(selector, force: force, noWaitAfter: noWaitAfter, position: position, timeout: timeout)
|
587
620
|
end
|
588
621
|
|
589
622
|
def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
|
@@ -629,6 +662,36 @@ module Playwright
|
|
629
662
|
decoded_binary
|
630
663
|
end
|
631
664
|
|
665
|
+
def video
|
666
|
+
return nil unless @browser_context.send(:has_record_video_option?)
|
667
|
+
@video ||= Video.new(self)
|
668
|
+
end
|
669
|
+
|
670
|
+
def start_js_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
|
671
|
+
params = {
|
672
|
+
resetOnNavigation: resetOnNavigation,
|
673
|
+
reportAnonymousScripts: reportAnonymousScripts,
|
674
|
+
}.compact
|
675
|
+
|
676
|
+
@channel.send_message_to_server('startJSCoverage', params)
|
677
|
+
end
|
678
|
+
|
679
|
+
def stop_js_coverage
|
680
|
+
@channel.send_message_to_server('stopJSCoverage')
|
681
|
+
end
|
682
|
+
|
683
|
+
def start_css_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
|
684
|
+
params = {
|
685
|
+
resetOnNavigation: resetOnNavigation,
|
686
|
+
}.compact
|
687
|
+
|
688
|
+
@channel.send_message_to_server('startCSSCoverage', params)
|
689
|
+
end
|
690
|
+
|
691
|
+
def stop_css_coverage
|
692
|
+
@channel.send_message_to_server('stopCSSCoverage')
|
693
|
+
end
|
694
|
+
|
632
695
|
class CrashedError < StandardError
|
633
696
|
def initialize
|
634
697
|
super('Page crashed')
|
@@ -24,38 +24,31 @@ module Playwright
|
|
24
24
|
@selectors ||= ::Playwright::ChannelOwners::Selectors.from(@initializer['selectors'])
|
25
25
|
end
|
26
26
|
|
27
|
-
class DeviceDescriptor
|
28
|
-
class Viewport
|
29
|
-
def initialize(hash)
|
30
|
-
@width = hash['width']
|
31
|
-
@heirhgt = hash['height']
|
32
|
-
end
|
33
|
-
attr_reader :width, :height
|
34
|
-
end
|
35
|
-
|
36
|
-
def initialize(hash)
|
37
|
-
@user_agent = hash["userAgent"]
|
38
|
-
@viewport = Viewport.new(hash["viewport"])
|
39
|
-
@device_scale_factor = hash["deviceScaleFactor"]
|
40
|
-
@is_mobile = hash["isMobile"]
|
41
|
-
@has_touch = hash["hasTouch"]
|
42
|
-
end
|
43
|
-
|
44
|
-
attr_reader :user_agent, :viewport, :device_scale_factor
|
45
|
-
|
46
|
-
def mobile?
|
47
|
-
@is_mobile
|
48
|
-
end
|
49
|
-
|
50
|
-
def has_touch?
|
51
|
-
@has_touch
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
27
|
def devices
|
56
28
|
@devices ||= @initializer['deviceDescriptors'].map do |item|
|
57
|
-
[item['name'],
|
29
|
+
[item['name'], parse_device_descriptor(item['descriptor'])]
|
58
30
|
end.to_h
|
59
31
|
end
|
32
|
+
|
33
|
+
private def parse_device_descriptor(descriptor)
|
34
|
+
# This return value can be passed into Browser#new_context as it is.
|
35
|
+
# ex:
|
36
|
+
# ```
|
37
|
+
# iPhone = playwright.devices['iPhone 6']
|
38
|
+
# context = browser.new_context(**iPhone)
|
39
|
+
# page = context.new_page
|
40
|
+
#
|
41
|
+
# ```
|
42
|
+
{
|
43
|
+
userAgent: descriptor['userAgent'],
|
44
|
+
viewport: {
|
45
|
+
width: descriptor['viewport']['width'],
|
46
|
+
height: descriptor['viewport']['height'],
|
47
|
+
},
|
48
|
+
deviceScaleFactor: descriptor['deviceScaleFactor'],
|
49
|
+
isMobile: descriptor['isMobile'],
|
50
|
+
hasTouch: descriptor['hasTouch'],
|
51
|
+
}
|
52
|
+
end
|
60
53
|
end
|
61
54
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Playwright
|
4
|
+
define_channel_owner :Stream do
|
5
|
+
def save_as(path)
|
6
|
+
File.open(path, 'wb') do |f|
|
7
|
+
loop do
|
8
|
+
binary = @channel.send_message_to_server('read')
|
9
|
+
break if !binary || binary.length == 0
|
10
|
+
f.write(Base64.strict_decode64(binary))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -12,6 +12,12 @@ module Playwright
|
|
12
12
|
@transport.on_message_received do |message|
|
13
13
|
dispatch(message)
|
14
14
|
end
|
15
|
+
@transport.on_driver_crashed do
|
16
|
+
@callbacks.each_value do |callback|
|
17
|
+
callback.reject(::Playwright::DriverCrashedError.new)
|
18
|
+
end
|
19
|
+
raise ::Playwright::DriverCrashedError.new
|
20
|
+
end
|
15
21
|
|
16
22
|
@objects = {} # Hash[ guid => ChannelOwner ]
|
17
23
|
@waiting_for_object = {} # Hash[ guid => Promise<ChannelOwner> ]
|
@@ -19,26 +25,22 @@ module Playwright
|
|
19
25
|
@root_object = RootChannelOwner.new(self)
|
20
26
|
end
|
21
27
|
|
22
|
-
def
|
23
|
-
@transport.
|
28
|
+
def async_run
|
29
|
+
@transport.async_run
|
24
30
|
end
|
25
31
|
|
26
32
|
def stop
|
27
33
|
@transport.stop
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
36
|
+
def wait_for_object_with_known_name(guid)
|
31
37
|
if @objects[guid]
|
32
38
|
return @objects[guid]
|
33
39
|
end
|
34
40
|
|
35
41
|
callback = Concurrent::Promises.resolvable_future
|
36
42
|
@waiting_for_object[guid] = callback
|
37
|
-
callback
|
38
|
-
end
|
39
|
-
|
40
|
-
def wait_for_object_with_known_name(guid)
|
41
|
-
async_wait_for_object_with_known_name.value!
|
43
|
+
callback.value!
|
42
44
|
end
|
43
45
|
|
44
46
|
def async_send_message_to_server(guid, method, params)
|
@@ -195,32 +197,9 @@ module Playwright
|
|
195
197
|
end
|
196
198
|
initializer = replace_guids_with_channels(initializer)
|
197
199
|
|
198
|
-
class_name = case type
|
199
|
-
when 'Browser'
|
200
|
-
case initializer['name']
|
201
|
-
when 'chromium'
|
202
|
-
'ChromiumBrowser'
|
203
|
-
when 'webkit'
|
204
|
-
'WebKitBrowser'
|
205
|
-
when 'firefox'
|
206
|
-
'FirefoxBrowser'
|
207
|
-
else
|
208
|
-
'Browser'
|
209
|
-
end
|
210
|
-
when 'BrowserContext'
|
211
|
-
browser_name = initializer['browserName']
|
212
|
-
if browser_name == 'chromium'
|
213
|
-
'ChromiumBrowserContext'
|
214
|
-
else
|
215
|
-
'BrowserContext'
|
216
|
-
end
|
217
|
-
else
|
218
|
-
type
|
219
|
-
end
|
220
|
-
|
221
200
|
result =
|
222
201
|
begin
|
223
|
-
ChannelOwners.const_get(
|
202
|
+
ChannelOwners.const_get(type).new(
|
224
203
|
parent,
|
225
204
|
type,
|
226
205
|
guid,
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Playwright
|
2
|
+
class Download
|
3
|
+
def initialize(url:, suggested_filename:, artifact:)
|
4
|
+
@url = url
|
5
|
+
@suggested_filename = suggested_filename
|
6
|
+
@artifact = artifact
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :url, :suggested_filename
|
10
|
+
|
11
|
+
def delete
|
12
|
+
@artifact.delete
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure
|
16
|
+
@artifact.failure
|
17
|
+
end
|
18
|
+
|
19
|
+
def path
|
20
|
+
@artifact.path_after_finished
|
21
|
+
end
|
22
|
+
|
23
|
+
def save_as(path)
|
24
|
+
@artifact.save_as(path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/playwright/errors.rb
CHANGED
@@ -27,6 +27,12 @@ module Playwright
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class DriverCrashedError < StandardError
|
31
|
+
def initialize
|
32
|
+
super("[BUG] Playwright driver is crashed!")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
30
36
|
class TimeoutError < Error
|
31
37
|
def initialize(message:, stack: [])
|
32
38
|
super(name: 'TimeoutError', message: message, stack: stack)
|
data/lib/playwright/events.rb
CHANGED
@@ -24,8 +24,10 @@ end
|
|
24
24
|
},
|
25
25
|
|
26
26
|
BrowserContext: {
|
27
|
+
BackgroundPage: 'backgroundpage',
|
27
28
|
Close: 'close',
|
28
29
|
Page: 'page',
|
30
|
+
ServiceWorker: 'serviceworker',
|
29
31
|
},
|
30
32
|
|
31
33
|
BrowserServer: {
|
@@ -67,11 +69,6 @@ end
|
|
67
69
|
Close: 'close',
|
68
70
|
},
|
69
71
|
|
70
|
-
ChromiumBrowserContext: {
|
71
|
-
BackgroundPage: 'backgroundpage',
|
72
|
-
ServiceWorker: 'serviceworker',
|
73
|
-
},
|
74
|
-
|
75
72
|
ElectronApplication: {
|
76
73
|
Close: 'close',
|
77
74
|
Window: 'window',
|