playwright-ruby-client 1.59.1 → 1.60.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.md +25 -1
- data/documentation/docs/api/api_request_context.md +13 -11
- data/documentation/docs/api/browser.md +18 -0
- data/documentation/docs/api/browser_context.md +1 -1
- data/documentation/docs/api/browser_type.md +18 -0
- data/documentation/docs/api/frame.md +1 -0
- data/documentation/docs/api/frame_locator.md +1 -0
- data/documentation/docs/api/locator.md +37 -2
- data/documentation/docs/api/locator_assertions.md +1 -1
- data/documentation/docs/api/page.md +12 -2
- data/documentation/docs/api/page_assertions.md +28 -0
- data/documentation/docs/api/playwright.md +5 -0
- data/documentation/docs/api/tracing.md +29 -0
- data/documentation/docs/include/api_coverage.md +14 -60
- data/lib/playwright/api_request_impl.rb +70 -0
- data/lib/playwright/channel_owners/api_request_context.rb +5 -1
- data/lib/playwright/channel_owners/binding_call.rb +3 -9
- data/lib/playwright/channel_owners/browser.rb +17 -0
- data/lib/playwright/channel_owners/browser_context.rb +10 -54
- data/lib/playwright/channel_owners/browser_type.rb +34 -1
- data/lib/playwright/channel_owners/frame.rb +89 -3
- data/lib/playwright/channel_owners/json_pipe.rb +4 -0
- data/lib/playwright/channel_owners/local_utils.rb +11 -2
- data/lib/playwright/channel_owners/page.rb +16 -11
- data/lib/playwright/channel_owners/playwright.rb +4 -0
- data/lib/playwright/channel_owners/tracing.rb +105 -4
- data/lib/playwright/connection.rb +5 -1
- data/lib/playwright/console_message_impl.rb +10 -1
- data/lib/playwright/errors.rb +3 -2
- data/lib/playwright/events.rb +7 -0
- data/lib/playwright/json_pipe_transport.rb +40 -0
- data/lib/playwright/locator_assertions_impl.rb +21 -4
- data/lib/playwright/locator_impl.rb +17 -3
- data/lib/playwright/locator_utils.rb +2 -0
- data/lib/playwright/page_assertions_impl.rb +33 -3
- data/lib/playwright/screencast.rb +5 -1
- data/lib/playwright/url_matcher.rb +35 -0
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright.rb +1 -0
- data/lib/playwright_api/api_request.rb +1 -1
- data/lib/playwright_api/api_request_context.rb +15 -11
- data/lib/playwright_api/browser.rb +2 -2
- data/lib/playwright_api/browser_context.rb +7 -7
- data/lib/playwright_api/browser_type.rb +5 -3
- data/lib/playwright_api/frame.rb +18 -7
- data/lib/playwright_api/frame_locator.rb +2 -1
- data/lib/playwright_api/locator.rb +34 -5
- data/lib/playwright_api/locator_assertions.rb +2 -2
- data/lib/playwright_api/page.rb +27 -20
- data/lib/playwright_api/page_assertions.rb +22 -0
- data/lib/playwright_api/playwright.rb +1 -1
- data/lib/playwright_api/tracing.rb +23 -0
- data/sig/playwright.rbs +35 -43
- metadata +5 -12
- data/documentation/docs/api/experimental/android.md +0 -42
- data/documentation/docs/api/experimental/android_device.md +0 -109
- data/documentation/docs/api/experimental/android_input.md +0 -43
- data/documentation/docs/api/experimental/android_socket.md +0 -7
- data/documentation/docs/api/experimental/android_web_view.md +0 -7
- data/lib/playwright_api/android.rb +0 -68
- data/lib/playwright_api/android_device.rb +0 -229
- data/lib/playwright_api/android_input.rb +0 -34
- data/lib/playwright_api/android_socket.rb +0 -18
- data/lib/playwright_api/android_web_view.rb +0 -24
|
@@ -20,7 +20,6 @@ module Playwright
|
|
|
20
20
|
@request = ChannelOwners::APIRequestContext.from(@initializer['requestContext'])
|
|
21
21
|
@request.send(:_update_timeout_settings, @timeout_settings)
|
|
22
22
|
@clock = ClockImpl.new(self)
|
|
23
|
-
@har_recorders = {}
|
|
24
23
|
|
|
25
24
|
@channel.on('bindingCall', ->(params) { on_binding(ChannelOwners::BindingCall.from(params['binding'])) })
|
|
26
25
|
@channel.once('close', ->(_) { on_close })
|
|
@@ -34,8 +33,9 @@ module Playwright
|
|
|
34
33
|
})
|
|
35
34
|
@channel.on('pageError', ->(params) {
|
|
36
35
|
on_page_error(
|
|
37
|
-
Error.parse(params
|
|
36
|
+
Error.parse(params.dig('error', 'error') || params['error']),
|
|
38
37
|
ChannelOwners::Page.from_nullable(params['page']),
|
|
38
|
+
params['location'],
|
|
39
39
|
)
|
|
40
40
|
})
|
|
41
41
|
@channel.on('dialog', ->(params) {
|
|
@@ -82,7 +82,7 @@ module Playwright
|
|
|
82
82
|
|
|
83
83
|
default_policy = record_har_path.end_with?('.zip') ? 'attach' : 'embed'
|
|
84
84
|
content_policy = record_har_content || (record_har_omit_content ? 'omit' : default_policy)
|
|
85
|
-
record_into_har
|
|
85
|
+
@tracing.send(:record_into_har, record_har_path, nil,
|
|
86
86
|
url: record_har_url_filter,
|
|
87
87
|
update_content: content_policy,
|
|
88
88
|
update_mode: record_har_mode || 'full',
|
|
@@ -186,8 +186,8 @@ module Playwright
|
|
|
186
186
|
end
|
|
187
187
|
end
|
|
188
188
|
|
|
189
|
-
private def on_page_error(error, page)
|
|
190
|
-
emit(Events::BrowserContext::WebError, WebError.new(error, page))
|
|
189
|
+
private def on_page_error(error, page, location)
|
|
190
|
+
emit(Events::BrowserContext::WebError, WebError.new(error, page, location))
|
|
191
191
|
if page
|
|
192
192
|
page.emit(Events::Page::PageError, error)
|
|
193
193
|
end
|
|
@@ -337,19 +337,15 @@ module Playwright
|
|
|
337
337
|
ChannelOwners::Disposable.from(result['disposable'])
|
|
338
338
|
end
|
|
339
339
|
|
|
340
|
-
def expose_binding(name, callback
|
|
340
|
+
def expose_binding(name, callback)
|
|
341
341
|
if @pages.any? { |page| page.send(:has_bindings?, name) }
|
|
342
342
|
raise ArgumentError.new("Function \"#{name}\" has been already registered in one of the pages")
|
|
343
343
|
end
|
|
344
344
|
if @bindings.key?(name)
|
|
345
345
|
raise ArgumentError.new("Function \"#{name}\" has been already registered")
|
|
346
346
|
end
|
|
347
|
-
params = {
|
|
348
|
-
name: name,
|
|
349
|
-
needsHandle: handle,
|
|
350
|
-
}.compact
|
|
351
347
|
@bindings[name] = callback
|
|
352
|
-
result = @channel.send_message_to_server_result('exposeBinding',
|
|
348
|
+
result = @channel.send_message_to_server_result('exposeBinding', name: name)
|
|
353
349
|
ChannelOwners::Disposable.from(result['disposable'])
|
|
354
350
|
end
|
|
355
351
|
|
|
@@ -376,32 +372,9 @@ module Playwright
|
|
|
376
372
|
update_interception_patterns
|
|
377
373
|
end
|
|
378
374
|
|
|
379
|
-
private def record_into_har(har, page, url:, update_content:, update_mode:)
|
|
380
|
-
options = {
|
|
381
|
-
zip: har.end_with?('.zip'),
|
|
382
|
-
content: update_content || 'attach',
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if url.is_a?(Regexp)
|
|
386
|
-
regex = ::Playwright::JavaScript::Regex.new(url)
|
|
387
|
-
options[:urlRegexSource] = regex.source
|
|
388
|
-
options[:urlRegexFlags] = regex.flag
|
|
389
|
-
elsif url.is_a?(String)
|
|
390
|
-
options[:urlGlob] = url
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
params = { options: options }
|
|
394
|
-
if page
|
|
395
|
-
params[:page] = page.channel
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
har_id = @channel.send_message_to_server('harStart', params)
|
|
399
|
-
@har_recorders[har_id] = { path: har, content: update_content || 'attach' }
|
|
400
|
-
end
|
|
401
|
-
|
|
402
375
|
def route_from_har(har, notFound: nil, update: nil, updateContent: nil, updateMode: nil, url: nil)
|
|
403
376
|
if update
|
|
404
|
-
record_into_har
|
|
377
|
+
@tracing.send(:record_into_har, har, nil, url: url, update_content: updateContent, update_mode: updateMode)
|
|
405
378
|
return
|
|
406
379
|
end
|
|
407
380
|
|
|
@@ -443,6 +416,7 @@ module Playwright
|
|
|
443
416
|
@browser.send(:remove_context, self)
|
|
444
417
|
@browser.browser_type.send(:playwright_selectors_browser_contexts).delete(self)
|
|
445
418
|
end
|
|
419
|
+
@tracing.send(:reset_stack_counter)
|
|
446
420
|
emit(Events::BrowserContext::Close)
|
|
447
421
|
@closed_promise.fulfill(true)
|
|
448
422
|
end
|
|
@@ -452,30 +426,12 @@ module Playwright
|
|
|
452
426
|
@close_was_called = true
|
|
453
427
|
@close_reason = reason
|
|
454
428
|
@request.dispose(reason: reason)
|
|
455
|
-
|
|
429
|
+
@tracing.send(:export_all_hars)
|
|
456
430
|
@channel.send_message_to_server('close', { reason: reason }.compact)
|
|
457
431
|
@closed_promise.value!
|
|
458
432
|
nil
|
|
459
433
|
end
|
|
460
434
|
|
|
461
|
-
private def inner_close
|
|
462
|
-
@har_recorders.each do |har_id, params|
|
|
463
|
-
har = ChannelOwners::Artifact.from(@channel.send_message_to_server('harExport', harId: har_id))
|
|
464
|
-
# Server side will compress artifact if content is attach or if file is .zip.
|
|
465
|
-
compressed = params[:content] == "attach" || params[:path].end_with?('.zip')
|
|
466
|
-
need_comppressed = params[:path].end_with?('.zip')
|
|
467
|
-
if compressed && !need_comppressed
|
|
468
|
-
tmp_path = "#{params[:path]}.tmp"
|
|
469
|
-
har.save_as(tmp_path)
|
|
470
|
-
@connection.local_utils.har_unzip(tmp_path, params[:path])
|
|
471
|
-
else
|
|
472
|
-
har.save_as(params[:path])
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
har.delete
|
|
476
|
-
end
|
|
477
|
-
end
|
|
478
|
-
|
|
479
435
|
# REMARK: enable_debug_console is playwright-ruby-client specific method.
|
|
480
436
|
def enable_debug_console!
|
|
481
437
|
# Ruby is not supported in Playwright officially,
|
|
@@ -43,6 +43,7 @@ module Playwright
|
|
|
43
43
|
browser = ChannelOwners::Browser.from(result['browser'])
|
|
44
44
|
browser.send(:connect_to_browser_type, self, params[:tracesDir])
|
|
45
45
|
context = ChannelOwners::BrowserContext.from(result['context'])
|
|
46
|
+
context.send(:update_options, context_options: params, browser_options: params)
|
|
46
47
|
context.send(:initialize_har_from_options,
|
|
47
48
|
record_har_content: params[:record_har_content],
|
|
48
49
|
record_har_mode: params[:record_har_mode],
|
|
@@ -60,13 +61,45 @@ module Playwright
|
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
63
|
|
|
63
|
-
def
|
|
64
|
+
def connect(endpoint, exposeNetwork: nil, headers: nil, slowMo: nil, timeout: nil, &block)
|
|
65
|
+
params = {
|
|
66
|
+
endpoint: endpoint,
|
|
67
|
+
headers: { 'x-playwright-browser' => name }.merge(headers || {}),
|
|
68
|
+
exposeNetwork: exposeNetwork,
|
|
69
|
+
slowMo: slowMo,
|
|
70
|
+
timeout: @timeout_settings.timeout(timeout),
|
|
71
|
+
}.compact
|
|
72
|
+
|
|
73
|
+
transport = JsonPipeTransport.new(@connection.local_utils, params)
|
|
74
|
+
connection = Connection.new(transport)
|
|
75
|
+
connection.mark_as_remote
|
|
76
|
+
connection.async_run
|
|
77
|
+
|
|
78
|
+
playwright = connection.initialize_playwright
|
|
79
|
+
browser = playwright.send(:pre_launched_browser)
|
|
80
|
+
browser.send(:should_close_connection_on_close!)
|
|
81
|
+
browser.send(:connect_to_browser_type, self, nil)
|
|
82
|
+
|
|
83
|
+
return browser unless block
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
block.call(browser)
|
|
87
|
+
ensure
|
|
88
|
+
browser.close
|
|
89
|
+
end
|
|
90
|
+
rescue
|
|
91
|
+
connection&.stop
|
|
92
|
+
raise
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def connect_over_cdp(endpointURL, headers: nil, isLocal: nil, noDefaults: nil, slowMo: nil, timeout: nil, &block)
|
|
64
96
|
raise 'Connecting over CDP is only supported in Chromium.' unless name == 'chromium'
|
|
65
97
|
|
|
66
98
|
params = {
|
|
67
99
|
endpointURL: endpointURL,
|
|
68
100
|
headers: headers,
|
|
69
101
|
isLocal: isLocal,
|
|
102
|
+
noDefaults: noDefaults,
|
|
70
103
|
slowMo: slowMo,
|
|
71
104
|
timeout: @timeout_settings.timeout(timeout),
|
|
72
105
|
}.compact
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'base64'
|
|
1
2
|
require_relative '../locator_utils'
|
|
2
3
|
|
|
3
4
|
module Playwright
|
|
@@ -47,6 +48,7 @@ module Playwright
|
|
|
47
48
|
unless @parent_frame
|
|
48
49
|
if add == 'load'
|
|
49
50
|
@page&.emit(Events::Page::Load, @page)
|
|
51
|
+
@page&.context&.emit(Events::BrowserContext::PageLoad, @page)
|
|
50
52
|
elsif add == 'domcontentloaded'
|
|
51
53
|
@page&.emit(Events::Page::DOMContentLoaded, @page)
|
|
52
54
|
end
|
|
@@ -65,6 +67,7 @@ module Playwright
|
|
|
65
67
|
|
|
66
68
|
unless event['error']
|
|
67
69
|
@page&.emit(Events::Page::FrameNavigated, self)
|
|
70
|
+
@page&.context&.emit(Events::BrowserContext::FrameNavigated, self)
|
|
68
71
|
end
|
|
69
72
|
end
|
|
70
73
|
|
|
@@ -388,6 +391,23 @@ module Playwright
|
|
|
388
391
|
nil
|
|
389
392
|
end
|
|
390
393
|
|
|
394
|
+
def drop(
|
|
395
|
+
selector,
|
|
396
|
+
payload,
|
|
397
|
+
position: nil,
|
|
398
|
+
strict: nil,
|
|
399
|
+
timeout: nil)
|
|
400
|
+
params = {
|
|
401
|
+
selector: selector,
|
|
402
|
+
position: position,
|
|
403
|
+
strict: strict,
|
|
404
|
+
timeout: _timeout(timeout),
|
|
405
|
+
}.compact.merge(drop_payload_params(payload))
|
|
406
|
+
@channel.send_message_to_server('drop', params)
|
|
407
|
+
|
|
408
|
+
nil
|
|
409
|
+
end
|
|
410
|
+
|
|
391
411
|
def dblclick(
|
|
392
412
|
selector,
|
|
393
413
|
button: nil,
|
|
@@ -690,8 +710,12 @@ module Playwright
|
|
|
690
710
|
@channel.send_message_to_server('title')
|
|
691
711
|
end
|
|
692
712
|
|
|
693
|
-
def highlight(selector)
|
|
694
|
-
@channel.send_message_to_server('highlight', selector: selector)
|
|
713
|
+
def highlight(selector, style: nil)
|
|
714
|
+
@channel.send_message_to_server('highlight', { selector: selector, style: style }.compact)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def hide_highlight(selector)
|
|
718
|
+
@channel.send_message_to_server('hideHighlight', selector: selector)
|
|
695
719
|
end
|
|
696
720
|
|
|
697
721
|
def expect(selector, expression, options, title)
|
|
@@ -712,12 +736,74 @@ module Playwright
|
|
|
712
736
|
)
|
|
713
737
|
|
|
714
738
|
if result.key?('received')
|
|
715
|
-
result['received']
|
|
739
|
+
if result['received'].is_a?(Hash) && result['received'].key?('value')
|
|
740
|
+
result['received']['value'] = JavaScript::ValueParser.new(result['received']['value']).parse
|
|
741
|
+
elsif !result['received'].is_a?(Hash)
|
|
742
|
+
result['received'] = JavaScript::ValueParser.new(result['received']).parse
|
|
743
|
+
end
|
|
716
744
|
end
|
|
717
745
|
|
|
718
746
|
result
|
|
719
747
|
end
|
|
720
748
|
|
|
749
|
+
private def drop_payload_params(payload)
|
|
750
|
+
unless payload.is_a?(Hash)
|
|
751
|
+
raise ArgumentError.new('payload must be a Hash')
|
|
752
|
+
end
|
|
753
|
+
unless payload.key?(:files) || payload.key?('files') || payload.key?(:data) || payload.key?('data')
|
|
754
|
+
raise ArgumentError.new('At least one of "files" or "data" must be specified')
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
params = {}
|
|
758
|
+
files = payload[:files] || payload['files']
|
|
759
|
+
params[:payloads] = drop_file_payloads(files) if files
|
|
760
|
+
|
|
761
|
+
data = payload[:data] || payload['data']
|
|
762
|
+
if data
|
|
763
|
+
params[:data] = data.map do |mime_type, value|
|
|
764
|
+
{ mimeType: mime_type, value: value }
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
params
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
private def drop_file_payloads(files)
|
|
772
|
+
items =
|
|
773
|
+
if files.is_a?(Array)
|
|
774
|
+
files
|
|
775
|
+
else
|
|
776
|
+
[files]
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
if items.any? { |item| item.is_a?(String) || item.is_a?(File) }
|
|
780
|
+
unless items.all? { |item| item.is_a?(String) || item.is_a?(File) }
|
|
781
|
+
raise ArgumentError.new('File paths cannot be mixed with buffers')
|
|
782
|
+
end
|
|
783
|
+
return items.map do |item|
|
|
784
|
+
path = item.is_a?(File) ? item.path : item
|
|
785
|
+
raise ArgumentError.new('Dropping a directory is not supported - pass individual files.') if File.directory?(path)
|
|
786
|
+
|
|
787
|
+
{
|
|
788
|
+
name: File.basename(path),
|
|
789
|
+
buffer: Base64.strict_encode64(File.binread(path)),
|
|
790
|
+
}
|
|
791
|
+
end
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
items.map do |item|
|
|
795
|
+
unless item.is_a?(Hash)
|
|
796
|
+
raise ArgumentError.new('files must be file paths or file payload hashes')
|
|
797
|
+
end
|
|
798
|
+
buffer = item[:buffer] || item['buffer']
|
|
799
|
+
{
|
|
800
|
+
name: item[:name] || item['name'],
|
|
801
|
+
mimeType: item[:mimeType] || item['mimeType'],
|
|
802
|
+
buffer: Base64.strict_encode64(buffer),
|
|
803
|
+
}.compact
|
|
804
|
+
end
|
|
805
|
+
end
|
|
806
|
+
|
|
721
807
|
# @param page [Page]
|
|
722
808
|
# @note This method should be used internally. Accessed via .send method, so keep private!
|
|
723
809
|
private def update_page_from_page(page)
|
|
@@ -37,8 +37,12 @@ module Playwright
|
|
|
37
37
|
@channel.async_send_message_to_server('harClose', harId: har_id)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def har_unzip(zip_file, har_file)
|
|
41
|
-
@channel.send_message_to_server('harUnzip',
|
|
40
|
+
def har_unzip(zip_file, har_file, resources_dir: nil)
|
|
41
|
+
@channel.send_message_to_server('harUnzip', {
|
|
42
|
+
zipFile: zip_file,
|
|
43
|
+
harFile: har_file,
|
|
44
|
+
resourcesDir: resources_dir,
|
|
45
|
+
}.compact)
|
|
42
46
|
end
|
|
43
47
|
|
|
44
48
|
def tracing_started(traces_dir, trace_name)
|
|
@@ -58,6 +62,11 @@ module Playwright
|
|
|
58
62
|
nil
|
|
59
63
|
end
|
|
60
64
|
|
|
65
|
+
def connect(params)
|
|
66
|
+
result = @channel.send_message_to_server_result('connect', params)
|
|
67
|
+
ChannelOwners::JsonPipe.from(result['pipe'])
|
|
68
|
+
end
|
|
69
|
+
|
|
61
70
|
private def parse_device_descriptor(descriptor)
|
|
62
71
|
# This return value can be passed into Browser#new_context as it is.
|
|
63
72
|
# ex:
|
|
@@ -53,7 +53,7 @@ module Playwright
|
|
|
53
53
|
on_frame_detached(ChannelOwners::Frame.from(params['frame']))
|
|
54
54
|
})
|
|
55
55
|
@channel.on('pageError', ->(params) {
|
|
56
|
-
emit(Events::Page::PageError, Error.parse(params
|
|
56
|
+
emit(Events::Page::PageError, Error.parse(params.dig('error', 'error') || params['error']))
|
|
57
57
|
})
|
|
58
58
|
@channel.on('route', ->(params) { on_route(ChannelOwners::Route.from(params['route'])) })
|
|
59
59
|
if @initializer['video']
|
|
@@ -90,12 +90,14 @@ module Playwright
|
|
|
90
90
|
frame.send(:update_page_from_page, self)
|
|
91
91
|
@frames << frame
|
|
92
92
|
emit(Events::Page::FrameAttached, frame)
|
|
93
|
+
@browser_context.emit(Events::BrowserContext::FrameAttached, frame)
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
private def on_frame_detached(frame)
|
|
96
97
|
@frames.delete(frame)
|
|
97
98
|
frame.detached = true
|
|
98
99
|
emit(Events::Page::FrameDetached, frame)
|
|
100
|
+
@browser_context.emit(Events::BrowserContext::FrameDetached, frame)
|
|
99
101
|
end
|
|
100
102
|
|
|
101
103
|
private def on_route(route)
|
|
@@ -153,6 +155,7 @@ module Playwright
|
|
|
153
155
|
@closed_or_crashed_promise.fulfill(close_error_with_reason)
|
|
154
156
|
end
|
|
155
157
|
emit(Events::Page::Close)
|
|
158
|
+
@browser_context.emit(Events::BrowserContext::PageClose, self)
|
|
156
159
|
end
|
|
157
160
|
|
|
158
161
|
private def on_crash
|
|
@@ -171,6 +174,7 @@ module Playwright
|
|
|
171
174
|
artifact: artifact,
|
|
172
175
|
)
|
|
173
176
|
emit(Events::Page::Download, download)
|
|
177
|
+
@browser_context.emit(Events::BrowserContext::Download, download)
|
|
174
178
|
end
|
|
175
179
|
|
|
176
180
|
private def on_viewport_size_changed(params)
|
|
@@ -309,12 +313,8 @@ module Playwright
|
|
|
309
313
|
ChannelOwners::Disposable.from(result['disposable'])
|
|
310
314
|
end
|
|
311
315
|
|
|
312
|
-
def expose_binding(name, callback
|
|
313
|
-
|
|
314
|
-
name: name,
|
|
315
|
-
needsHandle: handle,
|
|
316
|
-
}.compact
|
|
317
|
-
result = @channel.send_message_to_server_result('exposeBinding', params)
|
|
316
|
+
def expose_binding(name, callback)
|
|
317
|
+
result = @channel.send_message_to_server_result('exposeBinding', name: name)
|
|
318
318
|
@bindings[name] = callback
|
|
319
319
|
ChannelOwners::Disposable.from(result['disposable'])
|
|
320
320
|
end
|
|
@@ -436,7 +436,7 @@ module Playwright
|
|
|
436
436
|
|
|
437
437
|
def route_from_har(har, notFound: nil, update: nil, url: nil, updateContent: nil, updateMode: nil)
|
|
438
438
|
if update
|
|
439
|
-
@browser_context.send(:record_into_har, har, self, url: url, update_content: updateContent, update_mode: updateMode)
|
|
439
|
+
@browser_context.tracing.send(:record_into_har, har, self, url: url, update_content: updateContent, update_mode: updateMode)
|
|
440
440
|
return
|
|
441
441
|
end
|
|
442
442
|
|
|
@@ -676,9 +676,14 @@ module Playwright
|
|
|
676
676
|
@channel.send_message_to_server('cancelPickLocator')
|
|
677
677
|
end
|
|
678
678
|
|
|
679
|
-
def
|
|
679
|
+
def hide_highlight
|
|
680
|
+
@channel.send_message_to_server('hideHighlight')
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
def aria_snapshot(boxes: nil, depth: nil, mode: nil, timeout: nil, _track: nil)
|
|
680
684
|
params = { selector: 'body' }
|
|
681
685
|
params[:timeout] = @timeout_settings.timeout(timeout)
|
|
686
|
+
params[:boxes] = boxes unless boxes.nil?
|
|
682
687
|
params[:depth] = depth if depth
|
|
683
688
|
params[:mode] = mode if mode
|
|
684
689
|
if _track
|
|
@@ -947,8 +952,8 @@ module Playwright
|
|
|
947
952
|
@main_frame.locator(result['selector'])
|
|
948
953
|
end
|
|
949
954
|
|
|
950
|
-
def snapshot_for_ai(timeout: nil, depth: nil, _track: nil)
|
|
951
|
-
aria_snapshot(mode: 'ai', timeout: timeout, depth: depth, _track: _track)
|
|
955
|
+
def snapshot_for_ai(timeout: nil, depth: nil, boxes: nil, _track: nil)
|
|
956
|
+
aria_snapshot(mode: 'ai', timeout: timeout, depth: depth, boxes: boxes, _track: _track)
|
|
952
957
|
end
|
|
953
958
|
|
|
954
959
|
def _assertions(timeout, is_not, message)
|
|
@@ -34,6 +34,10 @@ module Playwright
|
|
|
34
34
|
@connection.local_utils.devices
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def request
|
|
38
|
+
@request ||= APIRequestImpl.new(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
# used only from Playwright#connect_to_browser_server
|
|
38
42
|
private def pre_launched_browser
|
|
39
43
|
unless @initializer['preLaunchedBrowser']
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
module Playwright
|
|
2
2
|
define_channel_owner :Tracing do
|
|
3
|
+
private def after_initialize
|
|
4
|
+
@har_recorders = {}
|
|
5
|
+
@har_id = nil
|
|
6
|
+
end
|
|
7
|
+
|
|
3
8
|
def start(name: nil, title: nil, screenshots: nil, snapshots: nil, sources: nil, live: nil)
|
|
4
9
|
params = {
|
|
5
10
|
name: name,
|
|
@@ -38,10 +43,7 @@ module Playwright
|
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
private def do_stop_chunk(file_path:)
|
|
41
|
-
|
|
42
|
-
@is_tracing = false
|
|
43
|
-
@connection.set_in_tracing(false)
|
|
44
|
-
end
|
|
46
|
+
reset_stack_counter
|
|
45
47
|
local_utils = @connection.local_utils
|
|
46
48
|
|
|
47
49
|
unless file_path
|
|
@@ -99,6 +101,105 @@ module Playwright
|
|
|
99
101
|
)
|
|
100
102
|
end
|
|
101
103
|
|
|
104
|
+
def start_har(path, content: nil, mode: nil, urlFilter: nil, resourcesDir: nil)
|
|
105
|
+
raise 'HAR recording has already been started' if @har_id
|
|
106
|
+
if resourcesDir && path.end_with?('.zip')
|
|
107
|
+
raise 'resourcesDir option is not compatible with a .zip har file'
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
default_content = path.end_with?('.zip') ? 'attach' : 'embed'
|
|
111
|
+
@har_id = record_into_har(path, nil,
|
|
112
|
+
url: urlFilter,
|
|
113
|
+
update_content: content || default_content,
|
|
114
|
+
update_mode: mode || 'full',
|
|
115
|
+
resources_dir: resourcesDir,
|
|
116
|
+
)
|
|
117
|
+
DisposableStub.new { stop_har }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def stop_har
|
|
121
|
+
har_id = @har_id
|
|
122
|
+
raise 'HAR recording has not been started' unless har_id
|
|
123
|
+
|
|
124
|
+
@har_id = nil
|
|
125
|
+
export_har(har_id)
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private def record_into_har(har, page, url:, update_content:, update_mode:, resources_dir: nil)
|
|
130
|
+
options = {
|
|
131
|
+
content: update_content || 'attach',
|
|
132
|
+
mode: update_mode || 'minimal',
|
|
133
|
+
harPath: har.end_with?('.zip') ? nil : har,
|
|
134
|
+
resourcesDir: resources_dir,
|
|
135
|
+
}.compact
|
|
136
|
+
|
|
137
|
+
if url.is_a?(Regexp)
|
|
138
|
+
regex = ::Playwright::JavaScript::Regex.new(url)
|
|
139
|
+
options[:urlRegexSource] = regex.source
|
|
140
|
+
options[:urlRegexFlags] = regex.flag
|
|
141
|
+
elsif url.is_a?(String)
|
|
142
|
+
options[:urlGlob] = url
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
params = { options: options }
|
|
146
|
+
params[:page] = page.channel if page
|
|
147
|
+
|
|
148
|
+
result = @channel.send_message_to_server_result('harStart', params)
|
|
149
|
+
har_id = result['harId'] || result[:harId]
|
|
150
|
+
@har_recorders[har_id] = { path: har, resources_dir: resources_dir }
|
|
151
|
+
har_id
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private def export_har(har_id)
|
|
155
|
+
har_params = @har_recorders.delete(har_id)
|
|
156
|
+
return unless har_params
|
|
157
|
+
|
|
158
|
+
path = har_params[:path]
|
|
159
|
+
is_zip = path.end_with?('.zip')
|
|
160
|
+
local_utils = @connection.local_utils
|
|
161
|
+
|
|
162
|
+
if !@connection.remote?
|
|
163
|
+
result = @channel.send_message_to_server_result('harExport', harId: har_id, mode: 'entries')
|
|
164
|
+
return unless is_zip
|
|
165
|
+
raise 'Cannot save zipped HAR because localUtils is unavailable.' unless local_utils
|
|
166
|
+
|
|
167
|
+
local_utils.zip(
|
|
168
|
+
zipFile: path,
|
|
169
|
+
entries: result['entries'],
|
|
170
|
+
mode: 'write',
|
|
171
|
+
includeSources: false,
|
|
172
|
+
)
|
|
173
|
+
return
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
result = @channel.send_message_to_server_result('harExport', harId: har_id, mode: 'archive')
|
|
177
|
+
artifact = ChannelOwners::Artifact.from(result['artifact'])
|
|
178
|
+
if is_zip
|
|
179
|
+
artifact.save_as(path)
|
|
180
|
+
artifact.delete
|
|
181
|
+
return
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
raise 'Uncompressed har is not supported in thin clients' unless local_utils
|
|
185
|
+
|
|
186
|
+
tmp_path = "#{path}.tmp"
|
|
187
|
+
artifact.save_as(tmp_path)
|
|
188
|
+
local_utils.har_unzip(tmp_path, path, resources_dir: har_params[:resources_dir])
|
|
189
|
+
artifact.delete
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private def export_all_hars
|
|
193
|
+
@har_recorders.keys.each { |har_id| export_har(har_id) }
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private def reset_stack_counter
|
|
197
|
+
if @is_tracing
|
|
198
|
+
@is_tracing = false
|
|
199
|
+
@connection.set_in_tracing(false)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
102
203
|
private def update_traces_dir(traces_dir)
|
|
103
204
|
@traces_dir = traces_dir
|
|
104
205
|
end
|
|
@@ -213,7 +213,11 @@ module Playwright
|
|
|
213
213
|
return
|
|
214
214
|
end
|
|
215
215
|
|
|
216
|
-
object.
|
|
216
|
+
if object.is_a?(ChannelOwners::JsonPipe) && method == 'message'
|
|
217
|
+
object.channel.emit(method, params)
|
|
218
|
+
else
|
|
219
|
+
object.channel.emit(method, replace_guids_with_channels(params))
|
|
220
|
+
end
|
|
217
221
|
end
|
|
218
222
|
|
|
219
223
|
def replace_channels_with_guids(payload)
|
|
@@ -23,7 +23,16 @@ module Playwright
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def location
|
|
26
|
-
@event['location']
|
|
26
|
+
location = @event['location']
|
|
27
|
+
return location unless location
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
'url' => location['url'],
|
|
31
|
+
'line' => location['lineNumber'],
|
|
32
|
+
'column' => location['columnNumber'],
|
|
33
|
+
'lineNumber' => location['lineNumber'],
|
|
34
|
+
'columnNumber' => location['columnNumber'],
|
|
35
|
+
}
|
|
27
36
|
end
|
|
28
37
|
|
|
29
38
|
def timestamp
|
data/lib/playwright/errors.rb
CHANGED
|
@@ -60,12 +60,13 @@ module Playwright
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
class WebError
|
|
63
|
-
def initialize(error, page)
|
|
63
|
+
def initialize(error, page, location = nil)
|
|
64
64
|
@error = error
|
|
65
65
|
@page = PlaywrightApi.wrap(page)
|
|
66
|
+
@location = location
|
|
66
67
|
end
|
|
67
68
|
|
|
68
|
-
attr_reader :error, :page
|
|
69
|
+
attr_reader :error, :page, :location
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
class AssertionError < StandardError; end
|
data/lib/playwright/events.rb
CHANGED
|
@@ -20,6 +20,7 @@ end
|
|
|
20
20
|
},
|
|
21
21
|
|
|
22
22
|
Browser: {
|
|
23
|
+
Context: 'context',
|
|
23
24
|
Disconnected: 'disconnected'
|
|
24
25
|
},
|
|
25
26
|
|
|
@@ -28,7 +29,13 @@ end
|
|
|
28
29
|
Close: 'close',
|
|
29
30
|
Console: 'console',
|
|
30
31
|
Dialog: 'dialog',
|
|
32
|
+
Download: 'download',
|
|
33
|
+
FrameAttached: 'frameattached',
|
|
34
|
+
FrameDetached: 'framedetached',
|
|
35
|
+
FrameNavigated: 'framenavigated',
|
|
31
36
|
Page: 'page',
|
|
37
|
+
PageClose: 'pageclose',
|
|
38
|
+
PageLoad: 'pageload',
|
|
32
39
|
WebError: 'weberror',
|
|
33
40
|
ServiceWorker: 'serviceworker',
|
|
34
41
|
Request: 'request',
|