playwright-ruby-client 0.1.0 → 0.5.3
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.
- checksums.yaml +4 -4
- data/README.md +20 -8
- data/docs/api_coverage.md +123 -73
- data/lib/playwright.rb +48 -9
- data/lib/playwright/channel.rb +12 -2
- data/lib/playwright/channel_owner.rb +3 -5
- data/lib/playwright/channel_owners/android.rb +1 -1
- data/lib/playwright/channel_owners/android_device.rb +11 -11
- data/lib/playwright/channel_owners/artifact.rb +30 -0
- data/lib/playwright/channel_owners/binding_call.rb +3 -0
- data/lib/playwright/channel_owners/browser.rb +22 -1
- data/lib/playwright/channel_owners/browser_context.rb +155 -4
- data/lib/playwright/channel_owners/browser_type.rb +28 -0
- data/lib/playwright/channel_owners/dialog.rb +28 -0
- data/lib/playwright/channel_owners/element_handle.rb +18 -5
- data/lib/playwright/channel_owners/frame.rb +40 -5
- data/lib/playwright/channel_owners/js_handle.rb +3 -3
- data/lib/playwright/channel_owners/page.rb +172 -51
- data/lib/playwright/channel_owners/playwright.rb +24 -27
- data/lib/playwright/channel_owners/request.rb +27 -3
- data/lib/playwright/channel_owners/response.rb +60 -0
- data/lib/playwright/channel_owners/route.rb +78 -0
- data/lib/playwright/channel_owners/selectors.rb +19 -1
- 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 +3 -1
- data/lib/playwright/route_handler_entry.rb +28 -0
- data/lib/playwright/select_option_values.rb +14 -4
- data/lib/playwright/transport.rb +28 -7
- data/lib/playwright/url_matcher.rb +1 -1
- data/lib/playwright/utils.rb +11 -2
- 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 +72 -5
- data/lib/playwright_api/android_device.rb +139 -26
- data/lib/playwright_api/android_input.rb +17 -13
- data/lib/playwright_api/android_socket.rb +16 -0
- data/lib/playwright_api/android_web_view.rb +21 -0
- data/lib/playwright_api/browser.rb +87 -19
- data/lib/playwright_api/browser_context.rb +216 -32
- data/lib/playwright_api/browser_type.rb +45 -58
- data/lib/playwright_api/dialog.rb +54 -7
- data/lib/playwright_api/element_handle.rb +113 -33
- data/lib/playwright_api/file_chooser.rb +6 -1
- data/lib/playwright_api/frame.rb +238 -43
- data/lib/playwright_api/js_handle.rb +20 -2
- data/lib/playwright_api/keyboard.rb +48 -1
- data/lib/playwright_api/mouse.rb +26 -5
- data/lib/playwright_api/page.rb +534 -63
- data/lib/playwright_api/playwright.rb +43 -47
- data/lib/playwright_api/request.rb +38 -12
- data/lib/playwright_api/response.rb +27 -10
- data/lib/playwright_api/route.rb +51 -6
- data/lib/playwright_api/selectors.rb +28 -2
- data/lib/playwright_api/touchscreen.rb +1 -1
- data/lib/playwright_api/web_socket.rb +15 -0
- data/lib/playwright_api/worker.rb +25 -1
- data/playwright.gemspec +4 -2
- metadata +42 -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 -27
- data/lib/playwright_api/chromium_browser_context.rb +0 -59
- data/lib/playwright_api/download.rb +0 -100
- data/lib/playwright_api/video.rb +0 -24
@@ -20,38 +20,35 @@ module Playwright
|
|
20
20
|
@electron ||= ::Playwright::ChannelOwners::Electron.from(@initializer['electron'])
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
def initialize(hash)
|
26
|
-
@width = hash['width']
|
27
|
-
@heirhgt = hash['height']
|
28
|
-
end
|
29
|
-
attr_reader :width, :height
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(hash)
|
33
|
-
@user_agent = hash["userAgent"]
|
34
|
-
@viewport = Viewport.new(hash["viewport"])
|
35
|
-
@device_scale_factor = hash["deviceScaleFactor"]
|
36
|
-
@is_mobile = hash["isMobile"]
|
37
|
-
@has_touch = hash["hasTouch"]
|
38
|
-
end
|
39
|
-
|
40
|
-
attr_reader :user_agent, :viewport, :device_scale_factor
|
41
|
-
|
42
|
-
def mobile?
|
43
|
-
@is_mobile
|
44
|
-
end
|
45
|
-
|
46
|
-
def has_touch?
|
47
|
-
@has_touch
|
48
|
-
end
|
23
|
+
def selectors
|
24
|
+
@selectors ||= ::Playwright::ChannelOwners::Selectors.from(@initializer['selectors'])
|
49
25
|
end
|
50
26
|
|
51
27
|
def devices
|
52
28
|
@devices ||= @initializer['deviceDescriptors'].map do |item|
|
53
|
-
[item['name'],
|
29
|
+
[item['name'], parse_device_descriptor(item['descriptor'])]
|
54
30
|
end.to_h
|
55
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
|
56
53
|
end
|
57
54
|
end
|
@@ -3,7 +3,7 @@ require 'base64'
|
|
3
3
|
module Playwright
|
4
4
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
|
5
5
|
define_channel_owner :Request do
|
6
|
-
def after_initialize
|
6
|
+
private def after_initialize
|
7
7
|
@redirected_from = ChannelOwners::Request.from_nullable(@initializer['redirectedFrom'])
|
8
8
|
@redirected_from&.send(:update_redirected_to, self)
|
9
9
|
@timing = {
|
@@ -29,7 +29,7 @@ module Playwright
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def method
|
32
|
-
@
|
32
|
+
@initializer['method']
|
33
33
|
end
|
34
34
|
|
35
35
|
def post_data
|
@@ -69,7 +69,7 @@ module Playwright
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def frame
|
72
|
-
@initializer['frame']
|
72
|
+
ChannelOwners::Frame.from(@initializer['frame'])
|
73
73
|
end
|
74
74
|
|
75
75
|
def navigation_request?
|
@@ -90,6 +90,30 @@ module Playwright
|
|
90
90
|
@failure_text = failure_text
|
91
91
|
end
|
92
92
|
|
93
|
+
private def update_timings(
|
94
|
+
start_time:,
|
95
|
+
domain_lookup_start:,
|
96
|
+
domain_lookup_end:,
|
97
|
+
connect_start:,
|
98
|
+
secure_connection_start:,
|
99
|
+
connect_end:,
|
100
|
+
request_start:,
|
101
|
+
response_start:)
|
102
|
+
|
103
|
+
@timing["startTime"] = start_time
|
104
|
+
@timing["domainLookupStart"] = domain_lookup_start
|
105
|
+
@timing["domainLookupEnd"] = domain_lookup_end
|
106
|
+
@timing["connectStart"] = connect_start
|
107
|
+
@timing["secureConnectionStart"] = secure_connection_start
|
108
|
+
@timing["connectEnd"] = connect_end
|
109
|
+
@timing["requestStart"] = request_start
|
110
|
+
@timing["responseStart"] = response_start
|
111
|
+
end
|
112
|
+
|
113
|
+
private def update_headers(headers)
|
114
|
+
@headers = parse_headers(headers)
|
115
|
+
end
|
116
|
+
|
93
117
|
private def update_response_end_timing(response_end_timing)
|
94
118
|
@timing[:responseEnd] = response_end_timing
|
95
119
|
end
|
@@ -1,5 +1,65 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
|
1
4
|
module Playwright
|
2
5
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
|
3
6
|
define_channel_owner :Response do
|
7
|
+
def after_initialize
|
8
|
+
@request = ChannelOwners::Request.from(@initializer['request'])
|
9
|
+
timing = @initializer['timing']
|
10
|
+
@request.send(:update_timings,
|
11
|
+
start_time: timing["startTime"],
|
12
|
+
domain_lookup_start: timing["domainLookupStart"],
|
13
|
+
domain_lookup_end: timing["domainLookupEnd"],
|
14
|
+
connect_start: timing["connectStart"],
|
15
|
+
secure_connection_start: timing["secureConnectionStart"],
|
16
|
+
connect_end: timing["connectEnd"],
|
17
|
+
request_start: timing["requestStart"],
|
18
|
+
response_start: timing["responseStart"],
|
19
|
+
)
|
20
|
+
@request.send(:update_headers, @initializer['requestHeaders'])
|
21
|
+
end
|
22
|
+
attr_reader :request
|
23
|
+
|
24
|
+
def url
|
25
|
+
@initializer['url']
|
26
|
+
end
|
27
|
+
|
28
|
+
def ok
|
29
|
+
status == 0 || (200...300).include?(status)
|
30
|
+
end
|
31
|
+
alias_method :ok?, :ok
|
32
|
+
|
33
|
+
def status
|
34
|
+
@initializer['status']
|
35
|
+
end
|
36
|
+
|
37
|
+
def status_text
|
38
|
+
@initializer['statusText']
|
39
|
+
end
|
40
|
+
|
41
|
+
def headers
|
42
|
+
@initializer['headers'].map do |header|
|
43
|
+
[header['name'].downcase, header['value']]
|
44
|
+
end.to_h
|
45
|
+
end
|
46
|
+
|
47
|
+
def finished
|
48
|
+
@channel.send_message_to_server('finished')
|
49
|
+
end
|
50
|
+
|
51
|
+
def body
|
52
|
+
binary = @channel.send_message_to_server("body")
|
53
|
+
Base64.strict_decode64(binary)
|
54
|
+
end
|
55
|
+
alias_method :text, :body
|
56
|
+
|
57
|
+
def json
|
58
|
+
JSON.parse(text)
|
59
|
+
end
|
60
|
+
|
61
|
+
def frame
|
62
|
+
@request.frame
|
63
|
+
end
|
4
64
|
end
|
5
65
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
module Playwright
|
5
|
+
define_channel_owner :Route do
|
6
|
+
def request
|
7
|
+
ChannelOwners::Request.from(@initializer['request'])
|
8
|
+
end
|
9
|
+
|
10
|
+
def abort(errorCode: nil)
|
11
|
+
params = { errorCode: errorCode }.compact
|
12
|
+
@channel.async_send_message_to_server('abort', params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def fulfill(
|
16
|
+
body: nil,
|
17
|
+
contentType: nil,
|
18
|
+
headers: nil,
|
19
|
+
path: nil,
|
20
|
+
status: nil)
|
21
|
+
params = {
|
22
|
+
contentType: contentType,
|
23
|
+
status: status,
|
24
|
+
}.compact
|
25
|
+
|
26
|
+
length = 0
|
27
|
+
content =
|
28
|
+
if body
|
29
|
+
body
|
30
|
+
elsif path
|
31
|
+
File.read(path)
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
param_headers = headers || {}
|
37
|
+
if contentType
|
38
|
+
param_headers['content-type'] = contentType
|
39
|
+
elsif path
|
40
|
+
param_headers['content-type'] = mime_type_for(path)
|
41
|
+
end
|
42
|
+
|
43
|
+
if content
|
44
|
+
if content.is_a?(String)
|
45
|
+
params[:body] = content
|
46
|
+
params[:isBase64] = false
|
47
|
+
else
|
48
|
+
params[:body] = Base64.strict_encode64(content)
|
49
|
+
params[:isBase64] = true
|
50
|
+
end
|
51
|
+
param_headers['content-length'] ||= content.length.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
params[:headers] = HttpHeaders.new(param_headers).as_serialized
|
55
|
+
|
56
|
+
@channel.async_send_message_to_server('fulfill', params)
|
57
|
+
end
|
58
|
+
|
59
|
+
def continue(headers: nil, method: nil, postData: nil, url: nil)
|
60
|
+
overrides = { url: url, method: method }.compact
|
61
|
+
|
62
|
+
if headers
|
63
|
+
overrides[:headers] = HttpHeaders.new(headers).as_serialized
|
64
|
+
end
|
65
|
+
|
66
|
+
if postData
|
67
|
+
overrides[:postData] = Base64.strict_encode64(postData)
|
68
|
+
end
|
69
|
+
|
70
|
+
@channel.async_send_message_to_server('continue', overrides)
|
71
|
+
end
|
72
|
+
|
73
|
+
private def mime_type_for(filepath)
|
74
|
+
mime_types = MIME::Types.type_for(filepath)
|
75
|
+
mime_types.first.to_s || 'application/octet-stream'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,4 +1,22 @@
|
|
1
1
|
module Playwright
|
2
2
|
# https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_selectors.py
|
3
|
-
define_channel_owner :Selectors
|
3
|
+
define_channel_owner :Selectors do
|
4
|
+
def register(name, contentScript: nil, path: nil, script: nil)
|
5
|
+
source =
|
6
|
+
if path
|
7
|
+
File.read(path)
|
8
|
+
elsif script
|
9
|
+
script
|
10
|
+
else
|
11
|
+
raise ArgumentError.new('Either path or script parameter must be specified')
|
12
|
+
end
|
13
|
+
params = { name: name, source: source }
|
14
|
+
if contentScript
|
15
|
+
params[:contentScript] = true
|
16
|
+
end
|
17
|
+
@channel.send_message_to_server('register', params)
|
18
|
+
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
4
22
|
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',
|