playwright-ruby-client 0.0.8 → 0.3.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/docs/api_coverage.md +159 -101
  4. data/lib/playwright.rb +5 -2
  5. data/lib/playwright/{input_types/android_input.rb → android_input_impl.rb} +5 -1
  6. data/lib/playwright/api_implementation.rb +18 -0
  7. data/lib/playwright/channel.rb +13 -6
  8. data/lib/playwright/channel_owner.rb +3 -5
  9. data/lib/playwright/channel_owners/android.rb +1 -1
  10. data/lib/playwright/channel_owners/android_device.rb +12 -12
  11. data/lib/playwright/channel_owners/binding_call.rb +3 -0
  12. data/lib/playwright/channel_owners/browser.rb +1 -1
  13. data/lib/playwright/channel_owners/browser_context.rb +157 -3
  14. data/lib/playwright/channel_owners/dialog.rb +28 -0
  15. data/lib/playwright/channel_owners/download.rb +27 -0
  16. data/lib/playwright/channel_owners/element_handle.rb +15 -4
  17. data/lib/playwright/channel_owners/frame.rb +24 -5
  18. data/lib/playwright/channel_owners/js_handle.rb +1 -1
  19. data/lib/playwright/channel_owners/page.rb +367 -29
  20. data/lib/playwright/channel_owners/playwright.rb +4 -0
  21. data/lib/playwright/channel_owners/request.rb +35 -3
  22. data/lib/playwright/channel_owners/response.rb +60 -0
  23. data/lib/playwright/channel_owners/route.rb +78 -0
  24. data/lib/playwright/channel_owners/selectors.rb +19 -1
  25. data/lib/playwright/errors.rb +1 -1
  26. data/lib/playwright/event_emitter.rb +8 -1
  27. data/lib/playwright/event_emitter_proxy.rb +49 -0
  28. data/lib/playwright/file_chooser_impl.rb +23 -0
  29. data/lib/playwright/http_headers.rb +20 -0
  30. data/lib/playwright/input_files.rb +1 -1
  31. data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +5 -1
  32. data/lib/playwright/mouse_impl.rb +7 -0
  33. data/lib/playwright/playwright_api.rb +59 -20
  34. data/lib/playwright/route_handler_entry.rb +36 -0
  35. data/lib/playwright/select_option_values.rb +14 -4
  36. data/lib/playwright/touchscreen_impl.rb +7 -0
  37. data/lib/playwright/utils.rb +4 -3
  38. data/lib/playwright/version.rb +1 -1
  39. data/lib/playwright/wait_helper.rb +1 -1
  40. data/lib/playwright_api/android.rb +82 -11
  41. data/lib/playwright_api/android_device.rb +148 -32
  42. data/lib/playwright_api/android_input.rb +17 -13
  43. data/lib/playwright_api/android_socket.rb +16 -0
  44. data/lib/playwright_api/android_web_view.rb +21 -0
  45. data/lib/playwright_api/binding_call.rb +14 -5
  46. data/lib/playwright_api/browser.rb +22 -23
  47. data/lib/playwright_api/browser_context.rb +49 -35
  48. data/lib/playwright_api/browser_type.rb +24 -64
  49. data/lib/playwright_api/chromium_browser_context.rb +10 -8
  50. data/lib/playwright_api/console_message.rb +10 -6
  51. data/lib/playwright_api/dialog.rb +37 -6
  52. data/lib/playwright_api/download.rb +28 -11
  53. data/lib/playwright_api/element_handle.rb +107 -96
  54. data/lib/playwright_api/file_chooser.rb +18 -10
  55. data/lib/playwright_api/frame.rb +124 -117
  56. data/lib/playwright_api/js_handle.rb +20 -22
  57. data/lib/playwright_api/keyboard.rb +5 -5
  58. data/lib/playwright_api/page.rb +206 -148
  59. data/lib/playwright_api/playwright.rb +33 -45
  60. data/lib/playwright_api/request.rb +11 -12
  61. data/lib/playwright_api/response.rb +30 -16
  62. data/lib/playwright_api/route.rb +27 -5
  63. data/lib/playwright_api/selectors.rb +14 -10
  64. data/lib/playwright_api/web_socket.rb +10 -1
  65. data/lib/playwright_api/worker.rb +13 -13
  66. metadata +16 -7
  67. data/lib/playwright/input_type.rb +0 -19
  68. data/lib/playwright/input_types/mouse.rb +0 -4
  69. data/lib/playwright/input_types/touchscreen.rb +0 -4
