puppeteer-ruby 0.29.0 → 0.31.4

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