puppeteer-ruby 0.0.25 → 0.30.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.
@@ -314,33 +314,23 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
314
314
  end
315
315
  end
316
316
 
317
- # `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
317
+ private def query_handler_manager
318
+ Puppeteer::QueryHandlerManager.instance
319
+ end
320
+
321
+ # `$()` in JavaScript.
318
322
  # @param selector [String]
319
- def S(selector)
320
- handle = evaluate_handle(
321
- '(element, selector) => element.querySelector(selector)',
322
- selector,
323
- )
324
- element = handle.as_element
325
-
326
- if element
327
- return element
328
- end
329
- handle.dispose
330
- nil
323
+ def query_selector(selector)
324
+ query_handler_manager.detect_query_handler(selector).query_one(self)
331
325
  end
326
+ alias_method :S, :query_selector
332
327
 
333
- # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
328
+ # `$$()` in JavaScript.
334
329
  # @param selector [String]
335
- def SS(selector)
336
- handles = evaluate_handle(
337
- '(element, selector) => element.querySelectorAll(selector)',
338
- selector,
339
- )
340
- properties = handles.properties
341
- handles.dispose
342
- properties.values.map(&:as_element).compact
330
+ def query_selector_all(selector)
331
+ query_handler_manager.detect_query_handler(selector).query_all(self)
343
332
  end
333
+ alias_method :SS, :query_selector_all
344
334
 
345
335
  class ElementNotFoundError < StandardError
346
336
  def initialize(selector)
@@ -348,12 +338,12 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
348
338
  end
349
339
  end
350
340
 
351
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
341
+ # `$eval()` in JavaScript.
352
342
  # @param selector [String]
353
343
  # @param page_function [String]
354
344
  # @return [Object]
355
- def Seval(selector, page_function, *args)
356
- element_handle = S(selector)
345
+ def eval_on_selector(selector, page_function, *args)
346
+ element_handle = query_selector(selector)
357
347
  unless element_handle
358
348
  raise ElementNotFoundError.new(selector)
359
349
  end
@@ -362,25 +352,24 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
362
352
 
363
353
  result
364
354
  end
355
+ alias_method :Seval, :eval_on_selector
365
356
 
366
- define_async_method :async_Seval
357
+ define_async_method :async_eval_on_selector
367
358
 
368
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
359
+ # `$$eval()` in JavaScript.
369
360
  # @param selector [String]
370
361
  # @param page_function [String]
371
362
  # @return [Object]
372
- def SSeval(selector, page_function, *args)
373
- handles = evaluate_handle(
374
- '(element, selector) => Array.from(element.querySelectorAll(selector))',
375
- selector,
376
- )
363
+ def eval_on_selector_all(selector, page_function, *args)
364
+ handles = query_handler_manager.detect_query_handler(selector).query_all_array(self)
377
365
  result = handles.evaluate(page_function, *args)
378
366
  handles.dispose
379
367
 
380
368
  result
381
369
  end
370
+ alias_method :SSeval, :eval_on_selector_all
382
371
 
383
- define_async_method :async_SSeval
372
+ define_async_method :async_eval_on_selector_all
384
373
 
385
374
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
386
375
  # @param expression [String]
@@ -430,4 +419,10 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
430
419
  # https://en.wikipedia.org/wiki/Polygon#Simple_polygons
431
420
  quad.zip(quad.rotate).map { |p1, p2| (p1.x * p2.y - p2.x * p1.y) / 2 }.reduce(:+).abs
432
421
  end
422
+
423
+ # used in AriaQueryHandler
424
+ def query_ax_tree(accessible_name: nil, role: nil)
425
+ @remote_object.query_ax_tree(@client,
426
+ accessible_name: accessible_name, role: role)
427
+ end
433
428
  end
@@ -12,10 +12,21 @@ class Puppeteer::ExecutionContext
12
12
  @client = client
13
13
  @world = world
14
14
  @context_id = context_payload['id']
15
+ @context_name = context_payload['name']
15
16
  end
16
17
 
17
18
  attr_reader :client, :world
18
19
 
20
+ # only used in DOMWorld
21
+ private def _context_id
22
+ @context_id
23
+ end
24
+
25
+ # only used in DOMWorld::BindingFunction#add_binding_to_context
26
+ private def _context_name
27
+ @context_name
28
+ end
29
+
19
30
  # @return [Puppeteer::Frame]
20
31
  def frame
21
32
  if_present(@world) do |world|
@@ -223,6 +234,7 @@ class Puppeteer::ExecutionContext
223
234
  remote_object: Puppeteer::RemoteObject.new(response["object"]),
224
235
  )
225
236
  end
237
+ private define_async_method :async_adopt_backend_node_id
226
238
 
