puppeteer-ruby 0.0.25 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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