playwright-ruby-client 0.0.8 → 1.58.1.alpha1
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/AGENTS.md +4 -0
- data/CLAUDE/api_generation.md +28 -0
- data/CLAUDE/ci_expectations.md +23 -0
- data/CLAUDE/gem_release_flow.md +39 -0
- data/CLAUDE/past_upgrade_pr_patterns.md +42 -0
- data/CLAUDE/playwright_upgrade_workflow.md +35 -0
- data/CLAUDE/rspec_debugging.md +30 -0
- data/CLAUDE/unimplemented_examples.md +18 -0
- data/CLAUDE.md +32 -0
- data/CONTRIBUTING.md +5 -0
- data/README.md +60 -16
- data/documentation/README.md +33 -0
- data/documentation/babel.config.js +3 -0
- data/documentation/docs/api/api_request.md +7 -0
- data/documentation/docs/api/api_request_context.md +298 -0
- data/documentation/docs/api/api_response.md +114 -0
- data/documentation/docs/api/browser.md +237 -0
- data/documentation/docs/api/browser_context.md +503 -0
- data/documentation/docs/api/browser_type.md +184 -0
- data/documentation/docs/api/cdp_session.md +44 -0
- data/documentation/docs/api/clock.md +154 -0
- data/documentation/docs/api/console_message.md +85 -0
- data/documentation/docs/api/dialog.md +84 -0
- data/documentation/docs/api/download.md +111 -0
- data/documentation/docs/api/element_handle.md +694 -0
- data/documentation/docs/api/experimental/_category_.yml +3 -0
- data/documentation/docs/api/experimental/android.md +42 -0
- data/documentation/docs/api/experimental/android_device.md +109 -0
- data/documentation/docs/api/experimental/android_input.md +43 -0
- data/documentation/docs/api/experimental/android_socket.md +7 -0
- data/documentation/docs/api/experimental/android_web_view.md +7 -0
- data/documentation/docs/api/file_chooser.md +53 -0
- data/documentation/docs/api/frame.md +1218 -0
- data/documentation/docs/api/frame_locator.md +348 -0
- data/documentation/docs/api/js_handle.md +121 -0
- data/documentation/docs/api/keyboard.md +170 -0
- data/documentation/docs/api/locator.md +1495 -0
- data/documentation/docs/api/locator_assertions.md +827 -0
- data/documentation/docs/api/mouse.md +86 -0
- data/documentation/docs/api/page.md +1946 -0
- data/documentation/docs/api/page_assertions.md +65 -0
- data/documentation/docs/api/playwright.md +66 -0
- data/documentation/docs/api/request.md +255 -0
- data/documentation/docs/api/response.md +176 -0
- data/documentation/docs/api/route.md +205 -0
- data/documentation/docs/api/selectors.md +63 -0
- data/documentation/docs/api/touchscreen.md +22 -0
- data/documentation/docs/api/tracing.md +129 -0
- data/documentation/docs/api/web_socket.md +51 -0
- data/documentation/docs/api/worker.md +83 -0
- data/documentation/docs/article/api_coverage.mdx +11 -0
- data/documentation/docs/article/getting_started.md +161 -0
- data/documentation/docs/article/guides/_category_.yml +3 -0
- data/documentation/docs/article/guides/download_playwright_driver.md +55 -0
- data/documentation/docs/article/guides/inspector.md +31 -0
- data/documentation/docs/article/guides/launch_browser.md +121 -0
- data/documentation/docs/article/guides/playwright_on_alpine_linux.md +112 -0
- data/documentation/docs/article/guides/rails_integration.md +278 -0
- data/documentation/docs/article/guides/rails_integration_with_null_driver.md +145 -0
- data/documentation/docs/article/guides/recording_video.md +79 -0
- data/documentation/docs/article/guides/rspec_integration.md +59 -0
- data/documentation/docs/article/guides/semi_automation.md +71 -0
- data/documentation/docs/article/guides/use_storage_state.md +78 -0
- data/documentation/docs/include/api_coverage.md +671 -0
- data/documentation/docusaurus.config.js +114 -0
- data/documentation/package.json +39 -0
- data/documentation/sidebars.js +15 -0
- data/documentation/src/components/HomepageFeatures.js +61 -0
- data/documentation/src/components/HomepageFeatures.module.css +13 -0
- data/documentation/src/css/custom.css +44 -0
- data/documentation/src/pages/index.js +49 -0
- data/documentation/src/pages/index.module.css +41 -0
- data/documentation/src/pages/markdown-page.md +7 -0
- data/documentation/static/.nojekyll +0 -0
- data/documentation/static/img/playwright-logo.svg +9 -0
- data/documentation/static/img/playwright-ruby-client.png +0 -0
- data/documentation/static/img/undraw_dropdown_menu.svg +1 -0
- data/documentation/static/img/undraw_web_development.svg +1 -0
- data/documentation/static/img/undraw_windows.svg +1 -0
- data/documentation/yarn.lock +9005 -0
- data/lib/playwright/{input_types/android_input.rb → android_input_impl.rb} +5 -1
- data/lib/playwright/api_implementation.rb +18 -0
- data/lib/playwright/api_response_impl.rb +77 -0
- data/lib/playwright/channel.rb +62 -1
- data/lib/playwright/channel_owner.rb +70 -7
- data/lib/playwright/channel_owners/android.rb +16 -3
- data/lib/playwright/channel_owners/android_device.rb +22 -66
- data/lib/playwright/channel_owners/api_request_context.rb +247 -0
- data/lib/playwright/channel_owners/artifact.rb +40 -0
- data/lib/playwright/channel_owners/binding_call.rb +70 -0
- data/lib/playwright/channel_owners/browser.rb +114 -22
- data/lib/playwright/channel_owners/browser_context.rb +589 -15
- data/lib/playwright/channel_owners/browser_type.rb +90 -1
- data/lib/playwright/channel_owners/cdp_session.rb +19 -0
- data/lib/playwright/channel_owners/dialog.rb +32 -0
- data/lib/playwright/channel_owners/element_handle.rb +107 -43
- data/lib/playwright/channel_owners/fetch_request.rb +8 -0
- data/lib/playwright/channel_owners/frame.rb +334 -104
- data/lib/playwright/channel_owners/js_handle.rb +9 -13
- data/lib/playwright/channel_owners/local_utils.rb +82 -0
- data/lib/playwright/channel_owners/page.rb +778 -95
- data/lib/playwright/channel_owners/playwright.rb +25 -30
- data/lib/playwright/channel_owners/request.rb +120 -18
- data/lib/playwright/channel_owners/response.rb +113 -0
- data/lib/playwright/channel_owners/route.rb +181 -0
- data/lib/playwright/channel_owners/stream.rb +30 -0
- data/lib/playwright/channel_owners/tracing.rb +117 -0
- data/lib/playwright/channel_owners/web_socket.rb +96 -0
- data/lib/playwright/channel_owners/worker.rb +46 -0
- data/lib/playwright/channel_owners/writable_stream.rb +14 -0
- data/lib/playwright/clock_impl.rb +67 -0
- data/lib/playwright/connection.rb +111 -63
- data/lib/playwright/console_message_impl.rb +29 -0
- data/lib/playwright/download_impl.rb +32 -0
- data/lib/playwright/errors.rb +42 -5
- data/lib/playwright/event_emitter.rb +17 -3
- data/lib/playwright/event_emitter_proxy.rb +49 -0
- data/lib/playwright/events.rb +10 -5
- data/lib/playwright/file_chooser_impl.rb +24 -0
- data/lib/playwright/frame_locator_impl.rb +66 -0
- data/lib/playwright/har_router.rb +89 -0
- data/lib/playwright/http_headers.rb +14 -0
- data/lib/playwright/input_files.rb +102 -15
- data/lib/playwright/javascript/expression.rb +7 -11
- data/lib/playwright/javascript/regex.rb +23 -0
- data/lib/playwright/javascript/source_url.rb +16 -0
- data/lib/playwright/javascript/value_parser.rb +108 -19
- data/lib/playwright/javascript/value_serializer.rb +47 -8
- data/lib/playwright/javascript/visitor_info.rb +26 -0
- data/lib/playwright/javascript.rb +2 -10
- data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +6 -2
- data/lib/playwright/locator_assertions_impl.rb +571 -0
- data/lib/playwright/locator_impl.rb +544 -0
- data/lib/playwright/locator_utils.rb +136 -0
- data/lib/playwright/mouse_impl.rb +57 -0
- data/lib/playwright/page_assertions_impl.rb +154 -0
- data/lib/playwright/playwright_api.rb +102 -30
- data/lib/playwright/raw_headers.rb +61 -0
- data/lib/playwright/route_handler.rb +78 -0
- data/lib/playwright/select_option_values.rb +34 -13
- data/lib/playwright/selectors_impl.rb +45 -0
- data/lib/playwright/test.rb +102 -0
- data/lib/playwright/timeout_settings.rb +9 -4
- data/lib/playwright/touchscreen_impl.rb +14 -0
- data/lib/playwright/transport.rb +61 -10
- data/lib/playwright/url_matcher.rb +24 -2
- data/lib/playwright/utils.rb +48 -13
- data/lib/playwright/version.rb +2 -1
- data/lib/playwright/video.rb +54 -0
- data/lib/playwright/waiter.rb +166 -0
- data/lib/playwright/web_socket_client.rb +167 -0
- data/lib/playwright/web_socket_transport.rb +116 -0
- data/lib/playwright.rb +188 -11
- data/lib/playwright_api/android.rb +46 -11
- data/lib/playwright_api/android_device.rb +182 -31
- data/lib/playwright_api/android_input.rb +22 -13
- data/lib/playwright_api/android_socket.rb +18 -0
- data/lib/playwright_api/android_web_view.rb +24 -0
- data/lib/playwright_api/api_request.rb +26 -0
- data/lib/playwright_api/api_request_context.rb +311 -0
- data/lib/playwright_api/api_response.rb +92 -0
- data/lib/playwright_api/browser.rb +116 -103
- data/lib/playwright_api/browser_context.rb +290 -389
- data/lib/playwright_api/browser_type.rb +96 -118
- data/lib/playwright_api/cdp_session.rb +36 -39
- data/lib/playwright_api/clock.rb +121 -0
- data/lib/playwright_api/console_message.rb +35 -19
- data/lib/playwright_api/dialog.rb +53 -50
- data/lib/playwright_api/download.rb +49 -43
- data/lib/playwright_api/element_handle.rb +354 -402
- data/lib/playwright_api/file_chooser.rb +15 -18
- data/lib/playwright_api/frame.rb +703 -603
- data/lib/playwright_api/frame_locator.rb +285 -0
- data/lib/playwright_api/js_handle.rb +50 -76
- data/lib/playwright_api/keyboard.rb +67 -146
- data/lib/playwright_api/locator.rb +1304 -0
- data/lib/playwright_api/locator_assertions.rb +704 -0
- data/lib/playwright_api/mouse.rb +23 -29
- data/lib/playwright_api/page.rb +1196 -1176
- data/lib/playwright_api/page_assertions.rb +60 -0
- data/lib/playwright_api/playwright.rb +54 -122
- data/lib/playwright_api/request.rb +112 -74
- data/lib/playwright_api/response.rb +92 -20
- data/lib/playwright_api/route.rb +152 -62
- data/lib/playwright_api/selectors.rb +47 -61
- data/lib/playwright_api/touchscreen.rb +8 -2
- data/lib/playwright_api/tracing.rb +128 -0
- data/lib/playwright_api/web_socket.rb +43 -5
- data/lib/playwright_api/worker.rb +74 -34
- data/playwright.gemspec +14 -9
- data/sig/playwright.rbs +658 -0
- metadata +216 -50
- data/docs/api_coverage.md +0 -354
- data/lib/playwright/channel_owners/chromium_browser.rb +0 -8
- data/lib/playwright/channel_owners/chromium_browser_context.rb +0 -8
- data/lib/playwright/channel_owners/console_message.rb +0 -21
- data/lib/playwright/channel_owners/firefox_browser.rb +0 -8
- data/lib/playwright/channel_owners/selectors.rb +0 -4
- data/lib/playwright/channel_owners/webkit_browser.rb +0 -8
- data/lib/playwright/input_type.rb +0 -19
- data/lib/playwright/input_types/mouse.rb +0 -4
- data/lib/playwright/input_types/touchscreen.rb +0 -4
- data/lib/playwright/javascript/function.rb +0 -67
- data/lib/playwright/wait_helper.rb +0 -73
- data/lib/playwright_api/accessibility.rb +0 -93
- data/lib/playwright_api/binding_call.rb +0 -23
- data/lib/playwright_api/chromium_browser_context.rb +0 -57
- data/lib/playwright_api/video.rb +0 -24
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
module Playwright
|
|
2
2
|
define_channel_owner :Playwright do
|
|
3
3
|
def chromium
|
|
4
|
-
@chromium ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['chromium'])
|
|
4
|
+
@chromium ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['chromium']).tap do |browser_type|
|
|
5
|
+
browser_type.send(:update_playwright, self)
|
|
6
|
+
end
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
def firefox
|
|
8
|
-
@firefox ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['firefox'])
|
|
10
|
+
@firefox ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['firefox']).tap do |browser_type|
|
|
11
|
+
browser_type.send(:update_playwright, self)
|
|
12
|
+
end
|
|
9
13
|
end
|
|
10
14
|
|
|
11
15
|
def webkit
|
|
12
|
-
@webkit ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['webkit'])
|
|
16
|
+
@webkit ||= ::Playwright::ChannelOwners::BrowserType.from(@initializer['webkit']).tap do |browser_type|
|
|
17
|
+
browser_type.send(:update_playwright, self)
|
|
18
|
+
end
|
|
13
19
|
end
|
|
14
20
|
|
|
15
21
|
def android
|
|
@@ -20,38 +26,27 @@ module Playwright
|
|
|
20
26
|
@electron ||= ::Playwright::ChannelOwners::Electron.from(@initializer['electron'])
|
|
21
27
|
end
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@width = hash['width']
|
|
27
|
-
@heirhgt = hash['height']
|
|
28
|
-
end
|
|
29
|
-
attr_reader :width, :height
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def initialize(hash)
|
|
33
|
-
@user_agent = hash["userAgent"]
|
|
34
|
-
@viewport = Viewport.new(hash["viewport"])
|
|
35
|
-
@device_scale_factor = hash["deviceScaleFactor"]
|
|
36
|
-
@is_mobile = hash["isMobile"]
|
|
37
|
-
@has_touch = hash["hasTouch"]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
attr_reader :user_agent, :viewport, :device_scale_factor
|
|
29
|
+
def selectors
|
|
30
|
+
@selectors ||= ::Playwright::SelectorsImpl.new
|
|
31
|
+
end
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
def devices
|
|
34
|
+
@connection.local_utils.devices
|
|
35
|
+
end
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
# used only from Playwright#connect_to_browser_server
|
|
38
|
+
private def pre_launched_browser
|
|
39
|
+
unless @initializer['preLaunchedBrowser']
|
|
40
|
+
raise 'Malformed endpoint. Did you use launchServer method?'
|
|
48
41
|
end
|
|
42
|
+
::Playwright::ChannelOwners::Browser.from(@initializer['preLaunchedBrowser'])
|
|
49
43
|
end
|
|
50
44
|
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
45
|
+
private def pre_connected_android_device
|
|
46
|
+
unless @initializer['preConnectedAndroidDevice']
|
|
47
|
+
raise 'Malformed endpoint. Did you use Android.launchServer method?'
|
|
48
|
+
end
|
|
49
|
+
::Playwright::ChannelOwners::AndroidDevice.from(@initializer['preConnectedAndroidDevice'])
|
|
55
50
|
end
|
|
56
51
|
end
|
|
57
52
|
end
|
|
@@ -3,9 +3,10 @@ require 'base64'
|
|
|
3
3
|
module Playwright
|
|
4
4
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
|
|
5
5
|
define_channel_owner :Request do
|
|
6
|
-
def after_initialize
|
|
6
|
+
private def after_initialize
|
|
7
7
|
@redirected_from = ChannelOwners::Request.from_nullable(@initializer['redirectedFrom'])
|
|
8
8
|
@redirected_from&.send(:update_redirected_to, self)
|
|
9
|
+
@provisional_headers = RawHeaders.new(@initializer['headers'])
|
|
9
10
|
@timing = {
|
|
10
11
|
startTime: 0,
|
|
11
12
|
domainLookupStart: -1,
|
|
@@ -17,11 +18,29 @@ module Playwright
|
|
|
17
18
|
responseStart: -1,
|
|
18
19
|
responseEnd: -1,
|
|
19
20
|
}
|
|
20
|
-
@
|
|
21
|
+
@fallback_overrides = {}
|
|
22
|
+
@url = @initializer['url']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private def fallback_overrides
|
|
26
|
+
@fallback_overrides
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def apply_fallback_overrides(overrides)
|
|
30
|
+
allowed_key = %i[url method headers postData]
|
|
31
|
+
overrides.each do |key, value|
|
|
32
|
+
raise ArgumentError.new("invalid key: #{key}") unless allowed_key.include?(key)
|
|
33
|
+
@fallback_overrides[key] = value
|
|
34
|
+
end
|
|
35
|
+
@fallback_overrides
|
|
21
36
|
end
|
|
22
37
|
|
|
23
38
|
def url
|
|
24
|
-
@
|
|
39
|
+
@fallback_overrides[:url] || @url
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private def internal_url
|
|
43
|
+
@url
|
|
25
44
|
end
|
|
26
45
|
|
|
27
46
|
def resource_type
|
|
@@ -29,7 +48,7 @@ module Playwright
|
|
|
29
48
|
end
|
|
30
49
|
|
|
31
50
|
def method
|
|
32
|
-
@
|
|
51
|
+
@fallback_overrides[:method] || @initializer['method']
|
|
33
52
|
end
|
|
34
53
|
|
|
35
54
|
def post_data
|
|
@@ -40,10 +59,10 @@ module Playwright
|
|
|
40
59
|
data = post_data
|
|
41
60
|
return unless data
|
|
42
61
|
|
|
43
|
-
content_type =
|
|
62
|
+
content_type = headers['content-type']
|
|
44
63
|
return unless content_type
|
|
45
64
|
|
|
46
|
-
if content_type
|
|
65
|
+
if content_type.include?("application/x-www-form-urlencoded")
|
|
47
66
|
URI.decode_www_form(data).to_h
|
|
48
67
|
else
|
|
49
68
|
JSON.parse(data)
|
|
@@ -51,25 +70,40 @@ module Playwright
|
|
|
51
70
|
end
|
|
52
71
|
|
|
53
72
|
def post_data_buffer
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
if (override = @fallback_overrides[:postData])
|
|
74
|
+
return override
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if (base64_content = @initializer['postData'])
|
|
56
78
|
Base64.strict_decode64(base64_content)
|
|
57
79
|
else
|
|
58
80
|
nil
|
|
59
81
|
end
|
|
60
82
|
end
|
|
61
83
|
|
|
62
|
-
def headers
|
|
63
|
-
@headers
|
|
64
|
-
end
|
|
65
|
-
|
|
66
84
|
def response
|
|
67
85
|
resp = @channel.send_message_to_server('response')
|
|
68
86
|
ChannelOwners::Response.from_nullable(resp)
|
|
69
87
|
end
|
|
70
88
|
|
|
89
|
+
class FramePageNotReadyError < StandardError
|
|
90
|
+
MESSAGE = [
|
|
91
|
+
'Frame for this navigation request is not available, because the request',
|
|
92
|
+
'was issued before the frame is created. You can check whether the request',
|
|
93
|
+
'is a navigation request by calling isNavigationRequest() method.',
|
|
94
|
+
].join('\n').freeze
|
|
95
|
+
|
|
96
|
+
def initialize
|
|
97
|
+
super(MESSAGE)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
71
101
|
def frame
|
|
72
|
-
@initializer['frame']
|
|
102
|
+
ChannelOwners::Frame.from(@initializer['frame']).tap do |result|
|
|
103
|
+
unless result.page
|
|
104
|
+
raise FramePageNotReadyError.new
|
|
105
|
+
end
|
|
106
|
+
end
|
|
73
107
|
end
|
|
74
108
|
|
|
75
109
|
def navigation_request?
|
|
@@ -80,16 +114,84 @@ module Playwright
|
|
|
80
114
|
@failure_text
|
|
81
115
|
end
|
|
82
116
|
|
|
83
|
-
attr_reader :
|
|
117
|
+
attr_reader :redirected_from, :redirected_to, :timing
|
|
118
|
+
|
|
119
|
+
def headers
|
|
120
|
+
if (override = @fallback_overrides[:headers])
|
|
121
|
+
RawHeaders.new(HttpHeaders.new(override).as_serialized).headers
|
|
122
|
+
else
|
|
123
|
+
@provisional_headers.headers
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# @return [RawHeaders|nil]
|
|
128
|
+
private def actual_headers
|
|
129
|
+
if (override = @fallback_overrides[:headers])
|
|
130
|
+
RawHeaders.new(HttpHeaders.new(override).as_serialized)
|
|
131
|
+
else
|
|
132
|
+
@actual_headers ||= raw_request_headers
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private def raw_request_headers
|
|
137
|
+
RawHeaders.new(@channel.send_message_to_server('rawRequestHeaders'))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def all_headers
|
|
141
|
+
actual_headers.headers
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def headers_array
|
|
145
|
+
actual_headers.headers_array
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def header_value(name)
|
|
149
|
+
actual_headers.get(name)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def header_values(name)
|
|
153
|
+
actual_headers.get_all(name)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def sizes
|
|
157
|
+
res = response
|
|
158
|
+
unless res
|
|
159
|
+
raise 'Unable to fetch sizes for failed request'
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
res.send(:sizes)
|
|
163
|
+
end
|
|
84
164
|
|
|
85
165
|
private def update_redirected_to(request)
|
|
86
166
|
@redirected_to = request
|
|
87
167
|
end
|
|
88
168
|
|
|
89
|
-
private def
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
169
|
+
private def update_failure_text(failure_text)
|
|
170
|
+
@failure_text = failure_text
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
private def update_timings(
|
|
174
|
+
start_time:,
|
|
175
|
+
domain_lookup_start:,
|
|
176
|
+
domain_lookup_end:,
|
|
177
|
+
connect_start:,
|
|
178
|
+
secure_connection_start:,
|
|
179
|
+
connect_end:,
|
|
180
|
+
request_start:,
|
|
181
|
+
response_start:)
|
|
182
|
+
|
|
183
|
+
@timing[:startTime] = start_time
|
|
184
|
+
@timing[:domainLookupStart] = domain_lookup_start
|
|
185
|
+
@timing[:domainLookupEnd] = domain_lookup_end
|
|
186
|
+
@timing[:connectStart] = connect_start
|
|
187
|
+
@timing[:secureConnectionStart] = secure_connection_start
|
|
188
|
+
@timing[:connectEnd] = connect_end
|
|
189
|
+
@timing[:requestStart] = request_start
|
|
190
|
+
@timing[:responseStart] = response_start
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private def update_response_end_timing(response_end_timing)
|
|
194
|
+
@timing[:responseEnd] = response_end_timing
|
|
93
195
|
end
|
|
94
196
|
end
|
|
95
197
|
end
|
|
@@ -1,5 +1,118 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
1
4
|
module Playwright
|
|
2
5
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
|
|
3
6
|
define_channel_owner :Response do
|
|
7
|
+
private def after_initialize
|
|
8
|
+
@provisional_headers = RawHeaders.new(@initializer['headers'])
|
|
9
|
+
@request = ChannelOwners::Request.from(@initializer['request'])
|
|
10
|
+
timing = @initializer['timing']
|
|
11
|
+
@request.send(:update_timings,
|
|
12
|
+
start_time: timing["startTime"],
|
|
13
|
+
domain_lookup_start: timing["domainLookupStart"],
|
|
14
|
+
domain_lookup_end: timing["domainLookupEnd"],
|
|
15
|
+
connect_start: timing["connectStart"],
|
|
16
|
+
secure_connection_start: timing["secureConnectionStart"],
|
|
17
|
+
connect_end: timing["connectEnd"],
|
|
18
|
+
request_start: timing["requestStart"],
|
|
19
|
+
response_start: timing["responseStart"],
|
|
20
|
+
)
|
|
21
|
+
@finished_promise = Concurrent::Promises.resolvable_future
|
|
22
|
+
end
|
|
23
|
+
attr_reader :request
|
|
24
|
+
|
|
25
|
+
def url
|
|
26
|
+
@initializer['url']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ok
|
|
30
|
+
status == 0 || (200...300).include?(status)
|
|
31
|
+
end
|
|
32
|
+
alias_method :ok?, :ok
|
|
33
|
+
|
|
34
|
+
def status
|
|
35
|
+
@initializer['status']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def status_text
|
|
39
|
+
@initializer['statusText']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def headers
|
|
43
|
+
@provisional_headers.headers
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [RawHeaders]
|
|
47
|
+
private def actual_headers
|
|
48
|
+
@actual_headers ||= raw_response_headers
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private def raw_response_headers
|
|
52
|
+
RawHeaders.new(@channel.send_message_to_server('rawResponseHeaders'))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def from_service_worker
|
|
56
|
+
@initializer['fromServiceWorker']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
alias_method :from_service_worker?, :from_service_worker
|
|
60
|
+
|
|
61
|
+
def all_headers
|
|
62
|
+
actual_headers.headers
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def headers_array
|
|
66
|
+
actual_headers.headers_array
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def header_value(name)
|
|
70
|
+
actual_headers.get(name)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def header_values(name)
|
|
74
|
+
actual_headers.get_all(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def server_addr
|
|
78
|
+
@channel.send_message_to_server('serverAddr')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def security_details
|
|
82
|
+
@channel.send_message_to_server('securityDetails')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def finished
|
|
86
|
+
@finished_promise.value!
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def body
|
|
90
|
+
binary = @channel.send_message_to_server("body")
|
|
91
|
+
Base64.strict_decode64(binary)
|
|
92
|
+
end
|
|
93
|
+
alias_method :text, :body
|
|
94
|
+
|
|
95
|
+
def json
|
|
96
|
+
JSON.parse(text)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def frame
|
|
100
|
+
@request.frame
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private def sizes
|
|
104
|
+
resp = @channel.send_message_to_server('sizes')
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
requestBodySize: resp['requestBodySize'],
|
|
108
|
+
requestHeadersSize: resp['requestHeadersSize'],
|
|
109
|
+
responseBodySize: resp['responseBodySize'],
|
|
110
|
+
responseHeadersSize: resp['responseHeadersSize'],
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private def mark_as_finished
|
|
115
|
+
@finished_promise.fulfill(nil)
|
|
116
|
+
end
|
|
4
117
|
end
|
|
5
118
|
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'mime/types'
|
|
3
|
+
|
|
4
|
+
module Playwright
|
|
5
|
+
define_channel_owner :Route do
|
|
6
|
+
private def set_handling_future(future)
|
|
7
|
+
@handling_future = future
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private def handling_with_result(done, &block)
|
|
11
|
+
chain = @handling_future
|
|
12
|
+
raise 'Route is already handled!' unless chain
|
|
13
|
+
block.call
|
|
14
|
+
@handling_future = nil
|
|
15
|
+
chain.fulfill(done)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def request
|
|
19
|
+
ChannelOwners::Request.from(@initializer['request'])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def abort(errorCode: nil)
|
|
23
|
+
handling_with_result(true) do
|
|
24
|
+
params = { requestUrl: request.send(:internal_url), errorCode: errorCode }.compact
|
|
25
|
+
# TODO _race_with_page_close
|
|
26
|
+
@channel.async_send_message_to_server('abort', params)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fulfill(
|
|
31
|
+
body: nil,
|
|
32
|
+
contentType: nil,
|
|
33
|
+
headers: nil,
|
|
34
|
+
json: nil,
|
|
35
|
+
path: nil,
|
|
36
|
+
status: nil,
|
|
37
|
+
response: nil)
|
|
38
|
+
handling_with_result(true) do
|
|
39
|
+
option_status = status
|
|
40
|
+
option_headers = headers
|
|
41
|
+
option_body = body
|
|
42
|
+
|
|
43
|
+
if json
|
|
44
|
+
raise ArgumentError.new('Can specify either body or json parameters') if body
|
|
45
|
+
option_body = JSON.generate(json)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
params = {}
|
|
49
|
+
|
|
50
|
+
if response
|
|
51
|
+
option_status ||= response.status
|
|
52
|
+
option_headers ||= response.headers
|
|
53
|
+
|
|
54
|
+
if !body && !path && response.is_a?(APIResponseImpl)
|
|
55
|
+
if response.send(:_request).send(:same_connection?, self)
|
|
56
|
+
params[:fetchResponseUid] = response.send(:fetch_uid)
|
|
57
|
+
else
|
|
58
|
+
option_body = response.body
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
content =
|
|
64
|
+
if option_body
|
|
65
|
+
option_body
|
|
66
|
+
elsif path
|
|
67
|
+
File.read(path)
|
|
68
|
+
else
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
param_headers = option_headers || {}
|
|
73
|
+
if contentType
|
|
74
|
+
param_headers['content-type'] = contentType
|
|
75
|
+
elsif json
|
|
76
|
+
param_headers['content-type'] = 'application/json'
|
|
77
|
+
elsif path
|
|
78
|
+
param_headers['content-type'] = mime_type_for(path)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if content
|
|
82
|
+
if content.is_a?(String)
|
|
83
|
+
params[:body] = content
|
|
84
|
+
params[:isBase64] = false
|
|
85
|
+
else
|
|
86
|
+
params[:body] = Base64.strict_encode64(content)
|
|
87
|
+
params[:isBase64] = true
|
|
88
|
+
end
|
|
89
|
+
param_headers['content-length'] ||= content.length.to_s
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
params[:status] = option_status || 200
|
|
93
|
+
params[:headers] = HttpHeaders.new(param_headers).as_serialized
|
|
94
|
+
params[:requestUrl] = request.send(:internal_url)
|
|
95
|
+
|
|
96
|
+
@channel.async_send_message_to_server('fulfill', params)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def fallback(headers: nil, method: nil, postData: nil, url: nil)
|
|
101
|
+
overrides = {
|
|
102
|
+
headers: headers,
|
|
103
|
+
method: method,
|
|
104
|
+
postData: postData,
|
|
105
|
+
url: url,
|
|
106
|
+
}.compact
|
|
107
|
+
|
|
108
|
+
handling_with_result(false) do
|
|
109
|
+
request.apply_fallback_overrides(overrides)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def fetch(headers: nil, method: nil, postData: nil, url: nil, maxRedirects: nil, maxRetries: nil, timeout: nil)
|
|
114
|
+
api_request_context = @context.request
|
|
115
|
+
api_request_context.send(:_inner_fetch,
|
|
116
|
+
request,
|
|
117
|
+
url,
|
|
118
|
+
headers: headers,
|
|
119
|
+
method: method,
|
|
120
|
+
data: postData,
|
|
121
|
+
maxRedirects: maxRedirects,
|
|
122
|
+
maxRetries: maxRetries,
|
|
123
|
+
timeout: timeout,
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def continue(headers: nil, method: nil, postData: nil, url: nil)
|
|
128
|
+
overrides = {
|
|
129
|
+
headers: headers,
|
|
130
|
+
method: method,
|
|
131
|
+
postData: postData,
|
|
132
|
+
url: url,
|
|
133
|
+
}.compact
|
|
134
|
+
|
|
135
|
+
handling_with_result(true) do
|
|
136
|
+
request.apply_fallback_overrides(overrides)
|
|
137
|
+
async_continue_route
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private def async_continue_route(internal: false)
|
|
142
|
+
post_data_for_wire =
|
|
143
|
+
if (post_data_from_overrides = request.send(:fallback_overrides)[:postData])
|
|
144
|
+
post_data_for_wire = Base64.strict_encode64(post_data_from_overrides)
|
|
145
|
+
else
|
|
146
|
+
nil
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
params = request.send(:fallback_overrides).dup
|
|
150
|
+
|
|
151
|
+
if params[:headers]
|
|
152
|
+
params[:headers] = HttpHeaders.new(params[:headers]).as_serialized
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if post_data_for_wire
|
|
156
|
+
params[:postData] = post_data_for_wire
|
|
157
|
+
end
|
|
158
|
+
params[:requestUrl] = request.send(:internal_url)
|
|
159
|
+
params[:isFallback] = internal
|
|
160
|
+
|
|
161
|
+
# TODO _race_with_page_close
|
|
162
|
+
@channel.async_send_message_to_server('continue', params)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def redirect_navigation_request(url)
|
|
166
|
+
handling_with_result(true) do
|
|
167
|
+
# TODO _race_with_page_close
|
|
168
|
+
@channel.send_message_to_server('redirectNavigationRequest', { url: url })
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private def mime_type_for(filepath)
|
|
173
|
+
mime_types = MIME::Types.type_for(filepath)
|
|
174
|
+
mime_types.first.to_s || 'application/octet-stream'
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private def update_context(context)
|
|
178
|
+
@context = context
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
|
|
3
|
+
module Playwright
|
|
4
|
+
define_channel_owner :Stream do
|
|
5
|
+
def save_as(path)
|
|
6
|
+
File.open(path, 'wb') do |f|
|
|
7
|
+
read_with_block do |chunk|
|
|
8
|
+
f.write(chunk)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def read_all(&block)
|
|
14
|
+
out = StringIO.new
|
|
15
|
+
read_with_block do |chunk|
|
|
16
|
+
out.write(chunk)
|
|
17
|
+
end
|
|
18
|
+
out.string
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private def read_with_block(&block)
|
|
22
|
+
loop do
|
|
23
|
+
binary = @channel.send_message_to_server('read', size: 1024 * 1024)
|
|
24
|
+
break if !binary || binary.length == 0
|
|
25
|
+
decoded_chunk = Base64.strict_decode64(binary)
|
|
26
|
+
block.call(decoded_chunk)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|