puppeteer-ruby 0.29.0 → 0.31.4

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.
@@ -318,17 +318,19 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
318
318
  Puppeteer::QueryHandlerManager.instance
319
319
  end
320
320
 
321
- # `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
321
+ # `$()` in JavaScript.
322
322
  # @param selector [String]
323
- def S(selector)
323
+ def query_selector(selector)
324
324
  query_handler_manager.detect_query_handler(selector).query_one(self)
325
325
  end
326
+ alias_method :S, :query_selector
326
327
 
327
- # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
328
+ # `$$()` in JavaScript.
328
329
  # @param selector [String]
329
- def SS(selector)
330
+ def query_selector_all(selector)
330
331
  query_handler_manager.detect_query_handler(selector).query_all(self)
331
332
  end
333
+ alias_method :SS, :query_selector_all
332
334
 
333
335
  class ElementNotFoundError < StandardError
334
336
  def initialize(selector)
@@ -336,12 +338,12 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
336
338
  end
337
339
  end
338
340
 
339
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
341
+ # `$eval()` in JavaScript.
340
342
  # @param selector [String]
341
343
  # @param page_function [String]
342
344
  # @return [Object]
343
- def Seval(selector, page_function, *args)
344
- element_handle = S(selector)
345
+ def eval_on_selector(selector, page_function, *args)
346
+ element_handle = query_selector(selector)
345
347
  unless element_handle
346
348
  raise ElementNotFoundError.new(selector)
347
349
  end
@@ -350,22 +352,24 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
350
352
 
351
353
  result
352
354
  end
355
+ alias_method :Seval, :eval_on_selector
353
356
 
354
- define_async_method :async_Seval
357
+ define_async_method :async_eval_on_selector
355
358
 
356
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
359
+ # `$$eval()` in JavaScript.
357
360
  # @param selector [String]
358
361
  # @param page_function [String]
359
362
  # @return [Object]
360
- def SSeval(selector, page_function, *args)
363
+ def eval_on_selector_all(selector, page_function, *args)
361
364
  handles = query_handler_manager.detect_query_handler(selector).query_all_array(self)
362
365
  result = handles.evaluate(page_function, *args)
363
366
  handles.dispose
364
367
 
365
368
  result
366
369
  end
370
+ alias_method :SSeval, :eval_on_selector_all
367
371
 
368
- define_async_method :async_SSeval
372
+ define_async_method :async_eval_on_selector_all
369
373
 
370
374
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
371
375
  # @param expression [String]
data/lib/puppeteer/env.rb CHANGED
@@ -14,10 +14,14 @@ class Puppeteer::Env
14
14
  def darwin?
15
15
  RUBY_PLATFORM.include?('darwin')
16
16
  end
17
+
18
+ def windows?
19
+ RUBY_PLATFORM =~ /mswin|mingw|cygwin/
20
+ end
17
21
  end
18
22
 
19
- class Puppeteer
20
- def self.env
21
- Puppeteer::Env.new
23
+ module Puppeteer
24
+ module_function def env
25
+ ::Puppeteer::Env.new
22
26
  end
23
27
  end
@@ -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
@@ -149,16 +153,19 @@ class Puppeteer::Frame
149
153
  @detached
150
154
  end
151
155
 
152
- # @param style_tag [Puppeteer::Page::ScriptTag]
153
- # @return {!Promise<!ElementHandle>}
154
- def add_script_tag(script_tag)
155
- @main_world.add_script_tag(script_tag)
156
+ # @param url [String?]
157
+ # @param path [String?]
158
+ # @param content [String?]
159
+ # @param type [String?]
160
+ def add_script_tag(url: nil, path: nil, content: nil, type: nil)
161
+ @main_world.add_script_tag(url: url, path: path, content: content, type: type)
156
162
  end
157
163
 
158
- # @param style_tag [Puppeteer::Page::StyleTag]
159
- # @return {!Promise<!ElementHandle>}
160
- def add_style_tag(style_tag)
161
- @main_world.add_style_tag(style_tag)
164
+ # @param url [String?]
165
+ # @param path [String?]
166
+ # @param content [String?]
167
+ def add_style_tag(url: nil, path: nil, content: nil)
168
+ @main_world.add_style_tag(url: url, path: path, content: content)
162
169
  end
163
170
 
164
171
  # @param selector [String]
@@ -32,6 +32,14 @@ module Puppeteer::Launcher
32
32
  when Firefox
33
33
  '/Applications/Firefox Nightly.app/Contents/MacOS/firefox'
34
34
  end
35
+ elsif Puppeteer.env.windows?
36
+ case self
37
+ when Chrome
38
+ 'C:\Program Files\Google\Chrome\Application\chrome.exe'
39
+ # 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
40
+ when Firefox
41
+ 'C:\Program Files\Firefox Nightly\firefox.exe'
42
+ end
35
43
  else
