playwright-ruby-client 0.0.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,36 @@
1
+ module Playwright
2
+ class RouteHandlerEntry
3
+ # @param url [String]
4
+ # @param handler [Proc]
5
+ def initialize(url, handler)
6
+ @url_value = url
7
+ @url_matcher = UrlMatcher.new(url)
8
+ @handler = handler
9
+ end
10
+
11
+ def handle(route, request)
12
+ if url_match?(request.url)
13
+ @handler.call(route, request)
14
+ true
15
+ else
16
+ false
17
+ end
18
+ end
19
+
20
+ def same_value?(url:, handler: nil)
21
+ if handler
22
+ @url_value == url && @handler == handler
23
+ else
24
+ @url_value == url
25
+ end
26
+ end
27
+
28
+ private def url_match?(request_url)
29
+ if @url_value.is_a?(Regexp)
30
+ @url_matcher.match?(request_url)
31
+ else
32
+ @url_matcher.match?(request_url) || File.fnmatch?(@url_value, request_url)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,18 @@
1
1
  module Playwright
2
2
  class SelectOptionValues
3
- def initialize(values)
4
- @params = convert(values)
3
+ def initialize(element: nil, index: nil, value: nil, label: nil)
4
+ @params =
5
+ if element
6
+ convert(elmeent)
7
+ elsif index
8
+ convert(index)
9
+ elsif value
10
+ convert(value)
11
+ elsif label
12
+ convert(label)
13
+ else
14
+ {}
15
+ end
5
16
  end
6
17
 
7
18
  # @return [Hash]
@@ -10,8 +21,7 @@ module Playwright
10
21
  end
11
22
 
12
23
  private def convert(values)
13
- return {} unless values
14
- return convert([values]) unless values.is_a?('Array')
24
+ return convert([values]) unless values.is_a?(Enumerable)
15
25
  return {} if values.empty?
16
26
  values.each_with_index do |value, index|
17
27
  unless values
@@ -0,0 +1,7 @@
1
+ module Playwright
2
+ define_api_implementation :TouchscreenImpl do
3
+ def initialize(channel)
4
+ @channel = channel
5
+ end
6
+ end
7
+ end
@@ -3,12 +3,13 @@ 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
- if params[:viewport] == 0
7
- params.delete(:viewport)
6
+ params[:sdkLanguage] = 'ruby'
7
+ if params[:noViewport] == 0
8
+ params.delete(:noViewport)
8
9
  params[:noDefaultViewport] = true
9
10
  end
10
11
  if params[:extraHTTPHeaders]
11
- # TODO
12
+ params[:extraHTTPHeaders] = ::Playwright::HttpHeaders.new(params[:extraHTTPHeaders]).as_serialized
12
13
  end
13
14
  if params[:storageState].is_a?(String)
14
15
  params[:storageState] = JSON.parse(File.read(params[:storageState]))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '0.0.8'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -23,7 +23,7 @@ module Playwright
23
23
  return if timeout_ms <= 0
24
24
 
25
25
  Concurrent::Promises.schedule(timeout_ms / 1000.0) {
26
- reject(TimeoutError.new(message))
26
+ reject(TimeoutError.new(message: message))
27
27
  }
28
28
 
29
29
  self
@@ -1,33 +1,104 @@
1
1
  module Playwright
