playwright-ruby-client 0.0.5 → 0.0.6

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/lib/playwright.rb +2 -0
  3. data/lib/playwright/channel_owners/element_handle.rb +75 -0
  4. data/lib/playwright/channel_owners/frame.rb +117 -0
  5. data/lib/playwright/channel_owners/page.rb +68 -11
  6. data/lib/playwright/channel_owners/request.rb +90 -0
  7. data/lib/playwright/input_type.rb +19 -0
  8. data/lib/playwright/input_types/keyboard.rb +32 -0
  9. data/lib/playwright/input_types/mouse.rb +4 -0
  10. data/lib/playwright/input_types/touchscreen.rb +4 -0
  11. data/lib/playwright/javascript/expression.rb +22 -0
  12. data/lib/playwright/javascript/function.rb +22 -0
  13. data/lib/playwright/playwright_api.rb +31 -23
  14. data/lib/playwright/timeout_settings.rb +1 -1
  15. data/lib/playwright/url_matcher.rb +19 -0
  16. data/lib/playwright/version.rb +1 -1
  17. data/lib/playwright_api/accessibility.rb +46 -6
  18. data/lib/playwright_api/binding_call.rb +6 -6
  19. data/lib/playwright_api/browser.rb +76 -16
  20. data/lib/playwright_api/browser_context.rb +284 -30
  21. data/lib/playwright_api/browser_type.rb +54 -9
  22. data/lib/playwright_api/cdp_session.rb +23 -1
  23. data/lib/playwright_api/chromium_browser_context.rb +16 -6
  24. data/lib/playwright_api/console_message.rb +10 -10
  25. data/lib/playwright_api/dialog.rb +42 -0
  26. data/lib/playwright_api/download.rb +19 -4
  27. data/lib/playwright_api/element_handle.rb +174 -21
  28. data/lib/playwright_api/file_chooser.rb +8 -0
  29. data/lib/playwright_api/frame.rb +355 -68
  30. data/lib/playwright_api/js_handle.rb +45 -9
  31. data/lib/playwright_api/keyboard.rb +98 -8
  32. data/lib/playwright_api/mouse.rb +22 -0
  33. data/lib/playwright_api/page.rb +779 -127
  34. data/lib/playwright_api/playwright.rb +98 -19
  35. data/lib/playwright_api/request.rb +70 -23
  36. data/lib/playwright_api/response.rb +6 -6
  37. data/lib/playwright_api/route.rb +48 -0
  38. data/lib/playwright_api/selectors.rb +14 -6
  39. data/lib/playwright_api/video.rb +8 -0
  40. data/lib/playwright_api/web_socket.rb +3 -5
  41. data/lib/playwright_api/worker.rb +12 -0
  42. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c54a8690be4b1b2e33cecb6cda92071cd1d6867647fe939b004bf0434c31c74e
4
- data.tar.gz: 1c2c784a5970c7a89bffc6bdb12cf7c8e1353a676881a99862bb9bbe30dd3dea
3
+ metadata.gz: 243ef6d83fffde209cb8effe291c49b80fb90f7fd1fab7dacd451a524793f78a
4
+ data.tar.gz: 877db73a65179e2409423c73aa1fdf72b0da40ebe2d44bf22bce34533c438c98
5
5
  SHA512:
6
- metadata.gz: e9ca66a5edc3d168e16b552f3c84e4b4a939a7e8610da439fdea8350a87fed0656a9b5c715e4ac384d23b1d089ab23fa61ccd06288b1f11045aa83a3351a4f94
7
- data.tar.gz: cad563aa4e2f81a026f08a04a7fd3caf1295f6419b01f1601d324583243dd839bb4b7f3aec73967555c4dbb6b8ffb8b65e7607836ec2c11231512c6e45fbf526
6
+ metadata.gz: 01ea7a14404c07a54acd5112ad3704ce0d00ccd562061cbf46b0ec190c26ff0df850c613cddde6ff2d922de390063d6398a02a33f44fad88dd6d5d6ab1918893
7
+ data.tar.gz: 5e965b61082503371431d72a8b243c6212d5d2f3b6a232d62faf6fed2c85a920c041e259ea8f2d646722bf9e14eb4fcefebc9f40e86dca3a8ec2aa931c63d95b
@@ -15,9 +15,11 @@ require 'playwright/utils'
15
15
 
