playwright-ruby-client 1.14.beta3 → 1.15.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -14
  3. data/documentation/docs/api/browser.md +4 -0
  4. data/documentation/docs/api/browser_context.md +5 -1
  5. data/documentation/docs/api/browser_type.md +2 -0
  6. data/documentation/docs/api/element_handle.md +30 -5
  7. data/documentation/docs/api/experimental/android_device.md +2 -0
  8. data/documentation/docs/api/frame.md +32 -6
  9. data/documentation/docs/api/locator.md +67 -38
  10. data/documentation/docs/api/mouse.md +11 -0
  11. data/documentation/docs/api/page.md +38 -7
  12. data/documentation/docs/api/request.md +34 -1
  13. data/documentation/docs/api/response.md +37 -2
  14. data/documentation/docs/api/selectors.md +29 -3
  15. data/documentation/docs/api/tracing.md +42 -8
  16. data/documentation/docs/api/worker.md +12 -11
  17. data/documentation/docs/article/getting_started.md +10 -1
  18. data/documentation/docs/article/guides/download_playwright_driver.md +9 -0
  19. data/documentation/docs/article/guides/inspector.md +1 -1
  20. data/documentation/docs/article/guides/playwright_on_alpine_linux.md +56 -3
  21. data/documentation/docs/article/guides/rails_integration.md +4 -2
  22. data/documentation/docs/article/guides/rails_integration_with_null_driver.md +86 -0
  23. data/documentation/docs/article/guides/recording_video.md +1 -1
  24. data/documentation/docs/article/guides/semi_automation.md +2 -2
  25. data/documentation/docs/article/guides/use_storage_state.md +78 -0
  26. data/documentation/docs/include/api_coverage.md +15 -0
  27. data/documentation/docusaurus.config.js +1 -0
  28. data/documentation/package.json +2 -2
  29. data/documentation/src/pages/index.js +0 -1
  30. data/documentation/static/img/playwright-ruby-client.png +0 -0
  31. data/documentation/yarn.lock +625 -549
  32. data/lib/playwright/channel.rb +36 -2
  33. data/lib/playwright/channel_owners/artifact.rb +6 -2
  34. data/lib/playwright/channel_owners/browser.rb +4 -0
  35. data/lib/playwright/channel_owners/browser_context.rb +21 -14
  36. data/lib/playwright/channel_owners/browser_type.rb +0 -1
  37. data/lib/playwright/channel_owners/element_handle.rb +10 -2
  38. data/lib/playwright/channel_owners/frame.rb +8 -0
  39. data/lib/playwright/channel_owners/page.rb +20 -4
  40. data/lib/playwright/channel_owners/playwright.rb +9 -0
  41. data/lib/playwright/channel_owners/request.rb +53 -17
  42. data/lib/playwright/channel_owners/response.rb +48 -5
  43. data/lib/playwright/connection.rb +8 -11
  44. data/lib/playwright/http_headers.rb +0 -6
  45. data/lib/playwright/locator_impl.rb +8 -0
  46. data/lib/playwright/mouse_impl.rb +9 -0
  47. data/lib/playwright/raw_headers.rb +61 -0
  48. data/lib/playwright/{route_handler_entry.rb → route_handler.rb} +30 -2
  49. data/lib/playwright/tracing_impl.rb +18 -7
  50. data/lib/playwright/transport.rb +2 -0
  51. data/lib/playwright/utils.rb +8 -1
  52. data/lib/playwright/version.rb +2 -2
  53. data/lib/playwright/web_socket_transport.rb +2 -0
  54. data/lib/playwright.rb +46 -5
  55. data/lib/playwright_api/android.rb +6 -6
  56. data/lib/playwright_api/android_device.rb +11 -9
  57. data/lib/playwright_api/browser.rb +12 -8
  58. data/lib/playwright_api/browser_context.rb +12 -8
  59. data/lib/playwright_api/browser_type.rb +9 -7
  60. data/lib/playwright_api/cdp_session.rb +7 -7
  61. data/lib/playwright_api/console_message.rb +6 -6
  62. data/lib/playwright_api/dialog.rb +6 -6
  63. data/lib/playwright_api/element_handle.rb +31 -8
  64. data/lib/playwright_api/frame.rb +35 -12
  65. data/lib/playwright_api/js_handle.rb +6 -6
  66. data/lib/playwright_api/locator.rb +39 -0
  67. data/lib/playwright_api/mouse.rb +8 -0
  68. data/lib/playwright_api/page.rb +43 -15
  69. data/lib/playwright_api/playwright.rb +6 -6
  70. data/lib/playwright_api/request.rb +33 -7
  71. data/lib/playwright_api/response.rb +31 -8
  72. data/lib/playwright_api/route.rb +6 -6
  73. data/lib/playwright_api/selectors.rb +38 -7
  74. data/lib/playwright_api/tracing.rb +33 -4
  75. data/lib/playwright_api/web_socket.rb +6 -6
  76. data/lib/playwright_api/worker.rb +8 -8
  77. metadata +8 -4
