playwright-ruby-client 1.39.1 → 1.40.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +1 -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 +4 -1
- data/documentation/docs/api/frame.md +4 -1
- data/documentation/docs/api/locator.md +4 -1
- data/documentation/docs/api/locator_assertions.md +11 -1
- data/documentation/docs/api/page.md +6 -3
- data/documentation/docs/article/guides/rails_integration.md +80 -51
- data/documentation/docs/article/guides/rspec_integration.md +59 -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 +35 -15
- data/lib/playwright/channel_owners/frame.rb +38 -14
- data/lib/playwright/channel_owners/page.rb +29 -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/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 +3 -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 +4 -1
- data/lib/playwright_api/frame.rb +4 -1
- data/lib/playwright_api/locator.rb +4 -1
- data/lib/playwright_api/locator_assertions.rb +12 -2
- data/lib/playwright_api/page.rb +16 -13
- data/lib/playwright_api/request.rb +4 -4
- data/lib/playwright_api/worker.rb +4 -4
- data/sig/playwright.rbs +6 -6
- metadata +5 -4
- 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:)
|
@@ -382,13 +384,17 @@ module Playwright
|
|
382
384
|
end
|
383
385
|
|
384
386
|
def expect_event(event, predicate: nil, timeout: nil, &block)
|
385
|
-
|
386
|
-
|
387
|
-
|
387
|
+
waiter = Waiter.new(self, wait_name: "browser_context.expect_event(#{event})")
|
388
|
+
timeout_value = timeout || @timeout_settings.timeout
|
389
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout}ms exceeded while waiting for event \"#{event}\"")
|
390
|
+
unless event == Events::BrowserContext::Close
|
391
|
+
waiter.reject_on_event(self, Events::BrowserContext::Close, TargetClosedError.new)
|
392
|
+
end
|
393
|
+
waiter.wait_for_event(self, event, predicate: predicate)
|
388
394
|
|
389
395
|
block&.call
|
390
396
|
|
391
|
-
|
397
|
+
waiter.result.value!
|
392
398
|
end
|
393
399
|
|
394
400
|
private def on_close
|
@@ -397,7 +403,18 @@ module Playwright
|
|
397
403
|
@closed_promise.fulfill(true)
|
398
404
|
end
|
399
405
|
|
400
|
-
def close
|
406
|
+
def close(reason: nil)
|
407
|
+
return if @close_was_called
|
408
|
+
@close_was_called = true
|
409
|
+
@close_reason = reason
|
410
|
+
|
411
|
+
inner_close
|
412
|
+
@channel.send_message_to_server('close', { reason: reason }.compact)
|
413
|
+
@closed_promise.value!
|
414
|
+
nil
|
415
|
+
end
|
416
|
+
|
417
|
+
private def inner_close
|
401
418
|
@har_recorders.each do |har_id, params|
|
402
419
|
har = ChannelOwners::Artifact.from(@channel.send_message_to_server('harExport', harId: har_id))
|
403
420
|
# Server side will compress artifact if content is attach or if file is .zip.
|
@@ -413,11 +430,6 @@ module Playwright
|
|
413
430
|
|
414
431
|
har.delete
|
415
432
|
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
433
|
end
|
422
434
|
|
423
435
|
# REMARK: enable_debug_console is playwright-ruby-client specific method.
|
@@ -459,6 +471,10 @@ module Playwright
|
|
459
471
|
end
|
460
472
|
end
|
461
473
|
|
474
|
+
private def effective_close_reason
|
475
|
+
@close_reason || @browser&.send(:close_reason)
|
476
|
+
end
|
477
|
+
|
462
478
|
def expect_console_message(predicate: nil, timeout: nil, &block)
|
463
479
|
params = {
|
464
480
|
predicate: predicate,
|
@@ -502,10 +518,14 @@ module Playwright
|
|
502
518
|
end
|
503
519
|
|
504
520
|
# called from InputFiles
|
505
|
-
# @param
|
521
|
+
# @param filepath [string]
|
506
522
|
# @return [WritableStream]
|
507
|
-
private def create_temp_file(
|
508
|
-
result = @channel.send_message_to_server(
|
523
|
+
private def create_temp_file(filepath)
|
524
|
+
result = @channel.send_message_to_server(
|
525
|
+
'createTempFile',
|
526
|
+
name: File.basename(filepath),
|
527
|
+
lastModifiedMs: File.mtime(filepath).to_i * 1000,
|
528
|
+
)
|
509
529
|
ChannelOwners::WritableStream.from(result)
|
510
530
|
end
|
511
531
|
end
|
@@ -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(
|
@@ -479,7 +491,8 @@ module Playwright
|
|
479
491
|
@main_frame.title
|
480
492
|
end
|
481
493
|
|
482
|
-
def close(runBeforeUnload: nil)
|
494
|
+
def close(runBeforeUnload: nil, reason: nil)
|
495
|
+
@close_reason = reason
|
483
496
|
if @owned_context
|
484
497
|
@owned_context.close
|
485
498
|
else
|
@@ -488,7 +501,7 @@ module Playwright
|
|
488
501
|
end
|
489
502
|
nil
|
490
503
|
rescue => err
|
491
|
-
raise if !
|
504
|
+
raise if !target_closed_error?(err) || !runBeforeUnload
|
492
505
|
end
|
493
506
|
|
494
507
|
def closed?
|
@@ -878,34 +891,34 @@ module Playwright
|
|
878
891
|
end
|
879
892
|
end
|
880
893
|
|
881
|
-
class AlreadyClosedError < StandardError
|
882
|
-
def initialize
|
883
|
-
super('Page closed')
|
884
|
-
end
|
885
|
-
end
|
886
|
-
|
887
894
|
class FrameAlreadyDetachedError < StandardError
|
888
895
|
def initialize
|
889
896
|
super('Navigating frame was detached!')
|
890
897
|
end
|
891
898
|
end
|
892
899
|
|
900
|
+
private def close_error_with_reason
|
901
|
+
reason = @close_reason || @browser_context.send(:effective_close_reason)
|
902
|
+
TargetClosedError.new(message: reason)
|
903
|
+
end
|
904
|
+
|
893
905
|
def expect_event(event, predicate: nil, timeout: nil, &block)
|
894
|
-
|
895
|
-
|
906
|
+
waiter = Waiter.new(self, wait_name: "Page.expect_event(#{event})")
|
907
|
+
timeout_value = timeout || @timeout_settings.timeout
|
908
|
+
waiter.reject_on_timeout(timeout_value, "Timeout #{timeout_value}ms exceeded while waiting for event \"#{event}\"")
|
896
909
|
|
897
910
|
unless event == Events::Page::Crash
|
898
|
-
|
911
|
+
waiter.reject_on_event(self, Events::Page::Crash, CrashedError.new)
|
899
912
|
end
|
900
913
|
|
901
914
|
unless event == Events::Page::Close
|
902
|
-
|
915
|
+
waiter.reject_on_event(self, Events::Page::Close, -> { close_error_with_reason })
|
903
916
|
end
|
904
917
|
|
905
|
-
|
918
|
+
waiter.wait_for_event(self, event, predicate: predicate)
|
906
919
|
block&.call
|
907
920
|
|
908
|
-
|
921
|
+
waiter.result.value!
|
909
922
|
end
|
910
923
|
|
911
924
|
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
|
@@ -79,7 +79,7 @@ module Playwright
|
|
79
79
|
expected
|
80
80
|
end
|
81
81
|
|
82
|
-
private def to_expected_text_values(items, match_substring
|
82
|
+
private def to_expected_text_values(items, match_substring: false, normalize_white_space: false, ignore_case: false)
|
83
83
|
return [] unless items.respond_to?(:each)
|
84
84
|
|
85
85
|
items.each.with_object([]) do |item, out|
|
@@ -109,9 +109,9 @@ module Playwright
|
|
109
109
|
if expected.respond_to?(:each)
|
110
110
|
expected_text = to_expected_text_values(
|
111
111
|
expected,
|
112
|
-
true,
|
113
|
-
true,
|
114
|
-
ignoreCase,
|
112
|
+
match_substring: true,
|
113
|
+
normalize_white_space: true,
|
114
|
+
ignore_case: ignoreCase,
|
115
115
|
)
|
116
116
|
|
117
117
|
expect_impl(
|
@@ -127,9 +127,9 @@ module Playwright
|
|
127
127
|
else
|
128
128
|
expected_text = to_expected_text_values(
|
129
129
|
[expected],
|
130
|
-
true,
|
131
|
-
true,
|
132
|
-
ignoreCase
|
130
|
+
match_substring: true,
|
131
|
+
normalize_white_space: true,
|
132
|
+
ignore_case: ignoreCase,
|
133
133
|
)
|
134
134
|
|
135
135
|
expect_impl(
|
@@ -146,8 +146,8 @@ module Playwright
|
|
146
146
|
end
|
147
147
|
_define_negation :to_contain_text
|
148
148
|
|
149
|
-
def to_have_attribute(name, value, timeout: nil)
|
150
|
-
expected_text = to_expected_text_values([value])
|
149
|
+
def to_have_attribute(name, value, ignoreCase: nil, timeout: nil)
|
150
|
+
expected_text = to_expected_text_values([value], ignore_case: ignoreCase)
|
151
151
|
expect_impl(
|
152
152
|
"to.have.attribute.value",
|
153
153
|
{
|
@@ -278,9 +278,9 @@ module Playwright
|
|
278
278
|
if expected.respond_to?(:each)
|
279
279
|
expected_text = to_expected_text_values(
|
280
280
|
expected,
|
281
|
-
true,
|
282
|
-
true,
|
283
|
-
ignoreCase,
|
281
|
+
match_substring: true,
|
282
|
+
normalize_white_space: true,
|
283
|
+
ignore_case: ignoreCase,
|
284
284
|
)
|
285
285
|
expect_impl(
|
286
286
|
"to.have.text.array",
|
@@ -295,9 +295,9 @@ module Playwright
|
|
295
295
|
else
|
296
296
|
expected_text = to_expected_text_values(
|
297
297
|
[expected],
|
298
|
-
true,
|
299
|
-
true,
|
300
|
-
ignoreCase,
|
298
|
+
match_substring: true,
|
299
|
+
normalize_white_space: true,
|
300
|
+
ignore_case: ignoreCase,
|
301
301
|
)
|
302
302
|
expect_impl(
|
303
303
|
"to.have.text",
|
data/lib/playwright/test.rb
CHANGED
@@ -60,9 +60,9 @@ module Playwright
|
|
60
60
|
# to_be_visible => be_visible
|
61
61
|
# not_to_be_visible => not_be_visible
|
62
62
|
root_method_name = method_name.gsub("to_", "")
|
63
|
-
Matchers.define_method
|
63
|
+
Matchers.send(:define_method, root_method_name) do |*args, **kwargs|
|
64
64
|
Matchers::PlaywrightMatcher.new(method_name, *args, **kwargs)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|