puppeteer-ruby 0.31.6 → 0.32.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 507fa71a263e1db4d502af25ee13ea935decbc6beab69433c1bd51daf4f8b7d8
4
- data.tar.gz: 8538c60b117b2e86b12677ecf68f39fbdaeccac58871af2c796efe50b4499b5f
3
+ metadata.gz: 3ac3b08e88fc4d18d756dd760d8960783498e4fb84c23b02e248471de8097636
4
+ data.tar.gz: b9c14719e9b13c56eb529cc58b71648985245158b4c3edffa9a6cff4f191463a
5
5
  SHA512:
6
- metadata.gz: c644e6ac6ff1fe024cc84e5d8723bfebaf2572a257333c79285f5c9b31ea8e2994ebdabf1d66d87c09b9cfb903b0b061bad8d591e8a38bc88eac8fc8d339eafd
7
- data.tar.gz: 8893204e6caf63f74de48af650b7b29c12e1b8dea0ededdd786032a3b6a5f87471bfaf26a7f4be136811c4a08230273d8c4577bbc9c7433775ef27bad1c600a1
6
+ metadata.gz: 103c5d80b62d51bfa877884627ef9544a05cc901abaa8386f877e9eb64da58438e540a6e263dc47f176aca2709d0e4f43a2a43bc7922226cbd428b04a3f23d6d
7
+ data.tar.gz: a7adb58a5747c563c8f55041e007516a497c7721d25ec69a3ec20a0e75ce9016362aa0f1f468e4c78a6cbbece37964e71d90c7bc5b8c1b7aa0cfdd324845de27
data/CHANGELOG.md CHANGED
@@ -1,8 +1,19 @@
1
- ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.6...master)]
1
+ ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.0...master)]
2
2
 
3
3
  * xxx
4
4
 
5
- ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.5...0.31.6)]
5
+ ### 0.32.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.6...0.32.0)]
6
+
7
+ New features:
8
+
9
+ * Tracing
10
+ * JS/CSS coverages
11
+
12
+ Improvement:
13
+
14
+ * Increase stability [#92](https://github.com/YusukeIwaki/puppeteer-ruby/pull/92)
15
+
16
+ ### 0.31.6 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.5...0.31.6)]
6
17
 
7
18
  Improvement:
8
19
 
data/docs/api_coverage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API coverages
2
2
  - Puppeteer version: v8.0.0
3
- - puppeteer-ruby version: 0.31.5
3
+ - puppeteer-ruby version: 0.32.0
4
4
 
5
5
  ## Puppeteer
6
6
 
@@ -124,7 +124,7 @@
124
124
  * target
125
125
  * title
126
126
  * ~~touchscreen~~
127
- * ~~tracing~~
127
+ * tracing
128
128
  * type => `#type_text`
129
129
  * url
130
130
  * viewport
@@ -170,10 +170,10 @@
170
170
 
171
171
  * ~~tap~~
172
172
 
173
- ## ~~Tracing~~
173
+ ## Tracing
174
174
 
175
- * ~~start~~
176
- * ~~stop~~
175
+ * start
176
+ * stop
177
177
 
178
178
  ## FileChooser
179
179
 
@@ -337,12 +337,12 @@
337
337
  * detach
338
338
  * send
339
339
 
340
- ## ~~Coverage~~
340
+ ## Coverage
341
341
 
342
- * ~~startCSSCoverage~~
343
- * ~~startJSCoverage~~
344
- * ~~stopCSSCoverage~~
345
- * ~~stopJSCoverage~~
342
+ * startCSSCoverage => `#start_css_coverage`
343
+ * startJSCoverage => `#start_js_coverage`
344
+ * stopCSSCoverage => `#stop_css_coverage`
345
+ * stopJSCoverage => `#stop_js_coverage`
346
346
 
347
347
  ## TimeoutError
348
348
 
data/lib/puppeteer.rb CHANGED
@@ -26,6 +26,8 @@ require 'puppeteer/browser_runner'
26
26
  require 'puppeteer/cdp_session'
27
27
  require 'puppeteer/connection'
28
28
  require 'puppeteer/console_message'
29
+ require 'puppeteer/coverage'
30
+ require 'puppeteer/css_coverage'
29
31
  require 'puppeteer/custom_query_handler'
30
32
  require 'puppeteer/devices'
31
33
  require 'puppeteer/dialog'
@@ -36,6 +38,7 @@ require 'puppeteer/execution_context'
36
38
  require 'puppeteer/file_chooser'
37
39
  require 'puppeteer/frame'
38
40
  require 'puppeteer/frame_manager'
41
+ require 'puppeteer/js_coverage'
39
42
  require 'puppeteer/js_handle'
40
43
  require 'puppeteer/keyboard'
41
44
  require 'puppeteer/launcher'
@@ -43,12 +46,14 @@ require 'puppeteer/lifecycle_watcher'
43
46
  require 'puppeteer/mouse'
44
47
  require 'puppeteer/network_manager'
45
48
  require 'puppeteer/page'
49
+ require 'puppeteer/protocol_stream_reader'
46
50
  require 'puppeteer/puppeteer'
47
51
  require 'puppeteer/query_handler_manager'
48
52
  require 'puppeteer/remote_object'
49
53
  require 'puppeteer/request'
50
54
  require 'puppeteer/response'
51
55
  require 'puppeteer/target'
56
+ require 'puppeteer/tracing'
52
57
  require 'puppeteer/timeout_settings'
53
58
  require 'puppeteer/touch_screen'
54
59
  require 'puppeteer/version'
@@ -45,6 +45,7 @@ class Puppeteer::Browser
45
45
  @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id)
