playwright-ruby-client 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +79 -2
  3. data/docs/api_coverage.md +354 -0
  4. data/lib/playwright.rb +2 -0
  5. data/lib/playwright/channel_owner.rb +3 -2
  6. data/lib/playwright/channel_owners/android.rb +10 -1
  7. data/lib/playwright/channel_owners/android_device.rb +93 -0
  8. data/lib/playwright/channel_owners/browser.rb +13 -13
  9. data/lib/playwright/channel_owners/element_handle.rb +232 -1
  10. data/lib/playwright/channel_owners/frame.rb +41 -3
  11. data/lib/playwright/channel_owners/js_handle.rb +51 -0
  12. data/lib/playwright/channel_owners/page.rb +48 -10
  13. data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
  14. data/lib/playwright/connection.rb +9 -6
  15. data/lib/playwright/errors.rb +1 -1
  16. data/lib/playwright/input_files.rb +42 -0
  17. data/lib/playwright/input_types/keyboard.rb +1 -1
  18. data/lib/playwright/javascript/value_serializer.rb +11 -11
  19. data/lib/playwright/playwright_api.rb +8 -0
  20. data/lib/playwright/select_option_values.rb +32 -0
  21. data/lib/playwright/utils.rb +18 -0
  22. data/lib/playwright/version.rb +1 -1
  23. data/lib/playwright_api/android.rb +33 -0
  24. data/lib/playwright_api/android_device.rb +48 -0
  25. data/lib/playwright_api/binding_call.rb +3 -3
  26. data/lib/playwright_api/browser.rb +7 -6
  27. data/lib/playwright_api/browser_context.rb +6 -6
  28. data/lib/playwright_api/browser_type.rb +4 -4
  29. data/lib/playwright_api/chromium_browser_context.rb +3 -3
  30. data/lib/playwright_api/console_message.rb +3 -8
  31. data/lib/playwright_api/dialog.rb +2 -2
  32. data/lib/playwright_api/element_handle.rb +40 -39
  33. data/lib/playwright_api/frame.rb +23 -27
  34. data/lib/playwright_api/js_handle.rb +15 -9
  35. data/lib/playwright_api/keyboard.rb +6 -6
  36. data/lib/playwright_api/page.rb +35 -54
  37. data/lib/playwright_api/playwright.rb +7 -7
  38. data/lib/playwright_api/request.rb +3 -3
  39. data/lib/playwright_api/response.rb +3 -3
  40. data/lib/playwright_api/selectors.rb +3 -3
  41. data/playwright.gemspec +1 -0
  42. metadata +22 -2
@@ -1,4 +1,55 @@
1
1
  module Playwright
2
2
  define_channel_owner :JSHandle do
3
+ 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
@@ -143,6 +143,19 @@ module Playwright
143
143
  @main_frame.goto(url, timeout: timeout, waitUntil: waitUntil, referer: referer)
144
144
  end
145
145
 
146
+ def reload(timeout: nil, waitUntil: nil)
147
+ params = {
148
+ timeout: timeout,
149
+ waitUntil: waitUntil,
150
+ }.compact
151
+ resp = @channel.send_message_to_server('reoad', params)
152
+ ChannelOwners::Response.from_nullable(resp)
153
+ end
154
+
155
+ def wait_for_load_state(state: nil, timeout: nil)
156
+ @main_frame.wait_for_load_state(state: state, timeout: timeout)
157
+ end
158
+
146
159
  def set_viewport_size(viewportSize)
147
160
  @viewport_size = viewportSize
148
161
  @channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
@@ -167,7 +180,7 @@ module Playwright
167
180
  timeout: timeout,
168
181
  }.compact
169
182
  encoded_binary = @channel.send_message_to_server('screenshot', params)
170
- decoded_binary = Base64.decode64(encoded_binary)
183
+ decoded_binary = Base64.strict_decode64(encoded_binary)
171
184
  if path
172
185
  File.open(path, 'wb') do |f|
173
186
  f.write(decoded_binary)