16
16
  require 'playwright/channel'
17
17
  require 'playwright/channel_owner'
18
+ require 'playwright/input_type'
18
19
  require 'playwright/connection'
19
20
  require 'playwright/timeout_settings'
20
21
  require 'playwright/transport'
22
+ require 'playwright/url_matcher'
21
23
  require 'playwright/version'
22
24
  require 'playwright/wait_helper'
23
25
 
@@ -3,6 +3,81 @@ require_relative './js_handle'
3
3
  module Playwright
4
4
  module ChannelOwners
5
5
  class ElementHandle < JSHandle
6
+ def click(
7
+ button: nil,
8
+ clickCount: nil,
9
+ delay: nil,
10
+ force: nil,
11
+ modifiers: nil,
12
+ noWaitAfter: nil,
13
+ position: nil,
14
+ timeout: nil)
15
+
16
+ params = {
17
+ button: button,
18
+ clickCount: clickCount,
19
+ delay: delay,
20
+ force: force,
21
+ modifiers: modifiers,
22
+ noWaitAfter: noWaitAfter,
23
+ position: position,
24
+ timeout: timeout,
25
+ }.compact
26
+ @channel.send_message_to_server('click', params)
27
+
28
+ nil
29
+ end
30
+
31
+ def type_text(text, delay: nil, noWaitAfter: nil, timeout: nil)
32
+ params = {
33
+ text: text,
34
+ delay: delay,
35
+ noWaitAfter: noWaitAfter,
36
+ timeout: timeout,
37
+ }.compact
38
+ @channel.send_message_to_server('type', params)
39
+
40
+ nil
41
+ end
42
+
43
+ def press(key, delay: nil, noWaitAfter: nil, timeout: nil)
44
+ params = {
45
+ key: key,
46
+ delay: delay,
47
+ noWaitAfter: noWaitAfter,
48
+ timeout: timeout,
49
+ }.compact
50
+ @channel.send_message_to_server('press', params)
51
+
52
+ nil
53
+ end
54
+
55
+ def query_selector(selector)
56
+ resp = @channel.send_message_to_server('querySelector', selector: selector)
57
+ ChannelOwners::ElementHandle.from_nullable(resp)
58
+ end
59
+
60
+ def query_selector_all(selector)
61
+ @channel.send_message_to_server('querySelectorAll', selector: selector).map do |el|
62
+ ChannelOwners::ElementHandle.from(el)
63
+ end
64
+ end
65
+
66
+ def eval_on_selector(selector, pageFunction, arg: nil)
67
+ if JavaScript.function?(pageFunction)
68
+ JavaScript::Function.new(pageFunction, arg).eval_on_selector(@channel, selector)
69
+ else
70
+ JavaScript::Expression.new(pageFunction).eval_on_selector(@channel, selector)
71
+ end
72
+ end
73
+
74
+ def eval_on_selector_all(selector, pageFunction, arg: nil)
75
+ if JavaScript.function?(pageFunction)
76
+ JavaScript::Function.new(pageFunction, arg).eval_on_selector_all(@channel, selector)
77
+ else
78
+ JavaScript::Expression.new(pageFunction).eval_on_selector_all(@channel, selector)
79
+ end
80
+ end
6
81
  end
7
82
  end
8
83
  end
@@ -53,6 +53,69 @@ module Playwright
53
53
  ChannelOwners::Response.from_nullable(resp)
54
54
  end
55
55
 