46
46
  end
47
47
  @targets = {}
48
+ @wait_for_creating_targets = {}
48
49
  @connection.on_event(ConnectionEmittedEvents::Disconnected) do
49
50
  emit_event(BrowserEmittedEvents::Disconnected)
50
51
  end
@@ -125,8 +126,10 @@ class Puppeteer::Browser
125
126
  ignore_https_errors: @ignore_https_errors,
126
127
  default_viewport: @default_viewport,
127
128
  )
128
- # assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated');
129
129
  @targets[target_info.target_id] = target
130
+ if_present(@wait_for_creating_targets.delete(target_info.target_id)) do |promise|
131
+ promise.fulfill(target)
132
+ end
130
133
  if await target.initialized_promise
131
134
  emit_event(BrowserEmittedEvents::TargetCreated, target)
132
135
  context.emit_event(BrowserContextEmittedEvents::TargetCreated, target)
@@ -139,6 +142,9 @@ class Puppeteer::Browser
139
142
  target = @targets[target_id]
140
143
  target.ignore_initialize_callback_promise
141
144
  @targets.delete(target_id)
145
+ if_present(@wait_for_creating_targets.delete(target_id)) do |promise|
146
+ promise.reject('target destroyed')
147
+ end
142
148
  target.closed_callback
143
149
  if await target.initialized_promise
144
150
  emit_event(BrowserEmittedEvents::TargetDestroyed, target)
@@ -184,6 +190,17 @@ class Puppeteer::Browser
184
190
  result = @connection.send_message('Target.createTarget', **create_target_params)
185
191
  target_id = result['targetId']
186
192
  target = @targets[target_id]
193
+ unless target
194
+ # Target.targetCreated is often notified before the response of Target.createdTarget.
195
+ # https://github.com/YusukeIwaki/puppeteer-ruby/issues/91
196
+ # D, [2021-04-07T03:00:10.125241 #187] DEBUG -- : SEND >> {"method":"Target.createTarget","params":{"url":"about:blank","browserContextId":"56A86FC3391B50180CF9A6450A0D8C21"},"id":3}
197
+ # D, [2021-04-07T03:00:10.142396 #187] DEBUG -- : RECV << {"id"=>3, "result"=>{"targetId"=>"A518447C415A1A3E1A8979454A155632"}}
198
+ # D, [2021-04-07T03:00:10.145360 #187] DEBUG -- : RECV << {"method"=>"Target.targetCreated", "params"=>{"targetInfo"=>{"targetId"=>"A518447C415A1A3E1A8979454A155632", "type"=>"page", "title"=>"", "url"=>"", "attached"=>false, "canAccessOpener"=>false, "browserContextId"=>"56A86FC3391B50180CF9A6450A0D8C21"}}}
199
+ # This is just a workaround logic...
200
+ Rollbar.info("Workaround of YusukeIwaki/puppeteer-ruby#91")
201
+ @wait_for_creating_targets[target_id] = resolvable_future
202
+ target = await @wait_for_creating_targets[target_id]
203
+ end
187
204
  await target.initialized_promise
