1'use strict'; 2 3const common = require('../common'); 4const assert = require('assert'); 5const util = require('util'); 6const { 7 PerformanceObserver, 8 PerformanceEntry, 9 PerformanceResourceTiming, 10 performance: { 11 clearResourceTimings, 12 markResourceTiming, 13 }, 14} = require('perf_hooks'); 15 16assert(PerformanceObserver); 17assert(PerformanceEntry); 18assert.throws(() => new PerformanceEntry(), { code: 'ERR_ILLEGAL_CONSTRUCTOR' }); 19assert(PerformanceResourceTiming); 20assert(clearResourceTimings); 21assert(markResourceTiming); 22 23function createTimingInfo({ 24 startTime = 0, 25 redirectStartTime = 0, 26 redirectEndTime = 0, 27 postRedirectStartTime = 0, 28 finalServiceWorkerStartTime = 0, 29 finalNetworkRequestStartTime = 0, 30 finalNetworkResponseStartTime = 0, 31 endTime = 0, 32 encodedBodySize = 0, 33 decodedBodySize = 0, 34 finalConnectionTimingInfo = null 35}) { 36 if (finalConnectionTimingInfo !== null) { 37 finalConnectionTimingInfo.domainLookupStartTime = 38 finalConnectionTimingInfo.domainLookupStartTime || 0; 39 finalConnectionTimingInfo.domainLookupEndTime = 40 finalConnectionTimingInfo.domainLookupEndTime || 0; 41 finalConnectionTimingInfo.connectionStartTime = 42 finalConnectionTimingInfo.connectionStartTime || 0; 43 finalConnectionTimingInfo.connectionEndTime = 44 finalConnectionTimingInfo.connectionEndTime || 0; 45 finalConnectionTimingInfo.secureConnectionStartTime = 46 finalConnectionTimingInfo.secureConnectionStartTime || 0; 47 finalConnectionTimingInfo.ALPNNegotiatedProtocol = 48 finalConnectionTimingInfo.ALPNNegotiatedProtocol || []; 49 } 50 return { 51 startTime, 52 redirectStartTime, 53 redirectEndTime, 54 postRedirectStartTime, 55 finalServiceWorkerStartTime, 56 finalNetworkRequestStartTime, 57 finalNetworkResponseStartTime, 58 endTime, 59 encodedBodySize, 60 decodedBodySize, 61 finalConnectionTimingInfo, 62 }; 63} 64 65// PerformanceResourceTiming should not be initialized externally 66{ 67 assert.throws(() => new PerformanceResourceTiming(), { 68 name: 'TypeError', 69 message: 'Illegal constructor', 70 code: 'ERR_ILLEGAL_CONSTRUCTOR', 71 }); 72} 73 74// Using performance.getEntries*() 75{ 76 const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} }); 77 const customGlobal = {}; 78 const requestedUrl = 'http://localhost:8080'; 79 const cacheMode = 'local'; 80 const initiatorType = 'fetch'; 81 const resource = markResourceTiming( 82 timingInfo, 83 requestedUrl, 84 initiatorType, 85 customGlobal, 86 cacheMode, 87 ); 88 89 assert(resource instanceof PerformanceEntry); 90 assert(resource instanceof PerformanceResourceTiming); 91 92 { 93 const entries = performance.getEntries(); 94 assert.strictEqual(entries.length, 1); 95 assert(entries[0] instanceof PerformanceResourceTiming); 96 } 97 98 { 99 const entries = performance.getEntriesByType('resource'); 100 assert.strictEqual(entries.length, 1); 101 assert(entries[0] instanceof PerformanceResourceTiming); 102 } 103 104 { 105 const entries = performance.getEntriesByName(resource.name); 106 assert.strictEqual(entries.length, 1); 107 assert(entries[0] instanceof PerformanceResourceTiming); 108 } 109 110 clearResourceTimings(); 111 assert.strictEqual(performance.getEntries().length, 0); 112} 113 114// Assert resource data based in timingInfo 115 116// default values 117{ 118 const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} }); 119 const customGlobal = {}; 120 const requestedUrl = 'http://localhost:8080'; 121 const cacheMode = 'local'; 122 const initiatorType = 'fetch'; 123 const resource = markResourceTiming( 124 timingInfo, 125 requestedUrl, 126 initiatorType, 127 customGlobal, 128 cacheMode, 129 ); 130 131 assert(resource instanceof PerformanceEntry); 132 assert(resource instanceof PerformanceResourceTiming); 133 134 assert.strictEqual(resource.entryType, 'resource'); 135 assert.strictEqual(resource.name, requestedUrl); 136 assert.ok(typeof resource.cacheMode === 'undefined', 'cacheMode does not have a getter'); 137 assert.strictEqual(resource.startTime, timingInfo.startTime); 138 assert.strictEqual(resource.duration, 0); 139 assert.strictEqual(resource.initiatorType, initiatorType); 140 assert.strictEqual(resource.workerStart, 0); 141 assert.strictEqual(resource.redirectStart, 0); 142 assert.strictEqual(resource.redirectEnd, 0); 143 assert.strictEqual(resource.fetchStart, 0); 144 assert.strictEqual(resource.domainLookupStart, 0); 145 assert.strictEqual(resource.domainLookupEnd, 0); 146 assert.strictEqual(resource.connectStart, 0); 147 assert.strictEqual(resource.connectEnd, 0); 148 assert.strictEqual(resource.secureConnectionStart, 0); 149 assert.deepStrictEqual(resource.nextHopProtocol, []); 150 assert.strictEqual(resource.requestStart, 0); 151 assert.strictEqual(resource.responseStart, 0); 152 assert.strictEqual(resource.responseEnd, 0); 153 assert.strictEqual(resource.encodedBodySize, 0); 154 assert.strictEqual(resource.decodedBodySize, 0); 155 assert.strictEqual(resource.transferSize, 0); 156 assert.deepStrictEqual(resource.toJSON(), { 157 name: requestedUrl, 158 entryType: 'resource', 159 startTime: 0, 160 duration: 0, 161 initiatorType, 162 nextHopProtocol: [], 163 workerStart: 0, 164 redirectStart: 0, 165 redirectEnd: 0, 166 fetchStart: 0, 167 domainLookupStart: 0, 168 domainLookupEnd: 0, 169 connectStart: 0, 170 connectEnd: 0, 171 secureConnectionStart: 0, 172 requestStart: 0, 173 responseStart: 0, 174 responseEnd: 0, 175 transferSize: 0, 176 encodedBodySize: 0, 177 decodedBodySize: 0, 178 }); 179 assert.strictEqual(util.inspect(performance.getEntries()), `[ 180 PerformanceResourceTiming { 181 name: 'http://localhost:8080', 182 entryType: 'resource', 183 startTime: 0, 184 duration: 0, 185 initiatorType: 'fetch', 186 nextHopProtocol: [], 187 workerStart: 0, 188 redirectStart: 0, 189 redirectEnd: 0, 190 fetchStart: 0, 191 domainLookupStart: 0, 192 domainLookupEnd: 0, 193 connectStart: 0, 194 connectEnd: 0, 195 secureConnectionStart: 0, 196 requestStart: 0, 197 responseStart: 0, 198 responseEnd: 0, 199 transferSize: 0, 200 encodedBodySize: 0, 201 decodedBodySize: 0 202 } 203]`); 204 assert.strictEqual(util.inspect(resource), `PerformanceResourceTiming { 205 name: 'http://localhost:8080', 206 entryType: 'resource', 207 startTime: 0, 208 duration: 0, 209 initiatorType: 'fetch', 210 nextHopProtocol: [], 211 workerStart: 0, 212 redirectStart: 0, 213 redirectEnd: 0, 214 fetchStart: 0, 215 domainLookupStart: 0, 216 domainLookupEnd: 0, 217 connectStart: 0, 218 connectEnd: 0, 219 secureConnectionStart: 0, 220 requestStart: 0, 221 responseStart: 0, 222 responseEnd: 0, 223 transferSize: 0, 224 encodedBodySize: 0, 225 decodedBodySize: 0 226}`); 227 228 assert(resource instanceof PerformanceEntry); 229 assert(resource instanceof PerformanceResourceTiming); 230 231 clearResourceTimings(); 232 const entries = performance.getEntries(); 233 assert.strictEqual(entries.length, 0); 234} 235 236// custom getters math 237{ 238 const timingInfo = createTimingInfo({ 239 endTime: 100, 240 startTime: 50, 241 encodedBodySize: 150, 242 }); 243 const customGlobal = {}; 244 const requestedUrl = 'http://localhost:8080'; 245 const cacheMode = ''; 246 const initiatorType = 'fetch'; 247 const resource = markResourceTiming( 248 timingInfo, 249 requestedUrl, 250 initiatorType, 251 customGlobal, 252 cacheMode, 253 ); 254 255 assert(resource instanceof PerformanceEntry); 256 assert(resource instanceof PerformanceResourceTiming); 257 258 assert.strictEqual(resource.entryType, 'resource'); 259 assert.strictEqual(resource.name, requestedUrl); 260 assert.ok(typeof resource.cacheMode === 'undefined', 'cacheMode does not have a getter'); 261 assert.strictEqual(resource.startTime, timingInfo.startTime); 262 // Duration should be the timingInfo endTime - startTime 263 assert.strictEqual(resource.duration, 50); 264 // TransferSize should be encodedBodySize + 300 when cacheMode is empty 265 assert.strictEqual(resource.transferSize, 450); 266 267 assert(resource instanceof PerformanceEntry); 268 assert(resource instanceof PerformanceResourceTiming); 269 270 clearResourceTimings(); 271 const entries = performance.getEntries(); 272 assert.strictEqual(entries.length, 0); 273} 274 275// Using PerformanceObserver 276{ 277 const obs = new PerformanceObserver(common.mustCall((list) => { 278 { 279 const entries = list.getEntries(); 280 assert.strictEqual(entries.length, 1); 281 assert(entries[0] instanceof PerformanceResourceTiming); 282 } 283 { 284 const entries = list.getEntriesByType('resource'); 285 assert.strictEqual(entries.length, 1); 286 assert(entries[0] instanceof PerformanceResourceTiming); 287 } 288 { 289 const entries = list.getEntriesByName('http://localhost:8080'); 290 assert.strictEqual(entries.length, 1); 291 assert(entries[0] instanceof PerformanceResourceTiming); 292 } 293 obs.disconnect(); 294 })); 295 obs.observe({ entryTypes: ['resource'] }); 296 297 const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} }); 298 const customGlobal = {}; 299 const requestedUrl = 'http://localhost:8080'; 300 const cacheMode = 'local'; 301 const initiatorType = 'fetch'; 302 const resource = markResourceTiming( 303 timingInfo, 304 requestedUrl, 305 initiatorType, 306 customGlobal, 307 cacheMode, 308 ); 309 310 assert(resource instanceof PerformanceEntry); 311 assert(resource instanceof PerformanceResourceTiming); 312 313 clearResourceTimings(); 314 const entries = performance.getEntries(); 315 assert.strictEqual(entries.length, 0); 316} 317