36
44
  case self
37
45
  when Chrome
@@ -1,4 +1,5 @@
1
1
  require 'base64'
2
+ require 'json'
2
3
  require "stringio"
3
4
 
4
5
  require_relative './page/pdf_options'
@@ -98,7 +99,9 @@ class Puppeteer::Page
98
99
  @client.on_event('Page.loadEventFired') do |event|
99
100
  emit_event(PageEmittedEvents::Load)
100
101
  end
101
- # client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
102
+ @client.on('Runtime.consoleAPICalled') do |event|
103
+ handle_console_api(event)
104
+ end
102
105
  # client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
103
106
  @client.on_event('Page.javascriptDialogOpening') do |event|
104
107
  handle_dialog_opening(event)
@@ -199,6 +202,7 @@ class Puppeteer::Page
199
202
  end
200
203
 
201
204
  attr_reader :javascript_enabled, :target
205
+ alias_method :javascript_enabled?, :javascript_enabled
202
206
 
203
207
  def browser
204
208
  @target.browser
@@ -276,23 +280,25 @@ class Puppeteer::Page
276
280
  @timeout_settings.default_timeout = timeout
277
281
  end
278
282
 
279
- # `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
283
+ # `$()` in JavaScript.
280
284
  # @param {string} selector
281
285
  # @return {!Promise<?Puppeteer.ElementHandle>}
282
- def S(selector)
283
- main_frame.S(selector)
286
+ def query_selector(selector)
287
+ main_frame.query_selector(selector)
284
288
  end
289
+ alias_method :S, :query_selector
285
290
 
286
- define_async_method :async_S
291
+ define_async_method :async_query_selector
287
292
 
288
- # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
293
+ # `$$()` in JavaScript.
289
294
  # @param {string} selector
290
295
  # @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
291
- def SS(selector)
292
- main_frame.SS(selector)
296
+ def query_selector_all(selector)
297
+ main_frame.query_selector_all(selector)
293
298
  end
299
+ alias_method :SS, :query_selector_all
294
300
 
295
- define_async_method :async_SS
301
+ define_async_method :async_query_selector_all
296
302
 
297
303
  # @param {Function|string} pageFunction
298
304
  # @param {!Array<*>} args
@@ -311,25 +317,27 @@ class Puppeteer::Page
311
317
  context.query_objects(prototype_handle)
312
318
  end
313
319
 
314
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
320
+ # `$eval()` in JavaScript.
315
321
  # @param selector [String]
316
322
  # @param page_function [String]
317
323
  # @return [Object]
318
- def Seval(selector, page_function, *args)
319
- main_frame.Seval(selector, page_function, *args)
324
+ def eval_on_selector(selector, page_function, *args)
325
+ main_frame.eval_on_selector(selector, page_function, *args)
320
326
  end
327
+ alias_method :Seval, :eval_on_selector
321
328
 
322
- define_async_method :async_Seval
329
+ define_async_method :async_eval_on_selector
323
330
 
324
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
331
+ # `$$eval()` in JavaScript.
325
332
  # @param selector [String]
326
333
  # @param page_function [String]
327
334
  # @return [Object]
328
- def SSeval(selector, page_function, *args)
329
- main_frame.SSeval(selector, page_function, *args)
335
+ def eval_on_selector_all(selector, page_function, *args)
336
+ main_frame.eval_on_selector_all(selector, page_function, *args)
330
337
  end
338
+ alias_method :SSeval, :eval_on_selector_all
331
339
 
332
- define_async_method :async_SSeval
340
+ define_async_method :async_eval_on_selector_all
333
341
 
334
342
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
335
343
  # @param {string} expression
@@ -369,37 +377,19 @@ class Puppeteer::Page
369
377
  end
370
378
  end
371
379
 
372
- class ScriptTag
373
- # @param {!{content?: string, path?: string, type?: string, url?: string}} options
374
- def initialize(content: nil, path: nil, type: nil, url: nil)
375
- @content = content
376
- @path = path
377
- @type = type
378
- @url = url
379
- end
380
- attr_reader :content, :path, :type, :url
381
- end
382
-
383
- # @param style_tag [Puppeteer::Page::ScriptTag]
384
- # @return {!Promise<!ElementHandle>}
385
- def add_script_tag(script_tag)
386
- main_frame.add_script_tag(script_tag)
387
- end
388
-
389
- class StyleTag
390
- # @param {!{content?: string, path?: string, url?: string}} options
391
- def initialize(content: nil, path: nil, url: nil)
392
- @content = content
393
- @path = path
394
- @url = url
395
- end
396
- attr_reader :content, :path, :url
380
+ # @param url [String?]
381
+ # @param path [String?]
382
+ # @param content [String?]
383
+ # @param type [String?]
384
+ def add_script_tag(url: nil, path: nil, content: nil, type: nil)
385
+ main_frame.add_script_tag(url: url, path: path, content: content, type: type)
397
386
  end