@@ -31,17 +31,12 @@ module Playwright
31
31
  @transport.stop
32
32
  end
33
33
 
34
- def wait_for_object_with_known_name(guid)
35
- if @objects[guid]
36
- return @objects[guid]
37
- end
38
-
39
- callback = Concurrent::Promises.resolvable_future
40
- @waiting_for_object[guid] = callback
41
- callback.value!
34
+ def initialize_playwright
35
+ result = send_message_to_server('', 'initialize', { sdkLanguage: 'ruby' })
36
+ ChannelOwners::Playwright.from(result['playwright'])
42
37
  end
43
38
 
44
- def async_send_message_to_server(guid, method, params)
39
+ def async_send_message_to_server(guid, method, params, metadata: nil)
45
40
  callback = Concurrent::Promises.resolvable_future
46
41
 
47
42
  with_generated_id do |id|
@@ -54,7 +49,9 @@ module Playwright
54
49
  guid: guid,
55
50
  method: method,
56
51
  params: replace_channels_with_guids(params),
52
+ metadata: metadata || {},
57
53
  }
54
+
58
55
  begin
59
56
  @transport.send_message(message)
60
57
  rescue => err
@@ -67,8 +64,8 @@ module Playwright
67
64
  callback
68
65
  end
69
66
 
70
- def send_message_to_server(guid, method, params)
71
- async_send_message_to_server(guid, method, params).value!
67
+ def send_message_to_server(guid, method, params, metadata: nil)
68
+ async_send_message_to_server(guid, method, params, metadata: metadata).value!
72
69
  end
73
70
 
74
71
  private
@@ -10,11 +10,5 @@ module Playwright
10
10
  { name: key, value: value }
11
11
  end
12
12
  end
13
-
14
- def self.parse_serialized(serialized_headers)
15
- new(serialized_headers.map do |header|
16
- [header['name'].downcase, header['value']]
17
- end.to_h)
18
- end
19
13
  end
20
14
  end
@@ -303,6 +303,14 @@ module Playwright
303
303
  trial: trial)
304
304
  end
305
305
 
306
+ def set_checked(checked, **options)
307
+ if checked
308
+ check(**options)
309
+ else
310
+ uncheck(**options)
311
+ end
312
+ end
313
+
306
314
  def all_inner_texts
307
315
  @frame.eval_on_selector_all(@selector, 'ee => ee.map(e => e.innerText)')
308
316
  end
@@ -44,5 +44,14 @@ module Playwright
44
44
  def dblclick(x, y, button: nil, delay: nil)
45
45
  click(x, y, button: button, clickCount: 2, delay: delay)
46
46
  end
47
+
48
+ def wheel(deltaX, deltaY)
49
+ params = {
50
+ deltaX: deltaX,
51
+ deltaY: deltaY,
52
+ }
53
+ @channel.send_message_to_server('mouseWheel', params)
54
+ nil
55
+ end
47
56
  end
48
57
  end