2
- # @nodoc
2
+ # Playwright has **experimental** support for Android automation. You can access android namespace via:
3
+ #
4
+ #
5
+ # ```js
6
+ # const { _android } = require('playwright');
7
+ # ```
8
+ #
9
+ # An example of the Android automation script would be:
10
+ #
11
+ #
12
+ # ```js
13
+ # const { _android } = require('playwright');
14
+ #
15
+ # (async () => {
16
+ # // Connect to the device.
17
+ # const [device] = await playwright._android.devices();
18
+ # console.log(`Model: ${device.model()}`);
19
+ # console.log(`Serial: ${device.serial()}`);
20
+ # // Take screenshot of the whole device.
21
+ # await device.screenshot({ path: 'device.png' });
22
+ #
23
+ # {
24
+ # // --------------------- WebView -----------------------
25
+ #
26
+ # // Launch an application with WebView.
27
+ # await device.shell('am force-stop org.chromium.webview_shell');
28
+ # await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
29
+ # // Get the WebView.
30
+ # const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
31
+ #
32
+ # // Fill the input box.
33
+ # await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
34
+ # await device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter');
35
+ #
36
+ # // Work with WebView's page as usual.
37
+ # const page = await webview.page();
38
+ # await page.page.waitForNavigation({ url: /.*microsoft\/playwright.*/ });
39
+ # console.log(await page.title());
40
+ # }
41
+ #
42
+ # {
43
+ # // --------------------- Browser -----------------------
44
+ #
45
+ # // Launch Chrome browser.
46
+ # await device.shell('am force-stop com.android.chrome');
47
+ # const context = await device.launchBrowser();
48
+ #
49
+ # // Use BrowserContext as usual.
50
+ # const page = await context.newPage();
51
+ # await page.goto('https://webkit.org/');
52
+ # console.log(await page.evaluate(() => window.location.href));
53
+ # await page.screenshot({ path: 'page.png' });
54
+ #
55
+ # await context.close();
56
+ # }
57
+ #
58
+ # // Close the device.
59
+ # await device.close();
60
+ # })();
61
+ # ```
62
+ #
63
+ # Note that since you don't need Playwright to install web browsers when testing Android, you can omit browser download
64
+ # via setting the following environment variable when installing Playwright:
65
+ #
66
+ # ```sh js
67
+ # $ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
68
+ # ```
3
69
  class Android < PlaywrightApi
4
70
 
5
- # @nodoc
71
+ # Returns the list of detected Android devices.
6
72
  def devices
7
73
  wrap_impl(@impl.devices)
8
74
  end
9
75
 
10
- # @nodoc
11
- def after_initialize
12
- wrap_impl(@impl.after_initialize)
76
+ # This setting will change the default maximum time for all the methods accepting `timeout` option.
77
+ def set_default_timeout(timeout)
78
+ raise NotImplementedError.new('set_default_timeout is not implemented yet.')
13
79
  end
80
+ alias_method :default_timeout=, :set_default_timeout
14
81
 
15
82
  # -- inherited from EventEmitter --
16
83
  # @nodoc
17
- def on(event, callback)
18
- wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
84
+ def off(event, callback)
85
+ event_emitter_proxy.off(event, callback)
19
86
  end
20
87
 
21
88
  # -- inherited from EventEmitter --
22
89
  # @nodoc
23
- def off(event, callback)
24
- wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
90
+ def once(event, callback)
91
+ event_emitter_proxy.once(event, callback)
25
92
  end
26
93
 
27
94
  # -- inherited from EventEmitter --
28
95
  # @nodoc
29
- def once(event, callback)
30
- wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
96
+ def on(event, callback)
97
+ event_emitter_proxy.on(event, callback)
98
+ end
99
+
100
+ private def event_emitter_proxy
101
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
31
102
  end
32
103
  end
33
104
  end
@@ -1,78 +1,194 @@
1
1
  module Playwright
2
- # @nodoc
2
+ # `AndroidDevice` represents a connected device, either real hardware or emulated. Devices can be obtained using
3
+ # [`method: Android.devices`].
3
4
  class AndroidDevice < PlaywrightApi
4
5
 
5
- # @nodoc
6
- def tree
7
- wrap_impl(@impl.tree)
6
+ def input # property
7
+ wrap_impl(@impl.input)
8
8
  end
9
9
 
10
- # @nodoc
10
+ # Disconnects from the device.
11
11
  def close
12
12
  wrap_impl(@impl.close)
13
13
  end
14
14
 
15
- # @nodoc
16
- def after_initialize
17
- wrap_impl(@impl.after_initialize)
15
+ # Drags the widget defined by `selector` towards `dest` point.
16
+ def drag(selector, dest, speed: nil)
17
+ raise NotImplementedError.new('drag is not implemented yet.')
18
18
  end
19
19
 