56
+ private def setup_navigation_wait_helper(timeout:)
57
+ WaitHelper.new.tap do |helper|
58
+ helper.reject_on_event(@page, Events::Page::Close, AlreadyClosedError.new)
59
+ helper.reject_on_event(@page, Events::Page::Crash, CrashedError.new)
60
+ helper.reject_on_event(@page, Events::Page::FrameDetached, FrameAlreadyDetachedError.new)
61
+ helper.reject_on_timeout(timeout, "Timeout #{timeout}ms exceeded.")
62
+ end
63
+ end
64
+
65
+ def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
66
+ option_wait_until = waitUntil || 'load'
67
+ option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
68
+ time_start = Time.now
69
+
70
+ wait_helper = setup_navigation_wait_helper(timeout: option_timeout)
71
+
72
+ predicate =
73
+ if url
74
+ matcher = UrlMatcher.new(url)
75
+ ->(event) { event['error'] || matcher.match?(event['url']) }
76
+ else
77
+ ->(_) { true }
78
+ end
79
+
80
+ wait_helper.wait_for_event(@event_emitter, 'navigated', predicate: predicate)
81
+
82
+ block&.call
83
+
84
+ event = wait_helper.promise.value!
85
+ if event['error']
86
+ raise event['error']
87
+ end
88
+
89
+ unless @load_states.include?(option_wait_until)
90
+ elapsed_time = Time.now - time_start
91
+ if elapsed_time < option_timeout
92
+ wait_for_load_state(state: option_wait_until, timeout: option_timeout - elapsed_time)
93
+ end
94
+ end
95
+
96
+ request_json = event.dig('newDocument', 'request')
97
+ request = ChannelOwners::Request.from_nullable(request_json)
98
+ request&.response
99
+ end
100
+
101
+ def wait_for_load_state(state: nil, timeout: nil)
102
+ option_state = state || 'load'
103
+ unless %w(load domcontentloaded networkidle).include?(option_state)
104
+ raise ArgumentError.new('state: expected one of (load|domcontentloaded|networkidle)')
105
+ end
106
+ if @load_states.include?(option_state)
107
+ return
108
+ end
109
+
110
+ wait_helper = setup_navigation_wait_helper(timeout: timeout)
111
+
112
+ predicate = ->(state) { state == option_state }
113
+ wait_helper.wait_for_event(@event_emitter, 'loadstate', predicate: predicate)
114
+ wait_helper.promise.value!
115
+
116
+ nil
117
+ end
118
+
56
119
  def evaluate(pageFunction, arg: nil)
57
120
  if JavaScript.function?(pageFunction)
58
121
  JavaScript::Function.new(pageFunction, arg).evaluate(@channel)
@@ -69,6 +132,33 @@ module Playwright
69
132
  end
70
133
  end
71
134
 
135
+ def query_selector(selector)
136
+ resp = @channel.send_message_to_server('querySelector', selector: selector)
137
+ ChannelOwners::ElementHandle.from_nullable(resp)
138
+ end
139
+
140
+ def query_selector_all(selector)
141
+ @channel.send_message_to_server('querySelectorAll', selector: selector).map do |el|
142
+ ChannelOwners::ElementHandle.from(el)
143
+ end
144
+ end
145
+
146
+ def eval_on_selector(selector, pageFunction, arg: nil)
147
+ if JavaScript.function?(pageFunction)
148
+ JavaScript::Function.new(pageFunction, arg).eval_on_selector(@channel, selector)
149
+ else
150
+ JavaScript::Expression.new(pageFunction).eval_on_selector(@channel, selector)
151
+ end
152
+ end
153
+
154
+ def eval_on_selector_all(selector, pageFunction, arg: nil)
155
+ if JavaScript.function?(pageFunction)
156
+ JavaScript::Function.new(pageFunction, arg).eval_on_selector_all(@channel, selector)
157
+ else
158
+ JavaScript::Expression.new(pageFunction).eval_on_selector_all(@channel, selector)
159
+ end
160
+ end
161
+
72
162
  def content
73
163
  @channel.send_message_to_server('content')
74
164
  end
@@ -85,6 +175,33 @@ module Playwright
85
175
  nil
86
176
  end
87
177
 