@@ -1,5 +1,9 @@
1
1
  module Playwright
2
- define_input_type :AndroidInput do
2
+ define_api_implementation :AndroidInputImpl do
3
+ def initialize(channel)
4
+ @channel = channel
5
+ end
6
+
3
7
  def type(text)
4
8
  @channel.send_message_to_server('inputType', text: text)
5
9
  end
@@ -0,0 +1,18 @@
1
+ module Playwright
2
+ # Each Impl class include this module.
3
+ # Used for detecting whether the object is a XXXXImpl or not.
4
+ module ApiImplementation ; end
5
+
6
+ def self.define_api_implementation(class_name, &block)
7
+ klass = Class.new
8
+ klass.include(ApiImplementation)
9
+ klass.class_eval(&block) if block
10
+ if ::Playwright.const_defined?(class_name)
11
+ raise ArgumentError.new("Playwright::#{class_name} already exist. Choose another class name.")
12
+ end
13
+ ::Playwright.const_set(class_name, klass)
14
+ end
15
+ end
16
+
17
+ # load subclasses
18
+ Dir[File.join(__dir__, '*_impl.rb')].each { |f| require f }
@@ -16,12 +16,19 @@ module Playwright
16
16
  # @param method [String]
17
17
  # @param params [Hash]
18
18
  def send_message_to_server(method, params = {})
19
- result = @connection.send_message_to_server(@guid, method, params)
20
- if result.is_a?(Hash)
21
- _type, channel_owner = result.first
22
- channel_owner
23
- else
24
- nil
19
+ async_send_message_to_server(method, params).value!
20
+ end
21
+
22
+ # @param method [String]
23
+ # @param params [Hash]
24
+ def async_send_message_to_server(method, params = {})
25
+ @connection.async_send_message_to_server(@guid, method, params).then do |result|
26
+ if result.is_a?(Hash)
27
+ _type, channel_owner = result.first
28
+ channel_owner
29
+ else
30
+ nil
31
+ end
25
32
  end
26
33
  end
27
34
  end
@@ -59,16 +59,14 @@ module Playwright
59
59
  "#<#{@guid}>"
60
60
  end
61
61
 
62
- private
63
-
64
- def after_initialize
62
+ private def after_initialize
65
63
  end
66
64
 
67
- def update_object_from_child(guid, child)
65
+ private def update_object_from_child(guid, child)
68
66
  @objects[guid] = child
69
67
  end
70
68
 
71
- def delete_object_from_child(guid)
69
+ private def delete_object_from_child(guid)
72
70
  @objects.delete(guid)
73
71
  end
74
72
  end
@@ -1,6 +1,6 @@
1
1
  module Playwright
2
2
  define_channel_owner :Android do
3
- def after_initialize
3
+ private def after_initialize
4
4
  @timeout_settings = TimeoutSettings.new
5
5
  end
6
6
 
@@ -2,8 +2,8 @@ module Playwright
2
2
  define_channel_owner :AndroidDevice do
3
3
  include Utils::PrepareBrowserContextOptions
4
4
 
5
- def after_initialize
6
- @input = InputTypes::AndroidInput.new(@channel)
5
+ private def after_initialize
6
+ @input = AndroidInputImpl.new(@channel)
7
7
  end
8
8
 
9
9
  attr_reader :input
@@ -104,17 +104,17 @@ module Playwright
104
104
  isMobile: nil,
