playwright-ruby-client 0.0.6 → 0.0.7
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/README.md +79 -2
- data/docs/api_coverage.md +354 -0
- data/lib/playwright.rb +2 -0
- data/lib/playwright/channel_owner.rb +3 -2
- data/lib/playwright/channel_owners/android.rb +10 -1
- data/lib/playwright/channel_owners/android_device.rb +93 -0
- data/lib/playwright/channel_owners/browser.rb +13 -13
- data/lib/playwright/channel_owners/element_handle.rb +232 -1
- data/lib/playwright/channel_owners/frame.rb +41 -3
- data/lib/playwright/channel_owners/js_handle.rb +51 -0
- data/lib/playwright/channel_owners/page.rb +48 -10
- data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
- data/lib/playwright/connection.rb +9 -6
- data/lib/playwright/errors.rb +1 -1
- data/lib/playwright/input_files.rb +42 -0
- data/lib/playwright/input_types/keyboard.rb +1 -1
- data/lib/playwright/javascript/value_serializer.rb +11 -11
- data/lib/playwright/playwright_api.rb +8 -0
- data/lib/playwright/select_option_values.rb +32 -0
- data/lib/playwright/utils.rb +18 -0
- data/lib/playwright/version.rb +1 -1
- data/lib/playwright_api/android.rb +33 -0
- data/lib/playwright_api/android_device.rb +48 -0
- data/lib/playwright_api/binding_call.rb +3 -3
- data/lib/playwright_api/browser.rb +7 -6
- data/lib/playwright_api/browser_context.rb +6 -6
- data/lib/playwright_api/browser_type.rb +4 -4
- data/lib/playwright_api/chromium_browser_context.rb +3 -3
- data/lib/playwright_api/console_message.rb +3 -8
- data/lib/playwright_api/dialog.rb +2 -2
- data/lib/playwright_api/element_handle.rb +40 -39
- data/lib/playwright_api/frame.rb +23 -27
- data/lib/playwright_api/js_handle.rb +15 -9
- data/lib/playwright_api/keyboard.rb +6 -6
- data/lib/playwright_api/page.rb +35 -54
- data/lib/playwright_api/playwright.rb +7 -7
- data/lib/playwright_api/request.rb +3 -3
- data/lib/playwright_api/response.rb +3 -3
- data/lib/playwright_api/selectors.rb +3 -3
- data/playwright.gemspec +1 -0
- metadata +22 -2
data/lib/playwright.rb
CHANGED
@@ -15,8 +15,10 @@ require 'playwright/utils'
|
|
15
15
|
|
16
16
|
require 'playwright/channel'
|
17
17
|
require 'playwright/channel_owner'
|
18
|
+
require 'playwright/input_files'
|
18
19
|
require 'playwright/input_type'
|
19
20
|
require 'playwright/connection'
|
21
|
+
require 'playwright/select_option_values'
|
20
22
|
require 'playwright/timeout_settings'
|
21
23
|
require 'playwright/transport'
|
22
24
|
require 'playwright/url_matcher'
|
@@ -39,13 +39,14 @@ module Playwright
|
|
39
39
|
|
40
40
|
attr_reader :channel
|
41
41
|
|
42
|
-
|
42
|
+
# used only from Connection. Not intended for public use. So keep private.
|
43
|
+
private def dispose!
|
43
44
|
# Clean up from parent and connection.
|
44
45
|
@parent&.send(:delete_object_from_child, @guid)
|
45
46
|
@connection.send(:delete_object_from_channel_owner, @guid)
|
46
47
|
|
47
48
|
# Dispose all children.
|
48
|
-
@objects.each_value(
|
49
|
+
@objects.each_value { |object| object.send(:dispose!) }
|
49
50
|
@objects.clear
|
50
51
|
end
|
51
52
|
|
@@ -1,3 +1,12 @@
|
|
1
1
|
module Playwright
|
2
|
-
define_channel_owner :Android
|
2
|
+
define_channel_owner :Android do
|
3
|
+
def after_initialize
|
4
|
+
@timeout_settings = TimeoutSettings.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def devices
|
8
|
+
resp = @channel.send_message_to_server('devices')
|
9
|
+
resp.map { |device| ChannelOwners::AndroidDevice.from(device) }
|
10
|
+
end
|
11
|
+
end
|
3
12
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_channel_owner :AndroidDevice do
|
3
|
+
include Utils::PrepareBrowserContextOptions
|
4
|
+
|
5
|
+
def serial
|
6
|
+
@initializer['serial']
|
7
|
+
end
|
8
|
+
|
9
|
+
def model
|
10
|
+
@initializer['model']
|
11
|
+
end
|
12
|
+
|
13
|
+
def shell(command)
|
14
|
+
resp = @channel.send_message_to_server('shell', command: command)
|
15
|
+
Base64.strict_decode64(resp)
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@channel.send_message_to_server('close')
|
20
|
+
emit(Events::AndroidDevice::Close)
|
21
|
+
end
|
22
|
+
|
23
|
+
def launch_browser(
|
24
|
+
pkg: nil,
|
25
|
+
acceptDownloads: nil,
|
26
|
+
bypassCSP: nil,
|
27
|
+
colorScheme: nil,
|
28
|
+
deviceScaleFactor: nil,
|
29
|
+
extraHTTPHeaders: nil,
|
30
|
+
geolocation: nil,
|
31
|
+
hasTouch: nil,
|
32
|
+
httpCredentials: nil,
|
33
|
+
ignoreHTTPSErrors: nil,
|
34
|
+
isMobile: nil,
|
35
|
+
javaScriptEnabled: nil,
|
36
|
+
locale: nil,
|
37
|
+
logger: nil,
|
38
|
+
offline: nil,
|
39
|
+
permissions: nil,
|
40
|
+
proxy: nil,
|
41
|
+
recordHar: nil,
|
42
|
+
recordVideo: nil,
|
43
|
+
storageState: nil,
|
44
|
+
timezoneId: nil,
|
45
|
+
userAgent: nil,
|
46
|
+
videoSize: nil,
|
47
|
+
videosPath: nil,
|
48
|
+
viewport: nil,
|
49
|
+
&block)
|
50
|
+
params = {
|
51
|
+
pkg: pkg,
|
52
|
+
acceptDownloads: acceptDownloads,
|
53
|
+
bypassCSP: bypassCSP,
|
54
|
+
colorScheme: colorScheme,
|
55
|
+
deviceScaleFactor: deviceScaleFactor,
|
56
|
+
extraHTTPHeaders: extraHTTPHeaders,
|
57
|
+
geolocation: geolocation,
|
58
|
+
hasTouch: hasTouch,
|
59
|
+
httpCredentials: httpCredentials,
|
60
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
61
|
+
isMobile: isMobile,
|
62
|
+
javaScriptEnabled: javaScriptEnabled,
|
63
|
+
locale: locale,
|
64
|
+
logger: logger,
|
65
|
+
offline: offline,
|
66
|
+
permissions: permissions,
|
67
|
+
proxy: proxy,
|
68
|
+
recordHar: recordHar,
|
69
|
+
recordVideo: recordVideo,
|
70
|
+
storageState: storageState,
|
71
|
+
timezoneId: timezoneId,
|
72
|
+
userAgent: userAgent,
|
73
|
+
videoSize: videoSize,
|
74
|
+
videosPath: videosPath,
|
75
|
+
viewport: viewport,
|
76
|
+
}.compact
|
77
|
+
prepare_browser_context_options(params)
|
78
|
+
|
79
|
+
resp = @channel.send_message_to_server('launchBrowser', params)
|
80
|
+
context = ChannelOwners::BrowserContext.from(resp)
|
81
|
+
|
82
|
+
if block
|
83
|
+
begin
|
84
|
+
block.call(context)
|
85
|
+
ensure
|
86
|
+
context.close
|
87
|
+
end
|
88
|
+
else
|
89
|
+
context
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -2,6 +2,7 @@ module Playwright
|
|
2
2
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_browser.py
|
3
3
|
define_channel_owner :Browser do
|
4
4
|
include Utils::Errors::SafeCloseError
|
5
|
+
include Utils::PrepareBrowserContextOptions
|
5
6
|
|
6
7
|
def after_initialize
|
7
8
|
@contexts = Set.new
|
@@ -16,26 +17,25 @@ module Playwright
|
|
16
17
|
@connected
|
17
18
|
end
|
18
19
|
|
19
|
-
def new_context(**options)
|
20
|
+
def new_context(**options, &block)
|
20
21
|
params = options.dup
|
21
|
-
|
22
|
-
if params[:viewport] == 0
|
23
|
-
params.delete(:viewport)
|
24
|
-
params[:noDefaultViewport] = true
|
25
|
-
end
|
26
|
-
if params[:extraHTTPHeaders]
|
27
|
-
# TODO
|
28
|
-
end
|
29
|
-
if params[:storageState].is_a?(String)
|
30
|
-
params[:storageState] = JSON.parse(File.read(params[:storageState]))
|
31
|
-
end
|
22
|
+
prepare_browser_context_options(params)
|
32
23
|
|
33
24
|
resp = @channel.send_message_to_server('newContext', params.compact)
|
34
25
|
context = ChannelOwners::BrowserContext.from(resp)
|
35
26
|
@contexts << context
|
36
27
|
context.browser = self
|
37
28
|
context.options = params
|
38
|
-
|
29
|
+
|
30
|
+
if block
|
31
|
+
begin
|
32
|
+
block.call(context)
|
33
|
+
ensure
|
34
|
+
context.close
|
35
|
+
end
|
36
|
+
else
|
37
|
+
context
|
38
|
+
end
|
39
39
|
end
|
40
40
|
|
41
41
|
def new_page(**options)
|
@@ -3,6 +3,91 @@ require_relative './js_handle'
|
|
3
3
|
module Playwright
|
4
4
|
module ChannelOwners
|
5
5
|
class ElementHandle < JSHandle
|
6
|
+
def as_element
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def owner_frame
|
11
|
+
resp = @channel.send_message_to_server('ownerFrame')
|
12
|
+
ChannelOwners::Frame.from_nullable(resp)
|
13
|
+
end
|
14
|
+
|
15
|
+
def content_frame
|
16
|
+
resp = @channel.send_message_to_server('contentFrame')
|
17
|
+
ChannelOwners::Frame.from_nullable(resp)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_attribute(name)
|
21
|
+
@channel.send_message_to_server('getAttribute', name: name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def text_content
|
25
|
+
@channel.send_message_to_server('textContent')
|
26
|
+
end
|
27
|
+
|
28
|
+
def inner_text
|
29
|
+
@channel.send_message_to_server('innerText')
|
30
|
+
end
|
31
|
+
|
32
|
+
def inner_html
|
33
|
+
@channel.send_message_to_server('innerHTML')
|
34
|
+
end
|
35
|
+
|
36
|
+
def checked?
|
37
|
+
@channel.send_message_to_server('isChecked')
|
38
|
+
end
|
39
|
+
|
40
|
+
def disabled?
|
41
|
+
@channel.send_message_to_server('isDisabled')
|
42
|
+
end
|
43
|
+
|
44
|
+
def editable?
|
45
|
+
@channel.send_message_to_server('isEditable')
|
46
|
+
end
|
47
|
+
|
48
|
+
def enabled?
|
49
|
+
@channel.send_message_to_server('isEnabled')
|
50
|
+
end
|
51
|
+
|
52
|
+
def hidden?
|
53
|
+
@channel.send_message_to_server('isHidden')
|
54
|
+
end
|
55
|
+
|
56
|
+
def visible?
|
57
|
+
@channel.send_message_to_server('isVisible')
|
58
|
+
end
|
59
|
+
|
60
|
+
def dispatch_event(type, eventInit: nil)
|
61
|
+
params = {
|
62
|
+
type: type,
|
63
|
+
eventInit: JavaScript::ValueSerializer.new(eventInit).serialize,
|
64
|
+
}.compact
|
65
|
+
@channel.send_message_to_server('dispatchEvent', params)
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def scroll_into_view_if_needed(timeout: nil)
|
71
|
+
params = {
|
72
|
+
timeout: timeout,
|
73
|
+
}.compact
|
74
|
+
@channel.send_message_to_server('scrollIntoViewIfNeeded', params)
|
75
|
+
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def hover(force: nil, modifiers: nil, position: nil, timeout: nil)
|
80
|
+
params = {
|
81
|
+
force: force,
|
82
|
+
modifiers: modifiers,
|
83
|
+
position: position,
|
84
|
+
timeout: timeout,
|
85
|
+
}
|
86
|
+
@channel.send_message_to_server('hover', params)
|
87
|
+
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
6
91
|
def click(
|
7
92
|
button: nil,
|
8
93
|
clickCount: nil,
|
@@ -28,7 +113,89 @@ module Playwright
|
|
28
113
|
nil
|
29
114
|
end
|
30
115
|
|
31
|
-
def
|
116
|
+
def dblclick(
|
117
|
+
button: nil,
|
118
|
+
delay: nil,
|
119
|
+
force: nil,
|
120
|
+
modifiers: nil,
|
121
|
+
noWaitAfter: nil,
|
122
|
+
position: nil,
|
123
|
+
timeout: nil)
|
124
|
+
|
125
|
+
params = {
|
126
|
+
button: button,
|
127
|
+
delay: delay,
|
128
|
+
force: force,
|
129
|
+
modifiers: modifiers,
|
130
|
+
noWaitAfter: noWaitAfter,
|
131
|
+
position: position,
|
132
|
+
timeout: timeout,
|
133
|
+
}.compact
|
134
|
+
@channel.send_message_to_server('dblclick', params)
|
135
|
+
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def select_option(values, noWaitAfter: nil, timeout: nil)
|
140
|
+
base_params = SelectOptionValues.new(values).as_params
|
141
|
+
params = base_params + { noWaitAfter: noWaitAfter, timeout: timeout }.compact
|
142
|
+
@channel.send_message_to_server('selectOption', params)
|
143
|
+
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def tap_point(
|
148
|
+
force: nil,
|
149
|
+
modifiers: nil,
|
150
|
+
noWaitAfter: nil,
|
151
|
+
position: nil,
|
152
|
+
timeout: nil)
|
153
|
+
|
154
|
+
params = {
|
155
|
+
force: force,
|
156
|
+
modifiers: modifiers,
|
157
|
+
noWaitAfter: noWaitAfter,
|
158
|
+
position: position,
|
159
|
+
timeout: timeout,
|
160
|
+
}.compact
|
161
|
+
@channel.send_message_to_server('tap', params)
|
162
|
+
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
|
166
|
+
def fill(value, noWaitAfter: nil, timeout: nil)
|
167
|
+
params = {
|
168
|
+
value: value,
|
169
|
+
noWaitAfter: noWaitAfter,
|
170
|
+
timeout: timeout,
|
171
|
+
}
|
172
|
+
@channel.send_message_to_server('fill', params)
|
173
|
+
|
174
|
+
nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def select_text(timeout: nil)
|
178
|
+
params = { timeout: timeout }.compact
|
179
|
+
@channel.send_message_to_server('selectText', params)
|
180
|
+
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def set_input_files(files, noWaitAfter: nil, timeout: nil)
|
185
|
+
base_params = InputFiles.new(values).as_params
|
186
|
+
params = base_params + { noWaitAfter: noWaitAfter, timeout: timeout }.compact
|
187
|
+
@channel.send_message_to_server('setInputFiles', params)
|
188
|
+
|
189
|
+
nil
|
190
|
+
end
|
191
|
+
|
192
|
+
def focus
|
193
|
+
@channel.send_message_to_server('focus')
|
194
|
+
|
195
|
+
nil
|
196
|
+
end
|
197
|
+
|
198
|
+
def type(text, delay: nil, noWaitAfter: nil, timeout: nil)
|
32
199
|
params = {
|
33
200
|
text: text,
|
34
201
|
delay: delay,
|
@@ -52,6 +219,56 @@ module Playwright
|
|
52
219
|
nil
|
53
220
|
end
|
54
221
|
|
222
|
+
def check(force: nil, noWaitAfter: nil, timeout: nil)
|
223
|
+
params = {
|
224
|
+
force: force,
|
225
|
+
noWaitAfter: noWaitAfter,
|
226
|
+
timeout: timeout,
|
227
|
+
}.compact
|
228
|
+
@channel.send_message_to_server('check', params)
|
229
|
+
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
|
233
|
+
def uncheck(force: nil, noWaitAfter: nil, timeout: nil)
|
234
|
+
params = {
|
235
|
+
force: force,
|
236
|
+
noWaitAfter: noWaitAfter,
|
237
|
+
timeout: timeout,
|
238
|
+
}.compact
|
239
|
+
@channel.send_message_to_server('uncheck', params)
|
240
|
+
|
241
|
+
nil
|
242
|
+
end
|
243
|
+
|
244
|
+
def bounding_box
|
245
|
+
@channel.send_message_to_server('boundingBox')
|
246
|
+
end
|
247
|
+
|
248
|
+
def screenshot(
|
249
|
+
omitBackground: nil,
|
250
|
+
path: nil,
|
251
|
+
quality: nil,
|
252
|
+
timeout: nil,
|
253
|
+
type: nil)
|
254
|
+
|
255
|
+
params = {
|
256
|
+
omitBackground: omitBackground,
|
257
|
+
path: path,
|
258
|
+
quality: quality,
|
259
|
+
timeout: timeout,
|
260
|
+
type: type,
|
261
|
+
}.compact
|
262
|
+
encoded_binary = @channel.send_message_to_server('screenshot', params)
|
263
|
+
decoded_binary = Base64.strict_decode64(encoded_binary)
|
264
|
+
if path
|
265
|
+
File.open(path, 'wb') do |f|
|
266
|
+
f.write(decoded_binary)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
decoded_binary
|
270
|
+
end
|
271
|
+
|
55
272
|
def query_selector(selector)
|
56
273
|
resp = @channel.send_message_to_server('querySelector', selector: selector)
|
57
274
|
ChannelOwners::ElementHandle.from_nullable(resp)
|
@@ -78,6 +295,20 @@ module Playwright
|
|
78
295
|
JavaScript::Expression.new(pageFunction).eval_on_selector_all(@channel, selector)
|
79
296
|
end
|
80
297
|
end
|
298
|
+
|
299
|
+
def wait_for_element_state(state, timeout: nil)
|
300
|
+
params = { state: state, timeout: timeout }.compact
|
301
|
+
@channel.send_message_to_server('waitForElementState', params)
|
302
|
+
|
303
|
+
nil
|
304
|
+
end
|
305
|
+
|
306
|
+
def wait_for_selector(selector, state: nil, timeout: nil)
|
307
|
+
params = { selector: selector, state: state, timeout: timeout }.compact
|
308
|
+
resp = @channel.send_message_to_server('waitForSelector', params)
|
309
|
+
|
310
|
+
ChannelOwners::ElementHandle.from_nullable(resp)
|
311
|
+
end
|
81
312
|
end
|
82
313
|
end
|
83
314
|
end
|
@@ -62,7 +62,7 @@ module Playwright
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
65
|
+
def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
|
66
66
|
option_wait_until = waitUntil || 'load'
|
67
67
|
option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
|
68
68
|
time_start = Time.now
|
@@ -100,6 +100,7 @@ module Playwright
|
|
100
100
|
|
101
101
|
def wait_for_load_state(state: nil, timeout: nil)
|
102
102
|
option_state = state || 'load'
|
103
|
+
option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
|
103
104
|
unless %w(load domcontentloaded networkidle).include?(option_state)
|
104
105
|
raise ArgumentError.new('state: expected one of (load|domcontentloaded|networkidle)')
|
105
106
|
end
|
@@ -107,7 +108,7 @@ module Playwright
|
|
107
108
|
return
|
108
109
|
end
|
109
110
|
|
110
|
-
wait_helper = setup_navigation_wait_helper(timeout:
|
111
|
+
wait_helper = setup_navigation_wait_helper(timeout: option_timeout)
|
111
112
|
|
112
113
|
predicate = ->(state) { state == option_state }
|
113
114
|
wait_helper.wait_for_event(@event_emitter, 'loadstate', predicate: predicate)
|
@@ -202,13 +203,50 @@ module Playwright
|
|
202
203
|
nil
|
203
204
|
end
|
204
205
|
|
206
|
+
def dblclick(
|
207
|
+
selector,
|
208
|
+
button: nil,
|
209
|
+
delay: nil,
|
210
|
+
force: nil,
|
211
|
+
modifiers: nil,
|
212
|
+
noWaitAfter: nil,
|
213
|
+
position: nil,
|
214
|
+
timeout: nil)
|
215
|
+
|
216
|
+
params = {
|
217
|
+
selector: selector,
|
218
|
+
button: button,
|
219
|
+
delay: delay,
|
220
|
+
force: force,
|
221
|
+
modifiers: modifiers,
|
222
|
+
noWaitAfter: noWaitAfter,
|
223
|
+
position: position,
|
224
|
+
timeout: timeout,
|
225
|
+
}.compact
|
226
|
+
@channel.send_message_to_server('dblclick', params)
|
227
|
+
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
|
231
|
+
def fill(selector, value, noWaitAfter: nil, timeout: nil)
|
232
|
+
params = {
|
233
|
+
selector: selector,
|
234
|
+
value: value,
|
235
|
+
noWaitAfter: noWaitAfter,
|
236
|
+
timeout: timeout,
|
237
|
+
}.compact
|
238
|
+
@channel.send_message_to_server('fill', params)
|
239
|
+
|
240
|
+
nil
|
241
|
+
end
|
242
|
+
|
205
243
|
def focus(selector, timeout: nil)
|
206
244
|
params = { selector: selector, timeout: timeout }.compact
|
207
245
|
@channel.send_message_to_server('focus', params)
|
208
246
|
nil
|
209
247
|
end
|
210
248
|
|
211
|
-
def
|
249
|
+
def type(
|
212
250
|
selector,
|
213
251
|
text,
|
214
252
|
delay: nil,
|