398
387
 
399
- # @param style_tag [Puppeteer::Page::StyleTag]
400
- # @return {!Promise<!ElementHandle>}
401
- def add_style_tag(style_tag)
402
- main_frame.add_style_tag(style_tag)
388
+ # @param url [String?]
389
+ # @param path [String?]
390
+ # @param content [String?]
391
+ def add_style_tag(url: nil, path: nil, content: nil)
392
+ main_frame.add_style_tag(url: url, path: path, content: content)
403
393
  end
404
394
 
405
395
  # /**
@@ -490,30 +480,31 @@ class Puppeteer::Page
490
480
  emit_event(PageEmittedEvents::PageError, err)
491
481
  end
492
482
 
493
- # /**
494
- # * @param {!Protocol.Runtime.consoleAPICalledPayload} event
495
- # */
496
- # async _onConsoleAPI(event) {
497
- # if (event.executionContextId === 0) {
498
- # // DevTools protocol stores the last 1000 console messages. These
499
- # // messages are always reported even for removed execution contexts. In
500
- # // this case, they are marked with executionContextId = 0 and are
501
- # // reported upon enabling Runtime agent.
502
- # //
503
- # // Ignore these messages since:
504
- # // - there's no execution context we can use to operate with message
505
- # // arguments
506
- # // - these messages are reported before Puppeteer clients can subscribe
507
- # // to the 'console'
508
- # // page event.
509
- # //
510
- # // @see https://github.com/puppeteer/puppeteer/issues/3865
511
- # return;
512
- # }
513
- # const context = this._frameManager.executionContextById(event.executionContextId);
514
- # const values = event.args.map(arg => createJSHandle(context, arg));
515
- # this._addConsoleMessage(event.type, values, event.stackTrace);
516
- # }
483
+ private def handle_console_api(event)
484
+ if event['executionContextId'] == 0
485
+ # DevTools protocol stores the last 1000 console messages. These
486
+ # messages are always reported even for removed execution contexts. In
487
+ # this case, they are marked with executionContextId = 0 and are
488
+ # reported upon enabling Runtime agent.
489
+ #
490
+ # Ignore these messages since:
491
+ # - there's no execution context we can use to operate with message
492
+ # arguments
493
+ # - these messages are reported before Puppeteer clients can subscribe
494
+ # to the 'console'
495
+ # page event.
496
+ #
497
+ # @see https://github.com/puppeteer/puppeteer/issues/3865
498
+ return
499
+ end
500
+
501
+ context = @frame_manager.execution_context_by_id(event['executionContextId'])
502
+ values = event['args'].map do |arg|
503
+ remote_object = Puppeteer::RemoteObject.new(arg)
504
+ Puppeteer::JSHandle.create(context: context, remote_object: remote_object)
505
+ end
506
+ add_console_message(event['type'], values, event['stackTrace'])
507
+ end
517
508
 
518
509
  # /**
519
510
  # * @param {!Protocol.Runtime.bindingCalledPayload} event
@@ -566,32 +557,23 @@ class Puppeteer::Page
566
557
  # }
567
558
  # }
568
559
 
569
- # /**
570
- # * @param {string} type
571
- # * @param {!Array<!Puppeteer.JSHandle>} args
572
- # * @param {Protocol.Runtime.StackTrace=} stackTrace
573
- # */
574
- # _addConsoleMessage(type, args, stackTrace) {
575
- # if (!this.listenerCount(PageEmittedEvents::Console)) {
576
- # args.forEach(arg => arg.dispose());
577
- # return;
578
- # }
579
- # const textTokens = [];
580
- # for (const arg of args) {
581
- # const remoteObject = arg._remoteObject;
582
- # if (remoteObject.objectId)
583
- # textTokens.push(arg.toString());
584
- # else
585
- # textTokens.push(helper.valueFromRemoteObject(remoteObject));
586
- # }
587
- # const location = stackTrace && stackTrace.callFrames.length ? {
588
- # url: stackTrace.callFrames[0].url,
589
- # lineNumber: stackTrace.callFrames[0].lineNumber,
590
- # columnNumber: stackTrace.callFrames[0].columnNumber,
591
- # } : {};
592
- # const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
593
- # this.emit(PageEmittedEvents::Console, message);
594
- # }
560
+ private def add_console_message(type, args, stack_trace)
561
+ text_tokens = args.map { |arg| arg.remote_object.value }
562
+
563
+ call_frame = stack_trace['callFrames']&.first
564
+ location =
565
+ if call_frame
566
+ Puppeteer::ConsoleMessage::Location.new(
567
+ url: call_frame['url'],
568
+ line_number: call_frame['lineNumber'],
569
+ column_number: call_frame['columnNumber'],
570
+ )
571
+ else
572
+ nil
573
+ end
574
+ console_message = Puppeteer::ConsoleMessage.new(type, text_tokens.join(' '), args, location)
575
+ emit_event(PageEmittedEvents::Console, console_message)
576
+ end
595
577
 