227
239
  # @param element_handle [Puppeteer::ElementHandle]
228
240
  # @return [Puppeteer::ElementHandle]
@@ -61,14 +61,15 @@ class Puppeteer::Frame
61
61
 
62
62
  define_async_method :async_evaluate
63
63
 
64
- # `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
64
+ # `$()` in JavaScript.
65
65
  # @param {string} selector
66
66
  # @return {!Promise<?Puppeteer.ElementHandle>}
67
- def S(selector)
68
- @main_world.S(selector)
67
+ def query_selector(selector)
68
+ @main_world.query_selector(selector)
69
69
  end
70
+ alias_method :S, :query_selector
70
71
 
71
- define_async_method :async_S
72
+ define_async_method :async_query_selector
72
73
 
73
74
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
74
75
  # @param {string} expression
@@ -79,36 +80,39 @@ class Puppeteer::Frame
79
80
 
80
81
  define_async_method :async_Sx
81
82
 
82
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
83
+ # `$eval()` in JavaScript.
83
84
  # @param {string} selector
84
85
  # @param {Function|string} pageFunction
85
86
  # @param {!Array<*>} args
86
87
  # @return {!Promise<(!Object|undefined)>}
87
- def Seval(selector, page_function, *args)
88
- @main_world.Seval(selector, page_function, *args)
88
+ def eval_on_selector(selector, page_function, *args)
89
+ @main_world.eval_on_selector(selector, page_function, *args)
89
90
  end
91
+ alias_method :Seval, :eval_on_selector
90
92
 
91
- define_async_method :async_Seval
93
+ define_async_method :async_eval_on_selector
92
94
 
93
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
95
+ # `$$eval()` in JavaScript.
94
96
  # @param {string} selector
95
97
  # @param {Function|string} pageFunction
96
98
  # @param {!Array<*>} args
97
99
  # @return {!Promise<(!Object|undefined)>}
98
- def SSeval(selector, page_function, *args)
99
- @main_world.SSeval(selector, page_function, *args)
100
+ def eval_on_selector_all(selector, page_function, *args)
101
+ @main_world.eval_on_selector_all(selector, page_function, *args)
100
102
  end
103
+ alias_method :SSeval, :eval_on_selector_all
101
104
 
102
- define_async_method :async_SSeval
105
+ define_async_method :async_eval_on_selector_all
103
106
 
104
- # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
107
+ # `$$()` in JavaScript.
105
108
  # @param {string} selector
106
109
  # @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
107
- def SS(selector)
108
- @main_world.SS(selector)
110
+ def query_selector_all(selector)
111
+ @main_world.query_selector_all(selector)
109
112
  end
113
+ alias_method :SS, :query_selector_all
110
114
 
111
- define_async_method :async_SS
115
+ define_async_method :async_query_selector_all
112
116
 
113
117
  # @return [String]
114
118
  def content
@@ -92,7 +92,7 @@ module Puppeteer::Launcher
92
92
  '--disable-default-apps',
93
93
  '--disable-dev-shm-usage',
94
94
  '--disable-extensions',
95
- '--disable-features=TranslateUI',
95
+ '--disable-features=Translate',
96
96
  '--disable-hang-monitor',
97
97
  '--disable-ipc-flooding-protection',
98
98
  '--disable-popup-blocking',
@@ -105,6 +105,9 @@ module Puppeteer::Launcher
105
105
  '--enable-automation',
106
106
  '--password-store=basic',
107
107
  '--use-mock-keychain',
108
+ # TODO(sadym): remove '--enable-blink-features=IdleDetection'
109
+ # once IdleDetection is turned on by default.
110
+ '--enable-blink-features=IdleDetection',
108
111
  ]
109
112
 
110
113
  if chrome_arg_options.user_data_dir
@@ -3,6 +3,7 @@ require "stringio"
3
3
 
4
4
  require_relative './page/pdf_options'
5
5
  require_relative './page/screenshot_options'
6
+ require_relative './page/screenshot_task_queue'
6
7
 
7
8
  class Puppeteer::Page
8
9
  include Puppeteer::EventCallbackable
@@ -13,10 +14,9 @@ class Puppeteer::Page
13
14
  # @param {!Puppeteer.Target} target
14
15
  # @param {boolean} ignoreHTTPSErrors
15
16
  # @param {?Puppeteer.Viewport} defaultViewport
16
- # @param {!Puppeteer.TaskQueue} screenshotTaskQueue
17
17
  # @return {!Promise<!Page>}
18
- def self.create(client, target, ignore_https_errors, default_viewport, screenshot_task_queue)
19
- page = Puppeteer::Page.new(client, target, ignore_https_errors, screenshot_task_queue)
18
+ def self.create(client, target, ignore_https_errors, default_viewport)
19
+ page = Puppeteer::Page.new(client, target, ignore_https_errors)
20
20
  page.init
