playwright-ruby-client 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/docs/api_coverage.md +12 -12
  3. data/lib/playwright.rb +3 -2
  4. data/lib/playwright/{input_types/android_input.rb → android_input_impl.rb} +5 -1
  5. data/lib/playwright/api_implementation.rb +18 -0
  6. data/lib/playwright/channel.rb +7 -0
  7. data/lib/playwright/channel_owners/android_device.rb +1 -1
  8. data/lib/playwright/channel_owners/download.rb +27 -0
  9. data/lib/playwright/channel_owners/element_handle.rb +2 -2
  10. data/lib/playwright/channel_owners/frame.rb +2 -2
  11. data/lib/playwright/channel_owners/page.rb +33 -3
  12. data/lib/playwright/errors.rb +1 -1
  13. data/lib/playwright/event_emitter.rb +4 -0
  14. data/lib/playwright/event_emitter_proxy.rb +49 -0
  15. data/lib/playwright/file_chooser_impl.rb +23 -0
  16. data/lib/playwright/input_files.rb +1 -1
  17. data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +5 -1
  18. data/lib/playwright/mouse_impl.rb +7 -0
  19. data/lib/playwright/playwright_api.rb +59 -20
  20. data/lib/playwright/touchscreen_impl.rb +7 -0
  21. data/lib/playwright/version.rb +1 -1
  22. data/lib/playwright/wait_helper.rb +1 -1
  23. data/lib/playwright_api/android.rb +12 -8
  24. data/lib/playwright_api/android_device.rb +15 -11
  25. data/lib/playwright_api/android_input.rb +5 -5
  26. data/lib/playwright_api/binding_call.rb +10 -6
  27. data/lib/playwright_api/browser.rb +10 -6
  28. data/lib/playwright_api/browser_context.rb +10 -6
  29. data/lib/playwright_api/browser_type.rb +10 -6
  30. data/lib/playwright_api/chromium_browser_context.rb +10 -6
  31. data/lib/playwright_api/console_message.rb +10 -6
  32. data/lib/playwright_api/download.rb +28 -6
  33. data/lib/playwright_api/element_handle.rb +10 -6
  34. data/lib/playwright_api/file_chooser.rb +4 -4
  35. data/lib/playwright_api/frame.rb +10 -6
  36. data/lib/playwright_api/js_handle.rb +10 -6
  37. data/lib/playwright_api/keyboard.rb +5 -5
  38. data/lib/playwright_api/page.rb +10 -6
  39. data/lib/playwright_api/playwright.rb +10 -6
  40. data/lib/playwright_api/request.rb +12 -8
  41. data/lib/playwright_api/response.rb +10 -6
  42. data/lib/playwright_api/selectors.rb +10 -6
  43. metadata +10 -7
  44. data/lib/playwright/input_type.rb +0 -19
  45. data/lib/playwright/input_types/mouse.rb +0 -4
  46. data/lib/playwright/input_types/touchscreen.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eccb7fbb7a1fba3116ceaa61893b164850dc7f21eb45cac637da161bc137120a
4
- data.tar.gz: ceeab7bc64c7a743ef3b682dda05271ff49eb3727ad7b47ed722f527aedacba0
3
+ metadata.gz: a8e526e28e95751a08697bc93b14ec33f4f82e827b8adf4dc45aed4bf44dd1d2
4
+ data.tar.gz: 647596db5628a1014a7816bb43d2ca41a21eeb6cf8c7263dea701d8f9a6ba4e7
5
5
  SHA512:
6
- metadata.gz: 1414afc026223b47750708cd2f30dab6453aebb5b3ce06f97a7f4a51c793f6b2b57ef307ffc0b31df2f91158d7d7e40623f443846b1653ca8778b7a67bfe7a47
7
- data.tar.gz: 33cf15f92e23a118264627067f534d4379876090b6a3bf74fb8c67253e2905b575495c548247144f82ed282b8b86a1c891e89ffdf8e51423202bd38ce03a5bb2
6
+ metadata.gz: 0051320ee1e574680ebc6be4d5cf359a28bd8ada9a737fc60d734f017c43142b6f267553f15d0e1ac0ed368f12d57dac5a887a39695f59a11f774344405dcfd1
7
+ data.tar.gz: 14f97b51a9462a8bfb587c5752eb13b3db0c132d0d56d7bdaab829389f2cb7c17bb879b171773e1e21259bb6b352f6020a5b7165be577bb147b22b5b0155c28e
data/docs/api_coverage.md CHANGED
@@ -113,12 +113,12 @@
113
113
 
