playwright-ruby-client 0.0.6 → 0.2.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/README.md +117 -5
- data/docs/api_coverage.md +359 -0
- data/lib/playwright.rb +6 -2
- data/lib/playwright/android_input_impl.rb +23 -0
- data/lib/playwright/api_implementation.rb +18 -0
- data/lib/playwright/channel.rb +7 -0
- data/lib/playwright/channel_owner.rb +6 -7
- data/lib/playwright/channel_owners/android.rb +10 -1
- data/lib/playwright/channel_owners/android_device.rb +163 -0
- data/lib/playwright/channel_owners/browser.rb +14 -14
- data/lib/playwright/channel_owners/browser_context.rb +10 -2
- data/lib/playwright/channel_owners/download.rb +27 -0
- data/lib/playwright/channel_owners/element_handle.rb +243 -1
- data/lib/playwright/channel_owners/frame.rb +269 -22
- data/lib/playwright/channel_owners/js_handle.rb +51 -0
- data/lib/playwright/channel_owners/page.rb +379 -34
- data/lib/playwright/channel_owners/request.rb +9 -1
- data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
- data/lib/playwright/connection.rb +9 -6
- data/lib/playwright/errors.rb +2 -2
- 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 +42 -0
- data/lib/playwright/javascript/expression.rb +15 -0
- data/lib/playwright/javascript/function.rb +15 -0
- data/lib/playwright/javascript/value_parser.rb +1 -1
- data/lib/playwright/javascript/value_serializer.rb +11 -11
- data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +6 -2
- data/lib/playwright/mouse_impl.rb +7 -0
- data/lib/playwright/playwright_api.rb +66 -19
- data/lib/playwright/select_option_values.rb +42 -0
- data/lib/playwright/timeout_settings.rb +1 -1
- data/lib/playwright/touchscreen_impl.rb +7 -0
- data/lib/playwright/utils.rb +18 -0
- data/lib/playwright/version.rb +1 -1
- data/lib/playwright/wait_helper.rb +1 -1
- data/lib/playwright_api/android.rb +32 -0
- data/lib/playwright_api/android_device.rb +77 -0
- data/lib/playwright_api/android_input.rb +25 -0
- data/lib/playwright_api/binding_call.rb +10 -6
- data/lib/playwright_api/browser.rb +22 -22
- data/lib/playwright_api/browser_context.rb +31 -22
- data/lib/playwright_api/browser_type.rb +16 -56
- data/lib/playwright_api/chromium_browser_context.rb +10 -8
- data/lib/playwright_api/console_message.rb +9 -10
- data/lib/playwright_api/dialog.rb +7 -3
- data/lib/playwright_api/download.rb +28 -11
- data/lib/playwright_api/element_handle.rb +139 -127
- data/lib/playwright_api/file_chooser.rb +17 -9
- data/lib/playwright_api/frame.rb +148 -148
- data/lib/playwright_api/js_handle.rb +26 -22
- data/lib/playwright_api/keyboard.rb +6 -6
- data/lib/playwright_api/page.rb +215 -179
- data/lib/playwright_api/playwright.rb +34 -46
- data/lib/playwright_api/request.rb +7 -8
- data/lib/playwright_api/response.rb +10 -6
- data/lib/playwright_api/selectors.rb +13 -9
- data/lib/playwright_api/web_socket.rb +10 -1
- data/lib/playwright_api/worker.rb +13 -13
- data/playwright.gemspec +1 -0
- metadata +32 -6
- 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
@@ -1,7 +1,7 @@
|
|
1
1
|
module Playwright
|
2
2
|
# @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_frame.py
|
3
3
|
define_channel_owner :Frame do
|
4
|
-
def after_initialize
|
4
|
+
private def after_initialize
|
5
5
|
if @initializer['parentFrame']
|
6
6
|
@parent_frame = ChannelOwners::Frame.from(@initializer['parentFrame'])
|
7
7
|
@parent_frame.send(:append_child_frame_from_child, self)
|
@@ -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)
|
@@ -143,6 +144,55 @@ module Playwright
|
|
143
144
|
end
|
144
145
|
end
|
145
146
|
|
147
|
+
def wait_for_selector(selector, state: nil, timeout: nil)
|
148
|
+
params = { selector: selector, state: state, timeout: timeout }.compact
|
149
|
+
resp = @channel.send_message_to_server('waitForSelector', params)
|
150
|
+
|
151
|
+
ChannelOwners::ElementHandle.from_nullable(resp)
|
152
|
+
end
|
153
|
+
|
154
|
+
def checked?(selector, timeout: nil)
|
155
|
+
params = { selector: selector, timeout: timeout }.compact
|
156
|
+
@channel.send_message_to_server('isChecked', params)
|
157
|
+
end
|
158
|
+
|
159
|
+
def disabled?(selector, timeout: nil)
|
160
|
+
params = { selector: selector, timeout: timeout }.compact
|
161
|
+
@channel.send_message_to_server('isDisabled', params)
|
162
|
+
end
|
163
|
+
|
164
|
+
def editable?(selector, timeout: nil)
|
165
|
+
params = { selector: selector, timeout: timeout }.compact
|
166
|
+
@channel.send_message_to_server('isEditable', params)
|
167
|
+
end
|
168
|
+
|
169
|
+
def enabled?(selector, timeout: nil)
|
170
|
+
params = { selector: selector, timeout: timeout }.compact
|
171
|
+
@channel.send_message_to_server('isEnabled', params)
|
172
|
+
end
|
173
|
+
|
174
|
+
def hidden?(selector, timeout: nil)
|
175
|
+
params = { selector: selector, timeout: timeout }.compact
|
176
|
+
@channel.send_message_to_server('isHidden', params)
|
177
|
+
end
|
178
|
+
|
179
|
+
def visible?(selector, timeout: nil)
|
180
|
+
params = { selector: selector, timeout: timeout }.compact
|
181
|
+
@channel.send_message_to_server('isVisible', params)
|
182
|
+
end
|
183
|
+
|
184
|
+
def dispatch_event(selector, type, eventInit: nil, timeout: nil)
|
185
|
+
params = {
|
186
|
+
selector: selector,
|
187
|
+
type: type,
|
188
|
+
eventInit: JavaScript::ValueSerializer.new(eventInit).serialize,
|
189
|
+
timeout: timeout,
|
190
|
+
}.compact
|
191
|
+
@channel.send_message_to_server('dispatchEvent', params)
|
192
|
+
|
193
|
+
nil
|
194
|
+
end
|
195
|
+
|
146
196
|
def eval_on_selector(selector, pageFunction, arg: nil)
|
147
197
|
if JavaScript.function?(pageFunction)
|
148
198
|
JavaScript::Function.new(pageFunction, arg).eval_on_selector(@channel, selector)
|
@@ -175,6 +225,47 @@ module Playwright
|
|
175
225
|
nil
|
176
226
|
end
|
177
227
|
|
228
|
+
def name
|
229
|
+
@name || ''
|
230
|
+
end
|
231
|
+
|
232
|
+
def url
|
233
|
+
@url || ''
|
234
|
+
end
|
235
|
+
|
236
|
+
def child_frames
|
237
|
+
@child_frames.to_a
|
238
|
+
end
|
239
|
+
|
240
|
+
def detached?
|
241
|
+
@detached
|
242
|
+
end
|
243
|
+
|
244
|
+
def add_script_tag(content: nil, path: nil, type: nil, url: nil)
|
245
|
+
params = {
|
246
|
+
content: content,
|
247
|
+
type: type,
|
248
|
+
url: url,
|
249
|
+
}.compact
|
250
|
+
if path
|
251
|
+
params[:content] = "#{File.read(path)}\n//# sourceURL=#{path}"
|
252
|
+
end
|
253
|
+
resp = @channel.send_message_to_server('addScriptTag', params)
|
254
|
+
ChannelOwners::ElementHandle.from(resp)
|
255
|
+
end
|
256
|
+
|
257
|
+
def add_style_tag(content: nil, path: nil, url: nil)
|
258
|
+
params = {
|
259
|
+
content: content,
|
260
|
+
url: url,
|
261
|
+
}.compact
|
262
|
+
if path
|
263
|
+
params[:content] = "#{File.read(path)}\n/*# sourceURL=#{path}*/"
|
264
|
+
end
|
265
|
+
resp = @channel.send_message_to_server('addStyleTag', params)
|
266
|
+
ChannelOwners::ElementHandle.from(resp)
|
267
|
+
end
|
268
|
+
|
178
269
|
def click(
|
179
270
|
selector,
|
180
271
|
button: nil,
|
@@ -202,18 +293,145 @@ module Playwright
|
|
202
293
|
nil
|
203
294
|
end
|
204
295
|
|
296
|
+
def dblclick(
|
297
|
+
selector,
|
298
|
+
button: nil,
|
299
|
+
delay: nil,
|
300
|
+
force: nil,
|
301
|
+
modifiers: nil,
|
302
|
+
noWaitAfter: nil,
|
303
|
+
position: nil,
|
304
|
+
timeout: nil)
|
305
|
+
|
306
|
+
params = {
|
307
|
+
selector: selector,
|
308
|
+
button: button,
|
309
|
+
delay: delay,
|
310
|
+
force: force,
|
311
|
+
modifiers: modifiers,
|
312
|
+
noWaitAfter: noWaitAfter,
|
313
|
+
position: position,
|
314
|
+
timeout: timeout,
|
315
|
+
}.compact
|
316
|
+
@channel.send_message_to_server('dblclick', params)
|
317
|
+
|
318
|
+
nil
|
319
|
+
end
|
320
|
+
|
321
|
+
def tap_point(
|
322
|
+
selector,
|
323
|
+
force: nil,
|
324
|
+
modifiers: nil,
|
325
|
+
noWaitAfter: nil,
|
326
|
+
position: nil,
|
327
|
+
timeout: nil)
|
328
|
+
params = {
|
329
|
+
selector: selector,
|
330
|
+
force: force,
|
331
|
+
modifiers: modifiers,
|
332
|
+
noWaitAfter: noWaitAfter,
|
333
|
+
position: position,
|
334
|
+
timeout: timeout,
|
335
|
+
}.compact
|
336
|
+
@channel.send_message_to_server('tap', params)
|
337
|
+
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
|
341
|
+
def fill(selector, value, noWaitAfter: nil, timeout: nil)
|
342
|
+
params = {
|
343
|
+
selector: selector,
|
344
|
+
value: value,
|
345
|
+
noWaitAfter: noWaitAfter,
|
346
|
+
timeout: timeout,
|
347
|
+
}.compact
|
348
|
+
@channel.send_message_to_server('fill', params)
|
349
|
+
|
350
|
+
nil
|
351
|
+
end
|
352
|
+
|
205
353
|
def focus(selector, timeout: nil)
|
206
354
|
params = { selector: selector, timeout: timeout }.compact
|
207
355
|
@channel.send_message_to_server('focus', params)
|
208
356
|
nil
|
209
357
|
end
|
210
358
|
|
211
|
-
def
|
212
|
-
selector,
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
359
|
+
def text_content(selector, timeout: nil)
|
360
|
+
params = { selector: selector, timeout: timeout }.compact
|
361
|
+
@channel.send_message_to_server('textContent', params)
|
362
|
+
end
|
363
|
+
|
364
|
+
def inner_text(selector, timeout: nil)
|
365
|
+
params = { selector: selector, timeout: timeout }.compact
|
366
|
+
@channel.send_message_to_server('innerText', params)
|
367
|
+
end
|
368
|
+
|
369
|
+
def inner_html(selector, timeout: nil)
|
370
|
+
params = { selector: selector, timeout: timeout }.compact
|
371
|
+
@channel.send_message_to_server('innerHTML', params)
|
372
|
+
end
|
373
|
+
|
374
|
+
def get_attribute(selector, name, timeout: nil)
|
375
|
+
params = {
|
376
|
+
selector: selector,
|
377
|
+
name: name,
|
378
|
+
timeout: timeout,
|
379
|
+
}.compact
|
380
|
+
@channel.send_message_to_server('getAttribute', params)
|
381
|
+
end
|
382
|
+
|
383
|
+
def hover(
|
384
|
+
selector,
|
385
|
+
force: nil,
|
386
|
+
modifiers: nil,
|
387
|
+
position: nil,
|
388
|
+
timeout: nil)
|
389
|
+
params = {
|
390
|
+
selector: selector,
|
391
|
+
force: force,
|
392
|
+
modifiers: modifiers,
|
393
|
+
position: position,
|
394
|
+
timeout: timeout,
|
395
|
+
}.compact
|
396
|
+
@channel.send_message_to_server('hover', params)
|
397
|
+
|
398
|
+
nil
|
399
|
+
end
|
400
|
+
|
401
|
+
def select_option(
|
402
|
+
selector,
|
403
|
+
element: nil,
|
404
|
+
index: nil,
|
405
|
+
value: nil,
|
406
|
+
label: nil,
|
407
|
+
noWaitAfter: nil,
|
408
|
+
timeout: nil)
|
409
|
+
base_params = SelectOptionValues.new(
|
410
|
+
element: element,
|
411
|
+
index: index,
|
412
|
+
value: value,
|
413
|
+
label: label,
|
414
|
+
).as_params
|
415
|
+
params = base_params + { selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
|
416
|
+
@channel.send_message_to_server('selectOption', params)
|
417
|
+
|
418
|
+
nil
|
419
|
+
end
|
420
|
+
|
421
|
+
def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
|
422
|
+
file_payloads = InputFiles.new(files).as_params
|
423
|
+
params = { files: file_payloads, selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
|
424
|
+
@channel.send_message_to_server('setInputFiles', params)
|
425
|
+
|
426
|
+
nil
|
427
|
+
end
|
428
|
+
|
429
|
+
def type(
|
430
|
+
selector,
|
431
|
+
text,
|
432
|
+
delay: nil,
|
433
|
+
noWaitAfter: nil,
|
434
|
+
timeout: nil)
|
217
435
|
|
218
436
|
params = {
|
219
437
|
selector: selector,
|
@@ -222,16 +440,17 @@ module Playwright
|
|
222
440
|
noWaitAfter: noWaitAfter,
|
223
441
|
timeout: timeout,
|
224
442
|
}.compact
|
225
|
-
|
226
443
|
@channel.send_message_to_server('type', params)
|
444
|
+
|
445
|
+
nil
|
227
446
|
end
|
228
447
|
|
229
448
|
def press(
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
449
|
+
selector,
|
450
|
+
key,
|
451
|
+
delay: nil,
|
452
|
+
noWaitAfter: nil,
|
453
|
+
timeout: nil)
|
235
454
|
|
236
455
|
params = {
|
237
456
|
selector: selector,
|
@@ -240,20 +459,48 @@ module Playwright
|
|
240
459
|
noWaitAfter: noWaitAfter,
|
241
460
|
timeout: timeout,
|
242
461
|
}.compact
|
243
|
-
|
244
462
|
@channel.send_message_to_server('press', params)
|
463
|
+
|
464
|
+
nil
|
245
465
|
end
|
246
466
|
|
247
|
-
def
|
248
|
-
|
467
|
+
def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
|
468
|
+
params = {
|
469
|
+
selector: selector,
|
470
|
+
force: force,
|
471
|
+
noWaitAfter: noWaitAfter,
|
472
|
+
timeout: timeout,
|
473
|
+
}.compact
|
474
|
+
@channel.send_message_to_server('check', params)
|
475
|
+
|
476
|
+
nil
|
249
477
|
end
|
250
478
|
|
251
|
-
def
|
252
|
-
|
479
|
+
def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
|
480
|
+
params = {
|
481
|
+
selector: selector,
|
482
|
+
force: force,
|
483
|
+
noWaitAfter: noWaitAfter,
|
484
|
+
timeout: timeout,
|
485
|
+
}.compact
|
486
|
+
@channel.send_message_to_server('uncheck', params)
|
487
|
+
|
488
|
+
nil
|
253
489
|
end
|
254
490
|
|
255
|
-
def
|
256
|
-
|
491
|
+
def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
|
492
|
+
if polling.is_a?(String) && polling != 'raf'
|
493
|
+
raise ArgumentError.new("Unknown polling option: #{polling}")
|
494
|
+
end
|
495
|
+
|
496
|
+
function_or_expression =
|
497
|
+
if JavaScript.function?(pageFunction)
|
498
|
+
JavaScript::Function.new(pageFunction, arg)
|
499
|
+
else
|
500
|
+
JavaScript::Expression.new(pageFunction)
|
501
|
+
end
|
502
|
+
|
503
|
+
function_or_expression.wait_for_function(@channel, polling: polling, timeout: timeout)
|
257
504
|
end
|
258
505
|
|
259
506
|
def title
|
@@ -1,4 +1,55 @@
|
|
1
1
|
module Playwright
|
2
2
|
define_channel_owner :JSHandle do
|
3
|
+
private def after_initialize
|
4
|
+
@preview = @initializer['preview']
|
5
|
+
@channel.on('previewUpdated', method(:on_preview_updated))
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
@preview
|
10
|
+
end
|
11
|
+
|
12
|
+
private def on_preview_updated(preview)
|
13
|
+
@preview = preview
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate(pageFunction, arg: nil)
|
17
|
+
if JavaScript.function?(pageFunction)
|
18
|
+
JavaScript::Function.new(pageFunction, arg).evaluate(@channel)
|
19
|
+
else
|
20
|
+
JavaScript::Expression.new(pageFunction).evaluate(@channel)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def evaluate_handle(pageFunction, arg: nil)
|
25
|
+
if JavaScript.function?(pageFunction)
|
26
|
+
JavaScript::Function.new(pageFunction, arg).evaluate_handle(@channel)
|
27
|
+
else
|
28
|
+
JavaScript::Expression.new(pageFunction).evaluate_handle(@channel)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_properties
|
33
|
+
resp = @channel.send_message_to_server('getPropertyList')
|
34
|
+
resp.map { |prop| [prop['name'], ChannelOwner.from(prop['value'])] }.to_h
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_property(name)
|
38
|
+
resp = @channel.send_message_to_server('getProperty', name: name)
|
39
|
+
ChannelOwner.from(resp)
|
40
|
+
end
|
41
|
+
|
42
|
+
def as_element
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def dispose
|
47
|
+
@channel.send_message_to_server('dispose')
|
48
|
+
end
|
49
|
+
|
50
|
+
def json_value
|
51
|
+
value = @channel.send_message_to_server('jsonValue')
|
52
|
+
JavaScript::ValueParser.new(value).parse
|
53
|
+
end
|
3
54
|
end
|
4
55
|
end
|
@@ -6,13 +6,13 @@ module Playwright
|
|
6
6
|
include Utils::Errors::SafeCloseError
|
7
7
|
attr_writer :owned_context
|
8
8
|
|
9
|
-
def after_initialize
|
9
|
+
private def after_initialize
|
10
10
|
@browser_context = @parent
|
11
11
|
@timeout_settings = TimeoutSettings.new(@browser_context.send(:_timeout_settings))
|
12
12
|
@accessibility = Accessibility.new(@channel)
|
13
|
-
@keyboard =
|
14
|
-
@mouse =
|
15
|
-
@touchscreen =
|
13
|
+
@keyboard = KeyboardImpl.new(@channel)
|
14
|
+
@mouse = MouseImpl.new(@channel)
|
15
|
+
@touchscreen = TouchscreenImpl.new(@channel)
|
16
16
|
|
17
17
|
@viewport_size = @initializer['viewportSize']
|
18
18
|
@closed = false
|
@@ -26,7 +26,19 @@ module Playwright
|
|
26
26
|
console_message = ChannelOwners::ConsoleMessage.from(params['message'])
|
27
27
|
emit(Events::Page::Console, console_message)
|
28
28
|
})
|
29
|
+
@channel.on('crash', ->(_) { emit(Events::Page::Crash) })
|
30
|
+
@channel.on('dialog', method(:on_dialog))
|
29
31
|
@channel.on('domcontentloaded', ->(_) { emit(Events::Page::DOMContentLoaded) })
|
32
|
+
@channel.on('download', ->(params) {
|
33
|
+
emit(Events::Page::Download, ChannelOwners::Download.from(params['download']))
|
34
|
+
})
|
35
|
+
@channel.on('fileChooser', ->(params) {
|
36
|
+
chooser = FileChooserImpl.new(
|
37
|
+
page: self,
|
38
|
+
element_handle: ChannelOwners::ElementHandle.from(params['element']),
|
39
|
+
is_multiple: params['isMultiple'])
|
40
|
+
emit(Events::Page::FileChooser, chooser)
|
41
|
+
})
|
30
42
|
@channel.on('frameAttached', ->(params) {
|
31
43
|
on_frame_attached(ChannelOwners::Frame.from(params['frame']))
|
32
44
|
})
|
@@ -34,9 +46,43 @@ module Playwright
|
|
34
46
|
on_frame_detached(ChannelOwners::Frame.from(params['frame']))
|
35
47
|
})
|
36
48
|
@channel.on('load', ->(_) { emit(Events::Page::Load) })
|
49
|
+
@channel.on('pageError', ->(params) {
|
50
|
+
emit(Events::Page::PageError, Error.parse(params['error']['error']))
|
51
|
+
})
|
37
52
|
@channel.on('popup', ->(params) {
|
38
53
|
emit(Events::Page::Popup, ChannelOwners::Page.from(params['page']))
|
39
54
|
})
|
55
|
+
@channel.on('request', ->(params) {
|
56
|
+
emit(Events::Page::Request, ChannelOwners::Request.from(params['request']))
|
57
|
+
})
|
58
|
+
@channel.on('requestFailed', ->(params) {
|
59
|
+
on_request_failed(
|
60
|
+
ChannelOwners::Request.from(params['request']),
|
61
|
+
params['responseEndTiming'],
|
62
|
+
params['failureText'],
|
63
|
+
)
|
64
|
+
})
|
65
|
+
@channel.on('requestFinished', ->(params) {
|
66
|
+
on_request_finished(
|
67
|
+
ChannelOwners::Request.from(params['request']),
|
68
|
+
params['responseEndTiming'],
|
69
|
+
)
|
70
|
+
})
|
71
|
+
@channel.on('response', ->(params) {
|
72
|
+
emit(Events::Page::Response, ChannelOwners::Response.from(params['response']))
|
73
|
+
})
|
74
|
+
@channel.on('route', ->(params) {
|
75
|
+
on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
|
76
|
+
})
|
77
|
+
@channel.on('video', ->(params) {
|
78
|
+
video.send(:update_relative_path, params['relativePath'])
|
79
|
+
})
|
80
|
+
@channel.on('webSocket', ->(params) {
|
81
|
+
emit(Events::Page::WebSocket, ChannelOwners::WebSocket.from(params['webSocket']))
|
82
|
+
})
|
83
|
+
@channel.on('worker', ->(params) {
|
84
|
+
on_worker(ChannelOwners::Worker.from(params['worker']))
|
85
|
+
})
|
40
86
|
end
|
41
87
|
|
42
88
|
attr_reader \
|
@@ -47,6 +93,17 @@ module Playwright
|
|
47
93
|
:viewport_size,
|
48
94
|
:main_frame
|
49
95
|
|
96
|
+
private def on_request_failed(request, response_end_timing, failure_text)
|
97
|
+
request.send(:update_failure_text, failure_text)
|
98
|
+
request.send(:update_response_end_timing, response_end_timing)
|
99
|
+
emit(Events::Page::RequestFailed)
|
100
|
+
end
|
101
|
+
|
102
|
+
private def on_request_finished(request, response_end_timing)
|
103
|
+
request.send(:update_response_end_timing, response_end_timing)
|
104
|
+
emit(Events::Page::RequestFinished)
|
105
|
+
end
|
106
|
+
|
50
107
|
private def on_frame_attached(frame)
|
51
108
|
frame.send(:update_page_from_page, self)
|
52
109
|
@frames << frame
|
@@ -59,12 +116,48 @@ module Playwright
|
|
59
116
|
emit(Events::Page::FrameDetached, frame)
|
60
117
|
end
|
61
118
|
|
119
|
+
private def on_route(route, request)
|
120
|
+
# @routes.each ...
|
121
|
+
@browser_context.send(:on_route, route, request)
|
122
|
+
end
|
123
|
+
|
62
124
|
private def on_close
|
63
125
|
@closed = true
|
64
126
|
@browser_context.send(:remove_page, self)
|
65
127
|
emit(Events::Page::Close)
|
66
128
|
end
|
67
129
|
|
130
|
+
private def on_dialog(params)
|
131
|
+
dialog = ChannelOwners::Dialog.from(params['dialog'])
|
132
|
+
unless emit(Events::Page::Dialog, dialog)
|
133
|
+
dialog.dismiss # FIXME: this should be asynchronous
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# @override
|
138
|
+
def on(event, callback)
|
139
|
+
if event == Events::Page::FileChooser && listener_count(event) == 0
|
140
|
+
@channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: true)
|
141
|
+
end
|
142
|
+
super
|
143
|
+
end
|
144
|
+
|
145
|
+
# @override
|
146
|
+
def once(event, callback)
|
147
|
+
if event == Events::Page::FileChooser && listener_count(event) == 0
|
148
|
+
@channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: true)
|
149
|
+
end
|
150
|
+
super
|
151
|
+
end
|
152
|
+
|
153
|
+
# @override
|
154
|
+
def off(event, callback)
|
155
|
+
super
|
156
|
+
if event == Events::Page::FileChooser && listener_count(event) == 0
|
157
|
+
@channel.send_no_reply('setFileChooserInterceptedNoReply', intercepted: false)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
68
161
|
def context
|
69
162
|
@browser_context
|
70
163
|
end
|
@@ -74,14 +167,7 @@ module Playwright
|
|
74
167
|
ChannelOwners::Page.from(resp)
|
75
168
|
end
|
76
169
|
|
77
|
-
def frame(
|
78
|
-
name, url =
|
79
|
-
if frameSelector.is_a?(Hash)
|
80
|
-
[frameSelector[:name], frameSelector[:url]]
|
81
|
-
else
|
82
|
-
[frameSelector, nil]
|
83
|
-
end
|
84
|
-
|
170
|
+
def frame(name: nil, url: nil)
|
85
171
|
if name
|
86
172
|
@frames.find { |f| f.name == name }
|
87
173
|
elsif url
|
@@ -103,6 +189,16 @@ module Playwright
|
|
103
189
|
@frames.to_a
|
104
190
|
end
|
105
191
|
|
192
|
+
def set_default_navigation_timeout(timeout)
|
193
|
+
@timeout_settings.default_navigation_timeout = timeout
|
194
|
+
@channel.send_message_to_server('setDefaultNavigationTimeoutNoReply', timeout: timeout)
|
195
|
+
end
|
196
|
+
|
197
|
+
def set_default_timeout(timeout)
|
198
|
+
@timeout_settings.default_timeout = timeout
|
199
|
+
@channel.send_message_to_server('setDefaultTimeoutNoReply', timeout: timeout)
|
200
|
+
end
|
201
|
+
|
106
202
|
def query_selector(selector)
|
107
203
|
@main_frame.query_selector(selector)
|
108
204
|
end
|
@@ -111,6 +207,38 @@ module Playwright
|
|
111
207
|
@main_frame.query_selector_all(selector)
|
112
208
|
end
|
113
209
|
|
210
|
+
def wait_for_selector(selector, state: nil, timeout: nil)
|
211
|
+
@main_frame.wait_for_selector(selector, state: state, timeout: timeout)
|
212
|
+
end
|
213
|
+
|
214
|
+
def checked?(selector, timeout: nil)
|
215
|
+
@main_frame.checked?(selector, timeout: timeout)
|
216
|
+
end
|
217
|
+
|
218
|
+
def disabled?(selector, timeout: nil)
|
219
|
+
@main_frame.disabled?(selector, timeout: timeout)
|
220
|
+
end
|
221
|
+
|
222
|
+
def editable?(selector, timeout: nil)
|
223
|
+
@main_frame.editable?(selector, timeout: timeout)
|
224
|
+
end
|
225
|
+
|
226
|
+
def enabled?(selector, timeout: nil)
|
227
|
+
@main_frame.enabled?(selector, timeout: timeout)
|
228
|
+
end
|
229
|
+
|
230
|
+
def hidden?(selector, timeout: nil)
|
231
|
+
@main_frame.hidden?(selector, timeout: timeout)
|
232
|
+
end
|
233
|
+
|
234
|
+
def visible?(selector, timeout: nil)
|
235
|
+
@main_frame.visible?(selector, timeout: timeout)
|
236
|
+
end
|
237
|
+
|
238
|
+
def dispatch_event(selector, type, eventInit: nil, timeout: nil)
|
239
|
+
@main_frame.dispatch_event(selector, type, eventInit: eventInit, timeout: timeout)
|
240
|
+
end
|
241
|
+
|
114
242
|
def evaluate(pageFunction, arg: nil)
|
115
243
|
@main_frame.evaluate(pageFunction, arg: arg)
|
116
244
|
end
|
@@ -127,6 +255,33 @@ module Playwright
|
|
127
255
|
@main_frame.eval_on_selector_all(selector, pageFunction, arg: arg)
|
128
256
|
end
|
129
257
|
|
258
|
+
def add_script_tag(content: nil, path: nil, type: nil, url: nil)
|
259
|
+
@main_frame.add_script_tag(content: content, path: path, type: type, url: url)
|
260
|
+
end
|
261
|
+
|
262
|
+
def add_style_tag(content: nil, path: nil, url: nil)
|
263
|
+
@main_frame.add_style_tag(content: content, path: path, url: url)
|
264
|
+
end
|
265
|
+
|
266
|
+
def expose_function(name, callback)
|
267
|
+
@channel.send_message_to_server('exposeBinding', name: name)
|
268
|
+
@bindings[name] = ->(_source, *args) { callback.call(*args) }
|
269
|
+
end
|
270
|
+
|
271
|
+
def expose_binding(name, callback, handle: nil)
|
272
|
+
params = {
|
273
|
+
name: name,
|
274
|
+
needsHandle: handle,
|
275
|
+
}.compact
|
276
|
+
@channel.send_message_to_server('exposeBinding', params)
|
277
|
+
@bindings[name] = callback
|
278
|
+
end
|
279
|
+
|
280
|
+
def set_extra_http_headers(headers)
|
281
|
+
serialized_headers = HttpHeaders.new(headers).as_serialized
|
282
|
+
@channel.send_message_to_server('setExtraHTTPHeaders', headers: serialized_headers)
|
283
|
+
end
|
284
|
+
|
130
285
|
def url
|
131
286
|
@main_frame.url
|
132
287
|
end
|
@@ -143,12 +298,66 @@ module Playwright
|
|
143
298
|
@main_frame.goto(url, timeout: timeout, waitUntil: waitUntil, referer: referer)
|
144
299
|
end
|
145
300
|
|
301
|
+
def reload(timeout: nil, waitUntil: nil)
|
302
|
+
params = {
|
303
|
+
timeout: timeout,
|
304
|
+
waitUntil: waitUntil,
|
305
|
+
}.compact
|
306
|
+
resp = @channel.send_message_to_server('reoad', params)
|
307
|
+
ChannelOwners::Response.from_nullable(resp)
|
308
|
+
end
|
309
|
+
|
310
|
+
def wait_for_load_state(state: nil, timeout: nil)
|
311
|
+
@main_frame.wait_for_load_state(state: state, timeout: timeout)
|
312
|
+
end
|
313
|
+
|
314
|
+
def go_back(timeout: nil, waitUntil: nil)
|
315
|
+
params = { timeout: timeout, waitUntil: waitUntil }.compact
|
316
|
+
resp = @channel.send_message_to_server('goBack', params)
|
317
|
+
ChannelOwners::Response.from_nullable(resp)
|
318
|
+
end
|
319
|
+
|
320
|
+
def go_forward(timeout: nil, waitUntil: nil)
|
321
|
+
params = { timeout: timeout, waitUntil: waitUntil }.compact
|
322
|
+
resp = @channel.send_message_to_server('goForward', params)
|
323
|
+
ChannelOwners::Response.from_nullable(resp)
|
324
|
+
end
|
325
|
+
|
326
|
+
def emulate_media(colorScheme: nil, media: nil)
|
327
|
+
params = {
|
328
|
+
colorScheme: colorScheme,
|
329
|
+
media: media,
|
330
|
+
}.compact
|
331
|
+
@channel.send_message_to_server('emulateMedia', params)
|
332
|
+
|
333
|
+
nil
|
334
|
+
end
|
335
|
+
|
146
336
|
def set_viewport_size(viewportSize)
|
147
337
|
@viewport_size = viewportSize
|
148
338
|
@channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
|
149
339
|
nil
|
150
340
|
end
|
151
341
|
|
342
|
+
def bring_to_front
|
343
|
+
@channel.send_message_to_server('bringToFront')
|
344
|
+
nil
|
345
|
+
end
|
346
|
+
|
347
|
+
def add_init_script(path: nil, script: nil)
|
348
|
+
source =
|
349
|
+
if path
|
350
|
+
File.read(path, 'r')
|
351
|
+
elsif script
|
352
|
+
script
|
353
|
+
else
|
354
|
+
raise ArgumentError.new('Either path or script parameter must be specified')
|
355
|
+
end
|
356
|
+
|
357
|
+
@channel.send_message_to_server('addInitScript', source: script)
|
358
|
+
nil
|
359
|
+
end
|
360
|
+
|
152
361
|
def screenshot(
|
153
362
|
path: nil,
|
154
363
|
type: nil,
|
@@ -167,7 +376,7 @@ module Playwright
|
|
167
376
|
timeout: timeout,
|
168
377
|
}.compact
|
169
378
|
encoded_binary = @channel.send_message_to_server('screenshot', params)
|
170
|
-
decoded_binary = Base64.
|
379
|
+
decoded_binary = Base64.strict_decode64(encoded_binary)
|
171
380
|
if path
|
172
381
|
File.open(path, 'wb') do |f|
|
173
382
|
f.write(decoded_binary)
|
@@ -217,18 +426,114 @@ module Playwright
|
|
217
426
|
)
|
218
427
|
end
|
219
428
|
|
429
|
+
def dblclick(
|
430
|
+
selector,
|
431
|
+
button: nil,
|
432
|
+
delay: nil,
|
433
|
+
force: nil,
|
434
|
+
modifiers: nil,
|
435
|
+
noWaitAfter: nil,
|
436
|
+
position: nil,
|
437
|
+
timeout: nil)
|
438
|
+
@main_frame.dblclick(
|
439
|
+
selector,
|
440
|
+
button: button,
|
441
|
+
delay: delay,
|
442
|
+
force: force,
|
443
|
+
modifiers: modifiers,
|
444
|
+
noWaitAfter: noWaitAfter,
|
445
|
+
position: position,
|
446
|
+
timeout: timeout,
|
447
|
+
)
|
448
|
+
end
|
449
|
+
|
450
|
+
def tap_point(
|
451
|
+
selector,
|
452
|
+
force: nil,
|
453
|
+
modifiers: nil,
|
454
|
+
noWaitAfter: nil,
|
455
|
+
position: nil,
|
456
|
+
timeout: nil)
|
457
|
+
@main_frame.tap_point(
|
458
|
+
selector,
|
459
|
+
force: force,
|
460
|
+
modifiers: modifiers,
|
461
|
+
noWaitAfter: noWaitAfter,
|
462
|
+
position: position,
|
463
|
+
timeout: timeout,
|
464
|
+
)
|
465
|
+
end
|
466
|
+
|
467
|
+
def fill(selector, value, noWaitAfter: nil, timeout: nil)
|
468
|
+
@main_frame.fill(selector, value, noWaitAfter: noWaitAfter, timeout: timeout)
|
469
|
+
end
|
470
|
+
|
220
471
|
def focus(selector, timeout: nil)
|
221
472
|
@main_frame.focus(selector, timeout: timeout)
|
222
473
|
end
|
223
474
|
|
224
|
-
def
|
475
|
+
def text_content(selector, timeout: nil)
|
476
|
+
@main_frame.text_content(selector, timeout: timeout)
|
477
|
+
end
|
478
|
+
|
479
|
+
def inner_text(selector, timeout: nil)
|
480
|
+
@main_frame.inner_text(selector, timeout: timeout)
|
481
|
+
end
|
482
|
+
|
483
|
+
def inner_html(selector, timeout: nil)
|
484
|
+
@main_frame.inner_html(selector, timeout: timeout)
|
485
|
+
end
|
486
|
+
|
487
|
+
def get_attribute(selector, name, timeout: nil)
|
488
|
+
@main_frame.get_attribute(selector, name, timeout: timeout)
|
489
|
+
end
|
490
|
+
|
491
|
+
def hover(
|
492
|
+
selector,
|
493
|
+
force: nil,
|
494
|
+
modifiers: nil,
|
495
|
+
position: nil,
|
496
|
+
timeout: nil)
|
497
|
+
@main_frame.hover(
|
498
|
+
selector,
|
499
|
+
force: force,
|
500
|
+
modifiers: modifiers,
|
501
|
+
position: position,
|
502
|
+
timeout: timeout,
|
503
|
+
)
|
504
|
+
end
|
505
|
+
|
506
|
+
def select_option(
|
507
|
+
selector,
|
508
|
+
element: nil,
|
509
|
+
index: nil,
|
510
|
+
value: nil,
|
511
|
+
label: nil,
|
512
|
+
noWaitAfter: nil,
|
513
|
+
timeout: nil)
|
514
|
+
@main_frame.select_option(
|
515
|
+
selector,
|
516
|
+
element: element,
|
517
|
+
index: index,
|
518
|
+
value: value,
|
519
|
+
label: label,
|
520
|
+
noWaitAfter: noWaitAfter,
|
521
|
+
timeout: timeout,
|
522
|
+
)
|
523
|
+
end
|
524
|
+
|
525
|
+
def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
|
526
|
+
@main_frame.set_input_files(selector, files, noWaitAfter: noWaitAfter, timeout: timeout)
|
527
|
+
end
|
528
|
+
|
529
|
+
def type(
|
225
530
|
selector,
|
226
531
|
text,
|
227
532
|
delay: nil,
|
228
533
|
noWaitAfter: nil,
|
229
534
|
timeout: nil)
|
230
535
|
|
231
|
-
@main_frame.
|
536
|
+
@main_frame.type(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
|
232
537
|
end
|
233
538
|
|
234
539
|
def press(
|
@@ -241,6 +546,57 @@ module Playwright
|
|
241
546
|
@main_frame.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
|
242
547
|
end
|
243
548
|
|
549
|
+
def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
|
550
|
+
@main_frame.check(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
|
551
|
+
end
|
552
|
+
|
553
|
+
def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
|
554
|
+
@main_frame.uncheck(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
|
555
|
+
end
|
556
|
+
|
557
|
+
def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
|
558
|
+
@main_frame.wait_for_function(pageFunction, arg: arg, polling: polling, timeout: timeout)
|
559
|
+
end
|
560
|
+
|
561
|
+
def pdf(
|
562
|
+
displayHeaderFooter: nil,
|
563
|
+
footerTemplate: nil,
|
564
|
+
format: nil,
|
565
|
+
headerTemplate: nil,
|
566
|
+
height: nil,
|
567
|
+
landscape: nil,
|
568
|
+
margin: nil,
|
569
|
+
pageRanges: nil,
|
570
|
+
path: nil,
|
571
|
+
preferCSSPageSize: nil,
|
572
|
+
printBackground: nil,
|
573
|
+
scale: nil,
|
574
|
+
width: nil)
|
575
|
+
|
576
|
+
params = {
|
577
|
+
displayHeaderFooter: displayHeaderFooter,
|
578
|
+
footerTemplate: footerTemplate,
|
579
|
+
format: format,
|
580
|
+
headerTemplate: headerTemplate,
|
581
|
+
height: height,
|
582
|
+
landscape: landscape,
|
583
|
+
margin: margin,
|
584
|
+
pageRanges: pageRanges,
|
585
|
+
preferCSSPageSize: preferCSSPageSize,
|
586
|
+
printBackground: printBackground,
|
587
|
+
scale: scale,
|
588
|
+
width: width,
|
589
|
+
}.compact
|
590
|
+
encoded_binary = @channel.send_message_to_server('pdf', params)
|
591
|
+
decoded_binary = Base64.strict_decode64(encoded_binary)
|
592
|
+
if path
|
593
|
+
File.open(path, 'wb') do |f|
|
594
|
+
f.write(decoded_binary)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
decoded_binary
|
598
|
+
end
|
599
|
+
|
244
600
|
class CrashedError < StandardError
|
245
601
|
def initialize
|
246
602
|
super('Page crashed')
|
@@ -259,20 +615,9 @@ module Playwright
|
|
259
615
|
end
|
260
616
|
end
|
261
617
|
|
262
|
-
def
|
263
|
-
predicate, timeout =
|
264
|
-
case optionsOrPredicate
|
265
|
-
when Proc
|
266
|
-
[optionsOrPredicate, nil]
|
267
|
-
when Hash
|
268
|
-
[optionsOrPredicate[:predicate], optionsOrPredicate[:timeout]]
|
269
|
-
else
|
270
|
-
[nil, nil]
|
271
|
-
end
|
272
|
-
timeout ||= @timeout_settings.timeout
|
273
|
-
|
618
|
+
def expect_event(event, predicate: nil, timeout: nil, &block)
|
274
619
|
wait_helper = WaitHelper.new
|
275
|
-
wait_helper.reject_on_timeout(timeout, "Timeout while waiting for event \"#{event}\"")
|
620
|
+
wait_helper.reject_on_timeout(timeout || @timeout_settings.timeout, "Timeout while waiting for event \"#{event}\"")
|
276
621
|
|
277
622
|
unless event == Events::Page::Crash
|
278
623
|
wait_helper.reject_on_event(self, Events::Page::Crash, CrashedError.new)
|
@@ -289,15 +634,15 @@ module Playwright
|
|
289
634
|
wait_helper.promise.value!
|
290
635
|
end
|
291
636
|
|
292
|
-
def
|
293
|
-
@main_frame.
|
637
|
+
def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
|
638
|
+
@main_frame.expect_navigation(
|
294
639
|
timeout: timeout,
|
295
640
|
url: url,
|
296
641
|
waitUntil: waitUntil,
|
297
642
|
&block)
|
298
643
|
end
|
299
644
|
|
300
|
-
def
|
645
|
+
def expect_request(urlOrPredicate, timeout: nil)
|
301
646
|
predicate =
|
302
647
|
case urlOrPredicate
|
303
648
|
when String, Regexp
|
@@ -309,10 +654,10 @@ module Playwright
|
|
309
654
|
-> (_) { true }
|
310
655
|
end
|
311
656
|
|
312
|
-
|
657
|
+
expect_event(Events::Page::Request, predicate: predicate, timeout: timeout)
|
313
658
|
end
|
314
659
|
|
315
|
-
def
|
660
|
+
def expect_response(urlOrPredicate, timeout: nil)
|
316
661
|
predicate =
|
317
662
|
case urlOrPredicate
|
318
663
|
when String, Regexp
|
@@ -324,7 +669,7 @@ module Playwright
|
|
324
669
|
-> (_) { true }
|
325
670
|
end
|
326
671
|
|
327
|
-
|
672
|
+
expect_event(Events::Page::Response, predicate: predicate, timeout: timeout)
|
328
673
|
end
|
329
674
|
|
330
675
|
# called from BrowserContext#on_page with send(:update_browser_context, page), so keep private.
|