@@ -0,0 +1,61 @@
1
+ module Playwright
2
+ class RawHeaders
3
+ def initialize(headers_array)
4
+ h_array = []
5
+ h_map = {}
6
+ headers_array.each do |header|
7
+ name = header['name']
8
+ key = name.downcase
9
+ value = header['value']
10
+
11
+ h_array << [name, value]
12
+ h_map[key] ||= []
13
+ h_map[key] << value
14
+ end
15
+
16
+ @headers_array = h_array
17
+ @headers_map = h_map
18
+ end
19
+
20
+ # @return [String|nil]
21
+ def get(name)
22
+ key = name.downcase
23
+ values = @headers_map[key]
24
+ if values
25
+ join(key, values)
26
+ else
27
+ nil
28
+ end
29
+ end
30
+
31
+ # @return [Array<String>]
32
+ def get_all(name)
33
+ values = @headers_map[name.downcase]
34
+ if values
35
+ values.dup
36
+ else
37
+ []
38
+ end
39
+ end
40
+
41
+ def headers
42
+ @headers_map.map do |key, values|
43
+ [key, join(key, values)]
44
+ end.to_h
45
+ end
46
+
47
+ def headers_array
48
+ @headers_array.map do |name, value|
49
+ { name: name, value: value }
50
+ end
51
+ end
52
+
53
+ private def join(key, values)
54
+ if key == 'set-cookie'
55
+ values.join("\n")
56
+ else
57
+ values.join(", ")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,15 +1,43 @@
1
1
  module Playwright
2
- class RouteHandlerEntry
2
+ class RouteHandler
3
+ class CountDown
4
+ def initialize(count)
5
+ @count = count
6
+ end
7
+
8
+ def handle
9
+ return false if @count <= 0
10
+
11
+ @count = @count - 1
12
+ true
13
+ end
14
+ end
15
+
16
+ class StubCounter
17
+ def handle
18
+ true
19
+ end
20
+ end
21
+
3
22
  # @param url [String]
4
23
  # @param base_url [String|nil]
5
24
  # @param handler [Proc]
6
- def initialize(url, base_url, handler)
25
+ # @param times [Integer|nil]
26
+ def initialize(url, base_url, handler, times)
7
27
  @url_value = url
8
28
  @url_matcher = UrlMatcher.new(url, base_url: base_url)
9
29
  @handler = handler
30
+ @counter =
31
+ if times
32
+ CountDown.new(times)
33
+ else
34
+ StubCounter.new
35
+ end
10
36
  end
11
37
 
12
38
  def handle(route, request)
39
+ return false unless @counter.handle
40
+
13
41
  if @url_matcher.match?(request.url)
14
42
  @handler.call(route, request)
15
43
  true
@@ -12,19 +12,30 @@ module Playwright
12
12
  snapshots: snapshots,
13
13
  }.compact
14
14
  @channel.send_message_to_server('tracingStart', params)
15
+ @channel.send_message_to_server('tracingStartChunk')
16
+ end
17
+
18
+ def start_chunk
19
+ @channel.send_message_to_server('tracingStartChunk')
20
+ end
21
+
22
+ def stop_chunk(path: nil)
23
+ do_stop_chunk(path: path)
15
24
  end
16
25
 
17
- # Stop tracing.
18
26
  def stop(path: nil)
19
- export(path: path) if path
27
+ do_stop_chunk(path: path)
20
28
  @channel.send_message_to_server('tracingStop')
21
29
  end
22
30
 
23
- private def export(path:)
24
- resp = @channel.send_message_to_server('tracingExport')
25
- artifact = ChannelOwners::Artifact.from(resp)
26
- # if self._context._browser:
27
- # artifact._is_remote = self._context._browser._is_remote
31
+ private def do_stop_chunk(path:)
32
+ resp = @channel.send_message_to_server('tracingStopChunk', save: !path.nil?)
33
+ artifact = ChannelOwners::Artifact.from_nullable(resp)
34
+ return unless artifact
35
+
36
+ if @context.browser.send(:remote?)
37
+ artifact.update_as_remote
38
+ end
28
39
  artifact.save_as(path)
29
40
  artifact.delete
30
41
  end