114
114
  * ~~snapshot~~
115
115
 
116
- ## ~~FileChooser~~
116
+ ## FileChooser
117
117
 
118
- * ~~element~~
119
- * ~~multiple?~~
120
- * ~~page~~
121
- * ~~set_files~~
118
+ * element
119
+ * multiple?
120
+ * page
121
+ * set_files
122
122
 
123
123
  ## Frame
124
124
 
@@ -195,15 +195,15 @@
195
195
  * ~~message~~
196
196
  * ~~type~~
197
197
 
198
- ## ~~Download~~
198
+ ## Download
199
199
 
200
200
  * ~~create_read_stream~~
201
- * ~~delete~~
202
- * ~~failure~~
203
- * ~~path~~
204
- * ~~save_as~~
205
- * ~~suggested_filename~~
206
- * ~~url~~
201
+ * delete
202
+ * failure
203
+ * path
204
+ * save_as
205
+ * suggested_filename
206
+ * url
207
207
 
208
208
  ## ~~Video~~
209
209
 
data/lib/playwright.rb CHANGED
@@ -10,14 +10,15 @@ require 'concurrent'
10
10
  require 'playwright/errors'
11
11
  require 'playwright/events'
12
12
  require 'playwright/event_emitter'
13
+ require 'playwright/event_emitter_proxy'
13
14
  require 'playwright/javascript'
14
15
  require 'playwright/utils'
15
16
 
17
+ require 'playwright/api_implementation'
16
18
  require 'playwright/channel'
17
19
  require 'playwright/channel_owner'
18
20
  require 'playwright/http_headers'
19
21
  require 'playwright/input_files'
20
- require 'playwright/input_type'
21
22
  require 'playwright/connection'
22
23
  require 'playwright/select_option_values'
23
24
  require 'playwright/timeout_settings'
@@ -38,7 +39,7 @@ module Playwright
38
39
 
39
40
  playwright_promise = connection.async_wait_for_object_with_known_name('Playwright')
40
41
  Thread.new { connection.run }
41
- playwright = PlaywrightApi.from_channel_owner(playwright_promise.value!)
42
+ playwright = PlaywrightApi.wrap(playwright_promise.value!)
42
43
  begin
43
44
  block.call(playwright)
44
45
  ensure
@@ -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 }
@@ -24,5 +24,12 @@ module Playwright
24
24
  nil
25
25
  end
26
26
  end
27
+
28
+ # @param method [String]
29
+ # @param params [Hash]
30
+ def send_no_reply(method, params)
31
+ @connection.async_send_message_to_server(@guid, method, params)
32
+ nil
33
+ end
27
34
  end
28
35
  end
@@ -3,7 +3,7 @@ module Playwright
3
3
  include Utils::PrepareBrowserContextOptions
4
4
 
5
5
  def after_initialize
6
- @input = InputTypes::AndroidInput.new(@channel)
6
+ @input = AndroidInputImpl.new(@channel)
7
7
  end
8
8
 
9
9
  attr_reader :input
@@ -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
@@ -182,8 +182,8 @@ module Playwright
182
182
  end
183
183
 
184
184
  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
185
+ file_payloads = InputFiles.new(files).as_params
186
+ params = { files: file_payloads, noWaitAfter: noWaitAfter, timeout: timeout }.compact
187
187
  @channel.send_message_to_server('setInputFiles', params)
188
188
 
189
189
  nil
@@ -407,8 +407,8 @@ module Playwright
407
407
  end
408
408
 
409
409
  def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