105
105
  javaScriptEnabled: nil,
106
106
  locale: nil,
107
- logger: nil,
107
+ noViewport: nil,
108
108
  offline: nil,
109
109
  permissions: nil,
110
110
  proxy: nil,
111
- recordHar: nil,
112
- recordVideo: nil,
111
+ record_har_omit_content: nil,
112
+ record_har_path: nil,
113
+ record_video_dir: nil,
114
+ record_video_size: nil,
113
115
  storageState: nil,
114
116
  timezoneId: nil,
115
117
  userAgent: nil,
116
- videoSize: nil,
117
- videosPath: nil,
118
118
  viewport: nil,
119
119
  &block)
120
120
  params = {
@@ -131,17 +131,17 @@ module Playwright
131
131
  isMobile: isMobile,
132
132
  javaScriptEnabled: javaScriptEnabled,
133
133
  locale: locale,
134
- logger: logger,
134
+ noViewport: noViewport,
135
135
  offline: offline,
136
136
  permissions: permissions,
137
137
  proxy: proxy,
138
- recordHar: recordHar,
139
- recordVideo: recordVideo,
138
+ record_har_omit_content: record_har_omit_content,
139
+ record_har_path: record_har_path,
140
+ record_video_dir: record_video_dir,
141
+ record_video_size: record_video_size,
140
142
  storageState: storageState,
141
143
  timezoneId: timezoneId,
142
144
  userAgent: userAgent,
143
- videoSize: videoSize,
144
- videosPath: videosPath,
145
145
  viewport: viewport,
146
146
  }.compact
147
147
  prepare_browser_context_options(params)
@@ -1,4 +1,7 @@
1
1
  module Playwright
2
2
  define_channel_owner :BindingCall do
3
+ def name
4
+ @initializer['name']
5
+ end
3
6
  end
4
7
  end
@@ -4,7 +4,7 @@ module Playwright
4
4
  include Utils::Errors::SafeCloseError
5
5
  include Utils::PrepareBrowserContextOptions
6
6
 
7
- def after_initialize
7
+ private def after_initialize
8
8
  @contexts = Set.new
9
9
  @channel.on('close', method(:on_close))
10
10
  end
@@ -2,13 +2,21 @@ module Playwright
2
2
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_browser_context.py
3
3
  define_channel_owner :BrowserContext do
4
4
  include Utils::Errors::SafeCloseError
5
- attr_writer :browser, :owner_page, :options
5
+ attr_accessor :browser
6
+ attr_writer :owner_page, :options
6
7
 
7
- def after_initialize
8
+ private def after_initialize
8
9
  @pages = Set.new
10
+ @routes = Set.new
11
+ @bindings = {}
12
+ @timeout_settings = TimeoutSettings.new
9
13
 
14
+ @channel.on('bindingCall', ->(params) { on_binding(ChannelOwners::BindingCall.from(params['binding'])) })
10
15
  @channel.once('close', ->(_) { on_close })
11
- @channel.on('page', ->(hash) { on_page(ChannelOwners::Page.from(hash['page']) )})
16
+ @channel.on('page', ->(params) { on_page(ChannelOwners::Page.from(params['page']) )})
17
+ @channel.on('route', ->(params) {
18
+ on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
19
+ })
12
20
  end
13
21
 
14
22
  private def on_page(page)
@@ -17,6 +25,35 @@ module Playwright
17
25
  emit(Events::BrowserContext::Page, page)
18
26
  end
19
27
 
