playwright-ruby-client 1.39.1 → 1.41.beta1
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 +1 -2
- data/documentation/docs/api/browser.md +1 -1
- data/documentation/docs/api/browser_context.md +10 -1
- data/documentation/docs/api/browser_type.md +1 -0
- data/documentation/docs/api/download.md +1 -2
- data/documentation/docs/api/element_handle.md +5 -1
- data/documentation/docs/api/frame.md +4 -1
- data/documentation/docs/api/locator.md +5 -1
- data/documentation/docs/api/locator_assertions.md +12 -2
- data/documentation/docs/api/page.md +16 -3
- data/documentation/docs/api/tracing.md +2 -2
- data/documentation/docs/article/guides/rails_integration.md +80 -51
- data/documentation/docs/article/guides/rspec_integration.md +59 -0
- data/documentation/docs/include/api_coverage.md +2 -0
- data/documentation/docusaurus.config.js +1 -1
- data/documentation/package.json +7 -7
- data/documentation/yarn.lock +4641 -5023
- data/lib/playwright/api_response_impl.rb +2 -2
- data/lib/playwright/channel_owners/api_request_context.rb +12 -3
- data/lib/playwright/channel_owners/browser.rb +11 -7
- data/lib/playwright/channel_owners/browser_context.rb +40 -15
- data/lib/playwright/channel_owners/element_handle.rb +2 -0
- data/lib/playwright/channel_owners/frame.rb +38 -14
- data/lib/playwright/channel_owners/page.rb +36 -16
- data/lib/playwright/channel_owners/web_socket.rb +8 -13
- data/lib/playwright/connection.rb +18 -2
- data/lib/playwright/errors.rb +20 -2
- data/lib/playwright/input_files.rb +4 -4
- data/lib/playwright/locator_assertions_impl.rb +15 -15
- data/lib/playwright/locator_impl.rb +2 -0
- data/lib/playwright/test.rb +2 -2
- data/lib/playwright/utils.rb +3 -10
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright/waiter.rb +146 -0
- data/lib/playwright.rb +1 -1
- data/lib/playwright_api/api_request_context.rb +1 -2
- data/lib/playwright_api/browser.rb +2 -2
- data/lib/playwright_api/browser_context.rb +9 -3
- data/lib/playwright_api/browser_type.rb +2 -1
- data/lib/playwright_api/download.rb +1 -2
- data/lib/playwright_api/element_handle.rb +6 -2
- data/lib/playwright_api/frame.rb +4 -1
- data/lib/playwright_api/locator.rb +6 -2
- data/lib/playwright_api/locator_assertions.rb +14 -4
- data/lib/playwright_api/page.rb +20 -10
- data/lib/playwright_api/request.rb +4 -4
- data/lib/playwright_api/tracing.rb +2 -2
- data/lib/playwright_api/worker.rb +4 -4
- data/sig/playwright.rbs +12 -10
- metadata +7 -6
- data/lib/playwright/wait_helper.rb +0 -73
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Playwright
|
|
2
2
|
define_api_implementation :APIResponseImpl do
|
|
3
|
-
include Utils::Errors::
|
|
3
|
+
include Utils::Errors::TargetClosedErrorMethods
|
|
4
4
|
|
|
5
5
|
# @params context [APIRequestContext]
|
|
6
6
|
# @params initializer [Hash]
|
|
@@ -50,7 +50,7 @@ module Playwright
|
|
|
50
50
|
raise AlreadyDisposedError.new unless binary
|
|
51
51
|
Base64.strict_decode64(binary)
|
|
52
52
|
rescue => err
|
|
53
|
-
if
|
|
53
|
+
if target_closed_error?(err)
|
|
54
54
|
raise AlreadyDisposedError.new
|
|
55
55
|
else
|
|
56
56
|
raise
|
|
@@ -115,12 +115,12 @@ module Playwright
|
|
|
115
115
|
case data
|
|
116
116
|
when String
|
|
117
117
|
if headers_obj&.any? { |key, value| key.downcase == 'content-type' && value == 'application/json' }
|
|
118
|
-
json_data = data
|
|
118
|
+
json_data = json_parsable?(data) ? data : data.to_json
|
|
119
119
|
else
|
|
120
120
|
post_data_buffer = data
|
|
121
121
|
end
|
|
122
122
|
when Hash, Array, Numeric, true, false
|
|
123
|
-
json_data = data
|
|
123
|
+
json_data = data.to_json
|
|
124
124
|
else
|
|
125
125
|
raise ArgumentError.new("Unsupported 'data' type: #{data.class}")
|
|
126
126
|
end
|
|
@@ -142,7 +142,6 @@ module Playwright
|
|
|
142
142
|
if post_data_buffer
|
|
143
143
|
fetch_params[:postData] = Base64.strict_encode64(post_data_buffer)
|
|
144
144
|
end
|
|
145
|
-
|
|
146
145
|
fetch_params[:jsonData] = json_data
|
|
147
146
|
fetch_params[:formData] = form_data
|
|
148
147
|
fetch_params[:multipartData] = multipart_data
|
|
@@ -174,5 +173,15 @@ module Playwright
|
|
|
174
173
|
{ name: key, value: value.to_s }
|
|
175
174
|
end
|
|
176
175
|
end
|
|
176
|
+
|
|
177
|
+
private def json_parsable?(data)
|
|
178
|
+
return false unless data.is_a?(String)
|
|
179
|
+
begin
|
|
180
|
+
JSON.parse(data)
|
|
181
|
+
true
|
|
182
|
+
rescue JSON::ParserError
|
|
183
|
+
false
|
|
184
|
+
end
|
|
185
|
+
end
|
|
177
186
|
end
|
|
178
187
|
end
|
|
@@ -3,17 +3,21 @@ require 'fileutils'
|
|
|
3
3
|
module Playwright
|
|
4
4
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_browser.py
|
|
5
5
|
define_channel_owner :Browser do
|
|
6
|
-
include Utils::Errors::
|
|
6
|
+
include Utils::Errors::TargetClosedErrorMethods
|
|
7
7
|
include Utils::PrepareBrowserContextOptions
|
|
8
8
|
|
|
9
9
|
private def after_initialize
|
|
10
10
|
@browser_type = @parent
|
|
11
11
|
@connected = true
|
|
12
|
-
@closed_or_closing = false
|
|
13
12
|
@should_close_connection_on_close = false
|
|
14
13
|
|
|
15
14
|
@contexts = Set.new
|
|
16
15
|
@channel.on('close', method(:on_close))
|
|
16
|
+
@close_reason = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private def close_reason
|
|
20
|
+
@close_reason
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def contexts
|
|
@@ -63,16 +67,16 @@ module Playwright
|
|
|
63
67
|
@browser_type = browser_type
|
|
64
68
|
end
|
|
65
69
|
|
|
66
|
-
def close
|
|
67
|
-
|
|
68
|
-
@closed_or_closing = true
|
|
69
|
-
@channel.send_message_to_server('close')
|
|
70
|
+
def close(reason: nil)
|
|
71
|
+
@close_reason = reason
|
|
70
72
|
if @should_close_connection_on_close
|
|
71
73
|
@connection.stop
|
|
74
|
+
else
|
|
75
|
+
@channel.send_message_to_server('close', { reason: reason }.compact)
|
|
72
76
|
end
|
|
73
77
|
nil
|
|
74
78
|
rescue => err
|
|
75
|
-
raise unless
|
|
79
|
+
raise unless target_closed_error?(err)
|
|
76
80
|
end
|
|
77
81
|
|
|
78
82
|
def version
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
module Playwright
|
|
2
2
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_browser_context.py
|
|
3
3
|
define_channel_owner :BrowserContext do
|
|
4
|
-
include Utils::Errors::SafeCloseError
|
|
5
4
|
include Utils::PrepareBrowserContextOptions
|
|
6
5
|
|
|
7
6
|
attr_accessor :browser
|
|
@@ -68,6 +67,9 @@ module Playwright
|
|
|
68
67
|
ChannelOwners::Page.from_nullable(params['page']),
|
|
69
68
|
)
|
|
70
69
|
})
|
|
70
|
+
|
|
71
|
+
@closed_promise = Concurrent::Promises.resolvable_future
|
|
72
|
+
@close_reason = nil
|
|
71
73
|
set_event_to_subscription_mapping({
|
|
72
74
|
Events::BrowserContext::Console => 'console',
|
|
73
75
|
Events::BrowserContext::Dialog => 'dialog',
|
|
@@ -77,7 +79,7 @@ module Playwright
|
|
|
77
79
|
Events::BrowserContext::RequestFailed => "requestFailed",
|
|
78
80
|
})
|
|
79
81
|
|
|
80
|
-
@
|
|
82
|
+
@close_was_called = false
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
private def update_options(context_options:, browser_options:)
|
|
@@ -333,6 +335,11 @@ module Playwright
|
|
|
333
335
|
update_interception_patterns
|
|
334
336
|
end
|
|
335
337
|
|
|
338
|
+
def unroute_all(behavior: nil)
|
|
339
|
+
@routes.clear
|
|
340
|
+
update_interception_patterns
|
|
341
|
+
end
|
|
342
|
+
|
|
336
343
|
def unroute(url, handler: nil)
|
|
337
344
|
@routes.reject! do |handler_entry|
|
|
338
345
|
handler_entry.same_value?(url: url, handler: handler)
|
|
@@ -382,13 +389,17 @@ module Playwright
|
|
|
382
389
|
end
|
|
383
390
|
|
|
384
391
|
def expect_event(event, predicate: nil, timeout: nil, &block)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
392
|
+
waiter = Waiter.new(self, wait_name: "browser_context.expect_event(#{event})")
|
|
393
|
+
timeout_value = timeout || @timeout_settings.timeout
|
|
394
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout}ms exceeded while waiting for event \"#{event}\"")
|
|
395
|
+
unless event == Events::BrowserContext::Close
|
|
396
|
+
waiter.reject_on_event(self, Events::BrowserContext::Close, TargetClosedError.new)
|
|
397
|
+
end
|
|
398
|
+
waiter.wait_for_event(self, event, predicate: predicate)
|
|
388
399
|
|
|
389
400
|
block&.call
|
|
390
401
|
|
|
391
|
-
|
|
402
|
+
waiter.result.value!
|
|
392
403
|
end
|
|
393
404
|
|
|
394
405
|
private def on_close
|
|
@@ -397,7 +408,18 @@ module Playwright
|
|
|
397
408
|
@closed_promise.fulfill(true)
|
|
398
409
|
end
|
|
399
410
|
|
|
400
|
-
def close
|
|
411
|
+
def close(reason: nil)
|
|
412
|
+
return if @close_was_called
|
|
413
|
+
@close_was_called = true
|
|
414
|
+
@close_reason = reason
|
|
415
|
+
|
|
416
|
+
inner_close
|
|
417
|
+
@channel.send_message_to_server('close', { reason: reason }.compact)
|
|
418
|
+
@closed_promise.value!
|
|
419
|
+
nil
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
private def inner_close
|
|
401
423
|
@har_recorders.each do |har_id, params|
|
|
402
424
|
har = ChannelOwners::Artifact.from(@channel.send_message_to_server('harExport', harId: har_id))
|
|
403
425
|
# Server side will compress artifact if content is attach or if file is .zip.
|
|
@@ -413,11 +435,6 @@ module Playwright
|
|
|
413
435
|
|
|
414
436
|
har.delete
|
|
415
437
|
end
|
|
416
|
-
@channel.send_message_to_server('close')
|
|
417
|
-
@closed_promise.value!
|
|
418
|
-
nil
|
|
419
|
-
rescue => err
|
|
420
|
-
raise unless safe_close_error?(err)
|
|
421
438
|
end
|
|
422
439
|
|
|
423
440
|
# REMARK: enable_debug_console is playwright-ruby-client specific method.
|
|
@@ -459,6 +476,10 @@ module Playwright
|
|
|
459
476
|
end
|
|
460
477
|
end
|
|
461
478
|
|
|
479
|
+
private def effective_close_reason
|
|
480
|
+
@close_reason || @browser&.send(:close_reason)
|
|
481
|
+
end
|
|
482
|
+
|
|
462
483
|
def expect_console_message(predicate: nil, timeout: nil, &block)
|
|
463
484
|
params = {
|
|
464
485
|
predicate: predicate,
|
|
@@ -502,10 +523,14 @@ module Playwright
|
|
|
502
523
|
end
|
|
503
524
|
|
|
504
525
|
# called from InputFiles
|
|
505
|
-
# @param
|
|
526
|
+
# @param filepath [string]
|
|
506
527
|
# @return [WritableStream]
|
|
507
|
-
private def create_temp_file(
|
|
508
|
-
result = @channel.send_message_to_server(
|
|
528
|
+
private def create_temp_file(filepath)
|
|
529
|
+
result = @channel.send_message_to_server(
|
|
530
|
+
'createTempFile',
|
|
531
|
+
name: File.basename(filepath),
|
|
532
|
+
lastModifiedMs: File.mtime(filepath).to_i * 1000,
|
|
533
|
+
)
|
|
509
534
|
ChannelOwners::WritableStream.from(result)
|
|
510
535
|
end
|
|
511
536
|
end
|
|
@@ -301,6 +301,7 @@ module Playwright
|
|
|
301
301
|
path: nil,
|
|
302
302
|
quality: nil,
|
|
303
303
|
scale: nil,
|
|
304
|
+
style: nil,
|
|
304
305
|
timeout: nil,
|
|
305
306
|
type: nil)
|
|
306
307
|
|
|
@@ -312,6 +313,7 @@ module Playwright
|
|
|
312
313
|
path: path,
|
|
313
314
|
quality: quality,
|
|
314
315
|
scale: scale,
|
|
316
|
+
style: style,
|
|
315
317
|
timeout: timeout,
|
|
316
318
|
type: type,
|
|
317
319
|
}.compact
|
|
@@ -71,12 +71,24 @@ module Playwright
|
|
|
71
71
|
ChannelOwners::Response.from_nullable(resp)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
class CrashedError < StandardError
|
|
75
|
+
def initialize
|
|
76
|
+
super('Navigation failed because page crashed!')
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class FrameAlreadyDetachedError < StandardError
|
|
81
|
+
def initialize
|
|
82
|
+
super('Navigating frame was detached!')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private def setup_navigation_waiter(wait_name:, timeout_value:)
|
|
87
|
+
Waiter.new(page, wait_name: "frame.#{wait_name}").tap do |waiter|
|
|
88
|
+
waiter.reject_on_event(@page, Events::Page::Close, -> { @page.send(:close_error_with_reason) })
|
|
89
|
+
waiter.reject_on_event(@page, Events::Page::Crash, CrashedError.new)
|
|
90
|
+
waiter.reject_on_event(@page, Events::Page::FrameDetached, FrameAlreadyDetachedError.new, predicate: -> (frame) { frame == self })
|
|
91
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout_value}ms exceeded.")
|
|
80
92
|
end
|
|
81
93
|
end
|
|
82
94
|
|
|
@@ -85,21 +97,30 @@ module Playwright
|
|
|
85
97
|
option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
|
|
86
98
|
time_start = Time.now
|
|
87
99
|
|
|
88
|
-
|
|
100
|
+
waiter = setup_navigation_waiter(wait_name: :expect_navigation, timeout_value: option_timeout)
|
|
89
101
|
|
|
102
|
+
to_url = url ? " to \"#{url}\"" : ''
|
|
103
|
+
waiter.log("waiting for navigation#{to_url} until '#{option_wait_until}'")
|
|
90
104
|
predicate =
|
|
91
105
|
if url
|
|
92
106
|
matcher = UrlMatcher.new(url, base_url: @page.context.send(:base_url))
|
|
93
|
-
->(event) {
|
|
107
|
+
->(event) {
|
|
108
|
+
if event['error']
|
|
109
|
+
true
|
|
110
|
+
else
|
|
111
|
+
waiter.log(" navigated to \"#{event['url']}\"")
|
|
112
|
+
matcher.match?(event['url'])
|
|
113
|
+
end
|
|
114
|
+
}
|
|
94
115
|
else
|
|
95
116
|
->(_) { true }
|
|
96
117
|
end
|
|
97
118
|
|
|
98
|
-
|
|
119
|
+
waiter.wait_for_event(@event_emitter, 'navigated', predicate: predicate)
|
|
99
120
|
|
|
100
121
|
block&.call
|
|
101
122
|
|
|
102
|
-
event =
|
|
123
|
+
event = waiter.result.value!
|
|
103
124
|
if event['error']
|
|
104
125
|
raise event['error']
|
|
105
126
|
end
|
|
@@ -135,11 +156,14 @@ module Playwright
|
|
|
135
156
|
return
|
|
136
157
|
end
|
|
137
158
|
|
|
138
|
-
|
|
159
|
+
waiter = setup_navigation_waiter(wait_name: :wait_for_load_state, timeout_value: option_timeout)
|
|
139
160
|
|
|
140
|
-
predicate = ->(
|
|
141
|
-
|
|
142
|
-
|
|
161
|
+
predicate = ->(actual_state) {
|
|
162
|
+
waiter.log("\"#{actual_state}\" event fired")
|
|
163
|
+
actual_state == option_state
|
|
164
|
+
}
|
|
165
|
+
waiter.wait_for_event(@event_emitter, 'loadstate', predicate: predicate)
|
|
166
|
+
waiter.result.value!
|
|
143
167
|
|
|
144
168
|
nil
|
|
145
169
|
end
|
|
@@ -4,7 +4,7 @@ require_relative '../locator_utils'
|
|
|
4
4
|
module Playwright
|
|
5
5
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_page.py
|
|
6
6
|
define_channel_owner :Page do
|
|
7
|
-
include Utils::Errors::
|
|
7
|
+
include Utils::Errors::TargetClosedErrorMethods
|
|
8
8
|
include LocatorUtils
|
|
9
9
|
attr_writer :owned_context
|
|
10
10
|
|
|
@@ -33,10 +33,12 @@ module Playwright
|
|
|
33
33
|
@frames = Set.new
|
|
34
34
|
@frames << @main_frame
|
|
35
35
|
@opener = ChannelOwners::Page.from_nullable(@initializer['opener'])
|
|
36
|
+
@close_reason = nil
|
|
36
37
|
|
|
37
38
|
@channel.on('bindingCall', ->(params) { on_binding(ChannelOwners::BindingCall.from(params['binding'])) })
|
|
39
|
+
@closed_or_crashed_promise = Concurrent::Promises.resolvable_future
|
|
38
40
|
@channel.once('close', ->(_) { on_close })
|
|
39
|
-
@channel.on('crash', ->(_) {
|
|
41
|
+
@channel.on('crash', ->(_) { on_crash })
|
|
40
42
|
@channel.on('download', method(:on_download))
|
|
41
43
|
@channel.on('fileChooser', ->(params) {
|
|
42
44
|
chooser = FileChooserImpl.new(
|
|
@@ -147,9 +149,19 @@ module Playwright
|
|
|
147
149
|
@closed = true
|
|
148
150
|
@browser_context.send(:remove_page, self)
|
|
149
151
|
@browser_context.send(:remove_background_page, self)
|
|
152
|
+
if @closed_or_crashed_promise.pending?
|
|
153
|
+
@closed_or_crashed_promise.fulfill(close_error_with_reason)
|
|
154
|
+
end
|
|
150
155
|
emit(Events::Page::Close)
|
|
151
156
|
end
|
|
152
157
|
|
|
158
|
+
private def on_crash
|
|
159
|
+
if @closed_or_crashed_promise.pending?
|
|
160
|
+
@closed_or_crashed_promise.fulfill(TargetClosedError.new)
|
|
161
|
+
end
|
|
162
|
+
emit(Events::Page::Crash)
|
|
163
|
+
end
|
|
164
|
+
|
|
153
165
|
private def on_download(params)
|
|
154
166
|
artifact = ChannelOwners::Artifact.from(params['artifact'])
|
|
155
167
|
download = DownloadImpl.new(
|
|
@@ -402,6 +414,11 @@ module Playwright
|
|
|
402
414
|
update_interception_patterns
|
|
403
415
|
end
|
|
404
416
|
|
|
417
|
+
def unroute_all(behavior: nil)
|
|
418
|
+
@routes.clear
|
|
419
|
+
update_interception_patterns
|
|
420
|
+
end
|
|
421
|
+
|
|
405
422
|
def unroute(url, handler: nil)
|
|
406
423
|
@routes.reject! do |handler_entry|
|
|
407
424
|
handler_entry.same_value?(url: url, handler: handler)
|
|
@@ -445,6 +462,7 @@ module Playwright
|
|
|
445
462
|
path: nil,
|
|
446
463
|
quality: nil,
|
|
447
464
|
scale: nil,
|
|
465
|
+
style: nil,
|
|
448
466
|
timeout: nil,
|
|
449
467
|
type: nil)
|
|
450
468
|
|
|
@@ -458,6 +476,7 @@ module Playwright
|
|
|
458
476
|
animations: animations,
|
|
459
477
|
caret: caret,
|
|
460
478
|
scale: scale,
|
|
479
|
+
style: style,
|
|
461
480
|
timeout: timeout,
|
|
462
481
|
}.compact
|
|
463
482
|
if mask.is_a?(Enumerable)
|
|
@@ -479,7 +498,8 @@ module Playwright
|
|
|
479
498
|
@main_frame.title
|
|
480
499
|
end
|
|
481
500
|
|
|
482
|
-
def close(runBeforeUnload: nil)
|
|
501
|
+
def close(runBeforeUnload: nil, reason: nil)
|
|
502
|
+
@close_reason = reason
|
|
483
503
|
if @owned_context
|
|
484
504
|
@owned_context.close
|
|
485
505
|
else
|
|
@@ -488,7 +508,7 @@ module Playwright
|
|
|
488
508
|
end
|
|
489
509
|
nil
|
|
490
510
|
rescue => err
|
|
491
|
-
raise if !
|
|
511
|
+
raise if !target_closed_error?(err) || !runBeforeUnload
|
|
492
512
|
end
|
|
493
513
|
|
|
494
514
|
def closed?
|
|
@@ -878,34 +898,34 @@ module Playwright
|
|
|
878
898
|
end
|
|
879
899
|
end
|
|
880
900
|
|
|
881
|
-
class AlreadyClosedError < StandardError
|
|
882
|
-
def initialize
|
|
883
|
-
super('Page closed')
|
|
884
|
-
end
|
|
885
|
-
end
|
|
886
|
-
|
|
887
901
|
class FrameAlreadyDetachedError < StandardError
|
|
888
902
|
def initialize
|
|
889
903
|
super('Navigating frame was detached!')
|
|
890
904
|
end
|
|
891
905
|
end
|
|
892
906
|
|
|
907
|
+
private def close_error_with_reason
|
|
908
|
+
reason = @close_reason || @browser_context.send(:effective_close_reason)
|
|
909
|
+
TargetClosedError.new(message: reason)
|
|
910
|
+
end
|
|
911
|
+
|
|
893
912
|
def expect_event(event, predicate: nil, timeout: nil, &block)
|
|
894
|
-
|
|
895
|
-
|
|
913
|
+
waiter = Waiter.new(self, wait_name: "Page.expect_event(#{event})")
|
|
914
|
+
timeout_value = timeout || @timeout_settings.timeout
|
|
915
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout_value}ms exceeded while waiting for event \"#{event}\"")
|
|
896
916
|
|
|
897
917
|
unless event == Events::Page::Crash
|
|
898
|
-
|
|
918
|
+
waiter.reject_on_event(self, Events::Page::Crash, CrashedError.new)
|
|
899
919
|
end
|
|
900
920
|
|
|
901
921
|
unless event == Events::Page::Close
|
|
902
|
-
|
|
922
|
+
waiter.reject_on_event(self, Events::Page::Close, -> { close_error_with_reason })
|
|
903
923
|
end
|
|
904
924
|
|
|
905
|
-
|
|
925
|
+
waiter.wait_for_event(self, event, predicate: predicate)
|
|
906
926
|
block&.call
|
|
907
927
|
|
|
908
|
-
|
|
928
|
+
waiter.result.value!
|
|
909
929
|
end
|
|
910
930
|
|
|
911
931
|
def expect_console_message(predicate: nil, timeout: nil, &block)
|
|
@@ -33,29 +33,24 @@ module Playwright
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
class PageClosedError < StandardError
|
|
37
|
-
def initialize
|
|
38
|
-
super('Page closed')
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
36
|
def expect_event(event, predicate: nil, timeout: nil, &block)
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
waiter = Waiter.new(self, wait_name: "WebSocket.expect_event(#{event})")
|
|
38
|
+
timeout_value = timeout || @parent.send(:timeout_settings).timeout
|
|
39
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout_value}ms exceeded while waiting for event \"#{event}\"")
|
|
45
40
|
|
|
46
41
|
unless event == Events::WebSocket::Close
|
|
47
|
-
|
|
42
|
+
waiter.reject_on_event(self, Events::WebSocket::Close, SocketClosedError.new)
|
|
48
43
|
end
|
|
49
44
|
|
|
50
45
|
unless event == Events::WebSocket::Error
|
|
51
|
-
|
|
46
|
+
waiter.reject_on_event(self, Events::WebSocket::Error, SocketError.new)
|
|
52
47
|
end
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
waiter.reject_on_event(@parent, 'close', -> { @parent.send(:close_error_with_reason) })
|
|
50
|
+
waiter.wait_for_event(self, event, predicate: predicate)
|
|
56
51
|
block&.call
|
|
57
52
|
|
|
58
|
-
|
|
53
|
+
waiter.result.value!
|
|
59
54
|
end
|
|
60
55
|
alias_method :wait_for_event, :expect_event
|
|
61
56
|
|
|
@@ -23,6 +23,7 @@ module Playwright
|
|
|
23
23
|
@root_object = RootChannelOwner.new(self)
|
|
24
24
|
@remote = false
|
|
25
25
|
@tracing_count = 0
|
|
26
|
+
@closed_error = nil
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
attr_reader :local_utils
|
|
@@ -41,6 +42,15 @@ module Playwright
|
|
|
41
42
|
|
|
42
43
|
def stop
|
|
43
44
|
@transport.stop
|
|
45
|
+
cleanup
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def cleanup(cause: nil)
|
|
49
|
+
@closed_error = cause || TargetClosedError.new
|
|
50
|
+
@callbacks.each_value do |callback|
|
|
51
|
+
callback.reject(@closed_error)
|
|
52
|
+
end
|
|
53
|
+
@callbacks.clear
|
|
44
54
|
end
|
|
45
55
|
|
|
46
56
|
def initialize_playwright
|
|
@@ -60,6 +70,8 @@ module Playwright
|
|
|
60
70
|
end
|
|
61
71
|
|
|
62
72
|
def async_send_message_to_server(guid, method, params, metadata: nil)
|
|
73
|
+
return if @closed_error
|
|
74
|
+
|
|
63
75
|
callback = Concurrent::Promises.resolvable_future
|
|
64
76
|
|
|
65
77
|
with_generated_id do |id|
|
|
@@ -130,6 +142,8 @@ module Playwright
|
|
|
130
142
|
end
|
|
131
143
|
|
|
132
144
|
def dispatch(msg)
|
|
145
|
+
return if @closed_error
|
|
146
|
+
|
|
133
147
|
id = msg['id']
|
|
134
148
|
if id
|
|
135
149
|
callback = @callbacks.delete(id)
|
|
@@ -139,8 +153,10 @@ module Playwright
|
|
|
139
153
|
end
|
|
140
154
|
|
|
141
155
|
error = msg['error']
|
|
142
|
-
if error
|
|
143
|
-
|
|
156
|
+
if error && !msg['result']
|
|
157
|
+
parsed_error = ::Playwright::Error.parse(error['error'])
|
|
158
|
+
parsed_error.log = msg['log']
|
|
159
|
+
callback.reject(parsed_error)
|
|
144
160
|
else
|
|
145
161
|
result = replace_guids_with_channels(msg['result'])
|
|
146
162
|
callback.fulfill(result)
|
data/lib/playwright/errors.rb
CHANGED
|
@@ -7,6 +7,11 @@ module Playwright
|
|
|
7
7
|
message: error_payload['message'],
|
|
8
8
|
stack: error_payload['stack'],
|
|
9
9
|
)
|
|
10
|
+
elsif error_payload['name'] == 'TargetClosedError'
|
|
11
|
+
TargetClosedError.new(
|
|
12
|
+
message: error_payload['message'],
|
|
13
|
+
stack: error_payload['stack'],
|
|
14
|
+
)
|
|
10
15
|
else
|
|
11
16
|
new(
|
|
12
17
|
name: error_payload['name'],
|
|
@@ -19,14 +24,20 @@ module Playwright
|
|
|
19
24
|
# @param name [String]
|
|
20
25
|
# @param message [String]
|
|
21
26
|
# @param stack [Array<String>]
|
|
22
|
-
def initialize(
|
|
23
|
-
super(
|
|
27
|
+
def initialize(message:, name: nil, stack: nil)
|
|
28
|
+
super(message)
|
|
24
29
|
@name = name
|
|
25
30
|
@message = message
|
|
26
31
|
@stack = stack
|
|
27
32
|
end
|
|
28
33
|
|
|
29
34
|
attr_reader :name, :message, :stack
|
|
35
|
+
|
|
36
|
+
def log=(log)
|
|
37
|
+
return unless log
|
|
38
|
+
format_call_log = log.join("\n - ")
|
|
39
|
+
@message = "#{@message}\nCall log:\n#{format_call_log}\n"
|
|
40
|
+
end
|
|
30
41
|
end
|
|
31
42
|
|
|
32
43
|
class DriverCrashedError < StandardError
|
|
@@ -41,6 +52,13 @@ module Playwright
|
|
|
41
52
|
end
|
|
42
53
|
end
|
|
43
54
|
|
|
55
|
+
class TargetClosedError < Error
|
|
56
|
+
def initialize(message: nil, stack: [])
|
|
57
|
+
_message = message || 'Target page, context or browser has been closed'
|
|
58
|
+
super(name: 'TargetClosedError', message: _message, stack: stack)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
44
62
|
class WebError
|
|
45
63
|
def initialize(error, page)
|
|
46
64
|
@error = error
|
|
@@ -15,7 +15,7 @@ module Playwright
|
|
|
15
15
|
|
|
16
16
|
def as_method_and_params
|
|
17
17
|
if has_large_file?
|
|
18
|
-
['
|
|
18
|
+
['setInputFiles', params_for_set_input_file_paths]
|
|
19
19
|
else
|
|
20
20
|
['setInputFiles', params_for_set_input_files]
|
|
21
21
|
end
|
|
@@ -40,7 +40,7 @@ module Playwright
|
|
|
40
40
|
writable_streams = @files.map do |file|
|
|
41
41
|
case file
|
|
42
42
|
when String
|
|
43
|
-
writable_stream = @context.send(:create_temp_file,
|
|
43
|
+
writable_stream = @context.send(:create_temp_file, file)
|
|
44
44
|
|
|
45
45
|
File.open(file, 'rb') do |file|
|
|
46
46
|
writable_stream.write(file)
|
|
@@ -48,7 +48,7 @@ module Playwright
|
|
|
48
48
|
|
|
49
49
|
writable_stream.channel
|
|
50
50
|
when File
|
|
51
|
-
writable_stream = @context.send(:create_temp_file,
|
|
51
|
+
writable_stream = @context.send(:create_temp_file, file.path)
|
|
52
52
|
writable_stream.write(file)
|
|
53
53
|
|
|
54
54
|
writable_stream.channel
|
|
@@ -78,7 +78,7 @@ module Playwright
|
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
{
|
|
81
|
+
{ payloads: file_payloads }
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
private def raise_argument_error
|