playwright-ruby-client 1.16.0 → 1.17.1
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.md +7 -0
- data/documentation/docs/api/api_request_context.md +137 -0
- data/documentation/docs/api/api_response.md +90 -0
- data/documentation/docs/api/browser_context.md +4 -0
- data/documentation/docs/api/element_handle.md +2 -3
- data/documentation/docs/api/frame.md +30 -0
- data/documentation/docs/api/frame_locator.md +70 -0
- data/documentation/docs/api/locator.md +17 -2
- data/documentation/docs/api/page.md +33 -3
- data/documentation/docs/api/request.md +3 -3
- data/documentation/docs/api/selectors.md +1 -1
- data/documentation/docs/api/tracing.md +2 -2
- data/documentation/docs/include/api_coverage.md +42 -12
- data/lib/playwright/api_response_impl.rb +73 -0
- data/lib/playwright/channel.rb +1 -1
- data/lib/playwright/channel_owners/api_request_context.rb +232 -0
- data/lib/playwright/channel_owners/artifact.rb +1 -6
- data/lib/playwright/channel_owners/browser.rb +6 -8
- data/lib/playwright/channel_owners/browser_context.rb +3 -4
- data/lib/playwright/channel_owners/browser_type.rb +0 -1
- data/lib/playwright/channel_owners/fetch_request.rb +2 -0
- data/lib/playwright/channel_owners/frame.rb +10 -6
- data/lib/playwright/channel_owners/page.rb +17 -10
- data/lib/playwright/connection.rb +9 -0
- data/lib/playwright/frame_locator_impl.rb +49 -0
- data/lib/playwright/locator_impl.rb +13 -5
- data/lib/playwright/tracing_impl.rb +6 -9
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright/video.rb +3 -0
- data/lib/playwright.rb +2 -1
- data/lib/playwright_api/android_device.rb +4 -4
- data/lib/playwright_api/api_request.rb +18 -0
- data/lib/playwright_api/api_request_context.rb +11 -8
- data/lib/playwright_api/api_response.rb +68 -0
- data/lib/playwright_api/browser_context.rb +10 -5
- data/lib/playwright_api/element_handle.rb +2 -3
- data/lib/playwright_api/frame.rb +26 -1
- data/lib/playwright_api/frame_locator.rb +51 -0
- data/lib/playwright_api/locator.rb +12 -2
- data/lib/playwright_api/page.rb +34 -4
- data/lib/playwright_api/playwright.rb +9 -4
- data/lib/playwright_api/selectors.rb +2 -2
- data/lib/playwright_api/tracing.rb +4 -4
- data/playwright.gemspec +1 -1
- metadata +14 -6
@@ -0,0 +1,73 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_api_implementation :APIResponseImpl do
|
3
|
+
include Utils::Errors::SafeCloseError
|
4
|
+
|
5
|
+
# @params context [APIRequestContext]
|
6
|
+
# @params initializer [Hash]
|
7
|
+
def initialize(context, initializer)
|
8
|
+
@request = context
|
9
|
+
@initializer = initializer
|
10
|
+
@headers = RawHeaders.new(initializer['headers'])
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"#<APIResponse url=#{url} status=#{status} status_text=#{status_text}>"
|
15
|
+
end
|
16
|
+
|
17
|
+
def url
|
18
|
+
@initializer['url']
|
19
|
+
end
|
20
|
+
|
21
|
+
def ok
|
22
|
+
(200...300).include?(status)
|
23
|
+
end
|
24
|
+
alias_method :ok?, :ok
|
25
|
+
|
26
|
+
def status
|
27
|
+
@initializer['status']
|
28
|
+
end
|
29
|
+
|
30
|
+
def status_text
|
31
|
+
@initializer['statusText']
|
32
|
+
end
|
33
|
+
|
34
|
+
def headers
|
35
|
+
@headers.headers
|
36
|
+
end
|
37
|
+
|
38
|
+
def headers_array
|
39
|
+
@headers.headers_array
|
40
|
+
end
|
41
|
+
|
42
|
+
class AlreadyDisposedError < StandardError
|
43
|
+
def initialize
|
44
|
+
super('Response has been disposed')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def body
|
49
|
+
binary = @request.channel.send_message_to_server("fetchResponseBody", fetchUid: fetch_uid)
|
50
|
+
raise AlreadyDisposedError.new unless binary
|
51
|
+
Base64.strict_decode64(binary)
|
52
|
+
rescue => err
|
53
|
+
if safe_close_error?(err)
|
54
|
+
raise AlreadyDisposedError.new
|
55
|
+
else
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
end
|
59
|
+
alias_method :text, :body
|
60
|
+
|
61
|
+
def json
|
62
|
+
JSON.parse(text)
|
63
|
+
end
|
64
|
+
|
65
|
+
def dispose
|
66
|
+
@request.channel.send_message_to_server("disposeAPIResponse", fetchUid: fetch_uid)
|
67
|
+
end
|
68
|
+
|
69
|
+
private def fetch_uid
|
70
|
+
@initializer['fetchUid']
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/playwright/channel.rb
CHANGED
@@ -1,4 +1,236 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
1
3
|
module Playwright
|
2
4
|
define_channel_owner :APIRequestContext do
|
5
|
+
def dispose
|
6
|
+
@channel.send_message_to_server('dispose')
|
7
|
+
end
|
8
|
+
|
9
|
+
def delete(
|
10
|
+
url,
|
11
|
+
data: nil,
|
12
|
+
failOnStatusCode: nil,
|
13
|
+
form: nil,
|
14
|
+
headers: nil,
|
15
|
+
ignoreHTTPSErrors: nil,
|
16
|
+
multipart: nil,
|
17
|
+
params: nil,
|
18
|
+
timeout: nil)
|
19
|
+
fetch(
|
20
|
+
url,
|
21
|
+
method: 'DELETE',
|
22
|
+
data: data,
|
23
|
+
failOnStatusCode: failOnStatusCode,
|
24
|
+
form: form,
|
25
|
+
headers: headers,
|
26
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
27
|
+
multipart: multipart,
|
28
|
+
params: params,
|
29
|
+
timeout: timeout,
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def head(
|
34
|
+
url,
|
35
|
+
failOnStatusCode: nil,
|
36
|
+
headers: nil,
|
37
|
+
ignoreHTTPSErrors: nil,
|
38
|
+
params: nil,
|
39
|
+
timeout: nil)
|
40
|
+
fetch(
|
41
|
+
url,
|
42
|
+
method: 'HEAD',
|
43
|
+
failOnStatusCode: failOnStatusCode,
|
44
|
+
headers: headers,
|
45
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
46
|
+
params: params,
|
47
|
+
timeout: timeout,
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def get(
|
52
|
+
url,
|
53
|
+
failOnStatusCode: nil,
|
54
|
+
headers: nil,
|
55
|
+
ignoreHTTPSErrors: nil,
|
56
|
+
params: nil,
|
57
|
+
timeout: nil)
|
58
|
+
fetch(
|
59
|
+
url,
|
60
|
+
method: 'GET',
|
61
|
+
failOnStatusCode: failOnStatusCode,
|
62
|
+
headers: headers,
|
63
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
64
|
+
params: params,
|
65
|
+
timeout: timeout,
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def patch(
|
70
|
+
url,
|
71
|
+
data: nil,
|
72
|
+
failOnStatusCode: nil,
|
73
|
+
form: nil,
|
74
|
+
headers: nil,
|
75
|
+
ignoreHTTPSErrors: nil,
|
76
|
+
multipart: nil,
|
77
|
+
params: nil,
|
78
|
+
timeout: nil)
|
79
|
+
fetch(
|
80
|
+
url,
|
81
|
+
method: 'PATCH',
|
82
|
+
data: data,
|
83
|
+
failOnStatusCode: failOnStatusCode,
|
84
|
+
form: form,
|
85
|
+
headers: headers,
|
86
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
87
|
+
multipart: multipart,
|
88
|
+
params: params,
|
89
|
+
timeout: timeout,
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def put(
|
94
|
+
url,
|
95
|
+
data: nil,
|
96
|
+
failOnStatusCode: nil,
|
97
|
+
form: nil,
|
98
|
+
headers: nil,
|
99
|
+
ignoreHTTPSErrors: nil,
|
100
|
+
multipart: nil,
|
101
|
+
params: nil,
|
102
|
+
timeout: nil)
|
103
|
+
fetch(
|
104
|
+
url,
|
105
|
+
method: 'PUT',
|
106
|
+
data: data,
|
107
|
+
failOnStatusCode: failOnStatusCode,
|
108
|
+
form: form,
|
109
|
+
headers: headers,
|
110
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
111
|
+
multipart: multipart,
|
112
|
+
params: params,
|
113
|
+
timeout: timeout,
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def post(
|
118
|
+
url,
|
119
|
+
data: nil,
|
120
|
+
failOnStatusCode: nil,
|
121
|
+
form: nil,
|
122
|
+
headers: nil,
|
123
|
+
ignoreHTTPSErrors: nil,
|
124
|
+
multipart: nil,
|
125
|
+
params: nil,
|
126
|
+
timeout: nil)
|
127
|
+
fetch(
|
128
|
+
url,
|
129
|
+
method: 'POST',
|
130
|
+
data: data,
|
131
|
+
failOnStatusCode: failOnStatusCode,
|
132
|
+
form: form,
|
133
|
+
headers: headers,
|
134
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
135
|
+
multipart: multipart,
|
136
|
+
params: params,
|
137
|
+
timeout: timeout,
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def fetch(
|
142
|
+
urlOrRequest,
|
143
|
+
data: nil,
|
144
|
+
failOnStatusCode: nil,
|
145
|
+
form: nil,
|
146
|
+
headers: nil,
|
147
|
+
ignoreHTTPSErrors: nil,
|
148
|
+
method: nil,
|
149
|
+
multipart: nil,
|
150
|
+
params: nil,
|
151
|
+
timeout: nil)
|
152
|
+
|
153
|
+
if [ChannelOwners::Request, String].none? { |type| urlOrRequest.is_a?(type) }
|
154
|
+
raise ArgumentError.new("First argument must be either URL string or Request")
|
155
|
+
end
|
156
|
+
if [data, form, multipart].compact.count > 1
|
157
|
+
raise ArgumentError.new("Only one of 'data', 'form' or 'multipart' can be specified")
|
158
|
+
end
|
159
|
+
|
160
|
+
request = urlOrRequest.is_a?(ChannelOwners::Request) ? urlOrRequest : nil
|
161
|
+
headers_obj = headers || request&.headers
|
162
|
+
fetch_params = {
|
163
|
+
url: request&.url || urlOrRequest,
|
164
|
+
params: object_to_array(params),
|
165
|
+
method: method || request&.method || 'GET',
|
166
|
+
headers: headers_obj ? HttpHeaders.new(headers_obj).as_serialized : nil,
|
167
|
+
}
|
168
|
+
|
169
|
+
json_data = nil
|
170
|
+
form_data = nil
|
171
|
+
multipart_data = nil
|
172
|
+
post_data_buffer = nil
|
173
|
+
if data
|
174
|
+
case data
|
175
|
+
when String
|
176
|
+
if headers_obj&.any? { |key, value| key.downcase == 'content-type' && value == 'application/json' }
|
177
|
+
json_data = data
|
178
|
+
else
|
179
|
+
post_data_buffer = data
|
180
|
+
end
|
181
|
+
when Hash, Array, Numeric, true, false
|
182
|
+
json_data = data
|
183
|
+
else
|
184
|
+
raise ArgumentError.new("Unsupported 'data' type: #{data.class}")
|
185
|
+
end
|
186
|
+
elsif form
|
187
|
+
form_data = object_to_array(form)
|
188
|
+
elsif multipart
|
189
|
+
multipart_data = multipart.map do |name, value|
|
190
|
+
if file_payload?(value)
|
191
|
+
{ name: name, file: file_payload_to_json(value) }
|
192
|
+
else
|
193
|
+
{ name: name, value: value.to_s }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
if !json_data && !form_data && !multipart_data
|
199
|
+
post_data_buffer ||= request&.post_data_buffer
|
200
|
+
end
|
201
|
+
if post_data_buffer
|
202
|
+
fetch_params[:postData] = Base64.strict_encode64(post_data_buffer)
|
203
|
+
end
|
204
|
+
|
205
|
+
fetch_params[:jsonData] = json_data
|
206
|
+
fetch_params[:formData] = form_data
|
207
|
+
fetch_params[:multipartData] = multipart_data
|
208
|
+
fetch_params[:timeout] = timeout
|
209
|
+
fetch_params[:failOnStatusCode] = failOnStatusCode
|
210
|
+
fetch_params[:ignoreHTTPSErrors] = ignoreHTTPSErrors
|
211
|
+
fetch_params.compact!
|
212
|
+
response = @channel.send_message_to_server('fetch', fetch_params)
|
213
|
+
|
214
|
+
APIResponseImpl.new(self, response)
|
215
|
+
end
|
216
|
+
|
217
|
+
private def file_payload?(value)
|
218
|
+
value.is_a?(Hash) &&
|
219
|
+
%w(name mimeType buffer).all? { |key| value.has_key?(key) || value.has_key?(key.to_sym) }
|
220
|
+
end
|
221
|
+
|
222
|
+
private def file_payload_to_json(payload)
|
223
|
+
{
|
224
|
+
name: payload[:name] || payload['name'],
|
225
|
+
mimeType: payload[:mimeType] || payload['mimeType'],
|
226
|
+
buffer: Base64.strict_encode64(payload[:buffer] || payload['buffer'])
|
227
|
+
}
|
228
|
+
end
|
229
|
+
|
230
|
+
private def object_to_array(hash)
|
231
|
+
hash&.map do |key, value|
|
232
|
+
{ name: key, value: value.to_s }
|
233
|
+
end
|
234
|
+
end
|
3
235
|
end
|
4
236
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Playwright
|
2
2
|
define_channel_owner :Artifact do
|
3
3
|
private def after_initialize
|
4
|
-
@remote = false
|
5
4
|
@absolute_path = @initializer['absolutePath']
|
6
5
|
end
|
7
6
|
|
8
7
|
attr_reader :absolute_path
|
9
8
|
|
10
9
|
def path_after_finished
|
11
|
-
if @remote
|
10
|
+
if @connection.remote?
|
12
11
|
raise "Path is not available when using browser_type.connect(). Use save_as() to save a local copy."
|
13
12
|
end
|
14
13
|
@channel.send_message_to_server('pathAfterFinished')
|
@@ -30,9 +29,5 @@ module Playwright
|
|
30
29
|
def cancel
|
31
30
|
@channel.send_message_to_server('cancel')
|
32
31
|
end
|
33
|
-
|
34
|
-
private def update_as_remote
|
35
|
-
@remote = true
|
36
|
-
end
|
37
32
|
end
|
38
33
|
end
|
@@ -7,7 +7,7 @@ module Playwright
|
|
7
7
|
private def after_initialize
|
8
8
|
@connected = true
|
9
9
|
@closed_or_closing = false
|
10
|
-
@
|
10
|
+
@should_close_connection_on_close = false
|
11
11
|
|
12
12
|
@contexts = Set.new
|
13
13
|
@channel.on('close', method(:on_close))
|
@@ -58,6 +58,9 @@ module Playwright
|
|
58
58
|
return if @closed_or_closing
|
59
59
|
@closed_or_closing = true
|
60
60
|
@channel.send_message_to_server('close')
|
61
|
+
if @should_close_connection_on_close
|
62
|
+
@connection.stop
|
63
|
+
end
|
61
64
|
nil
|
62
65
|
rescue => err
|
63
66
|
raise unless safe_close_error?(err)
|
@@ -99,13 +102,8 @@ module Playwright
|
|
99
102
|
@contexts << context
|
100
103
|
end
|
101
104
|
|
102
|
-
|
103
|
-
|
104
|
-
@remote = true
|
105
|
-
end
|
106
|
-
|
107
|
-
private def remote?
|
108
|
-
@remote
|
105
|
+
private def should_close_connection_on_close!
|
106
|
+
@should_close_connection_on_close = true
|
109
107
|
end
|
110
108
|
|
111
109
|
# called from BrowserContext#on_close with send(:remove_context), so keep private.
|
@@ -4,7 +4,7 @@ module Playwright
|
|
4
4
|
include Utils::Errors::SafeCloseError
|
5
5
|
attr_accessor :browser
|
6
6
|
attr_writer :owner_page, :options
|
7
|
-
attr_reader :tracing
|
7
|
+
attr_reader :tracing, :request
|
8
8
|
|
9
9
|
private def after_initialize
|
10
10
|
@pages = Set.new
|
@@ -15,6 +15,8 @@ module Playwright
|
|
15
15
|
@background_pages = Set.new
|
16
16
|
|
17
17
|
@tracing = TracingImpl.new(@channel, self)
|
18
|
+
@request = ChannelOwners::APIRequestContext.from(@initializer['APIRequestContext'])
|
19
|
+
|
18
20
|
@channel.on('bindingCall', ->(params) { on_binding(ChannelOwners::BindingCall.from(params['binding'])) })
|
19
21
|
@channel.once('close', ->(_) { on_close })
|
20
22
|
@channel.on('page', ->(params) { on_page(ChannelOwners::Page.from(params['page']) )})
|
@@ -276,9 +278,6 @@ module Playwright
|
|
276
278
|
def close
|
277
279
|
if @options && @options.key?(:recordHar)
|
278
280
|
har = ChannelOwners::Artifact.from(@channel.send_message_to_server('harExport'))
|
279
|
-
if @browser.send(:remote?)
|
280
|
-
har.update_as_remote
|
281
|
-
end
|
282
281
|
har.save_as(@options[:recordHar][:path])
|
283
282
|
har.delete
|
284
283
|
end
|
@@ -54,7 +54,6 @@ module Playwright
|
|
54
54
|
|
55
55
|
result = @channel.send_message_to_server_result('connectOverCDP', params)
|
56
56
|
browser = ChannelOwners::Browser.from(result['browser'])
|
57
|
-
browser.send(:update_as_remote)
|
58
57
|
|
59
58
|
if result['defaultContext']
|
60
59
|
context = ChannelOwners::BrowserContext.from(result['defaultContext'])
|
@@ -110,8 +110,8 @@ module Playwright
|
|
110
110
|
def wait_for_load_state(state: nil, timeout: nil)
|
111
111
|
option_state = state || 'load'
|
112
112
|
option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
|
113
|
-
unless %w(load domcontentloaded networkidle).include?(option_state)
|
114
|
-
raise ArgumentError.new('state: expected one of (load|domcontentloaded|networkidle)')
|
113
|
+
unless %w(load domcontentloaded networkidle commit).include?(option_state)
|
114
|
+
raise ArgumentError.new('state: expected one of (load|domcontentloaded|networkidle|commit)')
|
115
115
|
end
|
116
116
|
if @load_states.include?(option_state)
|
117
117
|
return
|
@@ -191,10 +191,6 @@ module Playwright
|
|
191
191
|
@channel.send_message_to_server('isVisible', params)
|
192
192
|
end
|
193
193
|
|
194
|
-
def locator(selector)
|
195
|
-
LocatorImpl.new(frame: self, timeout_settings: @page.send(:timeout_settings), selector: selector)
|
196
|
-
end
|
197
|
-
|
198
194
|
def dispatch_event(selector, type, eventInit: nil, strict: nil, timeout: nil)
|
199
195
|
params = {
|
200
196
|
selector: selector,
|
@@ -404,6 +400,14 @@ module Playwright
|
|
404
400
|
nil
|
405
401
|
end
|
406
402
|
|
403
|
+
def locator(selector)
|
404
|
+
LocatorImpl.new(frame: self, timeout_settings: @page.send(:timeout_settings), selector: selector)
|
405
|
+
end
|
406
|
+
|
407
|
+
def frame_locator(selector)
|
408
|
+
FrameLocatorImpl.new(frame: self, timeout_settings: @page.send(:timeout_settings), frame_selector: selector)
|
409
|
+
end
|
410
|
+
|
407
411
|
def focus(selector, strict: nil, timeout: nil)
|
408
412
|
params = { selector: selector, strict: strict, timeout: timeout }.compact
|
409
413
|
@channel.send_message_to_server('focus', params)
|
@@ -138,9 +138,6 @@ module Playwright
|
|
138
138
|
|
139
139
|
private def on_download(params)
|
140
140
|
artifact = ChannelOwners::Artifact.from(params['artifact'])
|
141
|
-
if @browser_context.browser.send(:remote?)
|
142
|
-
artifact.update_as_remote
|
143
|
-
end
|
144
141
|
download = DownloadImpl.new(
|
145
142
|
page: self,
|
146
143
|
url: params['url'],
|
@@ -152,9 +149,6 @@ module Playwright
|
|
152
149
|
|
153
150
|
private def on_video(params)
|
154
151
|
artifact = ChannelOwners::Artifact.from(params['artifact'])
|
155
|
-
if @browser_context.browser.send(:remote?)
|
156
|
-
artifact.update_as_remote
|
157
|
-
end
|
158
152
|
video.send(:set_artifact, artifact)
|
159
153
|
end
|
160
154
|
|
@@ -261,10 +255,6 @@ module Playwright
|
|
261
255
|
@main_frame.visible?(selector, strict: strict, timeout: timeout)
|
262
256
|
end
|
263
257
|
|
264
|
-
def locator(selector)
|
265
|
-
@main_frame.locator(selector)
|
266
|
-
end
|
267
|
-
|
268
258
|
def dispatch_event(selector, type, eventInit: nil, strict: nil, timeout: nil)
|
269
259
|
@main_frame.dispatch_event(selector, type, eventInit: eventInit, strict: strict, timeout: timeout)
|
270
260
|
end
|
@@ -568,6 +558,14 @@ module Playwright
|
|
568
558
|
timeout: timeout)
|
569
559
|
end
|
570
560
|
|
561
|
+
def locator(selector)
|
562
|
+
@main_frame.locator(selector)
|
563
|
+
end
|
564
|
+
|
565
|
+
def frame_locator(selector)
|
566
|
+
@main_frame.frame_locator(selector)
|
567
|
+
end
|
568
|
+
|
571
569
|
def focus(selector, strict: nil, timeout: nil)
|
572
570
|
@main_frame.focus(selector, strict: strict, timeout: timeout)
|
573
571
|
end
|
@@ -735,6 +733,10 @@ module Playwright
|
|
735
733
|
@workers.to_a
|
736
734
|
end
|
737
735
|
|
736
|
+
def request
|
737
|
+
@browser_context.request
|
738
|
+
end
|
739
|
+
|
738
740
|
def pause
|
739
741
|
@browser_context.send(:pause)
|
740
742
|
end
|
@@ -925,6 +927,11 @@ module Playwright
|
|
925
927
|
@workers.delete(worker)
|
926
928
|
end
|
927
929
|
|
930
|
+
# called from Video
|
931
|
+
private def remote_connection?
|
932
|
+
@connection.remote?
|
933
|
+
end
|
934
|
+
|
928
935
|
# Expose guid for library developers.
|
929
936
|
# Not intended to be used by users.
|
930
937
|
def guid
|
@@ -21,6 +21,15 @@ module Playwright
|
|
21
21
|
@waiting_for_object = {} # Hash[ guid => Promise<ChannelOwner> ]
|
22
22
|
@callbacks = {} # Hash [ guid => Promise<ChannelOwner> ]
|
23
23
|
@root_object = RootChannelOwner.new(self)
|
24
|
+
@remote = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def mark_as_remote
|
28
|
+
@remote = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def remote?
|
32
|
+
@remote
|
24
33
|
end
|
25
34
|
|
26
35
|
def async_run
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_api_implementation :FrameLocatorImpl do
|
3
|
+
def initialize(frame:, timeout_settings:, frame_selector:)
|
4
|
+
@frame = frame
|
5
|
+
@timeout_settings = timeout_settings
|
6
|
+
@frame_selector = frame_selector
|
7
|
+
end
|
8
|
+
|
9
|
+
def locator(selector)
|
10
|
+
LocatorImpl.new(
|
11
|
+
frame: @frame,
|
12
|
+
timeout_settings: @timeout_settings,
|
13
|
+
selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def frame_locator(selector)
|
18
|
+
FrameLocatorImpl.new(
|
19
|
+
frame: @frame,
|
20
|
+
timeout_settings: @timeout_settings,
|
21
|
+
frame_selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def first
|
26
|
+
FrameLocatorImpl.new(
|
27
|
+
frame: @frame,
|
28
|
+
timeout_settings: @timeout_settings,
|
29
|
+
frame_selector: "#{@frame_selector} >> nth=0",
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def last
|
34
|
+
FrameLocatorImpl.new(
|
35
|
+
frame: @frame,
|
36
|
+
timeout_settings: @timeout_settings,
|
37
|
+
frame_selector: "#{@frame_selector} >> nth=-1",
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def nth(index)
|
42
|
+
FrameLocatorImpl.new(
|
43
|
+
frame: @frame,
|
44
|
+
timeout_settings: @timeout_settings,
|
45
|
+
frame_selector: "#{@frame_selector} >> nth=#{index}",
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -11,17 +11,17 @@ module Playwright
|
|
11
11
|
end
|
12
12
|
|
13
13
|
private def with_element(timeout: nil, &block)
|
14
|
+
timeout_or_default = @timeout_settings.timeout(timeout)
|
14
15
|
start_time = Time.now
|
15
16
|
|
16
|
-
handle = @frame.wait_for_selector(@selector, strict: true, state: 'attached', timeout:
|
17
|
+
handle = @frame.wait_for_selector(@selector, strict: true, state: 'attached', timeout: timeout_or_default)
|
17
18
|
unless handle
|
18
19
|
raise "Could not resolve #{@selector} to DOM Element"
|
19
20
|
end
|
20
21
|
|
21
|
-
call_options = {
|
22
|
-
|
23
|
-
|
24
|
-
end
|
22
|
+
call_options = {
|
23
|
+
timeout: (timeout_or_default - (Time.now - start_time) * 1000).to_i,
|
24
|
+
}
|
25
25
|
|
26
26
|
begin
|
27
27
|
block.call(handle, call_options)
|
@@ -130,6 +130,14 @@ module Playwright
|
|
130
130
|
)
|
131
131
|
end
|
132
132
|
|
133
|
+
def frame_locator(selector)
|
134
|
+
FrameLocatorImpl.new(
|
135
|
+
frame: @frame,
|
136
|
+
timeout_settings: @timeout_settings,
|
137
|
+
frame_selector: "#{@selector} >> #{selector}",
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
133
141
|
def element_handle(timeout: nil)
|
134
142
|
@frame.wait_for_selector(@selector, strict: true, state: 'attached', timeout: timeout)
|
135
143
|
end
|
@@ -5,18 +5,18 @@ module Playwright
|
|
5
5
|
@context = context
|
6
6
|
end
|
7
7
|
|
8
|
-
def start(name: nil, screenshots: nil, snapshots: nil)
|
8
|
+
def start(name: nil, title: nil, screenshots: nil, snapshots: nil)
|
9
9
|
params = {
|
10
10
|
name: name,
|
11
11
|
screenshots: screenshots,
|
12
12
|
snapshots: snapshots,
|
13
13
|
}.compact
|
14
14
|
@channel.send_message_to_server('tracingStart', params)
|
15
|
-
@channel.send_message_to_server('tracingStartChunk')
|
15
|
+
@channel.send_message_to_server('tracingStartChunk', { title: title }.compact)
|
16
16
|
end
|
17
17
|
|
18
|
-
def start_chunk
|
19
|
-
@channel.send_message_to_server('tracingStartChunk')
|
18
|
+
def start_chunk(title: nil)
|
19
|
+
@channel.send_message_to_server('tracingStartChunk', { title: title }.compact)
|
20
20
|
end
|
21
21
|
|
22
22
|
def stop_chunk(path: nil)
|
@@ -29,13 +29,10 @@ module Playwright
|
|
29
29
|
end
|
30
30
|
|
31
31
|
private def do_stop_chunk(path:)
|
32
|
-
|
33
|
-
artifact = ChannelOwners::Artifact.from_nullable(
|
32
|
+
result = @channel.send_message_to_server_result('tracingStopChunk', save: !path.nil?, skipCompress: false)
|
33
|
+
artifact = ChannelOwners::Artifact.from_nullable(result['artifact'])
|
34
34
|
return unless artifact
|
35
35
|
|
36
|
-
if @context.browser.send(:remote?)
|
37
|
-
artifact.update_as_remote
|
38
|
-
end
|
39
36
|
artifact.save_as(path)
|
40
37
|
artifact.delete
|
41
38
|
end
|
data/lib/playwright/version.rb
CHANGED
data/lib/playwright/video.rb
CHANGED
@@ -22,6 +22,9 @@ module Playwright
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def path
|
25
|
+
if @page.send(:remote_connection?)
|
26
|
+
raise 'Path is not available when using browserType.connect(). Use save_as() to save a local copy.'
|
27
|
+
end
|
25
28
|
wait_for_artifact_and do |artifact|
|
26
29
|
artifact.absolute_path
|
27
30
|
end
|