20
- # @nodoc
21
- def tap_on(selector, duration: nil, timeout: nil)
22
- wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
20
+ # Fills the specific `selector` input box with `text`.
21
+ def fill(selector, text)
22
+ raise NotImplementedError.new('fill is not implemented yet.')
23
23
  end
24
24
 
25
- # @nodoc
25
+ # Flings the widget defined by `selector` in the specified `direction`.
26
+ def fling(selector, direction, speed: nil)
27
+ raise NotImplementedError.new('fling is not implemented yet.')
28
+ end
29
+
30
+ # Returns information about a widget defined by `selector`.
31
+ def info(selector)
32
+ wrap_impl(@impl.info(unwrap_impl(selector)))
33
+ end
34
+
35
+ # Installs an apk on the device.
36
+ def install_apk(file, args: nil)
37
+ raise NotImplementedError.new('install_apk is not implemented yet.')
38
+ end
39
+
40
+ # Launches Chrome browser on the device, and returns its persistent context.
41
+ def launch_browser(
42
+ acceptDownloads: nil,
43
+ bypassCSP: nil,
44
+ colorScheme: nil,
45
+ command: nil,
46
+ deviceScaleFactor: nil,
47
+ extraHTTPHeaders: nil,
48
+ geolocation: nil,
49
+ hasTouch: nil,
50
+ httpCredentials: nil,
51
+ ignoreHTTPSErrors: nil,
52
+ isMobile: nil,
53
+ javaScriptEnabled: nil,
54
+ locale: nil,
55
+ noViewport: nil,
56
+ offline: nil,
57
+ permissions: nil,
58
+ record_har_omit_content: nil,
59
+ record_har_path: nil,
60
+ record_video_dir: nil,
61
+ record_video_size: nil,
62
+ timezoneId: nil,
63
+ userAgent: nil,
64
+ viewport: nil,
65
+ &block)
66
+ wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), 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), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
67
+ end
68
+
69
+ # Performs a long tap on the widget defined by `selector`.
70
+ def long_tap(selector)
71
+ raise NotImplementedError.new('long_tap is not implemented yet.')
72
+ end
73
+
74
+ # Device model.
75
+ def model
76
+ wrap_impl(@impl.model)
77
+ end
78
+
79
+ # Launches a process in the shell on the device and returns a socket to communicate with the launched process.
80
+ def open(command)
81
+ raise NotImplementedError.new('open is not implemented yet.')
82
+ end
83
+
84
+ # Pinches the widget defined by `selector` in the closing direction.
85
+ def pinch_close(selector, percent, speed: nil)
86
+ raise NotImplementedError.new('pinch_close is not implemented yet.')
87
+ end
88
+
89
+ # Pinches the widget defined by `selector` in the open direction.
90
+ def pinch_open(selector, percent, speed: nil)
91
+ raise NotImplementedError.new('pinch_open is not implemented yet.')
92
+ end
93
+
94
+ # Presses the specific `key` in the widget defined by `selector`.
95
+ def press(selector, key)
96
+ raise NotImplementedError.new('press is not implemented yet.')
97
+ end
98
+
99
+ # Copies a file to the device.
100
+ def push(file, path, mode: nil)
101
+ raise NotImplementedError.new('push is not implemented yet.')
102
+ end
103
+
104
+ # Returns the buffer with the captured screenshot of the device.
26
105
  def screenshot(path: nil)
27
106
  wrap_impl(@impl.screenshot(path: unwrap_impl(path)))
28
107
  end
29
108
 
30
- # @nodoc
109
+ # Scrolls the widget defined by `selector` in the specified `direction`.
110
+ def scroll(selector, direction, percent, speed: nil)
111
+ raise NotImplementedError.new('scroll is not implemented yet.')
112
+ end
113
+
114
+ # Device serial number.
115
+ def serial
116
+ wrap_impl(@impl.serial)
117
+ end
118
+
119
+ # This setting will change the default maximum time for all the methods accepting `timeout` option.
120
+ def set_default_timeout(timeout)
121
+ raise NotImplementedError.new('set_default_timeout is not implemented yet.')
122
+ end
123
+ alias_method :default_timeout=, :set_default_timeout
124
+
125
+ # Executes a shell command on the device and returns its output.
31
126
  def shell(command)
