playwright-ruby-client 0.0.3 → 0.0.8
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 +119 -12
- data/docs/api_coverage.md +354 -0
- data/lib/playwright.rb +8 -0
- data/lib/playwright/channel_owner.rb +16 -2
- data/lib/playwright/channel_owners/android.rb +10 -1
- data/lib/playwright/channel_owners/android_device.rb +163 -0
- data/lib/playwright/channel_owners/browser.rb +22 -29
- data/lib/playwright/channel_owners/browser_context.rb +43 -0
- data/lib/playwright/channel_owners/console_message.rb +21 -0
- data/lib/playwright/channel_owners/element_handle.rb +314 -0
- data/lib/playwright/channel_owners/frame.rb +466 -7
- data/lib/playwright/channel_owners/js_handle.rb +55 -0
- data/lib/playwright/channel_owners/page.rb +353 -5
- data/lib/playwright/channel_owners/request.rb +90 -0
- data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
- data/lib/playwright/connection.rb +15 -14
- data/lib/playwright/errors.rb +1 -1
- data/lib/playwright/event_emitter.rb +13 -0
- data/lib/playwright/input_files.rb +42 -0
- data/lib/playwright/input_type.rb +19 -0
- data/lib/playwright/input_types/android_input.rb +19 -0
- data/lib/playwright/input_types/keyboard.rb +32 -0
- data/lib/playwright/input_types/mouse.rb +4 -0
- data/lib/playwright/input_types/touchscreen.rb +4 -0
- data/lib/playwright/javascript.rb +13 -0
- data/lib/playwright/javascript/expression.rb +67 -0
- data/lib/playwright/javascript/function.rb +67 -0
- data/lib/playwright/javascript/value_parser.rb +75 -0
- data/lib/playwright/javascript/value_serializer.rb +54 -0
- data/lib/playwright/playwright_api.rb +45 -25
- data/lib/playwright/select_option_values.rb +32 -0
- data/lib/playwright/timeout_settings.rb +19 -0
- data/lib/playwright/url_matcher.rb +19 -0
- data/lib/playwright/utils.rb +37 -0
- data/lib/playwright/version.rb +1 -1
- data/lib/playwright/wait_helper.rb +73 -0
- data/lib/playwright_api/accessibility.rb +60 -6
- data/lib/playwright_api/android.rb +33 -0
- data/lib/playwright_api/android_device.rb +78 -0
- data/lib/playwright_api/android_input.rb +25 -0
- data/lib/playwright_api/binding_call.rb +18 -0
- data/lib/playwright_api/browser.rb +136 -44
- data/lib/playwright_api/browser_context.rb +378 -51
- data/lib/playwright_api/browser_type.rb +137 -55
- data/lib/playwright_api/cdp_session.rb +32 -7
- data/lib/playwright_api/chromium_browser_context.rb +31 -0
- data/lib/playwright_api/console_message.rb +27 -7
- data/lib/playwright_api/dialog.rb +47 -3
- data/lib/playwright_api/download.rb +29 -5
- data/lib/playwright_api/element_handle.rb +429 -143
- data/lib/playwright_api/file_chooser.rb +13 -2
- data/lib/playwright_api/frame.rb +633 -179
- data/lib/playwright_api/js_handle.rb +97 -17
- data/lib/playwright_api/keyboard.rb +152 -24
- data/lib/playwright_api/mouse.rb +28 -3
- data/lib/playwright_api/page.rb +1183 -317
- data/lib/playwright_api/playwright.rb +174 -13
- data/lib/playwright_api/request.rb +115 -30
- data/lib/playwright_api/response.rb +22 -3
- data/lib/playwright_api/route.rb +63 -4
- data/lib/playwright_api/selectors.rb +29 -7
- data/lib/playwright_api/touchscreen.rb +2 -1
- data/lib/playwright_api/video.rb +11 -1
- data/lib/playwright_api/web_socket.rb +5 -5
- data/lib/playwright_api/worker.rb +29 -5
- data/playwright.gemspec +3 -0
- metadata +68 -2
@@ -55,10 +55,13 @@ module Playwright
|
|
55
55
|
method: method,
|
56
56
|
params: replace_channels_with_guids(params),
|
57
57
|
}
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
begin
|
59
|
+
@transport.send_message(message)
|
60
|
+
rescue => err
|
61
|
+
@callbacks.delete(id)
|
62
|
+
callback.reject(err)
|
63
|
+
raise unless err.is_a?(Transport::AlreadyDisconnectedError)
|
64
|
+
end
|
62
65
|
end
|
63
66
|
|
64
67
|
callback
|
@@ -132,7 +135,7 @@ module Playwright
|
|
132
135
|
unless object
|
133
136
|
raise "Cannot find object to dispose: #{guid}"
|
134
137
|
end
|
135
|
-
object.dispose
|
138
|
+
object.send(:dispose!)
|
136
139
|
return
|
137
140
|
end
|
138
141
|
|
@@ -153,7 +156,7 @@ module Playwright
|
|
153
156
|
end
|
154
157
|
|
155
158
|
if payload.is_a?(Channel)
|
156
|
-
{ guid: payload.guid }
|
159
|
+
return { guid: payload.guid }
|
157
160
|
end
|
158
161
|
|
159
162
|
if payload.is_a?(Hash)
|
@@ -192,12 +195,6 @@ module Playwright
|
|
192
195
|
end
|
193
196
|
initializer = replace_guids_with_channels(initializer)
|
194
197
|
|
195
|
-
params = [
|
196
|
-
parent,
|
197
|
-
type,
|
198
|
-
guid,
|
199
|
-
initializer,
|
200
|
-
]
|
201
198
|
class_name = case type
|
202
199
|
when 'Browser'
|
203
200
|
case initializer['name']
|
@@ -215,7 +212,6 @@ module Playwright
|
|
215
212
|
if browser_name == 'chromium'
|
216
213
|
'ChromiumBrowserContext'
|
217
214
|
else
|
218
|
-
params << browser_name
|
219
215
|
'BrowserContext'
|
220
216
|
end
|
221
217
|
else
|
@@ -224,7 +220,12 @@ module Playwright
|
|
224
220
|
|
225
221
|
result =
|
226
222
|
begin
|
227
|
-
ChannelOwners.const_get(class_name).new(
|
223
|
+
ChannelOwners.const_get(class_name).new(
|
224
|
+
parent,
|
225
|
+
type,
|
226
|
+
guid,
|
227
|
+
initializer,
|
228
|
+
)
|
228
229
|
rescue NameError
|
229
230
|
raise "Missing type #{type}"
|
230
231
|
end
|
data/lib/playwright/errors.rb
CHANGED
@@ -3,7 +3,7 @@ module Playwright
|
|
3
3
|
# ref: https://github.com/microsoft/playwright-python/blob/0b4a980fed366c4c1dee9bfcdd72662d629fdc8d/playwright/_impl/_helper.py#L155
|
4
4
|
def self.parse(error_payload)
|
5
5
|
if error_payload['name'] == 'TimeoutError'
|
6
|
-
|
6
|
+
TimeoutError.new(
|
7
7
|
message: error_payload['message'],
|
8
8
|
stack: error_payload['stack'].split("\n"),
|
9
9
|
)
|
@@ -17,6 +17,19 @@ module Playwright
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
module EventListenerInterface
|
21
|
+
def on(event, callback)
|
22
|
+
raise NotImplementedError.new('NOT IMPLEMENTED')
|
23
|
+
end
|
24
|
+
|
25
|
+
def off(event, callback)
|
26
|
+
raise NotImplementedError.new('NOT IMPLEMENTED')
|
27
|
+
end
|
28
|
+
|
29
|
+
def once(event, callback)
|
30
|
+
raise NotImplementedError.new('NOT IMPLEMENTED')
|
31
|
+
end
|
32
|
+
end
|
20
33
|
|
21
34
|
# A subset of Events/EventEmitter in Node.js
|
22
35
|
module EventEmitter
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
module Playwright
|
5
|
+
class InputFiles
|
6
|
+
def initialize(files)
|
7
|
+
@params = convert(files)
|
8
|
+
end
|
9
|
+
|
10
|
+
def as_params
|
11
|
+
@params
|
12
|
+
end
|
13
|
+
|
14
|
+
private def convert(files)
|
15
|
+
return convert([files]) unless files.is_a?(Array)
|
16
|
+
|
17
|
+
files.map do |file|
|
18
|
+
case file
|
19
|
+
when String
|
20
|
+
{
|
21
|
+
name: File.basename(file),
|
22
|
+
mimeType: mime_type_for(file),
|
23
|
+
buffer: Base64.strict_encode64(File.read(file)),
|
24
|
+
}
|
25
|
+
when File
|
26
|
+
{
|
27
|
+
name: File.basename(file.path),
|
28
|
+
mimeType: mime_type_for(file.path),
|
29
|
+
buffer: Base64.strict_encode64(file.read),
|
30
|
+
}
|
31
|
+
else
|
32
|
+
raise ArgumentError.new('file must be a String or File.')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private def mime_type_for(filepath)
|
38
|
+
mime_types = MIME::Types.type_for(filepath)
|
39
|
+
mime_types.first || 'application/octet-stream'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Playwright
|
2
|
+
class InputType
|
3
|
+
def initialize(channel)
|
4
|
+
@channel = channel
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# namespace declaration
|
9
|
+
module InputTypes ; end
|
10
|
+
|
11
|
+
def self.define_input_type(class_name, &block)
|
12
|
+
klass = Class.new(InputType)
|
13
|
+
klass.class_eval(&block) if block
|
14
|
+
InputTypes.const_set(class_name, klass)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# load subclasses
|
19
|
+
Dir[File.join(__dir__, 'input_types', '*.rb')].each { |f| require f }
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_input_type :AndroidInput do
|
3
|
+
def type(text)
|
4
|
+
@channel.send_message_to_server('inputType', text: text)
|
5
|
+
end
|
6
|
+
|
7
|
+
def press(key)
|
8
|
+
@channel.send_message_to_server('inputPress', key: key)
|
9
|
+
end
|
10
|
+
|
11
|
+
def tap_point(point)
|
12
|
+
@channel.send_message_to_server('inputTap', point: point)
|
13
|
+
end
|
14
|
+
|
15
|
+
def drag(from, to, steps)
|
16
|
+
@channel.send_message_to_server('inputDrag', from: from, to: to, steps: steps)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_input_type :Keyboard do
|
3
|
+
def down(key)
|
4
|
+
@channel.send_message_to_server('keyboardDown', key: key)
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def up(key)
|
9
|
+
@channel.send_message_to_server('keyboardDown', key: key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def insert_text(text)
|
13
|
+
@channel.send_message_to_server('keyboardInsertText', text: text)
|
14
|
+
end
|
15
|
+
|
16
|
+
def type(text, delay: nil)
|
17
|
+
params = {
|
18
|
+
text: text,
|
19
|
+
delay: delay,
|
20
|
+
}.compact
|
21
|
+
@channel.send_message_to_server('keyboardType', params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def press(key, delay: nil)
|
25
|
+
params = {
|
26
|
+
key: key,
|
27
|
+
delay: delay,
|
28
|
+
}.compact
|
29
|
+
@channel.send_message_to_server('keyboardPress', params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative './javascript/expression'
|
2
|
+
require_relative './javascript/function'
|
3
|
+
require_relative './javascript/value_parser'
|
4
|
+
require_relative './javascript/value_serializer'
|
5
|
+
|
6
|
+
module Playwright
|
7
|
+
module JavaScript
|
8
|
+
# Detect if str is likely to be a function
|
9
|
+
module_function def function?(str)
|
10
|
+
['async', 'function'].any? { |key| str.strip.start_with?(key) } || str.include?('=>')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Playwright
|
2
|
+
module JavaScript
|
3
|
+
class Expression
|
4
|
+
def initialize(expression)
|
5
|
+
@expression = expression
|
6
|
+
@serialized_arg = ValueSerializer.new(nil).serialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(channel)
|
10
|
+
value = channel.send_message_to_server(
|
11
|
+
'evaluateExpression',
|
12
|
+
expression: @expression,
|
13
|
+
isFunction: false,
|
14
|
+
arg: @serialized_arg,
|
15
|
+
)
|
16
|
+
ValueParser.new(value).parse
|
17
|
+
end
|
18
|
+
|
19
|
+
def evaluate_handle(channel)
|
20
|
+
resp = channel.send_message_to_server(
|
21
|
+
'evaluateExpressionHandle',
|
22
|
+
expression: @expression,
|
23
|
+
isFunction: false,
|
24
|
+
arg: @serialized_arg,
|
25
|
+
)
|
26
|
+
::Playwright::ChannelOwner.from(resp)
|
27
|
+
end
|
28
|
+
|
29
|
+
def eval_on_selector(channel, selector)
|
30
|
+
value = channel.send_message_to_server(
|
31
|
+
'evalOnSelector',
|
32
|
+
selector: selector,
|
33
|
+
expression: @expression,
|
34
|
+
isFunction: false,
|
35
|
+
arg: @serialized_arg,
|
36
|
+
)
|
37
|
+
ValueParser.new(value).parse
|
38
|
+
end
|
39
|
+
|
40
|
+
def eval_on_selector_all(channel, selector)
|
41
|
+
value = channel.send_message_to_server(
|
42
|
+
'evalOnSelectorAll',
|
43
|
+
selector: selector,
|
44
|
+
expression: @expression,
|
45
|
+
isFunction: false,
|
46
|
+
arg: @serialized_arg,
|
47
|
+
)
|
48
|
+
ValueParser.new(value).parse
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_for_function(channel, polling:, timeout:)
|
52
|
+
params = {
|
53
|
+
expression: @expression,
|
54
|
+
isFunction: false,
|
55
|
+
arg: @serialized_arg,
|
56
|
+
polling: polling,
|
57
|
+
timeout: timeout,
|
58
|
+
}.compact
|
59
|
+
if polling.is_a?(Numeric)
|
60
|
+
params[:pollingInterval] = polling
|
61
|
+
end
|
62
|
+
resp = channel.send_message_to_server('waitForFunction', params)
|
63
|
+
ChannelOwners::JSHandle.from(resp)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Playwright
|
2
|
+
module JavaScript
|
3
|
+
class Function
|
4
|
+
def initialize(definition, arg)
|
5
|
+
@definition = definition
|
6
|
+
@serialized_arg = ValueSerializer.new(arg).serialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(channel)
|
10
|
+
value = channel.send_message_to_server(
|
11
|
+
'evaluateExpression',
|
12
|
+
expression: @definition,
|
13
|
+
isFunction: true,
|
14
|
+
arg: @serialized_arg,
|
15
|
+
)
|
16
|
+
ValueParser.new(value).parse
|
17
|
+
end
|
18
|
+
|
19
|
+
def evaluate_handle(channel)
|
20
|
+
resp = channel.send_message_to_server(
|
21
|
+
'evaluateExpressionHandle',
|
22
|
+
expression: @definition,
|
23
|
+
isFunction: true,
|
24
|
+
arg: @serialized_arg,
|
25
|
+
)
|
26
|
+
::Playwright::ChannelOwner.from(resp)
|
27
|
+
end
|
28
|
+
|
29
|
+
def eval_on_selector(channel, selector)
|
30
|
+
value = channel.send_message_to_server(
|
31
|
+
'evalOnSelector',
|
32
|
+
selector: selector,
|
33
|
+
expression: @definition,
|
34
|
+
isFunction: true,
|
35
|
+
arg: @serialized_arg,
|
36
|
+
)
|
37
|
+
ValueParser.new(value).parse
|
38
|
+
end
|
39
|
+
|
40
|
+
def eval_on_selector_all(channel, selector)
|
41
|
+
value = channel.send_message_to_server(
|
42
|
+
'evalOnSelectorAll',
|
43
|
+
selector: selector,
|
44
|
+
expression: @definition,
|
45
|
+
isFunction: true,
|
46
|
+
arg: @serialized_arg,
|
47
|
+
)
|
48
|
+
ValueParser.new(value).parse
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_for_function(channel, polling:, timeout:)
|
52
|
+
params = {
|
53
|
+
expression: @definition,
|
54
|
+
isFunction: true,
|
55
|
+
arg: @serialized_arg,
|
56
|
+
polling: polling,
|
57
|
+
timeout: timeout,
|
58
|
+
}.compact
|
59
|
+
if polling.is_a?(Numeric)
|
60
|
+
params[:pollingInterval] = polling
|
61
|
+
end
|
62
|
+
resp = channel.send_message_to_server('waitForFunction', params)
|
63
|
+
ChannelOwners::JSHandle.from(resp)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Playwright
|
4
|
+
module JavaScript
|
5
|
+
class ValueParser
|
6
|
+
def initialize(hash)
|
7
|
+
@hash = hash
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [Hash]
|
11
|
+
def parse
|
12
|
+
if @hash.nil?
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
parse_hash(@hash)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# ref: https://github.com/microsoft/playwright/blob/b45905ae3f1a066a8ecb358035ce745ddd21cf3a/src/protocol/serializers.ts#L42
|
20
|
+
# ref: https://github.com/microsoft/playwright-python/blob/25a99d53e00e35365cf5113b9525272628c0e65f/playwright/_impl/_js_handle.py#L140
|
21
|
+
private def parse_hash(hash)
|
22
|
+
%w(n s b).each do |key|
|
23
|
+
return hash[key] if hash.key?(key)
|
24
|
+
end
|
25
|
+
|
26
|
+
if hash.key?('v')
|
27
|
+
return
|
28
|
+
case hash['v']
|
29
|
+
when 'undefined'
|
30
|
+
nil
|
31
|
+
when 'null'
|
32
|
+
nil
|
33
|
+
when 'NaN'
|
34
|
+
Float::NAN
|
35
|
+
when 'Infinity'
|
36
|
+
Float::INFINITY
|
37
|
+
when '-Infinity'
|
38
|
+
-Float::INFINITY
|
39
|
+
when '-0'
|
40
|
+
-0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if hash.key?('d')
|
45
|
+
return DateTime.parse(hash['d'])
|
46
|
+
end
|
47
|
+
|
48
|
+
if hash.key?('r')
|
49
|
+
# @see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp
|
50
|
+
# @see https://docs.ruby-lang.org/ja/latest/class/Regexp.html
|
51
|
+
js_regex_flag = hash['r']['f']
|
52
|
+
flags = []
|
53
|
+
flags << Regexp::IGNORECASE if js_regex_flag.include?('i')
|
54
|
+
flags << Regexp::MULTILINE if js_regex_flag.include?('m') || js_regex_flag.include?('s')
|
55
|
+
|
56
|
+
return Regexp.compile(hash['r']['p'], flags.inject(:|))
|
57
|
+
end
|
58
|
+
|
59
|
+
if hash.key?('a')
|
60
|
+
return hash['a'].map { |value| parse_hash(value) }
|
61
|
+
end
|
62
|
+
|
63
|
+
if hash.key?('o')
|
64
|
+
return hash['o'].map { |obj| [obj['k'], parse_hash(obj['v'])] }.to_h
|
65
|
+
end
|
66
|
+
|
67
|
+
if hash.key?('h')
|
68
|
+
return @handles[hash['h']]
|
69
|
+
end
|
70
|
+
|
71
|
+
raise ArgumentError.new("Unexpected value: #{hash}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|