178
+ def click(
179
+ selector,
180
+ button: nil,
181
+ clickCount: nil,
182
+ delay: nil,
183
+ force: nil,
184
+ modifiers: nil,
185
+ noWaitAfter: nil,
186
+ position: nil,
187
+ timeout: nil)
188
+
189
+ params = {
190
+ selector: selector,
191
+ button: button,
192
+ clickCount: clickCount,
193
+ delay: delay,
194
+ force: force,
195
+ modifiers: modifiers,
196
+ noWaitAfter: noWaitAfter,
197
+ position: position,
198
+ timeout: timeout,
199
+ }.compact
200
+ @channel.send_message_to_server('click', params)
201
+
202
+ nil
203
+ end
204
+
88
205
  def focus(selector, timeout: nil)
89
206
  params = { selector: selector, timeout: timeout }.compact
90
207
  @channel.send_message_to_server('focus', params)
@@ -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 = Keyboard.new(@channel)
14
- @mouse = Mouse.new(@channel)
15
- @touchscreen = Touchscreen.new(@channel)
13
+ @keyboard = InputTypes::Keyboard.new(@channel)
14
+ @mouse = InputTypes::Mouse.new(@channel)
15
+ @touchscreen = InputTypes::Touchscreen.new(@channel)
16
16
 
17
17
  @viewport_size = @initializer['viewportSize']
18
18
  @closed = false
@@ -103,6 +103,14 @@ module Playwright
103
103
  @frames.to_a
104
104
  end
105
105
 
106
+ def query_selector(selector)
107
+ @main_frame.query_selector(selector)
108
+ end
109
+
110
+ def query_selector_all(selector)
111
+ @main_frame.query_selector_all(selector)
112
+ end
113
+
106
114
  def evaluate(pageFunction, arg: nil)
107
115
  @main_frame.evaluate(pageFunction, arg: arg)
108
116
  end
@@ -111,6 +119,14 @@ module Playwright
111
119
  @main_frame.evaluate_handle(pageFunction, arg: arg)
112
120
  end
113
121
 
122
+ def eval_on_selector(selector, pageFunction, arg: nil)
123
+ @main_frame.eval_on_selector(selector, pageFunction, arg: arg)
124
+ end
125
+
126
+ def eval_on_selector_all(selector, pageFunction, arg: nil)
127
+ @main_frame.eval_on_selector_all(selector, pageFunction, arg: arg)
128
+ end
129
+
114
130
  def url
115
131
  @main_frame.url
116
132
  end
@@ -177,6 +193,30 @@ module Playwright
177
193
  @closed
178
194
  end
179
195
 
196
+ def click(
197
+ selector,
198
+ button: nil,
199
+ clickCount: nil,
200
+ delay: nil,
201
+ force: nil,
202
+ modifiers: nil,
203
+ noWaitAfter: nil,
204
+ position: nil,
205
+ timeout: nil)
206
+
207
+ @main_frame.click(
208
+ selector,
209
+ button: button,
210
+ clickCount: clickCount,
211
+ delay: delay,
212
+ force: force,
213
+ modifiers: modifiers,
214
+ noWaitAfter: noWaitAfter,
215
+ position: position,
216
+ timeout: timeout,
217
+ )
218
+ end
219
+
180
220
  def focus(selector, timeout: nil)
181
221
  @main_frame.focus(selector, timeout: timeout)
182
222
  end
@@ -213,6 +253,12 @@ module Playwright
213
253
  end
214
254
  end
215
255
 
256
+ class FrameAlreadyDetachedError < StandardError
257
+ def initialize
258
+ super('Navigating frame was detached!')
259
+ end
260
+ end
261
+
216
262
  def wait_for_event(event, optionsOrPredicate: nil, &block)
217
263
  predicate, timeout =
218
264
  case optionsOrPredicate
@@ -243,13 +289,20 @@ module Playwright
243
289
  wait_helper.promise.value!
244
290
  end
245
291
 
292
+ def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
293
+ @main_frame.wait_for_navigation(
294
+ timeout: timeout,
295
+ url: url,
296
+ waitUntil: waitUntil,
297
+ &block)
298
+ end
299
+
246
300
  def wait_for_request(urlOrPredicate, timeout: nil)
