Skip to content

Commit 3f082bb

Browse files
committed
perf_hooks: test resource timing fetch integration
Signed-off-by: greenhead <greenheadhq@gmail.com>
1 parent 1037870 commit 3f082bb

3 files changed

Lines changed: 89 additions & 11 deletions

File tree

‎doc/api/perf_hooks.md‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ added: REPLACEME
11001100
* Type: {number}
11011101

11021102
The high resolution millisecond timestamp representing the time immediately
1103-
after Node.js receives the first byte of the headers of the final response,
1103+
after Node.js receives the first byte of the final response,
11041104
as opposed to an interim response.
11051105

11061106
### `performanceResourceTiming.firstInterimResponseStart`
@@ -1113,8 +1113,8 @@ added: REPLACEME
11131113

11141114
The high resolution millisecond timestamp representing the time immediately
11151115
after Node.js receives the first byte of the first interim response, such as
1116-
a `103 Early Hints` response. Node.js does not currently record interim
1117-
responses, so the property always returns 0.
1116+
a `103 Early Hints` response. For entries created by the built-in `fetch()`
1117+
implementation, this is currently `0` because interim response timings are not recorded.
11181118

11191119
### `performanceResourceTiming.responseStart`
11201120

@@ -1224,8 +1224,8 @@ added: REPLACEME
12241224
* Type: {string}
12251225

12261226
The render blocking status of the resource. It is either `'blocking'` or
1227-
`'non-blocking'`. Resources fetched by Node.js are never render blocking, so
1228-
the property always returns `'non-blocking'`.
1227+
`'non-blocking'`. Entries created by the built-in `fetch()` implementation
1228+
return `'non-blocking'`.
12291229

12301230
### `performanceResourceTiming.contentType`
12311231

@@ -1236,8 +1236,8 @@ added: REPLACEME
12361236
* Type: {string}
12371237

12381238
The minimized MIME type of the content of the fetched resource, or an empty
1239-
string if it cannot be determined. Node.js does not currently populate this
1240-
field, so the property returns an empty string.
1239+
string if it cannot be determined. Entries created by the built-in `fetch()`
1240+
implementation currently return an empty string.
12411241

12421242
### `performanceResourceTiming.contentEncoding`
12431243

@@ -1249,8 +1249,8 @@ added: REPLACEME
12491249

12501250
The content encoding, such as `'gzip'` or `'br'`, that was applied to the
12511251
fetched resource, or an empty string if none was applied or it cannot be
1252-
determined. Node.js does not currently populate this field, so the property
1253-
returns an empty string.
1252+
determined. Entries created by the built-in `fetch()` implementation currently
1253+
return an empty string.
12541254

12551255
### `performanceResourceTiming.toJSON()`
12561256

‎test/parallel/test-perf-hooks-resourcetiming-attributes.js‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ function markResourceTiming(timingInfo, bodyInfo) {
4242
);
4343
}
4444

45-
// Default values with an empty body info, mirroring what the fetch
46-
// implementation passes for a response with no body metadata.
45+
// Default values when no optional timing or body metadata is present.
4746
{
4847
const resource = markResourceTiming(createTimingInfo(), {});
4948

@@ -55,6 +54,18 @@ function markResourceTiming(timingInfo, bodyInfo) {
5554
assert.strictEqual(resource.contentEncoding, '');
5655
}
5756

57+
// responseStart falls back to the final response when no interim response timing was recorded.
58+
{
59+
const resource = markResourceTiming(createTimingInfo({
60+
finalNetworkResponseStartTime: 123,
61+
firstInterimNetworkResponseStartTime: 0,
62+
}), {});
63+
64+
assert.strictEqual(resource.finalResponseHeadersStart, 123);
65+
assert.strictEqual(resource.firstInterimResponseStart, 0);
66+
assert.strictEqual(resource.responseStart, 123);
67+
}
68+
5869
// Values reflected from timing info and body info.
5970
{
6071
const timingInfo = createTimingInfo({
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// The ESM common wrapper does not export localhostIPv4.
2+
// eslint-disable-next-line node-core/require-common-first
3+
import common from '../common/index.js';
4+
5+
import assert from 'node:assert';
6+
import { once } from 'node:events';
7+
import { createServer } from 'node:http';
8+
import {
9+
PerformanceResourceTiming,
10+
performance,
11+
} from 'node:perf_hooks';
12+
13+
// This test ensures that built-in fetch creates a PerformanceResourceTiming
14+
// entry with the resource timing attributes exposed by Node.js.
15+
16+
const responseBody = 'Hello world';
17+
const server = createServer(common.mustCall((req, res) => {
18+
res.end(responseBody);
19+
}));
20+
21+
server.listen(0, common.localhostIPv4);
22+
await once(server, 'listening');
23+
24+
async function closeServer() {
25+
if (server.listening) {
26+
await new Promise((resolve) => server.close(resolve));
27+
}
28+
}
29+
30+
try {
31+
performance.clearResourceTimings();
32+
33+
const url = `http://${common.localhostIPv4}:${server.address().port}/`;
34+
const response = await fetch(url);
35+
assert.strictEqual(await response.text(), responseBody);
36+
await closeServer();
37+
38+
const entries = performance.getEntriesByName(url, 'resource');
39+
assert.strictEqual(entries.length, 1);
40+
41+
const [entry] = entries;
42+
assert(entry instanceof PerformanceResourceTiming);
43+
assert.strictEqual(entry.initiatorType, 'fetch');
44+
assert.strictEqual(entry.responseStatus, 200);
45+
assert(entry.finalResponseHeadersStart > 0);
46+
assert.strictEqual(entry.firstInterimResponseStart, 0);
47+
assert.strictEqual(entry.responseStart, entry.finalResponseHeadersStart);
48+
assert(entry.responseEnd >= entry.responseStart);
49+
assert.strictEqual(entry.renderBlockingStatus, 'non-blocking');
50+
assert.strictEqual(entry.contentType, '');
51+
assert.strictEqual(entry.contentEncoding, '');
52+
53+
const json = entry.toJSON();
54+
for (const name of [
55+
'finalResponseHeadersStart',
56+
'firstInterimResponseStart',
57+
'responseStart',
58+
'renderBlockingStatus',
59+
'contentType',
60+
'contentEncoding',
61+
]) {
62+
assert.strictEqual(json[name], entry[name], name);
63+
}
64+
} finally {
65+
performance.clearResourceTimings();
66+
await closeServer();
67+
}

0 commit comments

Comments
 (0)