puppeteer-ruby 0.31.6 → 0.32.0

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