188
205
  await target.page
189
206
  end
@@ -0,0 +1,106 @@
1
+ class Puppeteer::Coverage
2
+ # @param client [Puppeteer::CDPSession]
3
+ def initialize(client)
4
+ @js = Puppeteer::JSCoverage.new(client)
5
+ @css = Puppeteer::CSSCoverage.new(client)
6
+ end
7
+
8
+ def start_js_coverage(reset_on_navigation: nil, report_anonymous_scripts: nil)
9
+ @js.start(
10
+ reset_on_navigation: reset_on_navigation,
11
+ report_anonymous_scripts: report_anonymous_scripts,
12
+ )
13
+ end
14
+
15
+ def stop_js_coverage
16
+ @js.stop
17
+ end
18
+
19
+ def js_coverage(reset_on_navigation: nil, report_anonymous_scripts: nil, &block)
20
+ unless block
21
+ raise ArgumentError.new('Block must be given')
22
+ end
23
+
24
+ start_js_coverage(
25
+ reset_on_navigation: reset_on_navigation,
26
+ report_anonymous_scripts: report_anonymous_scripts,
27
+ )
28
+ block.call
29
+ stop_js_coverage
30
+ end
31
+
32
+ def start_css_coverage(reset_on_navigation: nil)
33
+ @css.start(reset_on_navigation: reset_on_navigation)
34
+ end
35
+
36
+ def stop_css_coverage
37
+ @css.stop
38
+ end
39
+
40
+ def css_coverage(reset_on_navigation: nil, &block)
41
+ unless block
42
+ raise ArgumentError.new('Block must be given')
43
+ end
44
+
45
+ start_css_coverage(reset_on_navigation: reset_on_navigation)
46
+ block.call
47
+ stop_css_coverage
48
+ end
49
+
50
+ module UtilFunctions
51
+ private def convert_to_disjoint_ranges(nested_ranges)
52
+ points = []
53
+ nested_ranges.each do |range|
54
+ points << { offset: range['startOffset'], type: 0, range: range }
55
+ points << { offset: range['endOffset'], type: 1, range: range }
56
+ end
57
+
58
+ # Sort points to form a valid parenthesis sequence.
59
+ points.sort! do |a, b|
60
+ if a[:offset] != b[:offset]
61
+ # Sort with increasing offsets.
62
+ a[:offset] <=> b[:offset]
63
+ elsif a[:type] != b[:type]
64
+ # All "end" points should go before "start" points.
65
+ b[:type] <=> a[:type]
66
+ else
67
+ alength = a[:range]['endOffset'] - a[:range]['startOffset']
68
+ blength = b[:range]['endOffset'] - b[:range]['startOffset']
69
+ if a[:type] == 0
70
+ # For two "start" points, the one with longer range goes first.
71
+ blength <=> alength
72
+ else
73
+ # For two "end" points, the one with shorter range goes first.
74
+ alength <=> blength
75
+ end
76
+ end
77
+ end
78
+
79
+ hit_count_stack = []
80
+ results = []
81
+ last_offset = 0
82
+ # Run scanning line to intersect all ranges.
83
+ points.each do |point|
84
+ if !hit_count_stack.empty? && last_offset < point[:offset] && hit_count_stack.last > 0
85
+ last_result = results.last
86
+ if last_result && last_result[:end] == last_offset
87
+ last_result[:end] = point[:offset]
88
+ else
89
+ results << { start: last_offset, end: point[:offset] }
90
+ end
91
+ end
92
+ last_offset = point[:offset]
93
+ if point[:type] == 0
94
+ hit_count_stack << point[:range]['count']
95
+ else
96
+ hit_count_stack.pop
97
+ end
98
+ end
99
+
100
+ # Filter out empty ranges.
101
+ results.select do |range|
102
+ range[:end] - range[:start] > 1
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,110 @@
1
+ require_relative './coverage'
2
+
3
+ class Puppeteer::CSSCoverage
4
+ include Puppeteer::Coverage::UtilFunctions
5
+
6
+ class Item
7
+ def initialize(url:, ranges:, text:)
8
+ @url = url
9
+ @ranges = ranges
10
+ @text = text
11
+ end
12
+ attr_reader :url, :ranges, :text
13
+ end
14
+
15
+ # @param client [Puppeteer::CDPSession]
16
+ def initialize(client)
17
+ @client = client
18
+ @enabled = false
19
+ @stylesheet_urls = {}
20
+ @stylesheet_sources = {}
21
+ end
22
+
23
+ def start(reset_on_navigation: nil)
24
+ raise 'CSSCoverage is already enabled' if @enabled
25
+
26
+ @reset_on_navigation =
27
+ if [true, false].include?(reset_on_navigation)
28
+ reset_on_navigation
29
+ else
30
+ true
31
+ end
32
+
33
+ @enabled = true
34
+ @stylesheet_urls.clear
35
+ @stylesheet_sources.clear
36
+ @event_listeners = []
37
+ @event_listeners << @client.add_event_listener('CSS.styleSheetAdded') do |event|
38
+ future { on_stylesheet(event) }
39
+ end
40
+ @event_listeners << @client.add_event_listener('Runtime.executionContextsCleared') do
41
+ on_execution_contexts_cleared
42
+ end
43
+ await_all(
44
+ @client.async_send_message('DOM.enable'),
45
+ @client.async_send_message('CSS.enable'),
46
+ @client.async_send_message('CSS.startRuleUsageTracking'),
47
+ )
48
+ end
49
+
50
+ private def on_execution_contexts_cleared
51
+ return unless @reset_on_navigation
52
+ @stylesheet_urls.clear
53
+ @stylesheet_sources.clear
54
+ end
55
+
56
+ private def on_stylesheet(event)
57
+ header = event['header']
58
+ source_url =
59
+ if header['sourceURL'] == ""
60
+ nil
61
+ else
62
+ header['sourceURL']
63
+ end
64
+
65
+ # Ignore anonymous scripts
66
+ return if !source_url
67
+
68
+ response = @client.send_message('CSS.getStyleSheetText', styleSheetId: header['styleSheetId'])
69
+ @stylesheet_urls[header['styleSheetId']] = source_url
70
+ @stylesheet_sources[header['styleSheetId']] = response['text']
71
+ end
72
+
73
+
74
+ def stop
75
+ raise 'CSSCoverage is not enabled' unless @enabled
76
+ @enabled = false
77
+
78
+ rule_tracking_response = @client.send_message('CSS.stopRuleUsageTracking')
79
+ await_all(
80
+ @client.async_send_message('CSS.disable'),
81
+ @client.async_send_message('DOM.disable'),
82
+ )
83
+ @client.remove_event_listener(*@event_listeners)
84
+
85
+ # aggregate by styleSheetId
86
+ stylesheet_id_to_coverage = {}
87
+ rule_tracking_response['ruleUsage'].each do |entry|
88
+ ranges = stylesheet_id_to_coverage[entry['styleSheetId']]
89
+ unless ranges
90
+ ranges = []
91
+ stylesheet_id_to_coverage[entry['styleSheetId']] = ranges
92
+ end
93
+
94
+ ranges << {
95
+ 'startOffset' => entry['startOffset'],
96
+ 'endOffset' => entry['endOffset'],
97
+ 'count' => entry['used'] ? 1 : 0,
98
+ }
99
+ end
100
+
101
+ coverage = []
102
+ @stylesheet_urls.each do |stylesheet_id, url|
103
+ text = @stylesheet_sources[stylesheet_id]
104
+ ranges = convert_to_disjoint_ranges(stylesheet_id_to_coverage[stylesheet_id] || [])
105
+ coverage << Item.new(url: url, ranges: ranges, text: text)
106
+ end
107
+
108
+ coverage
109
+ end
110
+ end
@@ -0,0 +1,119 @@
1
+ require_relative './coverage'
2
+
3
+ class Puppeteer::JSCoverage
4
+ include Puppeteer::Coverage::UtilFunctions
5
+
6
+ class Item
7
+ def initialize(url:, ranges:, text:)
8
+ @url = url
9
+ @ranges = ranges
10
+ @text = text
11
+ end
12
+ attr_reader :url, :ranges, :text
13
+ end
14
+
15
+ # @param client [Puppeteer::CDPSession]
16
+ def initialize(client)
17
+ @client = client
18
+ @enabled = false
19
+ @script_urls = {}
20
+ @script_sources = {}
21
+ end
22
+
23
+ def start(reset_on_navigation: nil, report_anonymous_scripts: nil)
24
+ raise 'JSCoverage is already enabled' if @enabled
25
+
26
+ @reset_on_navigation =
27
+ if [true, false].include?(reset_on_navigation)
28
+ reset_on_navigation
29
+ else
30
+ true
31
+ end
32
+ @report_anonymous_scripts = report_anonymous_scripts || false
33
+ @enabled = true
34
+ @script_urls.clear
35
+ @script_sources.clear
36
+ @event_listeners = []
37
+ @event_listeners << @client.add_event_listener('Debugger.scriptParsed') do |event|
38
+ future { on_script_parsed(event) }
39
+ end
40
+ @event_listeners << @client.add_event_listener('Runtime.executionContextsCleared') do
41
+ on_execution_contexts_cleared
42
+ end
43
+ await_all(
44
+ @client.async_send_message('Profiler.enable'),
45
+ @client.async_send_message('Profiler.startPreciseCoverage',
46
+ callCount: false,
47
+ detailed: true,
48
+ ),
49
+ @client.async_send_message('Debugger.enable'),
50
+ @client.async_send_message('Debugger.setSkipAllPauses', skip: true),
51
+ )
52
+ end
53
+
54
+ private def on_execution_contexts_cleared
55
+ return unless @reset_on_navigation
56
+ @script_urls.clear
57
+ @script_sources.clear
58
+ end
59
+
60
+ private def on_script_parsed(event)
61
+ url =
62
+ if event['url'] == ""
63
+ nil
64
+ else
65
+ event['url']
66
+ end
67
+
68
+ # Ignore puppeteer-injected scripts
69
+ return if url == Puppeteer::ExecutionContext::EVALUATION_SCRIPT_URL
70
+
71
+ # Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
72
+ return if !url && !@report_anonymous_scripts
73
+
74
+ response = @client.send_message('Debugger.getScriptSource', scriptId: event['scriptId'])
75
+ @script_urls[event['scriptId']] = url
76
+ @script_sources[event['scriptId']] = response['scriptSource']
77
+ end
78
+
79
+ def stop
80
+ raise 'JSCoverage is not enabled' unless @enabled
81
+ @enabled = false
82
+
83
+ results = await_all(
84
+ @client.async_send_message('Profiler.takePreciseCoverage'),
85
+ @client.async_send_message('Profiler.stopPreciseCoverage'),
86
+ @client.async_send_message('Profiler.disable'),
87
+ @client.async_send_message('Debugger.disable'),
88
+ )
89
+ @client.remove_event_listener(*@event_listeners)
90
+
91
+ coverage = []
92
+ profile_response = results.first
93
+ profile_response['result'].each do |entry|
94
+ url = @script_urls[entry['scriptId']]
95
+
96
+ if @report_anonymous_scripts
97
+ url ||= "debugger://VM#{entry['scriptId']}"
98
+ end
99
+
100
+ text = @script_sources[entry['scriptId']]
101
+ next if !text || !url
102
+
103
+ flatten_ranges = []
104
+ entry['functions'].each do |func|
105
+ func['ranges'].each do |range|
106
+ flatten_ranges << range
107
+ end
108
+ end
109
+
110
+ coverage << Item.new(
111
+ url: url,
112
+ ranges: convert_to_disjoint_ranges(flatten_ranges),
113
+ text: text,
114
+ )
115
+ end
116
+
117
+ coverage
118
+ end
119
+ end
@@ -39,9 +39,9 @@ class Puppeteer::Page
39
39
  # @accessibility = Accessibility.new(client)