@@ -97,7 +97,9 @@ module Playwright
97
97
  end
98
98
 
99
99
  def debug_send_message(message)
100
+ metadata = message.delete(:metadata)
100
101
  puts "\x1b[33mSEND>\x1b[0m#{message}"
102
+ message[:metadata] = metadata
101
103
  end
102
104
 
103
105
  def debug_recv_message(message)
@@ -3,7 +3,6 @@ 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
- params[:sdkLanguage] = 'ruby'
7
6
  if params[:noViewport] == 0
8
7
  params.delete(:noViewport)
9
8
  params[:noDefaultViewport] = true
@@ -11,6 +10,14 @@ module Playwright
11
10
  if params[:extraHTTPHeaders]
12
11
  params[:extraHTTPHeaders] = ::Playwright::HttpHeaders.new(params[:extraHTTPHeaders]).as_serialized
13
12
  end
13
+ if params[:record_har_path]
14
+ params[:recordHar] = {
15
+ path: params.delete(:record_har_path)
16
+ }
17
+ if params[:record_har_omit_content]
18
+ params[:recordHar][:omitContent] = params.delete(:record_har_omit_content)
19
+ end
20
+ end
14
21
  if params[:record_video_dir]
15
22
  params[:recordVideo] = {
16
23
  dir: params.delete(:record_video_dir)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.14.beta3'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.14.0'
4
+ VERSION = '1.15.beta3'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.15.0'
6
6
  end
@@ -94,7 +94,9 @@ module Playwright
94
94
  end
95
95
 
96
96
  def debug_send_message(message)
97
+ metadata = message.delete(:metadata)
97
98
  puts "\x1b[33mSEND>\x1b[0m#{message}"
99
+ message[:metadata] = metadata
98
100
  end
99
101
 
100
102
  def debug_recv_message(message)
data/lib/playwright.rb CHANGED
@@ -20,7 +20,8 @@ require 'playwright/channel_owner'
20
20
  require 'playwright/http_headers'
21
21
  require 'playwright/input_files'
22
22
  require 'playwright/connection'
23
- require 'playwright/route_handler_entry'
23
+ require 'playwright/raw_headers'
24
+ require 'playwright/route_handler'
24
25
  require 'playwright/select_option_values'
25
26
  require 'playwright/timeout_settings'
26
27
  require 'playwright/transport'
@@ -35,16 +36,18 @@ Dir[File.join(__dir__, 'playwright_api', '*.rb')].each { |f| require f }
35
36
 
36
37
  module Playwright
37
38
  class Execution
38
- def initialize(connection, playwright)
39
+ def initialize(connection, playwright, browser = nil)
39
40
  @connection = connection
40
41
  @playwright = playwright
42
+ @browser = browser
41
43
  end
42
44
 
43
45
  def stop
46
+ @browser&.close
44
47
  @connection.stop
45
48
  end
46
49
 
47
- attr_reader :playwright
50
+ attr_reader :playwright, :browser
48
51
  end
49
52
 
50
53
  # Recommended to call this method with block.
@@ -64,7 +67,7 @@ module Playwright
64
67
 
65
68
  execution =
66
69
  begin
67
- playwright = connection.wait_for_object_with_known_name('Playwright')
70
+ playwright = connection.initialize_playwright
68
71
  Execution.new(connection, PlaywrightApi.wrap(playwright))
69
72
  rescue
70
73
  connection.stop
@@ -100,7 +103,7 @@ module Playwright
100
103
 
101
104
  execution =
102
105
  begin
103
- playwright = connection.wait_for_object_with_known_name('Playwright')
106
+ playwright = connection.initialize_playwright
104
107
  Execution.new(connection, PlaywrightApi.wrap(playwright))
105
108
  rescue
106
109
  connection.stop
@@ -117,4 +120,42 @@ module Playwright
117
120
  execution
118
121
  end
119
122
  end
123
+
124
+ # Connects to Playwright server, launched by `npx playwright launch-server chromium` or `playwright.chromium.launchServer()`
125
+ #
126
+ # Playwright.connect_to_browser_server('ws://....') do |browser|
127
+ # page = browser.new_page
128
+ # ...
129
+ # end
130
+ #
131
+ # @experimental
132
+ module_function def connect_to_browser_server(ws_endpoint, &block)
133
+ require 'playwright/web_socket_client'
134
+ require 'playwright/web_socket_transport'
135
+
136
+ transport = WebSocketTransport.new(ws_endpoint: ws_endpoint)
137
+ connection = Connection.new(transport)
138
+ connection.async_run
139
+
140
+ execution =
141
+ begin
142
+ playwright = connection.initialize_playwright
143
+ browser = playwright.send(:pre_launched_browser)
144
+ browser.send(:update_as_remote)
145
+ Execution.new(connection, PlaywrightApi.wrap(playwright), PlaywrightApi.wrap(browser))
146
+ rescue
147
+ connection.stop
148
+ raise
149
+ end
150
+
151
+ if block
152
+ begin
153
+ block.call(execution.browser)
154
+ ensure
155
+ execution.stop
156
+ end
157
+ else
158
+ execution
159
+ end
160
+ end
120
161
  end
@@ -38,20 +38,20 @@ module Playwright
38
38
 
39
39
  # -- inherited from EventEmitter --
40
40
  # @nodoc
41
- def once(event, callback)
42
- event_emitter_proxy.once(event, callback)
41
+ def off(event, callback)
42
+ event_emitter_proxy.off(event, callback)
43
43
  end
44
44
 
45
45
  # -- inherited from EventEmitter --
46
46
  # @nodoc
47
- def on(event, callback)
48
- event_emitter_proxy.on(event, callback)
47
+ def once(event, callback)
48
+ event_emitter_proxy.once(event, callback)
49
49
  end
50
50
 
51
51
  # -- inherited from EventEmitter --
52
52
  # @nodoc
53
- def off(event, callback)
54
- event_emitter_proxy.off(event, callback)
53
+ def on(event, callback)
54
+ event_emitter_proxy.on(event, callback)
55
55
  end
56
56
 
57
57
  private def event_emitter_proxy
@@ -46,6 +46,7 @@ module Playwright
46
46
  command: nil,
47
47
  deviceScaleFactor: nil,
48
48
  extraHTTPHeaders: nil,
49
+ forcedColors: nil,
49
50
  geolocation: nil,
50
51
  hasTouch: nil,
51
52
  httpCredentials: nil,
@@ -62,11 +63,12 @@ module Playwright
62
63
  record_video_size: nil,
63
64
  reducedMotion: nil,
64
65
  screen: nil,
66
+ strictSelectors: nil,
65
67
  timezoneId: nil,
66
68
  userAgent: nil,
67
69
  viewport: nil,
68
70
  &block)
