playwright-ruby-client 0.0.8 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/docs/api_coverage.md +159 -101
- data/lib/playwright.rb +5 -2
- 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/channel.rb +13 -6
- data/lib/playwright/channel_owner.rb +3 -5
- data/lib/playwright/channel_owners/android.rb +1 -1
- data/lib/playwright/channel_owners/android_device.rb +12 -12
- data/lib/playwright/channel_owners/binding_call.rb +3 -0
- data/lib/playwright/channel_owners/browser.rb +1 -1
- data/lib/playwright/channel_owners/browser_context.rb +157 -3
- data/lib/playwright/channel_owners/dialog.rb +28 -0
- data/lib/playwright/channel_owners/download.rb +27 -0
- data/lib/playwright/channel_owners/element_handle.rb +15 -4
- data/lib/playwright/channel_owners/frame.rb +24 -5
- data/lib/playwright/channel_owners/js_handle.rb +1 -1
- data/lib/playwright/channel_owners/page.rb +367 -29
- data/lib/playwright/channel_owners/playwright.rb +4 -0
- data/lib/playwright/channel_owners/request.rb +35 -3
- data/lib/playwright/channel_owners/response.rb +60 -0
- data/lib/playwright/channel_owners/route.rb +78 -0
- data/lib/playwright/channel_owners/selectors.rb +19 -1
- data/lib/playwright/errors.rb +1 -1
- data/lib/playwright/event_emitter.rb +8 -1
- data/lib/playwright/event_emitter_proxy.rb +49 -0
- data/lib/playwright/file_chooser_impl.rb +23 -0
- data/lib/playwright/http_headers.rb +20 -0
- data/lib/playwright/input_files.rb +1 -1
- data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +5 -1
- data/lib/playwright/mouse_impl.rb +7 -0
- data/lib/playwright/playwright_api.rb +59 -20
- data/lib/playwright/route_handler_entry.rb +36 -0
- data/lib/playwright/select_option_values.rb +14 -4
- data/lib/playwright/touchscreen_impl.rb +7 -0
- data/lib/playwright/utils.rb +4 -3
- data/lib/playwright/version.rb +1 -1
- data/lib/playwright/wait_helper.rb +1 -1
- data/lib/playwright_api/android.rb +82 -11
- data/lib/playwright_api/android_device.rb +148 -32
- data/lib/playwright_api/android_input.rb +17 -13
- data/lib/playwright_api/android_socket.rb +16 -0
- data/lib/playwright_api/android_web_view.rb +21 -0
- data/lib/playwright_api/binding_call.rb +14 -5
- data/lib/playwright_api/browser.rb +22 -23
- data/lib/playwright_api/browser_context.rb +49 -35
- data/lib/playwright_api/browser_type.rb +24 -64
- data/lib/playwright_api/chromium_browser_context.rb +10 -8
- data/lib/playwright_api/console_message.rb +10 -6
- data/lib/playwright_api/dialog.rb +37 -6
- data/lib/playwright_api/download.rb +28 -11
- data/lib/playwright_api/element_handle.rb +107 -96
- data/lib/playwright_api/file_chooser.rb +18 -10
- data/lib/playwright_api/frame.rb +124 -117
- data/lib/playwright_api/js_handle.rb +20 -22
- data/lib/playwright_api/keyboard.rb +5 -5
- data/lib/playwright_api/page.rb +206 -148
- data/lib/playwright_api/playwright.rb +33 -45
- data/lib/playwright_api/request.rb +11 -12
- data/lib/playwright_api/response.rb +30 -16
- data/lib/playwright_api/route.rb +27 -5
- data/lib/playwright_api/selectors.rb +14 -10
- data/lib/playwright_api/web_socket.rb +10 -1
- data/lib/playwright_api/worker.rb +13 -13
- metadata +16 -7
- 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
@@ -0,0 +1,36 @@
|
|
1
|
+
module Playwright
|
2
|
+
class RouteHandlerEntry
|
3
|
+
# @param url [String]
|
4
|
+
# @param handler [Proc]
|
5
|
+
def initialize(url, handler)
|
6
|
+
@url_value = url
|
7
|
+
@url_matcher = UrlMatcher.new(url)
|
8
|
+
@handler = handler
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle(route, request)
|
12
|
+
if url_match?(request.url)
|
13
|
+
@handler.call(route, request)
|
14
|
+
true
|
15
|
+
else
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def same_value?(url:, handler: nil)
|
21
|
+
if handler
|
22
|
+
@url_value == url && @handler == handler
|
23
|
+
else
|
24
|
+
@url_value == url
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private def url_match?(request_url)
|
29
|
+
if @url_value.is_a?(Regexp)
|
30
|
+
@url_matcher.match?(request_url)
|
31
|
+
else
|
32
|
+
@url_matcher.match?(request_url) || File.fnmatch?(@url_value, request_url)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,7 +1,18 @@
|
|
1
1
|
module Playwright
|
2
2
|
class SelectOptionValues
|
3
|
-
def initialize(
|
4
|
-
@params =
|
3
|
+
def initialize(element: nil, index: nil, value: nil, label: nil)
|
4
|
+
@params =
|
5
|
+
if element
|
6
|
+
convert(elmeent)
|
7
|
+
elsif index
|
8
|
+
convert(index)
|
9
|
+
elsif value
|
10
|
+
convert(value)
|
11
|
+
elsif label
|
12
|
+
convert(label)
|
13
|
+
else
|
14
|
+
{}
|
15
|
+
end
|
5
16
|
end
|
6
17
|
|
7
18
|
# @return [Hash]
|
@@ -10,8 +21,7 @@ module Playwright
|
|
10
21
|
end
|
11
22
|
|
12
23
|
private def convert(values)
|
13
|
-
return
|
14
|
-
return convert([values]) unless values.is_a?('Array')
|
24
|
+
return convert([values]) unless values.is_a?(Enumerable)
|
15
25
|
return {} if values.empty?
|
16
26
|
values.each_with_index do |value, index|
|
17
27
|
unless values
|
data/lib/playwright/utils.rb
CHANGED
@@ -3,12 +3,13 @@ module Playwright
|
|
3
3
|
module PrepareBrowserContextOptions
|
4
4
|
# @see https://github.com/microsoft/playwright/blob/5a2cfdbd47ed3c3deff77bb73e5fac34241f649d/src/client/browserContext.ts#L265
|
5
5
|
private def prepare_browser_context_options(params)
|
6
|
-
|
7
|
-
|
6
|
+
params[:sdkLanguage] = 'ruby'
|
7
|
+
if params[:noViewport] == 0
|
8
|
+
params.delete(:noViewport)
|
8
9
|
params[:noDefaultViewport] = true
|
9
10
|
end
|
10
11
|
if params[:extraHTTPHeaders]
|
11
|
-
|
12
|
+
params[:extraHTTPHeaders] = ::Playwright::HttpHeaders.new(params[:extraHTTPHeaders]).as_serialized
|
12
13
|
end
|
13
14
|
if params[:storageState].is_a?(String)
|
14
15
|
params[:storageState] = JSON.parse(File.read(params[:storageState]))
|
data/lib/playwright/version.rb
CHANGED
@@ -1,33 +1,104 @@
|
|
1
1
|
module Playwright
|
2
|
-
#
|
2
|
+
# Playwright has **experimental** support for Android automation. You can access android namespace via:
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# ```js
|
6
|
+
# const { _android } = require('playwright');
|
7
|
+
# ```
|
8
|
+
#
|
9
|
+
# An example of the Android automation script would be:
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# ```js
|
13
|
+
# const { _android } = require('playwright');
|
14
|
+
#
|
15
|
+
# (async () => {
|
16
|
+
# // Connect to the device.
|
17
|
+
# const [device] = await playwright._android.devices();
|
18
|
+
# console.log(`Model: ${device.model()}`);
|
19
|
+
# console.log(`Serial: ${device.serial()}`);
|
20
|
+
# // Take screenshot of the whole device.
|
21
|
+
# await device.screenshot({ path: 'device.png' });
|
22
|
+
#
|
23
|
+
# {
|
24
|
+
# // --------------------- WebView -----------------------
|
25
|
+
#
|
26
|
+
# // Launch an application with WebView.
|
27
|
+
# await device.shell('am force-stop org.chromium.webview_shell');
|
28
|
+
# await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
|
29
|
+
# // Get the WebView.
|
30
|
+
# const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
|
31
|
+
#
|
32
|
+
# // Fill the input box.
|
33
|
+
# await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
|
34
|
+
# await device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter');
|
35
|
+
#
|
36
|
+
# // Work with WebView's page as usual.
|
37
|
+
# const page = await webview.page();
|
38
|
+
# await page.page.waitForNavigation({ url: /.*microsoft\/playwright.*/ });
|
39
|
+
# console.log(await page.title());
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# {
|
43
|
+
# // --------------------- Browser -----------------------
|
44
|
+
#
|
45
|
+
# // Launch Chrome browser.
|
46
|
+
# await device.shell('am force-stop com.android.chrome');
|
47
|
+
# const context = await device.launchBrowser();
|
48
|
+
#
|
49
|
+
# // Use BrowserContext as usual.
|
50
|
+
# const page = await context.newPage();
|
51
|
+
# await page.goto('https://webkit.org/');
|
52
|
+
# console.log(await page.evaluate(() => window.location.href));
|
53
|
+
# await page.screenshot({ path: 'page.png' });
|
54
|
+
#
|
55
|
+
# await context.close();
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
# // Close the device.
|
59
|
+
# await device.close();
|
60
|
+
# })();
|
61
|
+
# ```
|
62
|
+
#
|
63
|
+
# Note that since you don't need Playwright to install web browsers when testing Android, you can omit browser download
|
64
|
+
# via setting the following environment variable when installing Playwright:
|
65
|
+
#
|
66
|
+
# ```sh js
|
67
|
+
# $ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
|
68
|
+
# ```
|
3
69
|
class Android < PlaywrightApi
|
4
70
|
|
5
|
-
#
|
71
|
+
# Returns the list of detected Android devices.
|
6
72
|
def devices
|
7
73
|
wrap_impl(@impl.devices)
|
8
74
|
end
|
9
75
|
|
10
|
-
#
|
11
|
-
def
|
12
|
-
|
76
|
+
# This setting will change the default maximum time for all the methods accepting `timeout` option.
|
77
|
+
def set_default_timeout(timeout)
|
78
|
+
raise NotImplementedError.new('set_default_timeout is not implemented yet.')
|
13
79
|
end
|
80
|
+
alias_method :default_timeout=, :set_default_timeout
|
14
81
|
|
15
82
|
# -- inherited from EventEmitter --
|
16
83
|
# @nodoc
|
17
|
-
def
|
18
|
-
|
84
|
+
def off(event, callback)
|
85
|
+
event_emitter_proxy.off(event, callback)
|
19
86
|
end
|
20
87
|
|
21
88
|
# -- inherited from EventEmitter --
|
22
89
|
# @nodoc
|
23
|
-
def
|
24
|
-
|
90
|
+
def once(event, callback)
|
91
|
+
event_emitter_proxy.once(event, callback)
|
25
92
|
end
|
26
93
|
|
27
94
|
# -- inherited from EventEmitter --
|
28
95
|
# @nodoc
|
29
|
-
def
|
30
|
-
|
96
|
+
def on(event, callback)
|
97
|
+
event_emitter_proxy.on(event, callback)
|
98
|
+
end
|
99
|
+
|
100
|
+
private def event_emitter_proxy
|
101
|
+
@event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
|
31
102
|
end
|
32
103
|
end
|
33
104
|
end
|
@@ -1,78 +1,194 @@
|
|
1
1
|
module Playwright
|
2
|
-
#
|
2
|
+
# `AndroidDevice` represents a connected device, either real hardware or emulated. Devices can be obtained using
|
3
|
+
# [`method: Android.devices`].
|
3
4
|
class AndroidDevice < PlaywrightApi
|
4
5
|
|
5
|
-
#
|
6
|
-
|
7
|
-
wrap_impl(@impl.tree)
|
6
|
+
def input # property
|
7
|
+
wrap_impl(@impl.input)
|
8
8
|
end
|
9
9
|
|
10
|
-
#
|
10
|
+
# Disconnects from the device.
|
11
11
|
def close
|
12
12
|
wrap_impl(@impl.close)
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
16
|
-
def
|
17
|
-
|
15
|
+
# Drags the widget defined by `selector` towards `dest` point.
|
16
|
+
def drag(selector, dest, speed: nil)
|
17
|
+
raise NotImplementedError.new('drag is not implemented yet.')
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
21
|
-
def
|
22
|
-
|
20
|
+
# Fills the specific `selector` input box with `text`.
|
21
|
+
def fill(selector, text)
|
22
|
+
raise NotImplementedError.new('fill is not implemented yet.')
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# Flings the widget defined by `selector` in the specified `direction`.
|
26
|
+
def fling(selector, direction, speed: nil)
|
27
|
+
raise NotImplementedError.new('fling is not implemented yet.')
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns information about a widget defined by `selector`.
|
31
|
+
def info(selector)
|
32
|
+
wrap_impl(@impl.info(unwrap_impl(selector)))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Installs an apk on the device.
|
36
|
+
def install_apk(file, args: nil)
|
37
|
+
raise NotImplementedError.new('install_apk is not implemented yet.')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Launches Chrome browser on the device, and returns its persistent context.
|
41
|
+
def launch_browser(
|
42
|
+
acceptDownloads: nil,
|
43
|
+
bypassCSP: nil,
|
44
|
+
colorScheme: nil,
|
45
|
+
command: nil,
|
46
|
+
deviceScaleFactor: nil,
|
47
|
+
extraHTTPHeaders: nil,
|
48
|
+
geolocation: nil,
|
49
|
+
hasTouch: nil,
|
50
|
+
httpCredentials: nil,
|
51
|
+
ignoreHTTPSErrors: nil,
|
52
|
+
isMobile: nil,
|
53
|
+
javaScriptEnabled: nil,
|
54
|
+
locale: nil,
|
55
|
+
noViewport: nil,
|
56
|
+
offline: nil,
|
57
|
+
permissions: nil,
|
58
|
+
record_har_omit_content: nil,
|
59
|
+
record_har_path: nil,
|
60
|
+
record_video_dir: nil,
|
61
|
+
record_video_size: nil,
|
62
|
+
timezoneId: nil,
|
63
|
+
userAgent: nil,
|
64
|
+
viewport: nil,
|
65
|
+
&block)
|
66
|
+
wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
|
67
|
+
end
|
68
|
+
|
69
|
+
# Performs a long tap on the widget defined by `selector`.
|
70
|
+
def long_tap(selector)
|
71
|
+
raise NotImplementedError.new('long_tap is not implemented yet.')
|
72
|
+
end
|
73
|
+
|
74
|
+
# Device model.
|
75
|
+
def model
|
76
|
+
wrap_impl(@impl.model)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Launches a process in the shell on the device and returns a socket to communicate with the launched process.
|
80
|
+
def open(command)
|
81
|
+
raise NotImplementedError.new('open is not implemented yet.')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Pinches the widget defined by `selector` in the closing direction.
|
85
|
+
def pinch_close(selector, percent, speed: nil)
|
86
|
+
raise NotImplementedError.new('pinch_close is not implemented yet.')
|
87
|
+
end
|
88
|
+
|
89
|
+
# Pinches the widget defined by `selector` in the open direction.
|
90
|
+
def pinch_open(selector, percent, speed: nil)
|
91
|
+
raise NotImplementedError.new('pinch_open is not implemented yet.')
|
92
|
+
end
|
93
|
+
|
94
|
+
# Presses the specific `key` in the widget defined by `selector`.
|
95
|
+
def press(selector, key)
|
96
|
+
raise NotImplementedError.new('press is not implemented yet.')
|
97
|
+
end
|
98
|
+
|
99
|
+
# Copies a file to the device.
|
100
|
+
def push(file, path, mode: nil)
|
101
|
+
raise NotImplementedError.new('push is not implemented yet.')
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the buffer with the captured screenshot of the device.
|
26
105
|
def screenshot(path: nil)
|
27
106
|
wrap_impl(@impl.screenshot(path: unwrap_impl(path)))
|
28
107
|
end
|
29
108
|
|
30
|
-
#
|
109
|
+
# Scrolls the widget defined by `selector` in the specified `direction`.
|
110
|
+
def scroll(selector, direction, percent, speed: nil)
|
111
|
+
raise NotImplementedError.new('scroll is not implemented yet.')
|
112
|
+
end
|
113
|
+
|
114
|
+
# Device serial number.
|
115
|
+
def serial
|
116
|
+
wrap_impl(@impl.serial)
|
117
|
+
end
|
118
|
+
|
119
|
+
# This setting will change the default maximum time for all the methods accepting `timeout` option.
|
120
|
+
def set_default_timeout(timeout)
|
121
|
+
raise NotImplementedError.new('set_default_timeout is not implemented yet.')
|
122
|
+
end
|
123
|
+
alias_method :default_timeout=, :set_default_timeout
|
124
|
+
|
125
|
+
# Executes a shell command on the device and returns its output.
|
31
126
|
def shell(command)
|
32
127
|
wrap_impl(@impl.shell(unwrap_impl(command)))
|
33
128
|
end
|
34
129
|
|
35
|
-
#
|
36
|
-
def
|
37
|
-
|
130
|
+
# Swipes the widget defined by `selector` in the specified `direction`.
|
131
|
+
def swipe(selector, direction, percent, speed: nil)
|
132
|
+
raise NotImplementedError.new('swipe is not implemented yet.')
|
38
133
|
end
|
39
134
|
|
40
|
-
#
|
41
|
-
def
|
42
|
-
|
135
|
+
# Taps on the widget defined by `selector`.
|
136
|
+
def tap_point(selector, duration: nil)
|
137
|
+
raise NotImplementedError.new('tap_point is not implemented yet.')
|
43
138
|
end
|
44
139
|
|
45
|
-
#
|
46
|
-
def
|
47
|
-
|
140
|
+
# Waits for the specific `selector` to either appear or disappear, depending on the `state`.
|
141
|
+
def wait(selector, state: nil)
|
142
|
+
raise NotImplementedError.new('wait is not implemented yet.')
|
48
143
|
end
|
49
144
|
|
50
|
-
#
|
51
|
-
|
52
|
-
|
145
|
+
# Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
|
146
|
+
# value.
|
147
|
+
def wait_for_event(event, optionsOrPredicate: nil)
|
148
|
+
raise NotImplementedError.new('wait_for_event is not implemented yet.')
|
149
|
+
end
|
150
|
+
|
151
|
+
# This method waits until `AndroidWebView` matching the `selector` is opened and returns it. If there is already an open
|
152
|
+
# `AndroidWebView` matching the `selector`, returns immediately.
|
153
|
+
def web_view(selector)
|
154
|
+
raise NotImplementedError.new('web_view is not implemented yet.')
|
155
|
+
end
|
156
|
+
|
157
|
+
# Currently open WebViews.
|
158
|
+
def web_views
|
159
|
+
raise NotImplementedError.new('web_views is not implemented yet.')
|
53
160
|
end
|
54
161
|
|
55
162
|
# @nodoc
|
56
|
-
def
|
57
|
-
wrap_impl(@impl.
|
163
|
+
def tree
|
164
|
+
wrap_impl(@impl.tree)
|
58
165
|
end
|
59
166
|
|
60
|
-
# -- inherited from EventEmitter --
|
61
167
|
# @nodoc
|
62
|
-
def
|
63
|
-
wrap_impl(@impl.
|
168
|
+
def tap_on(selector, duration: nil, timeout: nil)
|
169
|
+
wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
|
64
170
|
end
|
65
171
|
|
66
172
|
# -- inherited from EventEmitter --
|
67
173
|
# @nodoc
|
68
174
|
def off(event, callback)
|
69
|
-
|
175
|
+
event_emitter_proxy.off(event, callback)
|
70
176
|
end
|
71
177
|
|
72
178
|
# -- inherited from EventEmitter --
|
73
179
|
# @nodoc
|
74
180
|
def once(event, callback)
|
75
|
-
|
181
|
+
event_emitter_proxy.once(event, callback)
|
182
|
+
end
|
183
|
+
|
184
|
+
# -- inherited from EventEmitter --
|
185
|
+
# @nodoc
|
186
|
+
def on(event, callback)
|
187
|
+
event_emitter_proxy.on(event, callback)
|
188
|
+
end
|
189
|
+
|
190
|
+
private def event_emitter_proxy
|
191
|
+
@event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
|
76
192
|
end
|
77
193
|
end
|
78
194
|
end
|