40
40
  @frame_manager = Puppeteer::FrameManager.new(client, self, ignore_https_errors, @timeout_settings)
41
41
  @emulation_manager = Puppeteer::EmulationManager.new(client)
42
- # @tracing = Tracing.new(client)
42
+ @tracing = Puppeteer::Tracing.new(client)
43
43
  @page_bindings = {}
44
- # @coverage = Coverage.new(client)
44
+ @coverage = Puppeteer::Coverage.new(client)
45
45
  @javascript_enabled = true
46
46
  @screenshot_task_queue = ScreenshotTaskQueue.new
47
47
 
@@ -245,7 +245,7 @@ class Puppeteer::Page
245
245
  @frame_manager.main_frame
246
246
  end
247
247
 
248
- attr_reader :touch_screen, :coverage, :accessibility
248
+ attr_reader :touch_screen, :coverage, :tracing, :accessibility
249
249
 
250
250
  def keyboard(&block)
251
251
  @keyboard.instance_eval(&block) unless block.nil?
@@ -986,35 +986,6 @@ class Puppeteer::Page
986
986
  buffer
987
987
  end
988
988
 
989
- class ProtocolStreamReader
990
- def initialize(client:, handle:, path:)
991
- @client = client
992
- @handle = handle
993
- @path = path
994
- end
995
-
996
- def read
997
- out = StringIO.new
998
- File.open(@path, 'wb') do |file|
999
- eof = false
1000
- until eof
1001
- response = @client.send_message('IO.read', handle: @handle)
1002
- eof = response['eof']
1003
- data =
1004
- if response['base64Encoded']
1005
- Base64.decode64(response['data'])
1006
- else
1007
- response['data']
1008
- end
1009
- out.write(data)
1010
- file.write(data)
1011
- end
1012
- end
1013
- @client.send_message('IO.close', handle: @handle)
1014
- out.read
1015
- end
1016
- end
1017
-
1018
989
  class PrintToPdfIsNotImplementedError < StandardError