28
+ private def on_route(route, request)
29
+ # It is not desired to use PlaywrightApi.wrap directly.
30
+ # However it is a little difficult to define wrapper for `handler` parameter in generate_api.
31
+ # Just a workaround...
32
+ wrapped_route = PlaywrightApi.wrap(route)
33
+ wrapped_request = PlaywrightApi.wrap(request)
34
+
35
+ if @routes.none? { |handler_entry| handler_entry.handle(wrapped_route, wrapped_request) }
36
+ route.continue
37
+ end
38
+ end
39
+
40
+ private def on_binding(binding_call)
41
+ func = @binding[binding_call.name]
42
+ if func
43
+ binding_call.call(func)
44
+ end
45
+ end
46
+
47
+ def set_default_navigation_timeout(timeout)
48
+ @timeout_settings.default_navigation_timeout = timeout
49
+ @channel.send_message_to_server('setDefaultNavigationTimeoutNoReply', timeout: timeout)
50
+ end
51
+
52
+ def set_default_timeout(timeout)
53
+ @timeout_settings.default_timeout = timeout
54
+ @channel.send_message_to_server('setDefaultTimeoutNoReply', timeout: timeout)
55
+ end
56
+
20
57
  def pages
21
58
  @pages.to_a
22
59
  end
@@ -28,6 +65,111 @@ module Playwright
28
65
  ChannelOwners::Page.from(resp)
29
66
  end
30
67
 
68
+ def cookies(urls: nil)
69
+ target_urls =
70
+ if urls.nil?
71
+ []
72
+ elsif urls.is_a?(Enumerable)
73
+ urls
74
+ else
75
+ [urls]
76
+ end
77
+ @channel.send_message_to_server('cookies', urls: urls)
78
+ end
79
+
80
+ def add_cookies(cookies)
81
+ @channel.send_message_to_server('addCookies', cookies: cookies)
82
+ end
83
+
84
+ def clear_cookies
85
+ @channel.send_message_to_server('clearCookies')
86
+ end
87
+
88
+ def grant_permissions(permissions, origin: nil)
89
+ params = {
90
+ permissions: permissions,
91
+ origin: origin,
92
+ }.compact
93
+ @channel.send_message_to_server('grantPermissions', params)
94
+ end
95
+
96
+ def clear_permissions
97
+ @channel.send_message_to_server('clearPermissions')
98
+ end
99
+
100
+ def set_geolocation(geolocation)
101
+ @channel.send_message_to_server('setGeolocation', geolocation: geolocation)
102
+ end
103
+
104
+ def set_extra_http_headers(headers)
105
+ @channel.send_message_to_server('setExtraHTTPHeaders',
106
+ headers: HttpHeaders.new(headers).as_serialized)
107
+ end
108
+
109
+ def set_offline(offline)
110
+ @channel.send_message_to_server('setOffline', offline: offline)
111
+ end
112
+
113
+ def add_init_script(path: nil, script: nil)
114
+ source =
115
+ if path
116
+ File.read(path)
117
+ elsif script
118
+ script
119
+ else
120
+ raise ArgumentError.new('Either path or script parameter must be specified')
121
+ end
122
+
123
+ @channel.send_message_to_server('addInitScript', source: script)
124
+ nil
125
+ end
126
+
127
+ def expose_binding(name, callback, handle: nil)
128
+ if @pages.any? { |page| page.send(:has_bindings?, name) }
129
+ raise ArgumentError.new("Function \"#{name}\" has been already registered in one of the pages")
130
+ end
131
+ if @bindings.key?(name)
132
+ raise ArgumentError.new("Function \"#{name}\" has been already registered")
133
+ end
134
+ params = {
135
+ name: name,
136
+ needsHandle: handle,
137
+ }.compact
138
+ @bindings[name] = callback
139
+ @channel.send_message_to_server('exposeBinding', params)
140
+ end
141
+
142
+ def expose_function(name, callback)
143
+ expose_binding(name, ->(_source, *args) { callback.call(*args) }, )
144
+ end
145
+
146
+ def route(url, handler)
147
+ entry = RouteHandlerEntry.new(url, handler)
148
+ @routes << entry
149
+ if @routes.count >= 1
150
+ @channel.send_message_to_server('setNetworkInterceptionEnabled', enabled: true)
151
+ end
152
+ end
153
+
154
+ def unroute(url, handler: nil)
155
+ @routes.reject! do |handler_entry|
156
+ handler_entry.same_value?(url: url, handler: handler)
157
+ end
158
+ if @routes.count == 0
159
+ @channel.send_message_to_server('setNetworkInterceptionEnabled', enabled: false)
160
+ end
161
+ end
162
+
163
+ def expect_event(event, predicate: nil, timeout: nil, &block)
164
+ wait_helper = WaitHelper.new
165
+ wait_helper.reject_on_timeout(timeout || @timeout_settings.timeout, "Timeout while waiting for event \"#{event}\"")
166
+ wait_helper.wait_for_event(self, event, predicate: predicate)
167
+
168
+ block&.call
169
+
170
+ wait_helper.promise.value!
171
+ end
172
+
31
173
  private def on_close