247
301
  predicate =
248
302
  case urlOrPredicate
249
- when String
250
- -> (req){ req.url == urlOrPredicate }
251
- when Regexp
252
- -> (req){ urlOrPredicate.match?(req.url) }
303
+ when String, Regexp
304
+ url_matcher = UrlMatcher.new(urlOrPredicate)
305
+ -> (req){ url_matcher.match?(req.url) }
253
306
  when Proc
254
307
  urlOrPredicate
255
308
  else
@@ -262,10 +315,9 @@ module Playwright
262
315
  def wait_for_response(urlOrPredicate, timeout: nil)
263
316
  predicate =
264
317
  case urlOrPredicate
265
- when String
266
- -> (res){ res.url == urlOrPredicate }
267
- when Regexp
268
- -> (res){ urlOrPredicate.match?(res.url) }
318
+ when String, Regexp
319
+ url_matcher = UrlMatcher.new(urlOrPredicate)
320
+ -> (req){ url_matcher.match?(req.url) }
269
321
  when Proc
270
322
  urlOrPredicate
271
323
  else
@@ -280,5 +332,10 @@ module Playwright
280
332
  @browser_context = context
281
333
  @timeout_settings = TimeoutSettings.new(context.send(:_timeout_settings))
282
334
  end
335
+
336
+ # called from Frame with send(:timeout_settings)
337
+ private def timeout_settings
338
+ @timeout_settings
339
+ end
283
340
  end
284
341
  end
@@ -1,5 +1,95 @@
1
+ require 'base64'
2
+
1
3
  module Playwright
2
4
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
3
5
  define_channel_owner :Request do
6
+ def after_initialize
7
+ @redirected_from = ChannelOwners::Request.from_nullable(@initializer['redirectedFrom'])
8
+ @redirected_from&.send(:update_redirected_to, self)
9
+ @timing = {
10
+ startTime: 0,
11
+ domainLookupStart: -1,
12
+ domainLookupEnd: -1,
13
+ connectStart: -1,
14
+ secureConnectionStart: -1,
15
+ connectEnd: -1,
16
+ requestStart: -1,
17
+ responseStart: -1,
18
+ responseEnd: -1,
19
+ }
20
+ @headers = parse_headers(@initializer['headers'])
21
+ end
22
+
23
+ def url
24
+ @initializer['url']
25
+ end
26
+
27
+ def resource_type
28
+ @initializer['resourceType']
29
+ end
30
+
31
+ def method
32
+ @initialize['method']
33
+ end
34
+
35
+ def post_data
36
+ post_data_buffer
37
+ end
38
+
39
+ def post_data_json
40
+ data = post_data
41
+ return unless data
42
+
43
+ content_type = @headers['content-type']
44
+ return unless content_type
45
+
46
+ if content_type == "application/x-www-form-urlencoded"
47
+ URI.decode_www_form(data).to_h
48
+ else
49
+ JSON.parse(data)
50
+ end
51
+ end
52
+
53
+ def post_data_buffer
54
+ base64_content = @initializer['postData']
55
+ if base64_content
56
+ Base64.strict_decode64(base64_content)
57
+ else
58
+ nil
59
+ end
60
+ end
61
+
62
+ def headers
63
+ @headers
64
+ end
65
+
66
+ def response
67
+ resp = @channel.send_message_to_server('response')
68
+ ChannelOwners::Response.from_nullable(resp)
69
+ end
70
+
71
+ def frame
72
+ @initializer['frame']
73
+ end
74
+
75
+ def navigation_request?
76
+ @initializer['isNavigationRequest']
77
+ end
78
+
79
+ def failure
80
+ @failure_text
81
+ end
82
+
83
+ attr_reader :headers, :redirected_from, :redirected_to, :timing
84
+
85
+ private def update_redirected_to(request)
86
+ @redirected_to = request
87
+ end
88
+
89
+ private def parse_headers(headers)
90
+ headers.map do |header|
91
+ [header['name'].downcase, header['value']]
92
+ end.to_h
93
+ end
4
94
  end
5
95
  end