1019
990
  def initialize
1020
991
  super('pdf() is only available in headless mode. See https://github.com/puppeteer/puppeteer/issues/1829')
@@ -1028,7 +999,7 @@ class Puppeteer::Page
1028
999
  set_transparent_background_color if omit_background
1029
1000
  result = @client.send_message('Page.printToPDF', pdf_options.page_print_args)
1030
1001
  reset_default_background_color if omit_background
1031
- ProtocolStreamReader.new(client: @client, handle: result['stream'], path: pdf_options.path).read
1002
+ Puppeteer::ProtocolStreamReader.new(client: @client, handle: result['stream'], path: pdf_options.path).read
1032
1003
  rescue => err
1033
1004
  if err.message.include?('PrintToPDF is not implemented')
1034
1005
  raise PrintToPdfIsNotImplementedError.new
@@ -0,0 +1,45 @@
1
+ class Puppeteer::ProtocolStreamReader
2
+ def initialize(client:, handle:, path:)
3
+ @client = client
4
+ @handle = handle
5
+ @path = path
6
+ end
7
+
8
+ def read
9
+ StringIO.open do |out|
10
+ if @path
11
+ File.open(@path, 'wb') do |file|
12
+ io_read do |data|
13
+ out.write(data)
14
+ file.write(data)
15
+ end
16
+ end
17
+ else
18
+ io_read { |data| out.write(data) }
19
+ end
20
+ io_close
21
+
22
+ out.string
23
+ end
24
+ end
25
+
26
+ private def io_read(&block)
27
+ eof = false
28
+ until eof
29
+ response = @client.send_message('IO.read', handle: @handle)
30
+ eof = response['eof']
31
+ data =
32
+ if response['base64Encoded']
33
+ Base64.decode64(response['data'])
34
+ else
35
+ response['data']
36
+ end
37
+ block.call(data)
38
+ end
39
+ end
40
+
41
+
42
+ private def io_close
43
+ @client.send_message('IO.close', handle: @handle)
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ class Puppeteer::Tracing
2
+ # @param client [Puppeteer::CDPSession]
3
+ def initialize(client)
4
+ @client = client
5
+ @recording = false
6
+ end
7
+
8
+ DEFAULT_CATEGORIES = [
9
+ '-*',
10
+ 'devtools.timeline',
11
+ 'v8.execute',
12
+ 'disabled-by-default-devtools.timeline',
13
+ 'disabled-by-default-devtools.timeline.frame',
14
+ 'toplevel',
15
+ 'blink.console',
16
+ 'blink.user_timing',
17
+ 'latencyInfo',
18
+ 'disabled-by-default-devtools.timeline.stack',
19
+ 'disabled-by-default-v8.cpu_profiler',
20
+ 'disabled-by-default-v8.cpu_profiler.hires',
21
+ ].freeze
22
+
23
+ def start(path: nil, screenshots: nil, categories: nil)
24
+ option_categories = categories || DEFAULT_CATEGORIES.dup
25
+
26
+ if screenshots
27
+ option_categories << 'disabled-by-default-devtools.screenshot'
28
+ end
29
+
30
+ @path = path
31
+ @recording = true
32
+ @client.send_message('Tracing.start',
33
+ transferMode: 'ReturnAsStream',
34
+ categories: option_categories.join(','),
35
+ )
36
+ end
37
+
38
+ def stop
39
+ stream_promise = resolvable_future do |f|
40
+ @client.once('Tracing.tracingComplete') do |event|
41
+ f.fulfill(event['stream'])
42
+ end
43
+ end
44
+ @client.send_message('Tracing.end')
45
+ @recording = false
46
+
47
+ stream = await stream_promise
48
+ Puppeteer::ProtocolStreamReader.new(client: @client, handle: stream, path: @path).read
49
+ end
50
+ end
@@ -1,3 +1,3 @@
1
1
  module Puppeteer