32
174
  @closed_or_closing = true
33
175
  @browser&.send(:remove_context, self)
@@ -43,6 +185,18 @@ module Playwright
43
185
  raise unless safe_close_error?(err)
44
186
  end
45
187
 
188
+ def pause
189
+ @channel.send_message_to_server('pause')
190
+ end
191
+
192
+ def expect_page(predicate: nil, timeout: nil)
193
+ params = {
194
+ predicate: predicate,
195
+ timeout: timeout,
196
+ }.compact
197
+ expect_event(Events::BrowserContext::Page, params)
198
+ end
199
+
46
200
  # called from Page#on_close with send(:remove_page, page), so keep private
47
201
  private def remove_page(page)
48
202
  @pages.delete(page)
@@ -0,0 +1,28 @@
1
+ module Playwright
2
+ define_channel_owner :Dialog do
3
+ def type
4
+ @initializer['type']
5
+ end
6
+
7
+ def message
8
+ @initializer['message']
9
+ end
10
+
11
+ def default_value
12
+ @initializer['defaultValue']
13
+ end
14
+
15
+ def accept(promptText: nil)
16
+ accept_async(prompt_text: promptText).value!
17
+ end
18
+
19
+ def accept_async(promptText: nil)
20
+ params = { promptText: promptText }.compact
21
+ @channel.async_send_message_to_server('accept', params)
22
+ end
23
+
24
+ def dismiss
25
+ @channel.async_send_message_to_server('dismiss')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ module Playwright
2
+ define_channel_owner :Download do
3
+ def url
4
+ @initializer['url']
5
+ end
6
+
7
+ def suggested_filename
8
+ @initializer['suggestedFilename']
9
+ end
10
+
11
+ def delete
12
+ @channel.send_message_to_server('delete')
13
+ end
14
+
15
+ def failure
16
+ @channel.send_message_to_server('failure')
17
+ end
18
+
19
+ def path
20
+ @channel.send_message_to_server('path')
21
+ end
22
+
23
+ def save_as(path)
24
+ @channel.send_message_to_server('saveAs', path: path)
25
+ end
26
+ end
27
+ end
@@ -136,8 +136,19 @@ module Playwright
136
136
  nil
137
137
  end
138
138
 
139
- def select_option(values, noWaitAfter: nil, timeout: nil)
140
- base_params = SelectOptionValues.new(values).as_params
139
+ def select_option(
140
+ element: nil,
141
+ index: nil,
142
+ value: nil,
143
+ label: nil,
144
+ noWaitAfter: nil,
145
+ timeout: nil)
146
+ base_params = SelectOptionValues.new(
147
+ element: element,
148
+ index: index,
149
+ value: value,
150
+ label: label,
151
+ ).as_params
141
152
  params = base_params + { noWaitAfter: noWaitAfter, timeout: timeout }.compact
142
153
  @channel.send_message_to_server('selectOption', params)
143
154
 
@@ -182,8 +193,8 @@ module Playwright
182
193
  end
183
194
 
184
195
  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
196
+ file_payloads = InputFiles.new(files).as_params
197
+ params = { files: file_payloads, noWaitAfter: noWaitAfter, timeout: timeout }.compact
187
198
  @channel.send_message_to_server('setInputFiles', params)
188
199
 
189
200
  nil