@@ -217,18 +230,43 @@ module Playwright
217
230
  )
218
231
  end
219
232
 
233
+ def dblclick(
234
+ selector,
235
+ button: nil,
236
+ delay: nil,
237
+ force: nil,
238
+ modifiers: nil,
239
+ noWaitAfter: nil,
240
+ position: nil,
241
+ timeout: nil)
242
+ @main_frame.dblclick(
243
+ selector,
244
+ button: button,
245
+ delay: delay,
246
+ force: force,
247
+ modifiers: modifiers,
248
+ noWaitAfter: noWaitAfter,
249
+ position: position,
250
+ timeout: timeout,
251
+ )
252
+ end
253
+
254
+ def fill(selector, value, noWaitAfter: nil, timeout: nil)
255
+ @main_frame.fill(selector, value, noWaitAfter: noWaitAfter, timeout: timeout)
256
+ end
257
+
220
258
  def focus(selector, timeout: nil)
221
259
  @main_frame.focus(selector, timeout: timeout)
222
260
  end
223
261
 
224
- def type_text(
262
+ def type(
225
263
  selector,
226
264
  text,
227
265
  delay: nil,
228
266
  noWaitAfter: nil,
229
267
  timeout: nil)
230
268
 
231
- @main_frame.type_text(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
269
+ @main_frame.type(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
232
270
  end
233
271
 
234
272
  def press(
@@ -259,7 +297,7 @@ module Playwright
259
297
  end
260
298
  end
261
299
 
262
- def wait_for_event(event, optionsOrPredicate: nil, &block)
300
+ def expect_event(event, optionsOrPredicate: nil, &block)
263
301
  predicate, timeout =
264
302
  case optionsOrPredicate
265
303
  when Proc
@@ -289,15 +327,15 @@ module Playwright
289
327
  wait_helper.promise.value!
290
328
  end
291
329
 
292
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
293
- @main_frame.wait_for_navigation(
330
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
331
+ @main_frame.expect_navigation(
294
332
  timeout: timeout,
295
333
  url: url,
296
334
  waitUntil: waitUntil,
297
335
  &block)
298
336
  end
299
337
 
300
- def wait_for_request(urlOrPredicate, timeout: nil)
338
+ def expect_request(urlOrPredicate, timeout: nil)
301
339
  predicate =
302
340
  case urlOrPredicate
303
341
  when String, Regexp
@@ -309,10 +347,10 @@ module Playwright
309
347
  -> (_) { true }
310
348
  end
311
349
 
312
- wait_for_event(Events::Page::Request, optionsOrPredicate: { predicate: predicate, timeout: timeout})
350
+ expect_event(Events::Page::Request, optionsOrPredicate: { predicate: predicate, timeout: timeout})
313
351
  end
314
352
 
315
- def wait_for_response(urlOrPredicate, timeout: nil)
353
+ def expect_response(urlOrPredicate, timeout: nil)
316
354
  predicate =
317
355
  case urlOrPredicate
318
356
  when String, Regexp
@@ -324,7 +362,7 @@ module Playwright
324
362
  -> (_) { true }
325
363
  end
326
364
 
327
- wait_for_event(Events::Page::Response, optionsOrPredicate: { predicate: predicate, timeout: timeout})
365
+ expect_event(Events::Page::Response, optionsOrPredicate: { predicate: predicate, timeout: timeout})
328
366
  end
329
367
 
330
368
  # called from BrowserContext#on_page with send(:update_browser_context, page), so keep private.
@@ -2,7 +2,7 @@ require_relative './browser'
2
2
 
3
3
  module Playwright
4
4
  module ChannelOwners
5
- class WebkitBrowser < Browser
5
+ class WebKitBrowser < Browser
6
6
  end
7
7
  end
8
8
  end
@@ -55,10 +55,13 @@ module Playwright
55
55
  method: method,
56
56
  params: replace_channels_with_guids(params),
57
57
  }
58
- @transport.send_message(message)
59
- rescue Transport::AlreadyDisconnectedError => err
60
- @callbacks.delete(id)
61
- callback.reject(err)
58
+ begin
59
+ @transport.send_message(message)
60
+ rescue => err
61
+ @callbacks.delete(id)
62
+ callback.reject(err)
63
+ raise unless err.is_a?(Transport::AlreadyDisconnectedError)
64
+ end
62
65
  end
63
66
 
64
67
  callback
@@ -132,7 +135,7 @@ module Playwright
132
135
  unless object
133
136
  raise "Cannot find object to dispose: #{guid}"
134
137
  end
135
- object.dispose
138
+ object.send(:dispose!)
136
139
  return
137
140
  end
138
141
 
@@ -153,7 +156,7 @@ module Playwright
153
156
  end
154
157
 
155
158
  if payload.is_a?(Channel)
156
- { guid: payload.guid }
159
+ return { guid: payload.guid }
157
160
  end
158
161
 
159
162
  if payload.is_a?(Hash)
@@ -3,7 +3,7 @@ module Playwright
3
3
  # ref: https://github.com/microsoft/playwright-python/blob/0b4a980fed366c4c1dee9bfcdd72662d629fdc8d/playwright/_impl/_helper.py#L155
4
4
  def self.parse(error_payload)
5
5
  if error_payload['name'] == 'TimeoutError'
6
- Playwright::TimeoutError.new(
6
+ TimeoutError.new(
7
7
  message: error_payload['message'],
8
8
  stack: error_payload['stack'].split("\n"),
9
9
  )
@@ -0,0 +1,42 @@
1
+ require 'base64'
2
+ require 'mime/types'
3
+
4
+ module Playwright
5
+ class InputFiles
6
+ def initialize(files)
7
+ @params = convert(files)
8
+ end
9
+
10
+ def as_params
11
+ @params
12
+ end
13
+
14
+ private def convert(files)
15
+ return convert([files]) unless files.is_a?(Array)
16
+
17
+ files.map do |file|
18
+ case file
19
+ when String
20
+ {
21
+ name: File.basename(file),
22
+ mimeType: mime_type_for(file),
23
+ buffer: Base64.strict_encode64(File.read(file)),
24
+ }
25
+ when File
26
+ {
27
+ name: File.basename(file.path),
28
+ mimeType: mime_type_for(file.path),
29
+ buffer: Base64.strict_encode64(file.read),
30
+ }
31
+ else
32
+ raise ArgumentError.new('file must be a String or File.')
33
+ end
34
+ end
35
+ end
36
+
37
+ private def mime_type_for(filepath)
38
+ mime_types = MIME::Types.type_for(filepath)
39
+ mime_types.first || 'application/octet-stream'
40
+ end
41
+ end
42
+ end
@@ -13,7 +13,7 @@ module Playwright
13
13
  @channel.send_message_to_server('keyboardInsertText', text: text)
14
14
  end
15
15
 
16
- def type_text(text, delay: nil)
16
+ def type(text, delay: nil)
17
17
  params = {
18
18
  text: text,
19
19
  delay: delay,
@@ -15,9 +15,9 @@ module Playwright
15
15
  # ref: https://github.com/microsoft/playwright-python/blob/25a99d53e00e35365cf5113b9525272628c0e65f/playwright/_impl/_js_handle.py#L99
16
16
  private def serialize_value(value)
17
17
  case value
18
- when JSHandle
18
+ when ChannelOwners::JSHandle
19
19
  index = @handles.count
20
- @handles << v
20
+ @handles << value.channel
21
21
  { h: index }
22
22
  when nil
23
23
  { v: 'undefined' }
@@ -28,23 +28,23 @@ module Playwright
28
28
  when -Float::INFINITY
29
29
  { v: '-Infinity' }
30
30
  when true, false
31
- { b: v }
31
+ { b: value }
32
32
  when Numeric
33
- { n: v }
33
+ { n: value }
34
34
  when String
35
- { s: v }
35
+ { s: value }
36
36
  when Time
37
37
  require 'time'
38
- { d: v.utc.iso8601 }
38
+ { d: value.utc.iso8601 }
39
39
  when Regexp
40
40
  flags = []
41
- flags << 'ms' if (v.options & Regexp::MULTILINE) != 0
42
- flags << 'i' if (v.options & Regexp::IGNORECASE) != 0
43
- { r: { p: v.source, f: flags.join('') } }
41
+ flags << 'ms' if (value.options & Regexp::MULTILINE) != 0
42
+ flags << 'i' if (value.options & Regexp::IGNORECASE) != 0
43
+ { r: { p: value.source, f: flags.join('') } }
44
44
  when Array
45
- { a: v.map { |value| serialize_value(value) } }
45
+ { a: value.map { |v| serialize_value(v) } }
46
46
  when Hash
47
- { o: v.map { |key, value| [key, serialize_value(value)] }.to_h }
47
+ { o: value.map { |key, v| [key, serialize_value(v)] }.to_h }
48
48
  else
49
49
  raise ArgumentError.new("Unexpected value: #{value}")
50
50
  end
@@ -83,5 +83,13 @@ module Playwright
83
83
  object
84
84
  end
85
85
  end
86
+
87
+ private def unwrap_impl(object)
88
+ if object.is_a?(PlaywrightApi)
89
+ object.instance_variable_get(:@impl)
90
+ else
91
+ object
92
+ end
93
+ end
86
94
  end
87
95
  end
@@ -0,0 +1,32 @@
1
+ module Playwright
2
+ class SelectOptionValues
3
+ def initialize(values)
4
+ @params = convert(values)
5
+ end
6
+
7
+ # @return [Hash]
8
+ def as_params
9
+ @params
10
+ end
11
+
12
+ private def convert(values)
13
+ return {} unless values
14
+ return convert([values]) unless values.is_a?('Array')
15
+ return {} if values.empty?
16
+ values.each_with_index do |value, index|
17
+ unless values
18
+ raise ArgumentError.new("options[#{index}]: expected object, got null")
19
+ end
20
+ end
21
+
22
+ case values.first
23
+ when ElementHandle
24
+ { elements: values.map(&:channel) }
25
+ when String
26
+ { options: values.map { |value| { value: value } } }
27
+ else
28
+ { options: values }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,23 @@
1
1
  module Playwright
2
2
  module Utils
3
+ module PrepareBrowserContextOptions
4
+ # @see https://github.com/microsoft/playwright/blob/5a2cfdbd47ed3c3deff77bb73e5fac34241f649d/src/client/browserContext.ts#L265
5
+ private def prepare_browser_context_options(params)
6
+ if params[:viewport] == 0
7
+ params.delete(:viewport)
8
+ params[:noDefaultViewport] = true
9
+ end
10
+ if params[:extraHTTPHeaders]
11
+ # TODO
12
+ end
13
+ if params[:storageState].is_a?(String)
14
+ params[:storageState] = JSON.parse(File.read(params[:storageState]))
15
+ end
16
+
17
+ params
18
+ end
19
+ end
20
+
3
21
  module Errors
4
22
  module SafeCloseError
5
23
  # @param err [Exception]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.7'
5
5
  end
@@ -0,0 +1,33 @@
1
+ module Playwright
2
+ # @nodoc
3
+ class Android < PlaywrightApi
4
+
5
+ # @nodoc
6
+ def after_initialize
7
+ wrap_impl(@impl.after_initialize)
8
+ end
9
+
10
+ # @nodoc
11
+ def devices
12
+ wrap_impl(@impl.devices)
13
+ end
14
+
15
+ # -- inherited from EventEmitter --
16
+ # @nodoc
17
+ def on(event, callback)
18
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
19
+ end
20
+
21
+ # -- inherited from EventEmitter --
22
+ # @nodoc
23
+ def off(event, callback)
24
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
25
+ end
26
+
27
+ # -- inherited from EventEmitter --
28
+ # @nodoc
29
+ def once(event, callback)
30
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
31
+ end
32
+ end
33
+ end