2
- VERSION = '0.31.6'
2
+ VERSION = '0.32.0'
3
3
  end
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'dry-inflector'
29
29
  spec.add_development_dependency 'pry-byebug'
30
30
  spec.add_development_dependency 'rake', '~> 13.0.3'
31
+ spec.add_development_dependency 'rollbar'
31
32
  spec.add_development_dependency 'rspec', '~> 3.10.0 '
32
33
  spec.add_development_dependency 'rspec_junit_formatter' # for CircleCI.
33
34
  spec.add_development_dependency 'rubocop', '~> 1.12.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppeteer-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.6
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-03 00:00:00.000000000 Z
11
+ date: 2021-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 13.0.3
125
+ - !ruby/object:Gem::Dependency
126
+ name: rollbar
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: rspec
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -249,6 +263,8 @@ files:
249
263
  - lib/puppeteer/concurrent_ruby_utils.rb
250
264
  - lib/puppeteer/connection.rb
251
265
  - lib/puppeteer/console_message.rb
266
+ - lib/puppeteer/coverage.rb
267
+ - lib/puppeteer/css_coverage.rb
252
268
  - lib/puppeteer/custom_query_handler.rb
253
269
  - lib/puppeteer/debug_print.rb
254
270
  - lib/puppeteer/define_async_method.rb
