playwright-ruby-client 1.20.2 → 1.23.0
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/documentation/docs/api/api_request_context.md +15 -2
- data/documentation/docs/api/browser.md +16 -0
- data/documentation/docs/api/browser_context.md +15 -2
- data/documentation/docs/api/browser_type.md +5 -1
- data/documentation/docs/api/console_message.md +27 -1
- data/documentation/docs/api/element_handle.md +23 -13
- data/documentation/docs/api/experimental/android.md +1 -1
- data/documentation/docs/api/experimental/android_device.md +4 -0
- data/documentation/docs/api/file_chooser.md +1 -1
- data/documentation/docs/api/frame.md +12 -5
- data/documentation/docs/api/frame_locator.md +1 -1
- data/documentation/docs/api/locator.md +44 -13
- data/documentation/docs/api/page.md +32 -9
- data/documentation/docs/api/request.md +3 -1
- data/documentation/docs/api/response.md +12 -1
- data/documentation/docs/api/route.md +67 -0
- data/documentation/docs/include/api_coverage.md +6 -3
- data/documentation/package.json +6 -6
- data/documentation/yarn.lock +2931 -3220
- data/lib/playwright/channel.rb +1 -3
- data/lib/playwright/channel_owners/browser.rb +13 -0
- data/lib/playwright/channel_owners/browser_context.rb +89 -13
- data/lib/playwright/channel_owners/browser_type.rb +4 -0
- data/lib/playwright/channel_owners/element_handle.rb +12 -3
- data/lib/playwright/channel_owners/frame.rb +20 -7
- data/lib/playwright/channel_owners/local_utils.rb +29 -0
- data/lib/playwright/channel_owners/page.rb +54 -22
- data/lib/playwright/channel_owners/request.rb +31 -6
- data/lib/playwright/channel_owners/response.rb +6 -0
- data/lib/playwright/channel_owners/route.rb +104 -45
- data/lib/playwright/channel_owners/writable_stream.rb +14 -0
- data/lib/playwright/connection.rb +6 -1
- data/lib/playwright/har_router.rb +82 -0
- data/lib/playwright/http_headers.rb +1 -1
- data/lib/playwright/input_files.rb +60 -8
- data/lib/playwright/javascript/regex.rb +23 -0
- data/lib/playwright/javascript/value_parser.rb +17 -2
- data/lib/playwright/javascript/value_serializer.rb +16 -6
- data/lib/playwright/javascript/visitor_info.rb +26 -0
- data/lib/playwright/javascript.rb +1 -0
- data/lib/playwright/locator_impl.rb +18 -5
- data/lib/playwright/playwright_api.rb +26 -6
- data/lib/playwright/route_handler.rb +2 -6
- data/lib/playwright/transport.rb +12 -2
- data/lib/playwright/utils.rb +31 -6
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright.rb +2 -0
- data/lib/playwright_api/accessibility.rb +2 -1
- data/lib/playwright_api/android.rb +2 -2
- data/lib/playwright_api/android_device.rb +5 -1
- data/lib/playwright_api/api_request.rb +3 -3
- data/lib/playwright_api/api_request_context.rb +15 -2
- data/lib/playwright_api/browser.rb +15 -2
- data/lib/playwright_api/browser_context.rb +17 -7
- data/lib/playwright_api/browser_type.rb +7 -3
- data/lib/playwright_api/console_message.rb +20 -1
- data/lib/playwright_api/element_handle.rb +53 -49
- data/lib/playwright_api/file_chooser.rb +1 -1
- data/lib/playwright_api/frame.rb +30 -23
- data/lib/playwright_api/frame_locator.rb +1 -1
- data/lib/playwright_api/locator.rb +58 -38
- data/lib/playwright_api/page.rb +52 -32
- data/lib/playwright_api/playwright.rb +1 -1
- data/lib/playwright_api/request.rb +8 -1
- data/lib/playwright_api/response.rb +14 -1
- data/lib/playwright_api/route.rb +63 -2
- data/lib/playwright_api/selectors.rb +1 -1
- data/lib/playwright_api/tracing.rb +1 -1
- metadata +7 -4
- data/lib/playwright_api/local_utils.rb +0 -9
@@ -3,13 +3,28 @@ require 'mime/types'
|
|
3
3
|
|
4
4
|
module Playwright
|
5
5
|
define_channel_owner :Route do
|
6
|
+
private def set_handling_future(future)
|
7
|
+
@handling_future = future
|
8
|
+
end
|
9
|
+
|
10
|
+
private def handling_with_result(done, &block)
|
11
|
+
chain = @handling_future
|
12
|
+
raise 'Route is already handled!' unless chain
|
13
|
+
block.call
|
14
|
+
@handling_future = nil
|
15
|
+
chain.fulfill(done)
|
16
|
+
end
|
17
|
+
|
6
18
|
def request
|
7
19
|
ChannelOwners::Request.from(@initializer['request'])
|
8
20
|
end
|
9
21
|
|
10
22
|
def abort(errorCode: nil)
|
11
|
-
|
12
|
-
|
23
|
+
handling_with_result(true) do
|
24
|
+
params = { errorCode: errorCode }.compact
|
25
|
+
# TODO _race_with_page_close
|
26
|
+
@channel.async_send_message_to_server('abort', params)
|
27
|
+
end
|
13
28
|
end
|
14
29
|
|
15
30
|
def fulfill(
|
@@ -19,69 +34,113 @@ module Playwright
|
|
19
34
|
path: nil,
|
20
35
|
status: nil,
|
21
36
|
response: nil)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
37
|
+
handling_with_result(true) do
|
38
|
+
params = {
|
39
|
+
contentType: contentType,
|
40
|
+
status: status,
|
41
|
+
}.compact
|
42
|
+
option_body = body
|
27
43
|
|
28
|
-
|
29
|
-
|
30
|
-
|
44
|
+
if response
|
45
|
+
params[:status] ||= response.status
|
46
|
+
params[:headers] ||= response.headers
|
31
47
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
48
|
+
if !body && !path && response.is_a?(APIResponse)
|
49
|
+
if response.send(:_request).send(:same_connection?, self)
|
50
|
+
params[:fetchResponseUid] = response.send(:fetch_uid)
|
51
|
+
else
|
52
|
+
option_body = response.body
|
53
|
+
end
|
37
54
|
end
|
38
55
|
end
|
39
|
-
end
|
40
56
|
|
41
|
-
|
42
|
-
|
43
|
-
|
57
|
+
content =
|
58
|
+
if option_body
|
59
|
+
option_body
|
60
|
+
elsif path
|
61
|
+
File.read(path)
|
62
|
+
else
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
param_headers = headers || {}
|
67
|
+
if contentType
|
68
|
+
param_headers['content-type'] = contentType
|
44
69
|
elsif path
|
45
|
-
|
46
|
-
else
|
47
|
-
nil
|
70
|
+
param_headers['content-type'] = mime_type_for(path)
|
48
71
|
end
|
49
72
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
params[:body] = content
|
60
|
-
params[:isBase64] = false
|
61
|
-
else
|
62
|
-
params[:body] = Base64.strict_encode64(content)
|
63
|
-
params[:isBase64] = true
|
73
|
+
if content
|
74
|
+
if content.is_a?(String)
|
75
|
+
params[:body] = content
|
76
|
+
params[:isBase64] = false
|
77
|
+
else
|
78
|
+
params[:body] = Base64.strict_encode64(content)
|
79
|
+
params[:isBase64] = true
|
80
|
+
end
|
81
|
+
param_headers['content-length'] ||= content.length.to_s
|
64
82
|
end
|
65
|
-
|
83
|
+
|
84
|
+
params[:headers] = HttpHeaders.new(param_headers).as_serialized
|
85
|
+
|
86
|
+
@channel.async_send_message_to_server('fulfill', params)
|
66
87
|
end
|
88
|
+
end
|
67
89
|
|
68
|
-
|
90
|
+
def fallback(headers: nil, method: nil, postData: nil, url: nil)
|
91
|
+
overrides = {
|
92
|
+
headers: headers,
|
93
|
+
method: method,
|
94
|
+
postData: postData,
|
95
|
+
url: url,
|
96
|
+
}.compact
|
69
97
|
|
70
|
-
|
98
|
+
handling_with_result(false) do
|
99
|
+
request.apply_fallback_overrides(overrides)
|
100
|
+
end
|
71
101
|
end
|
72
102
|
|
73
103
|
def continue(headers: nil, method: nil, postData: nil, url: nil)
|
74
|
-
overrides = {
|
104
|
+
overrides = {
|
105
|
+
headers: headers,
|
106
|
+
method: method,
|
107
|
+
postData: postData,
|
108
|
+
url: url,
|
109
|
+
}.compact
|
75
110
|
|
76
|
-
|
77
|
-
|
111
|
+
handling_with_result(true) do
|
112
|
+
request.apply_fallback_overrides(overrides)
|
113
|
+
async_continue_route
|
78
114
|
end
|
115
|
+
end
|
79
116
|
|
80
|
-
|
81
|
-
|
117
|
+
private def async_continue_route
|
118
|
+
post_data_for_wire =
|
119
|
+
if (post_data_from_overrides = request.send(:fallback_overrides)[:postData])
|
120
|
+
post_data_for_wire = Base64.strict_encode64(post_data_from_overrides)
|
121
|
+
else
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
params = request.send(:fallback_overrides).dup
|
126
|
+
|
127
|
+
if params[:headers]
|
128
|
+
params[:headers] = HttpHeaders.new(params[:headers]).as_serialized
|
129
|
+
end
|
130
|
+
|
131
|
+
if post_data_for_wire
|
132
|
+
params[:postData] = post_data_for_wire
|
82
133
|
end
|
83
134
|
|
84
|
-
|
135
|
+
# TODO _race_with_page_close
|
136
|
+
@channel.async_send_message_to_server('continue', params)
|
137
|
+
end
|
138
|
+
|
139
|
+
def redirect_navigation_request(url)
|
140
|
+
handling_with_result(true) do
|
141
|
+
# TODO _race_with_page_close
|
142
|
+
@channel.send_message_to_server('redirectNavigationRequest', { url: url })
|
143
|
+
end
|
85
144
|
end
|
86
145
|
|
87
146
|
private def mime_type_for(filepath)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Playwright
|
4
|
+
define_channel_owner :WritableStream do
|
5
|
+
# @param readable [File|IO]
|
6
|
+
def write(readable, bufsize = 1048576)
|
7
|
+
while buf = readable.read(bufsize)
|
8
|
+
binary = Base64.strict_encode64(buf)
|
9
|
+
@channel.send_message_to_server('write', binary: binary)
|
10
|
+
end
|
11
|
+
@channel.send_message_to_server('close')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -24,6 +24,8 @@ module Playwright
|
|
24
24
|
@remote = false
|
25
25
|
end
|
26
26
|
|
27
|
+
attr_reader :local_utils
|
28
|
+
|
27
29
|
def mark_as_remote
|
28
30
|
@remote = true
|
29
31
|
end
|
@@ -127,12 +129,15 @@ module Playwright
|
|
127
129
|
params = msg['params']
|
128
130
|
|
129
131
|
if method == "__create__"
|
130
|
-
create_remote_object(
|
132
|
+
remote_object = create_remote_object(
|
131
133
|
parent_guid: guid,
|
132
134
|
type: params["type"],
|
133
135
|
guid: params["guid"],
|
134
136
|
initializer: params["initializer"],
|
135
137
|
)
|
138
|
+
if remote_object.is_a?(ChannelOwners::LocalUtils)
|
139
|
+
@local_utils = remote_object
|
140
|
+
end
|
136
141
|
return
|
137
142
|
end
|
138
143
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Playwright
|
2
|
+
class HarRouter
|
3
|
+
# @param local_utils [LocalUtils]
|
4
|
+
# @param file [String]
|
5
|
+
# @param not_found_action [String] 'abort' or 'fallback'
|
6
|
+
# @param url_match [String||Regexp|nil]
|
7
|
+
def self.create(local_utils, file, not_found_action, url_match: nil)
|
8
|
+
har_id = local_utils.har_open(file)
|
9
|
+
|
10
|
+
new(
|
11
|
+
local_utils: local_utils,
|
12
|
+
har_id: har_id,
|
13
|
+
not_found_action: not_found_action,
|
14
|
+
url_match: url_match,
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param local_utils [LocalUtils]
|
19
|
+
# @param har_id [String]
|
20
|
+
# @param not_found_action [String] 'abort' or 'fallback'
|
21
|
+
# @param url_match [String||Regexp|nil]
|
22
|
+
def initialize(local_utils:, har_id:, not_found_action:, url_match: nil)
|
23
|
+
unless ['abort', 'fallback'].include?(not_found_action)
|
24
|
+
raise ArgumentError.new("not_found_action must be either 'abort' or 'fallback'. '#{not_found_action}' is specified.")
|
25
|
+
end
|
26
|
+
|
27
|
+
@local_utils = local_utils
|
28
|
+
@har_id = har_id
|
29
|
+
@not_found_action = not_found_action
|
30
|
+
@url_match = url_match || '**/*'
|
31
|
+
@debug = ENV['DEBUG'].to_s == 'true' || ENV['DEBUG'].to_s == '1'
|
32
|
+
end
|
33
|
+
|
34
|
+
private def handle(route, request)
|
35
|
+
response = @local_utils.har_lookup(
|
36
|
+
har_id: @har_id,
|
37
|
+
url: request.url,
|
38
|
+
method: request.method,
|
39
|
+
headers: request.headers_array,
|
40
|
+
post_data: request.post_data_buffer,
|
41
|
+
is_navigation_request: request.navigation_request?,
|
42
|
+
)
|
43
|
+
case response['action']
|
44
|
+
when 'redirect'
|
45
|
+
redirect_url = response['redirectURL']
|
46
|
+
puts "pw:api HAR: #{request.url} redirected to #{redirect_url}" if @debug
|
47
|
+
route.redirect_navigation_request(redirect_url)
|
48
|
+
when 'fulfill'
|
49
|
+
route.fulfill(
|
50
|
+
status: response['status'],
|
51
|
+
headers: response['headers'].map { |header| [header['name'], header['value']] }.to_h,
|
52
|
+
body: Base64.strict_decode64(response['body']),
|
53
|
+
)
|
54
|
+
else
|
55
|
+
# Report the error, but fall through to the default handler.
|
56
|
+
if response['action'] == 'error'
|
57
|
+
puts "pw:api HAR: #{response['message']} redirected to #{redirect_url}" if @debug
|
58
|
+
end
|
59
|
+
|
60
|
+
if @not_found_action == 'abort'
|
61
|
+
route.abort
|
62
|
+
else
|
63
|
+
route.fallback
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_context_route(context)
|
69
|
+
context.route(@url_match, method(:handle))
|
70
|
+
context.once(Events::BrowserContext::Close, method(:dispose))
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_page_route(page)
|
74
|
+
page.route(@url_match, method(:handle))
|
75
|
+
page.once(Events::Page::Close, method(:dispose))
|
76
|
+
end
|
77
|
+
|
78
|
+
def dispose
|
79
|
+
@local_utils.async_har_close(@har_id)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -2,18 +2,64 @@ require 'base64'
|
|
2
2
|
|
3
3
|
module Playwright
|
4
4
|
class InputFiles
|
5
|
-
def initialize(files)
|
6
|
-
@
|
5
|
+
def initialize(context, files)
|
6
|
+
@context = context
|
7
|
+
if files.is_a?(Enumerable)
|
8
|
+
@files = files
|
9
|
+
else
|
10
|
+
@files = [files]
|
11
|
+
end
|
7
12
|
end
|
8
13
|
|
9
|
-
def
|
10
|
-
|
14
|
+
def as_method_and_params
|
15
|
+
if has_large_file?
|
16
|
+
['setInputFilePaths', params_for_set_input_file_paths]
|
17
|
+
else
|
18
|
+
['setInputFiles', params_for_set_input_files]
|
19
|
+
end
|
11
20
|
end
|
12
21
|
|
13
|
-
private def
|
14
|
-
|
22
|
+
private def has_large_file?
|
23
|
+
max_bufsize = 1024 * 1024 # 1MB
|
15
24
|
|
16
|
-
files.
|
25
|
+
@files.any? do |file|
|
26
|
+
case file
|
27
|
+
when String
|
28
|
+
File::Stat.new(file).size > max_bufsize
|
29
|
+
when File
|
30
|
+
file.stat.size > max_bufsize
|
31
|
+
else
|
32
|
+
raise_argument_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private def params_for_set_input_file_paths
|
38
|
+
writable_streams = @files.map do |file|
|
39
|
+
case file
|
40
|
+
when String
|
41
|
+
writable_stream = @context.send(:create_temp_file, File.basename(file))
|
42
|
+
|
43
|
+
File.open(file, 'rb') do |file|
|
44
|
+
writable_stream.write(file)
|
45
|
+
end
|
46
|
+
|
47
|
+
writable_stream.channel
|
48
|
+
when File
|
49
|
+
writable_stream = @context.send(:create_temp_file, File.basename(file.path))
|
50
|
+
writable_stream.write(file)
|
51
|
+
|
52
|
+
writable_stream.channel
|
53
|
+
else
|
54
|
+
raise_argument_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
{ streams: writable_streams }
|
59
|
+
end
|
60
|
+
|
61
|
+
private def params_for_set_input_files
|
62
|
+
file_payloads = @files.map do |file|
|
17
63
|
case file
|
18
64
|
when String
|
19
65
|
{
|
@@ -26,9 +72,15 @@ module Playwright
|
|
26
72
|
buffer: Base64.strict_encode64(file.read),
|
27
73
|
}
|
28
74
|
else
|
29
|
-
|
75
|
+
raise_argument_error
|
30
76
|
end
|
31
77
|
end
|
78
|
+
|
79
|
+
{ files: file_payloads }
|
80
|
+
end
|
81
|
+
|
82
|
+
private def raise_argument_error
|
83
|
+
raise ArgumentError.new('file must be a String or File.')
|
32
84
|
end
|
33
85
|
end
|
34
86
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Playwright
|
2
|
+
module JavaScript
|
3
|
+
class Regex
|
4
|
+
def initialize(regexp)
|
5
|
+
unless regexp.is_a?(Regexp)
|
6
|
+
raise ArgumentError("Argument must be a Regexp: #{regexp} (#{regexp.class})")
|
7
|
+
end
|
8
|
+
|
9
|
+
@source = regexp.source
|
10
|
+
@flag = flag_for(regexp)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :source, :flag
|
14
|
+
|
15
|
+
private def flag_for(regexp)
|
16
|
+
flags = []
|
17
|
+
flags << 'ms' if (regexp.options & Regexp::MULTILINE) != 0
|
18
|
+
flags << 'i' if (regexp.options & Regexp::IGNORECASE) != 0
|
19
|
+
flags.join('')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -5,6 +5,7 @@ module Playwright
|
|
5
5
|
class ValueParser
|
6
6
|
def initialize(hash)
|
7
7
|
@hash = hash
|
8
|
+
@refs = {}
|
8
9
|
end
|
9
10
|
|
10
11
|
# @return [Hash]
|
@@ -23,6 +24,10 @@ module Playwright
|
|
23
24
|
return hash[key] if hash.key?(key)
|
24
25
|
end
|
25
26
|
|
27
|
+
if hash.key?('ref')
|
28
|
+
return @refs[hash['ref']]
|
29
|
+
end
|
30
|
+
|
26
31
|
if hash.key?('v')
|
27
32
|
return case hash['v']
|
28
33
|
when 'undefined'
|
@@ -55,11 +60,21 @@ module Playwright
|
|
55
60
|
end
|
56
61
|
|
57
62
|
if hash.key?('a')
|
58
|
-
|
63
|
+
result = []
|
64
|
+
if hash['id']
|
65
|
+
@refs[hash['id']] = result
|
66
|
+
end
|
67
|
+
hash['a'].each { |value| result << parse_hash(value) }
|
68
|
+
return result
|
59
69
|
end
|
60
70
|
|
61
71
|
if hash.key?('o')
|
62
|
-
|
72
|
+
result = {}
|
73
|
+
if hash['id']
|
74
|
+
@refs[hash['id']] = result
|
75
|
+
end
|
76
|
+
hash['o'].each { |obj| result[obj['k']] = parse_hash(obj['v']) }
|
77
|
+
return result
|
63
78
|
end
|
64
79
|
|
65
80
|
if hash.key?('h')
|
@@ -1,8 +1,12 @@
|
|
1
|
+
require_relative './visitor_info'
|
2
|
+
require_relative './regex'
|
3
|
+
|
1
4
|
module Playwright
|
2
5
|
module JavaScript
|
3
6
|
class ValueSerializer
|
4
7
|
def initialize(ruby_value)
|
5
8
|
@value = ruby_value
|
9
|
+
@visited = VisitorInfo.new
|
6
10
|
end
|
7
11
|
|
8
12
|
# @return [Hash]
|
@@ -37,14 +41,20 @@ module Playwright
|
|
37
41
|
require 'time'
|
38
42
|
{ d: value.utc.iso8601 }
|
39
43
|
when Regexp
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
{
|
44
|
+
regex_value = Regex.new(value)
|
45
|
+
{ r: { p: regex_value.source, f: regex_value.flag } }
|
46
|
+
when -> (value) { @visited.ref(value) }
|
47
|
+
{ ref: @visited.ref(value) }
|
44
48
|
when Array
|
45
|
-
|
49
|
+
id = @visited.log(value)
|
50
|
+
result = []
|
51
|
+
value.each { |v| result << serialize_value(v) }
|
52
|
+
{ a: result, id: id }
|
46
53
|
when Hash
|
47
|
-
|
54
|
+
id = @visited.log(value)
|
55
|
+
result = []
|
56
|
+
value.each { |key, v| result << { k: key, v: serialize_value(v) } }
|
57
|
+
{ o: result, id: id }
|
48
58
|
else
|
49
59
|
raise ArgumentError.new("Unexpected value: #{value}")
|
50
60
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Playwright
|
2
|
+
module JavaScript
|
3
|
+
class VisitorInfo
|
4
|
+
def initialize
|
5
|
+
@data = {}
|
6
|
+
@last_id = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
# returns [Integer|nil]
|
10
|
+
def ref(object)
|
11
|
+
@data[object]
|
12
|
+
end
|
13
|
+
|
14
|
+
def log(object)
|
15
|
+
if @data[object]
|
16
|
+
raise ArgumentError.new("Already visited")
|
17
|
+
end
|
18
|
+
|
19
|
+
id = @last_id + 1
|
20
|
+
@last_id = id # FIXME: should thread-safe
|
21
|
+
|
22
|
+
@data[object] = id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -31,11 +31,9 @@ module Playwright
|
|
31
31
|
|
32
32
|
case hasText
|
33
33
|
when Regexp
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
flags << 'i' if (hasText.options & Regexp::IGNORECASE) != 0
|
38
|
-
selector_scopes << ":scope:text-matches(#{source}, \"#{flags.join('')}\")"
|
34
|
+
regex = JavaScript::Regex.new(hasText)
|
35
|
+
source = EscapeWithQuotes.new(regex.source, '"')
|
36
|
+
selector_scopes << ":scope:text-matches(#{source}, \"#{regex.flag}\")"
|
39
37
|
when String
|
40
38
|
text = EscapeWithQuotes.new(hasText, '"')
|
41
39
|
selector_scopes << ":scope:has-text(#{text})"
|
@@ -239,6 +237,16 @@ module Playwright
|
|
239
237
|
@frame.query_selector_all(@selector)
|
240
238
|
end
|
241
239
|
|
240
|
+
def filter(has: nil, hasText: nil)
|
241
|
+
LocatorImpl.new(
|
242
|
+
frame: @frame,
|
243
|
+
timeout_settings: @timeout_settings,
|
244
|
+
selector: @selector,
|
245
|
+
hasText: hasText,
|
246
|
+
has: has,
|
247
|
+
)
|
248
|
+
end
|
249
|
+
|
242
250
|
def first
|
243
251
|
LocatorImpl.new(
|
244
252
|
frame: @frame,
|
@@ -314,19 +322,24 @@ module Playwright
|
|
314
322
|
|
315
323
|
def screenshot(
|
316
324
|
animations: nil,
|
325
|
+
caret: nil,
|
317
326
|
mask: nil,
|
318
327
|
omitBackground: nil,
|
319
328
|
path: nil,
|
320
329
|
quality: nil,
|
330
|
+
scale: nil,
|
321
331
|
timeout: nil,
|
322
332
|
type: nil)
|
333
|
+
|
323
334
|
with_element(timeout: timeout) do |handle, options|
|
324
335
|
handle.screenshot(
|
325
336
|
animations: animations,
|
337
|
+
caret: caret,
|
326
338
|
mask: mask,
|
327
339
|
omitBackground: omitBackground,
|
328
340
|
path: path,
|
329
341
|
quality: quality,
|
342
|
+
scale: scale,
|
330
343
|
timeout: options[:timeout],
|
331
344
|
type: type)
|
332
345
|
end
|
@@ -122,21 +122,41 @@ module Playwright
|
|
122
122
|
}
|
123
123
|
end
|
124
124
|
|
125
|
-
private def wrap_impl(object)
|
125
|
+
private def wrap_impl(object, visited: {})
|
126
126
|
if object.is_a?(Array)
|
127
|
-
object
|
127
|
+
unless visited[object]
|
128
|
+
visited[object] = []
|
129
|
+
object.each { |obj| visited[object] << wrap_impl(obj) }
|
130
|
+
end
|
131
|
+
visited[object]
|
128
132
|
elsif object.is_a?(Hash)
|
129
|
-
|
133
|
+
unless visited[object]
|
134
|
+
visited[object] = {}
|
135
|
+
object.each do |key, obj|
|
136
|
+
visited[object][key] = wrap_impl(obj, visited: visited)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
visited[object]
|
130
140
|
else
|
131
141
|
::Playwright::PlaywrightApi.wrap(object)
|
132
142
|
end
|
133
143
|
end
|
134
144
|
|
135
|
-
private def unwrap_impl(object)
|
145
|
+
private def unwrap_impl(object, visited: {})
|
136
146
|
if object.is_a?(Array)
|
137
|
-
object
|
147
|
+
unless visited[object]
|
148
|
+
visited[object] = []
|
149
|
+
object.each { |obj| visited[object] << unwrap_impl(obj) }
|
150
|
+
end
|
151
|
+
visited[object]
|
138
152
|
elsif object.is_a?(Hash)
|
139
|
-
|
153
|
+
unless visited[object]
|
154
|
+
visited[object] = {}
|
155
|
+
object.each do |key, obj|
|
156
|
+
visited[object][key] = unwrap_impl(obj, visited: visited)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
visited[object]
|
140
160
|
elsif object.is_a?(PlaywrightApi)
|
141
161
|
::Playwright::PlaywrightApi.unwrap(object)
|
142
162
|
else
|
@@ -50,12 +50,8 @@ module Playwright
|
|
50
50
|
def async_handle(route, request)
|
51
51
|
@counter.increment
|
52
52
|
|
53
|
-
Concurrent::Promises.future do
|
54
|
-
|
55
|
-
@handler.call(route, request)
|
56
|
-
rescue => err
|
57
|
-
puts err, err.backtrace
|
58
|
-
end
|
53
|
+
Concurrent::Promises.future { @handler.call(route, request) }.rescue do |err|
|
54
|
+
puts err, err.backtrace
|
59
55
|
end
|
60
56
|
end
|
61
57
|
|