21
21
  if default_viewport
22
22
  page.viewport = default_viewport
@@ -27,8 +27,7 @@ class Puppeteer::Page
27
27
  # @param {!Puppeteer.CDPSession} client
28
28
  # @param {!Puppeteer.Target} target
29
29
  # @param {boolean} ignoreHTTPSErrors
30
- # @param {!Puppeteer.TaskQueue} screenshotTaskQueue
31
- def initialize(client, target, ignore_https_errors, screenshot_task_queue)
30
+ def initialize(client, target, ignore_https_errors)
32
31
  @closed = false
33
32
  @client = client
34
33
  @target = target
@@ -43,7 +42,7 @@ class Puppeteer::Page
43
42
  @page_bindings = {}
44
43
  # @coverage = Coverage.new(client)
45
44
  @javascript_enabled = true
46
- @screenshot_task_queue = screenshot_task_queue
45
+ @screenshot_task_queue = ScreenshotTaskQueue.new
47
46
 
48
47
  @workers = {}
49
48
  @client.on_event('Target.attachedToTarget') do |event|
@@ -277,23 +276,25 @@ class Puppeteer::Page
277
276
  @timeout_settings.default_timeout = timeout
278
277
  end
279
278
 
280
- # `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
279
+ # `$()` in JavaScript.
281
280
  # @param {string} selector
282
281
  # @return {!Promise<?Puppeteer.ElementHandle>}
283
- def S(selector)
284
- main_frame.S(selector)
282
+ def query_selector(selector)
283
+ main_frame.query_selector(selector)
285
284
  end
285
+ alias_method :S, :query_selector
286
286
 
287
- define_async_method :async_S
287
+ define_async_method :async_query_selector
288
288
 
289
- # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
289
+ # `$$()` in JavaScript.
290
290
  # @param {string} selector
291
291
  # @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
292
- def SS(selector)
293
- main_frame.SS(selector)
292
+ def query_selector_all(selector)
293
+ main_frame.query_selector_all(selector)
294
294
  end
295
+ alias_method :SS, :query_selector_all
295
296
 
296
- define_async_method :async_SS
297
+ define_async_method :async_query_selector_all
297
298
 
298
299
  # @param {Function|string} pageFunction
299
300
  # @param {!Array<*>} args
@@ -312,25 +313,27 @@ class Puppeteer::Page
312
313
  context.query_objects(prototype_handle)
313
314
  end
314
315
 
315
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
316
+ # `$eval()` in JavaScript.
316
317
  # @param selector [String]
317
318
  # @param page_function [String]
318
319
  # @return [Object]
319
- def Seval(selector, page_function, *args)
320
- main_frame.Seval(selector, page_function, *args)
320
+ def eval_on_selector(selector, page_function, *args)
321
+ main_frame.eval_on_selector(selector, page_function, *args)
321
322
  end
323
+ alias_method :Seval, :eval_on_selector
322
324
 
323
- define_async_method :async_Seval
325
+ define_async_method :async_eval_on_selector
324
326
 
325
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
327
+ # `$$eval()` in JavaScript.
326
328
  # @param selector [String]
327
329
  # @param page_function [String]
328
330
  # @return [Object]
329
- def SSeval(selector, page_function, *args)
330
- main_frame.SSeval(selector, page_function, *args)
331
+ def eval_on_selector_all(selector, page_function, *args)
332
+ main_frame.eval_on_selector_all(selector, page_function, *args)
331
333
  end
334
+ alias_method :SSeval, :eval_on_selector_all
332
335
 
333
- define_async_method :async_SSeval
336
+ define_async_method :async_eval_on_selector_all
334
337
 
335
338
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
336
339
  # @param {string} expression
@@ -830,6 +833,21 @@ class Puppeteer::Page
830
833
  end
831
834
  end
832
835
 
836
+ # @param is_user_active [Boolean]
837
+ # @param is_screen_unlocked [Boolean]
838
+ def emulate_idle_state(is_user_active: nil, is_screen_unlocked: nil)
839
+ overrides = {
840
+ isUserActive: is_user_active,
841
+ isScreenUnlocked: is_screen_unlocked,
842
+ }.compact
843
+
844
+ if overrides.empty?
845
+ @client.send_message('Emulation.clearIdleOverride')
846
+ else
847
+ @client.send_message('Emulation.setIdleOverride', overrides)
848
+ end
849
+ end
850
+
833
851
  # @param viewport [Viewport]
834
852
  def viewport=(viewport)
835
853
  needs_reload = @emulation_manager.emulate_viewport(viewport)
@@ -867,15 +885,28 @@ class Puppeteer::Page
867
885
  main_frame.title
