• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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