@@ -272,6 +288,7 @@ files:
272
288
  - lib/puppeteer/frame_manager.rb
273
289
  - lib/puppeteer/geolocation.rb
274
290
  - lib/puppeteer/if_present.rb
291
+ - lib/puppeteer/js_coverage.rb
275
292
  - lib/puppeteer/js_handle.rb
276
293
  - lib/puppeteer/keyboard.rb
277
294
  - lib/puppeteer/keyboard/key_description.rb
@@ -290,6 +307,7 @@ files:
290
307
  - lib/puppeteer/page/pdf_options.rb
291
308
  - lib/puppeteer/page/screenshot_options.rb
292
309
  - lib/puppeteer/page/screenshot_task_queue.rb
310
+ - lib/puppeteer/protocol_stream_reader.rb
293
311
  - lib/puppeteer/puppeteer.rb
294
312
  - lib/puppeteer/query_handler_manager.rb
295
313
  - lib/puppeteer/remote_object.rb
@@ -298,6 +316,7 @@ files:
298
316
  - lib/puppeteer/target.rb
299
317
  - lib/puppeteer/timeout_settings.rb
300
318
  - lib/puppeteer/touch_screen.rb
319
+ - lib/puppeteer/tracing.rb
301
320
  - lib/puppeteer/version.rb
302
321
  - lib/puppeteer/viewport.rb
303
322
  - lib/puppeteer/wait_task.rb