868
886
  end
869
887
 
870
- # /**
871
- # * @param {!ScreenshotOptions=} options
872
- # * @return {!Promise<!Buffer|!String>}
873
- # */
874
- def screenshot(options = {})
888
+ # @param type [String] "png"|"jpeg"
889
+ # @param path [String]
890
+ # @param full_page [Boolean]
891
+ # @param clip [Hash]
892
+ # @param quality [Integer]
893
+ # @param omit_background [Boolean]
894
+ # @param encoding [String]
895
+ def screenshot(type: nil, path: nil, full_page: nil, clip: nil, quality: nil, omit_background: nil, encoding: nil)
896
+ options = {
897
+ type: type,
898
+ path: path,
899
+ full_page: full_page,
900
+ clip: clip,
901
+ quality: quality,
902
+ omit_background: omit_background,
903
+ encoding: encoding,
904
+ }.compact
875
905
  screenshot_options = ScreenshotOptions.new(options)
876
906
 
877
- # @screenshot_task_queue.post_task(-> { screenshot_task(screenshot_options.type, screenshot_options) })
878
- screenshot_task(screenshot_options.type, screenshot_options)
907
+ @screenshot_task_queue.post_task do
908
+ screenshot_task(screenshot_options.type, screenshot_options)
909
+ end
879
910
  end
880
911
 
881
912
  # @param {"png"|"jpeg"} format
@@ -32,14 +32,14 @@ class Puppeteer::Page
32
32
  @type ||= 'png'
33
33
 
34
34
  if options[:quality]
35
- unless @type == 'png'
35
+ unless @type == 'jpeg'
36
36
  raise ArgumentError.new("options.quality is unsupported for the #{@type} screenshots")
37
37
  end
38
38
  unless options[:quality].is_a?(Numeric)
39
39
  raise ArgumentError.new("Expected options.quality to be a number but found #{options[:quality].class}")
40
40
  end
41
41
  quality = options[:quality].to_i
42
- unless (0..100).include?(qualizy)
42
+ unless (0..100).include?(quality)
43
43
  raise ArgumentError.new("Expected options.quality to be between 0 and 100 (inclusive), got #{quality}")
44
44
  end
45
45
  @quality = quality
@@ -0,0 +1,13 @@
1
+ class Puppeteer::Page
2
+ class ScreenshotTaskQueue
3
+ def initialize
4
+ @chain = Concurrent::Promises.fulfilled_future(nil)
5
+ end
6
+
7
+ def post_task(&block)
8
+ result = @chain.then { block.call }
9
+ @chain = result.rescue { nil }
10
+ result.value!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ require 'singleton'
2
+
3
+ class Puppeteer::QueryHandlerManager
4
+ include Singleton
5
+
6
+ def query_handlers
7
+ @query_handlers ||= {
8
+ aria: Puppeteer::AriaQueryHandler.new,
9
+ }
10
+ end
11
+
12
+ private def default_handler
13
+ @default_handler ||= Puppeteer::CustomQueryHandler.new(
14
+ query_one: '(element, selector) => element.querySelector(selector)',
15
+ query_all: '(element, selector) => element.querySelectorAll(selector)',
16
+ )
17
+ end
18
+
19
+ class Result
20
+ def initialize(query_handler:, selector:)
21
+ @query_handler = query_handler
22
+ @selector = selector
23
+ end
24
+
25
+ def query_one(element_handle)
26
+ @query_handler.query_one(element_handle, @selector)
27
+ end
28
+
29
+ def wait_for(dom_world, visible:, hidden:, timeout:)
30
+ @query_handler.wait_for(dom_world, @selector, visible: visible, hidden: hidden, timeout: timeout)
31
+ end
32
+
33
+ def query_all(element_handle)
34
+ @query_handler.query_all(element_handle, @selector)
35
+ end
36
+
37
+ def query_all_array(element_handle)
38
+ @query_handler.query_all_array(element_handle, @selector)
39
+ end
40
+ end
41
+
42
+ def detect_query_handler(selector)
43
+ unless /^[a-zA-Z]+\// =~ selector
44
+ return Result.new(
45
+ query_handler: default_handler,
46
+ selector: selector,
47
+ )
48
+ end
49
+
50
+ chunk = selector.split("/")
51
+ name = chunk.shift
52
+ updated_selector = chunk.join("/")
53
+
54
+ query_handler = query_handlers[name.to_sym]
55
+
56
+ unless query_handler
57
+ raise ArgumentError.new("Query set to use \"#{name}\", but no query handler of that name was found")
58
+ end
59
+
60
+ Result.new(
61
+ query_handler: query_handler,
62
+ selector: updated_selector,
63
+ )
64
+ end
65
+ end