596
578
  private def handle_dialog_opening(event)
597
579
  dialog_type = event['type']
@@ -605,6 +587,16 @@ class Puppeteer::Page
605
587
  emit_event(PageEmittedEvents::Dialog, dialog)
606
588
  end
607
589
 
590
+ private def set_transparent_background_color(&block)
591
+ @client.send_message(
592
+ 'Emulation.setDefaultBackgroundColorOverride',
593
+ color: { r: 0, g: 0, b: 0, a: 0 })
594
+ end
595
+
596
+ private def reset_default_background_color(&block)
597
+ @client.send_message('Emulation.setDefaultBackgroundColorOverride')
598
+ end
599
+
608
600
  # @return [String]
609
601
  def url
610
602
  main_frame.url
@@ -862,14 +854,41 @@ class Puppeteer::Page
862
854
 
863
855
  define_async_method :async_evaluate
864
856
 
865
- # /**
866
- # * @param {Function|string} pageFunction
867
- # * @param {!Array<*>} args
868
- # */
869
- # async evaluateOnNewDocument(pageFunction, ...args) {
870
- # const source = helper.evaluationString(pageFunction, ...args);
871
- # await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source });
872
- # }
857
+ class JavaScriptFunction
858
+ def initialize(expression, args)
859
+ @expression = expression
860
+ @args = args
861
+ end
862
+
863
+ def source
864
+ "(#{@expression})(#{arguments})"
865
+ end
866
+
867
+ private def arguments
868
+ @args.map { |arg| arg.nil? ? nil : JSON.dump(arg) }.join(", ")
869
+ end
870
+ end
871
+
872
+ class JavaScriptExpression
873
+ def initialize(expression)
874
+ @expression = expression
875
+ end
876
+
877
+ def source
878
+ @expression
879
+ end
880
+ end
881
+
882
+ def evaluate_on_new_document(page_function, *args)
883
+ source =
884
+ if ['=>', 'async', 'function'].any? { |keyword| page_function.include?(keyword) }
885
+ JavaScriptFunction.new(page_function, args).source
886
+ else
887
+ JavaScriptExpression.new(page_function).source
888
+ end
889
+
890
+ @client.send_message('Page.addScriptToEvaluateOnNewDocument', source: source)
891
+ end
873
892
 
874
893
  # @param {boolean} enabled
875
894
  def cache_enabled=(enabled)
@@ -940,18 +959,14 @@ class Puppeteer::Page
940
959
  end
941
960
 
942
961
  should_set_default_background = screenshot_options.omit_background? && format == 'png'
943
- if should_set_default_background
944
- @client.send_message('Emulation.setDefaultBackgroundColorOverride', color: { r: 0, g: 0, b: 0, a: 0 })
945
- end
962
+ set_transparent_background_color if should_set_default_background
946
963
  screenshot_params = {
947
964
  format: format,
948
965
  quality: screenshot_options.quality,
949
966
  clip: clip,
950
967
  }.compact
951
968
  result = @client.send_message('Page.captureScreenshot', screenshot_params)
952
- if should_set_default_background
953
- @client.send_message('Emulation.setDefaultBackgroundColorOverride')
954
- end
969
+ reset_default_background_color if should_set_default_background
955
970
 
956
971
  if screenshot_options.full_page? && @viewport
957
972
  self.viewport = @viewport
@@ -980,7 +995,7 @@ class Puppeteer::Page
980
995
 
981
996
  def read
982
997
  out = StringIO.new
983
- File.open(@path, 'w') do |file|
998
+ File.open(@path, 'wb') do |file|
984
999
  eof = false
985
1000
  until eof
986
1001
  response = @client.send_message('IO.read', handle: @handle)
@@ -1009,7 +1024,10 @@ class Puppeteer::Page
1009
1024
  # @return [String]
1010
1025
  def pdf(options = {})
1011
1026
  pdf_options = PDFOptions.new(options)
1027
+ omit_background = options[:omit_background]
1028
+ set_transparent_background_color if omit_background
1012
1029
  result = @client.send_message('Page.printToPDF', pdf_options.page_print_args)
1030
+ reset_default_background_color if omit_background
1013
1031
  ProtocolStreamReader.new(client: @client, handle: result['stream'], path: pdf_options.path).read
1014
1032
  rescue => err
1015
1033
  if err.message.include?('PrintToPDF is not implemented')