32
127
  wrap_impl(@impl.shell(unwrap_impl(command)))
33
128
  end
34
129
 
35
- # @nodoc
36
- def input
37
- wrap_impl(@impl.input)
130
+ # Swipes the widget defined by `selector` in the specified `direction`.
131
+ def swipe(selector, direction, percent, speed: nil)
132
+ raise NotImplementedError.new('swipe is not implemented yet.')
38
133
  end
39
134
 
40
- # @nodoc
41
- def launch_browser(pkg: nil, acceptDownloads: nil, bypassCSP: nil, colorScheme: nil, deviceScaleFactor: nil, extraHTTPHeaders: nil, geolocation: nil, hasTouch: nil, httpCredentials: nil, ignoreHTTPSErrors: nil, isMobile: nil, javaScriptEnabled: nil, locale: nil, logger: nil, offline: nil, permissions: nil, proxy: nil, recordHar: nil, recordVideo: nil, storageState: nil, timezoneId: nil, userAgent: nil, videoSize: nil, videosPath: nil, viewport: nil, &block)
42
- wrap_impl(@impl.launch_browser(pkg: unwrap_impl(pkg), acceptDownloads: unwrap_impl(acceptDownloads), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), 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), logger: unwrap_impl(logger), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), recordHar: unwrap_impl(recordHar), recordVideo: unwrap_impl(recordVideo), storageState: unwrap_impl(storageState), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), videoSize: unwrap_impl(videoSize), videosPath: unwrap_impl(videosPath), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
135
+ # Taps on the widget defined by `selector`.
136
+ def tap_point(selector, duration: nil)
137
+ raise NotImplementedError.new('tap_point is not implemented yet.')
43
138
  end
44
139
 
45
- # @nodoc
46
- def info(selector)
47
- wrap_impl(@impl.info(unwrap_impl(selector)))
140
+ # Waits for the specific `selector` to either appear or disappear, depending on the `state`.
141
+ def wait(selector, state: nil)
142
+ raise NotImplementedError.new('wait is not implemented yet.')
48
143
  end
49
144
 
50
- # @nodoc
51
- def serial
52
- wrap_impl(@impl.serial)
145
+ # Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
146
+ # value.
147
+ def wait_for_event(event, optionsOrPredicate: nil)
148
+ raise NotImplementedError.new('wait_for_event is not implemented yet.')
149
+ end
150
+
151
+ # This method waits until `AndroidWebView` matching the `selector` is opened and returns it. If there is already an open
152
+ # `AndroidWebView` matching the `selector`, returns immediately.
153
+ def web_view(selector)
154
+ raise NotImplementedError.new('web_view is not implemented yet.')
155
+ end
156
+
157
+ # Currently open WebViews.
158
+ def web_views
159
+ raise NotImplementedError.new('web_views is not implemented yet.')
53
160
  end
54
161
 
55
162
  # @nodoc
56
- def model
57
- wrap_impl(@impl.model)
163
+ def tree
164
+ wrap_impl(@impl.tree)
58
165
  end
59
166
 
60
- # -- inherited from EventEmitter --
61
167
  # @nodoc
62
- def on(event, callback)
63
- wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
168
+ def tap_on(selector, duration: nil, timeout: nil)
169
+ wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
64
170
  end
65
171
 
66
172
  # -- inherited from EventEmitter --
67
173
  # @nodoc
68
174
  def off(event, callback)
69
- wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
175
+ event_emitter_proxy.off(event, callback)
70
176
  end
71
177
 
72
178
  # -- inherited from EventEmitter --
73
179
  # @nodoc
74
180
  def once(event, callback)
75
- wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
181
+ event_emitter_proxy.once(event, callback)
182
+ end
183
+
184
+ # -- inherited from EventEmitter --
185
+ # @nodoc
186
+ def on(event, callback)
187
+ event_emitter_proxy.on(event, callback)
188
+ end
189
+
190
+ private def event_emitter_proxy
191
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
76
192
  end
77
193
  end
78
194
  end