69
- wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), 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), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
71
+ wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), 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), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
70
72
  end
71
73
 
72
74
  # Performs a long tap on the widget defined by `selector`.
@@ -162,14 +164,20 @@ module Playwright
162
164
  raise NotImplementedError.new('web_views is not implemented yet.')
163
165
  end
164
166
 
167
+ # @nodoc
168
+ def tree
169
+ wrap_impl(@impl.tree)
170
+ end
171
+
165
172
  # @nodoc
166
173
  def tap_on(selector, duration: nil, timeout: nil)
167
174
  wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
168
175
  end
169
176
 
177
+ # -- inherited from EventEmitter --
170
178
  # @nodoc
171
- def tree
172
- wrap_impl(@impl.tree)
179
+ def off(event, callback)
180
+ event_emitter_proxy.off(event, callback)
173
181
  end
174
182
 
175
183
  # -- inherited from EventEmitter --
@@ -184,12 +192,6 @@ module Playwright
184
192
  event_emitter_proxy.on(event, callback)
185
193
  end
186
194
 
187
- # -- inherited from EventEmitter --
188
- # @nodoc
189
- def off(event, callback)
190
- event_emitter_proxy.off(event, callback)
191
- end
192
-
193
195
  private def event_emitter_proxy
194
196
  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
195
197
  end