410
- base_params = InputFiles.new(values).as_params
411
- params = base_params + { selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
410
+ file_payloads = InputFiles.new(files).as_params
411
+ params = { files: file_payloads, selector: selector, noWaitAfter: noWaitAfter, timeout: timeout }.compact
412
412
  @channel.send_message_to_server('setInputFiles', params)
413
413
 
414
414
  nil
@@ -10,9 +10,9 @@ module Playwright
10
10
  @browser_context = @parent
11
11
  @timeout_settings = TimeoutSettings.new(@browser_context.send(:_timeout_settings))
12
12
  @accessibility = Accessibility.new(@channel)
13
- @keyboard = InputTypes::Keyboard.new(@channel)
14
- @mouse = InputTypes::Mouse.new(@channel)
15
- @touchscreen = InputTypes::Touchscreen.new(@channel)
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
@@ -32,6 +32,13 @@ module Playwright
32
32
  @channel.on('download', ->(params) {
33
33
  emit(Events::Page::Download, ChannelOwners::Download.from(params['download']))
34
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
+ })
35
42
  @channel.on('frameAttached', ->(params) {
36
43
  on_frame_attached(ChannelOwners::Frame.from(params['frame']))
37
44
  })
@@ -127,6 +134,29 @@ module Playwright
127
134
  end
128
135
  end
129
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
130
160
 
131
161
  def context
132
162
  @browser_context
@@ -28,7 +28,7 @@ module Playwright
28
28
  end
29
29
 
30
30
  class TimeoutError < Error
31
- def initialize(message:, stack:)
31
+ def initialize(message:, stack: [])
32
32
  super(name: 'TimeoutError', message: message, stack: stack)
33
33
  end
34
34
  end
@@ -44,6 +44,10 @@ module Playwright
44
44
  handled
45
45
  end
46
46
 
47
+ private def listener_count(event)
48
+ ((@__event_emitter ||= {})[event.to_s] ||= Set.new).count
49
+ end
50
+
47
51
  # @param event [String]
48
52
  # @param callback [Proc]
49
53
  def on(event, callback)
@@ -0,0 +1,49 @@
1
+ module Playwright
2
+ class EventEmitterProxy
3
+ include EventEmitter
4
+
5
+ # @param src [PlaywrightApi]
6
+ # @param dest [EventEmitter]
7
+ def initialize(api, impl)
8
+ @api = api
9
+ @impl = impl
10
+ @listeners = {}
11
+ end
12
+
13
+ def on(event, callback)
14
+ if listener_count(event) == 0
15
+ subscribe(event)
16
+ end
17
+ super
18
+ end
19
+
20
+ def once(event, callback)
21
+ if listener_count(event) == 0
22
+ subscribe(event)
23
+ end
24
+ super
25
+ end
26
+
27
+ def off(event, callback)
28
+ super
29
+ if listener_count(event) == 0
30
+ unsubscribe(event)
31
+ end
32
+ end
33
+
34
+ private def subscribe(event)
35
+ @listeners[event] = ->(*args) {
36
+ wrapped_args = args.map { |arg| ::Playwright::PlaywrightApi.wrap(arg) }
37
+ emit(event, *wrapped_args)
38
+ }
39
+ @impl.on(event, @listeners[event])
40
+ end
41
+
42
+ private def unsubscribe(event)
43
+ listener = @listeners.delete(event)
44
+ if listener
45
+ @impl.off(event, listener)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ module Playwright
2
+ define_api_implementation :FileChooserImpl do
3
+ def initialize(page:, element_handle:, is_multiple:)
4
+ @page = page
5
+ @element_handle = element_handle
6
+ @is_multiple = is_multiple
7
+ end
8
+
9
+ attr_reader :page
10
+
11
+ def element
12
+ @element_handle
13
+ end
14
+
15
+ def multiple?
16
+ @is_multiple
17
+ end
18
+
19
+ def set_files(files, noWaitAfter: nil, timeout: nil)
20
+ @element_handle.set_input_files(files, noWaitAfter: noWaitAfter, timeout: timeout)
21
+ end
22
+ end
23
+ end
@@ -36,7 +36,7 @@ module Playwright
36
36
 
37
37
  private def mime_type_for(filepath)
38
38
  mime_types = MIME::Types.type_for(filepath)
39
- mime_types.first || 'application/octet-stream'
39
+ mime_types.first.to_s || 'application/octet-stream'
40
40
  end
41
41
  end
42
42
  end
@@ -1,5 +1,9 @@
1
1
  module Playwright
2
- define_input_type :Keyboard do
2
+ define_api_implementation :KeyboardImpl do
3
+ def initialize(channel)
4
+ @channel = channel
5
+ end
6
+
3
7
  def down(key)
4
8
  @channel.send_message_to_server('keyboardDown', key: key)
5
9
  nil
@@ -0,0 +1,7 @@
1
+ module Playwright
2
+ define_api_implementation :MouseImpl do
3
+ def initialize(channel)
4
+ @channel = channel
5
+ end
6
+ end
7
+ end
@@ -1,27 +1,34 @@
1
1
  module Playwright
2
2
  class PlaywrightApi
3
- # Wrap ChannelOwner.
3
+ # Wrap ChannelOwner / ApiImplementation.
4
4
  # Playwright::ChannelOwners::XXXXX will be wrapped as Playwright::XXXXX
5
+ # Playwright::YYYYImpl will be wrapped as Playwright::YYYY
5
6
  # Playwright::XXXXX is automatically generated by development/generate_api
6
7
  #
7
- # @param channel_owner [ChannelOwner]
8
+ # @param channel_owner [ChannelOwner|ApiImplementation]
8
9
  # @note Intended for internal use only.
9
- def self.from_channel_owner(channel_owner)
10
- Factory.new(channel_owner, 'ChannelOwners').create
10
+ def self.wrap(channel_owner_or_api_implementation)
11
+ case channel_owner_or_api_implementation
12
+ when ChannelOwner
13
+ ChannelOwnerWrapper.new(channel_owner_or_api_implementation).wrap
14
+ when ApiImplementation
15
+ ApiImplementationWrapper.new(channel_owner_or_api_implementation).wrap
16
+ else
17
+ nil
18
+ end
11
19
  end
12
20
 
13
- class Factory
14
- def initialize(impl, module_name)
21
+ class ChannelOwnerWrapper
22
+ def initialize(impl)
15
23
  impl_class_name = impl.class.name
16
- unless impl_class_name.include?("::#{module_name}::")
17
- raise "#{impl_class_name} is not #{module_name}"
24
+ unless impl_class_name.include?("::ChannelOwners::")
25
+ raise "#{impl_class_name} is not ChannelOwners"
18
26
  end
19
27
 
20
28
  @impl = impl
21
- @module_name = module_name
22
29
  end
23
30
 
24
- def create
31
+ def wrap
25
32
  api_class = detect_class_for(@impl.class)
26
33
  if api_class
27
34
  api_class.new(@impl)
@@ -33,11 +40,11 @@ module Playwright
33
40
  private
34
41
 
35
42
  def expected_class_name_for(klass)
36
- klass.name.split("::#{@module_name}::").last
43
+ klass.name.split("::ChannelOwners::").last
37
44
  end
38
45
 
39
46
  def superclass_exist?(klass)
40
- ![::Playwright::ChannelOwner, ::Playwright::InputType, Object].include?(klass.superclass)
47
+ ![::Playwright::ChannelOwner, Object].include?(klass.superclass)
41
48
  end
42
49
 
43
50
  def detect_class_for(klass)
@@ -52,7 +59,44 @@ module Playwright
52
59
  end
53
60
  end
54
61
 
55
- # @param impl [Playwright::ChannelOwner|Playwright::InputType]
62
+ class ApiImplementationWrapper
63
+ def initialize(impl)
64
+ impl_class_name = impl.class.name
65
+ unless impl_class_name.end_with?("Impl")
66
+ raise "#{impl_class_name} is not Impl"
67
+ end
68
+
69
+ @impl = impl
70
+ end
71
+
72
+ def wrap
73
+ api_class = detect_class_for(@impl.class)
74
+ if api_class
75
+ api_class.new(@impl)
76
+ else
77
+ raise NotImplementedError.new("Playwright::#{expected_class_name_for(@impl.class)} is not implemented")
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def expected_class_name_for(klass)
84
+ # KeyboardImpl -> Keyboard
85
+ # MouseImpl -> Mouse
86
+ klass.name[0...-4].split("::").last
87
+ end
88
+
89
+ def detect_class_for(klass)
90
+ class_name = expected_class_name_for(klass)
91
+ if ::Playwright.const_defined?(class_name)
92
+ ::Playwright.const_get(class_name)
93
+ else
94
+ nil
95
+ end
96
+ end
97
+ end
98
+
99
+ # @param impl [Playwright::ChannelOwner|Playwright::ApiImplementation]
56
100
  def initialize(impl)
57
101
  @impl = impl
58
102
  end
@@ -72,15 +116,10 @@ module Playwright
72
116
  end
73
117
 
74
118
  private def wrap_impl(object)
75
- case object
76
- when ChannelOwner
77
- PlaywrightApi.from_channel_owner(object)
78
- when InputType
79
- Factory.new(object, 'InputTypes').create
80
- when Array
119
+ if object.is_a?(Array)
81
120
  object.map { |obj| wrap_impl(obj) }
82
121
  else
83
- object
122
+ ::Playwright::PlaywrightApi.wrap(object) || object
84
123
  end
85
124
  end
86
125