@elastic/synthetics 1.0.0-beta.24 → 1.0.0-beta.25
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.
- package/NOTICE.txt +0 -29
- package/dist/common_types.d.ts +3 -9
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/gatherer.d.ts +1 -1
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +14 -5
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/runner.js +1 -1
- package/dist/core/runner.js.map +1 -1
- package/dist/plugins/network.d.ts +17 -30
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +179 -245
- package/dist/plugins/network.js.map +1 -1
- package/dist/plugins/plugin-manager.d.ts +1 -1
- package/dist/plugins/plugin-manager.d.ts.map +1 -1
- package/dist/plugins/plugin-manager.js +2 -2
- package/dist/plugins/plugin-manager.js.map +1 -1
- package/dist/reporters/json.d.ts +0 -1
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +1 -19
- package/dist/reporters/json.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common_types.ts +3 -9
- package/src/core/gatherer.ts +16 -8
- package/src/core/runner.ts +1 -1
- package/src/plugins/network.ts +218 -294
- package/src/plugins/plugin-manager.ts +2 -2
- package/src/reporters/json.ts +1 -17
package/src/plugins/network.ts
CHANGED
|
@@ -23,360 +23,284 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { Page, Request, Response } from 'playwright-chromium';
|
|
27
27
|
import { NetworkInfo, BrowserInfo, Driver } from '../common_types';
|
|
28
28
|
import { Step } from '../dsl';
|
|
29
29
|
import { getTimestamp } from '../helpers';
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Kibana UI expects the requestStartTime and loadEndTime to be baseline
|
|
33
|
+
* in seconds as they have the logic to convert it to milliseconds before
|
|
34
|
+
* using for offset calculation
|
|
35
|
+
*/
|
|
36
|
+
function epochTimeInSeconds() {
|
|
37
|
+
return getTimestamp() / 1e6;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Used as a key in each Network Request to identify the
|
|
42
|
+
* associated request across distinct lifecycle events
|
|
43
|
+
*/
|
|
44
|
+
export const NETWORK_ENTRY_SUMBOL = Symbol.for('NetworkEntry');
|
|
45
|
+
|
|
46
|
+
type RequestWithEntry = Request & {
|
|
47
|
+
NETWORK_ENTRY_SUMBOL?: symbol;
|
|
48
|
+
};
|
|
49
|
+
|
|
31
50
|
export class NetworkManager {
|
|
32
51
|
private _browser: BrowserInfo;
|
|
33
|
-
private
|
|
52
|
+
private _barrierPromises = new Set<Promise<void>>();
|
|
34
53
|
results: Array<NetworkInfo> = [];
|
|
35
54
|
_currentStep: Partial<Step> = null;
|
|
36
55
|
|
|
37
56
|
constructor(private driver: Driver) {}
|
|
38
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Adds a protection barrier aganist all asynchronous extract operations from
|
|
60
|
+
* request/response object that are happening during page lifecycle, If the
|
|
61
|
+
* page is closed during the extraction, the barrier enforces those operations
|
|
62
|
+
* to not result in exception
|
|
63
|
+
*/
|
|
64
|
+
private _addBarrier(page: Page, promise: Promise<void>) {
|
|
65
|
+
if (!page) return;
|
|
66
|
+
const race = Promise.race([
|
|
67
|
+
new Promise<void>(resolve =>
|
|
68
|
+
page.on('close', () => {
|
|
69
|
+
this._barrierPromises.delete(race);
|
|
70
|
+
resolve();
|
|
71
|
+
})
|
|
72
|
+
),
|
|
73
|
+
promise,
|
|
74
|
+
]);
|
|
75
|
+
this._barrierPromises.add(race);
|
|
76
|
+
race.then(() => this._barrierPromises.delete(race));
|
|
77
|
+
}
|
|
78
|
+
|
|
39
79
|
async start() {
|
|
40
|
-
const { client } = this.driver;
|
|
80
|
+
const { client, context } = this.driver;
|
|
41
81
|
const { product } = await client.send('Browser.getVersion');
|
|
42
82
|
const [name, version] = product.split('/');
|
|
43
83
|
this._browser = { name, version };
|
|
44
84
|
await client.send('Network.enable');
|
|
45
85
|
/**
|
|
46
|
-
* Listen for all network events
|
|
86
|
+
* Listen for all network events from PW context
|
|
47
87
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
52
|
-
client.on(
|
|
53
|
-
'Network.requestWillBeSentExtraInfo',
|
|
54
|
-
this._onRequestWillBeSentExtraInfo.bind(this)
|
|
55
|
-
);
|
|
56
|
-
client.on('Network.dataReceived', this._onDataReceived.bind(this));
|
|
57
|
-
client.on('Network.responseReceived', this._onResponseReceived.bind(this));
|
|
58
|
-
client.on('Network.loadingFinished', this._onLoadingFinished.bind(this));
|
|
59
|
-
client.on('Network.loadingFailed', this._onLoadingFailed.bind(this));
|
|
88
|
+
context.on('request', this._onRequest.bind(this));
|
|
89
|
+
context.on('response', this._onResponse.bind(this));
|
|
90
|
+
context.on('requestfinished', this._onRequestCompleted.bind(this));
|
|
91
|
+
context.on('requestfailed', this._onRequestCompleted.bind(this));
|
|
60
92
|
}
|
|
61
93
|
|
|
62
|
-
|
|
63
|
-
|
|
94
|
+
private _findNetworkEntry(
|
|
95
|
+
request: RequestWithEntry
|
|
96
|
+
): NetworkInfo | undefined {
|
|
97
|
+
return request[NETWORK_ENTRY_SUMBOL];
|
|
64
98
|
}
|
|
65
99
|
|
|
66
|
-
|
|
67
|
-
const
|
|
100
|
+
private _onRequest(request: Request) {
|
|
101
|
+
const url = request.url();
|
|
68
102
|
/**
|
|
69
103
|
* Data URI should not show up as network requests
|
|
70
104
|
*/
|
|
71
105
|
if (url.startsWith('data:')) {
|
|
72
106
|
return;
|
|
73
107
|
}
|
|
74
|
-
const { requestId, timestamp, type, loaderId } = event;
|
|
75
|
-
const isNavigationRequest = requestId == loaderId && type === 'Document';
|
|
76
|
-
const record = this._findNetworkRecord(requestId);
|
|
77
|
-
/**
|
|
78
|
-
* On redirects, another `requestWillBeSent` event will be fired for the
|
|
79
|
-
* same requestId. We calculate the timings for the redirect request using
|
|
80
|
-
* the `redirectedResponse` from the redirected request.
|
|
81
|
-
*/
|
|
82
|
-
if (record) {
|
|
83
|
-
if (event.redirectResponse) {
|
|
84
|
-
record.response.redirectURL = url;
|
|
85
|
-
const response = event.redirectResponse;
|
|
86
|
-
const data = Object.assign(event, {
|
|
87
|
-
type: event.type,
|
|
88
|
-
response,
|
|
89
|
-
encodedDataLength: response.encodedDataLength,
|
|
90
|
-
hasExtraInfo: false,
|
|
91
|
-
});
|
|
92
|
-
this._onResponseReceived(data);
|
|
93
|
-
this._onLoadingFinished(data);
|
|
94
|
-
} else {
|
|
95
|
-
/**
|
|
96
|
-
* Edge case, we handle it to proceed with next navigation
|
|
97
|
-
*/
|
|
98
|
-
this._onLoadingFailed(
|
|
99
|
-
Object.assign(event, {
|
|
100
|
-
type: event.type,
|
|
101
|
-
errorText: 'redirectResponse data is not available',
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
const redirectedRecord = this._findNetworkRecord(requestId);
|
|
106
|
-
/**
|
|
107
|
-
* Rewrite the map with new redirect id to not reset
|
|
108
|
-
* the redirect request with original request
|
|
109
|
-
*/
|
|
110
|
-
this._InflightRequestMap.delete(requestId);
|
|
111
|
-
this._InflightRequestMap.set(
|
|
112
|
-
`redirect:${timestamp}:${requestId}`,
|
|
113
|
-
redirectedRecord
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
108
|
|
|
117
|
-
|
|
109
|
+
const timestamp = getTimestamp();
|
|
110
|
+
const networkEntry: NetworkInfo = {
|
|
118
111
|
browser: this._browser,
|
|
119
112
|
step: this._currentStep,
|
|
120
|
-
timestamp
|
|
113
|
+
timestamp,
|
|
121
114
|
url,
|
|
122
|
-
type,
|
|
115
|
+
type: request.resourceType(),
|
|
123
116
|
request: {
|
|
124
117
|
url,
|
|
125
|
-
method,
|
|
126
|
-
headers,
|
|
127
|
-
|
|
118
|
+
method: request.method(),
|
|
119
|
+
headers: {},
|
|
120
|
+
body: {
|
|
121
|
+
bytes: request.postDataBuffer()?.length || 0,
|
|
122
|
+
},
|
|
128
123
|
},
|
|
129
124
|
response: {
|
|
130
125
|
status: -1,
|
|
131
|
-
mimeType: 'x-unknown',
|
|
132
126
|
headers: {},
|
|
133
|
-
|
|
127
|
+
mimeType: 'x-unknown',
|
|
128
|
+
redirectURL: '',
|
|
134
129
|
},
|
|
135
|
-
isNavigationRequest,
|
|
136
|
-
requestSentTime:
|
|
137
|
-
responseReceivedTime: -1,
|
|
130
|
+
isNavigationRequest: request.isNavigationRequest(),
|
|
131
|
+
requestSentTime: epochTimeInSeconds(),
|
|
138
132
|
loadEndTime: -1,
|
|
133
|
+
responseReceivedTime: -1,
|
|
139
134
|
resourceSize: 0,
|
|
140
135
|
transferSize: 0,
|
|
141
136
|
timings: null,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
_onRequestWillBeSentExtraInfo(
|
|
146
|
-
event: Protocol.Network.requestWillBeSentExtraInfoPayload
|
|
147
|
-
) {
|
|
148
|
-
const { requestId, headers } = event;
|
|
149
|
-
const record = this._findNetworkRecord(requestId);
|
|
150
|
-
if (!record) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Enhance request headers with additional information
|
|
155
|
-
*/
|
|
156
|
-
record.request.headers = {
|
|
157
|
-
...record.request.headers,
|
|
158
|
-
...headers,
|
|
159
137
|
};
|
|
160
|
-
record.request.referrer = record.request.headers?.Referer;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
_onDataReceived(event: Protocol.Network.dataReceivedPayload) {
|
|
164
|
-
const { requestId, dataLength, encodedDataLength } = event;
|
|
165
|
-
const record = this._findNetworkRecord(requestId);
|
|
166
|
-
if (!record) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
record.resourceSize += dataLength;
|
|
170
|
-
if (encodedDataLength >= 0) record.transferSize += encodedDataLength;
|
|
171
|
-
}
|
|
172
138
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (!record) {
|
|
177
|
-
return;
|
|
139
|
+
if (request.redirectedFrom()) {
|
|
140
|
+
const fromEntry = this._findNetworkEntry(request.redirectedFrom());
|
|
141
|
+
if (fromEntry) fromEntry.response.redirectURL = request.url();
|
|
178
142
|
}
|
|
179
143
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
record.response = {
|
|
183
|
-
url: response.url,
|
|
184
|
-
status: response.status,
|
|
185
|
-
protocol: response.protocol,
|
|
186
|
-
statusText: response.statusText,
|
|
187
|
-
headers: response.headers,
|
|
188
|
-
mimeType: response.mimeType,
|
|
189
|
-
remoteIPAddress: response.remoteIPAddress,
|
|
190
|
-
remotePort: response.remotePort,
|
|
191
|
-
fromServiceWorker: response.fromServiceWorker,
|
|
192
|
-
redirectURL: record.response.redirectURL,
|
|
193
|
-
timing: response.timing,
|
|
194
|
-
};
|
|
195
|
-
if (response.securityDetails) {
|
|
196
|
-
record.response.securityDetails = {
|
|
197
|
-
protocol: response.securityDetails.protocol,
|
|
198
|
-
subjectName: response.securityDetails.subjectName,
|
|
199
|
-
issuer: response.securityDetails.issuer,
|
|
200
|
-
validFrom: response.securityDetails.validFrom,
|
|
201
|
-
validTo: response.securityDetails.validTo,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
_onLoadingFinished(event: Protocol.Network.loadingFinishedPayload) {
|
|
207
|
-
const { requestId, timestamp, encodedDataLength } = event;
|
|
208
|
-
this._requestCompleted(requestId, timestamp, encodedDataLength);
|
|
144
|
+
request[NETWORK_ENTRY_SUMBOL] = networkEntry;
|
|
145
|
+
this.results.push(networkEntry);
|
|
209
146
|
}
|
|
210
147
|
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
this.
|
|
214
|
-
|
|
148
|
+
private async _onResponse(response: Response) {
|
|
149
|
+
const request = response.request();
|
|
150
|
+
const networkEntry = this._findNetworkEntry(request);
|
|
151
|
+
if (!networkEntry) return;
|
|
215
152
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
if (encodedDataLength >= 0) {
|
|
226
|
-
record.transferSize = encodedDataLength;
|
|
227
|
-
record.response.body = {
|
|
228
|
-
bytes: encodedDataLength,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
record.loadEndTime = endTime;
|
|
232
|
-
record.timings = calculateTimings(record);
|
|
233
|
-
this.results.push(record);
|
|
234
|
-
/**
|
|
235
|
-
* When there is DNS failure, browsers keeps retrying requests which
|
|
236
|
-
* might result in incorrect timings so we get remove them to measure only once
|
|
237
|
-
*/
|
|
238
|
-
this._InflightRequestMap.delete(requestId);
|
|
239
|
-
}
|
|
153
|
+
networkEntry.responseReceivedTime = epochTimeInSeconds();
|
|
154
|
+
networkEntry.response = {
|
|
155
|
+
url: response.url(),
|
|
156
|
+
status: response.status(),
|
|
157
|
+
statusText: response.statusText(),
|
|
158
|
+
headers: {},
|
|
159
|
+
mimeType: 'x-unknown',
|
|
160
|
+
redirectURL: networkEntry.response.redirectURL,
|
|
161
|
+
};
|
|
240
162
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
163
|
+
const page = request.frame().page();
|
|
164
|
+
this._addBarrier(
|
|
165
|
+
page,
|
|
166
|
+
request.allHeaders().then(reqHeaders => {
|
|
167
|
+
networkEntry.request.headers = reqHeaders;
|
|
168
|
+
networkEntry.request.referrer = reqHeaders?.referer;
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
this._addBarrier(
|
|
172
|
+
page,
|
|
173
|
+
response.serverAddr().then(server => {
|
|
174
|
+
networkEntry.response.remoteIPAddress = server?.ipAddress;
|
|
175
|
+
networkEntry.response.remotePort = server?.port;
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
this._addBarrier(
|
|
179
|
+
page,
|
|
180
|
+
response.securityDetails().then(details => {
|
|
181
|
+
if (details) networkEntry.response.securityDetails = details;
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
this._addBarrier(
|
|
185
|
+
page,
|
|
186
|
+
response.allHeaders().then(resHeaders => {
|
|
187
|
+
networkEntry.response.headers = resHeaders;
|
|
245
188
|
|
|
246
|
-
|
|
247
|
-
|
|
189
|
+
const contentType = resHeaders['content-type'];
|
|
190
|
+
if (contentType)
|
|
191
|
+
networkEntry.response.mimeType = contentType.split(';')[0];
|
|
192
|
+
})
|
|
193
|
+
);
|
|
248
194
|
}
|
|
249
|
-
}
|
|
250
195
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
) {
|
|
255
|
-
if (timing == null) {
|
|
256
|
-
return responseReceivedTime;
|
|
257
|
-
}
|
|
258
|
-
const startTime = timing.requestTime;
|
|
259
|
-
const headersReceivedTime = startTime + timing.receiveHeadersEnd / 1000;
|
|
260
|
-
if (responseReceivedTime < 0 || responseReceivedTime > headersReceivedTime) {
|
|
261
|
-
responseReceivedTime = headersReceivedTime;
|
|
262
|
-
}
|
|
263
|
-
if (startTime > responseReceivedTime) {
|
|
264
|
-
responseReceivedTime = startTime;
|
|
265
|
-
}
|
|
266
|
-
return responseReceivedTime;
|
|
267
|
-
}
|
|
196
|
+
private async _onRequestCompleted(request: Request) {
|
|
197
|
+
const networkEntry = this._findNetworkEntry(request);
|
|
198
|
+
if (!networkEntry) return;
|
|
268
199
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
wait: -1,
|
|
283
|
-
receive: -1,
|
|
284
|
-
total: -1,
|
|
285
|
-
};
|
|
200
|
+
networkEntry.loadEndTime = epochTimeInSeconds();
|
|
201
|
+
const timing = request.timing();
|
|
202
|
+
const { loadEndTime, requestSentTime } = networkEntry;
|
|
203
|
+
networkEntry.timings = {
|
|
204
|
+
blocked: -1,
|
|
205
|
+
dns: -1,
|
|
206
|
+
ssl: -1,
|
|
207
|
+
connect: -1,
|
|
208
|
+
send: -1,
|
|
209
|
+
wait: -1,
|
|
210
|
+
receive: -1,
|
|
211
|
+
total: -1,
|
|
212
|
+
};
|
|
286
213
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
) => {
|
|
293
|
-
if (start < Number.MAX_VALUE && start <= end) {
|
|
294
|
-
result[name] = toMilliseconds(end - start);
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
const firstPositive = (numbers: number[]) => {
|
|
298
|
-
for (let i = 0; i < numbers.length; ++i) {
|
|
299
|
-
if (numbers[i] > 0) {
|
|
300
|
-
return numbers[i];
|
|
214
|
+
const firstPositive = (numbers: number[]) => {
|
|
215
|
+
for (let i = 0; i < numbers.length; ++i) {
|
|
216
|
+
if (numbers[i] > 0) {
|
|
217
|
+
return numbers[i];
|
|
218
|
+
}
|
|
301
219
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* from the requestTime, so we calculate the offset from that
|
|
308
|
-
*/
|
|
309
|
-
const addOffsetRange = (
|
|
310
|
-
name: keyof NetworkInfo['timings'],
|
|
311
|
-
start: number,
|
|
312
|
-
end: number
|
|
313
|
-
) => {
|
|
314
|
-
if (start >= 0 && end >= 0) {
|
|
315
|
-
calculateDiffInMs(name, startTime + start / 1000, startTime + end / 1000);
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
const { requestSentTime, loadEndTime, responseReceivedTime, response } =
|
|
319
|
-
record;
|
|
320
|
-
const timing = response.timing;
|
|
321
|
-
const actResRcvdTime = getResponseReceivedTime(timing, responseReceivedTime);
|
|
322
|
-
const issueTime = requestSentTime;
|
|
323
|
-
const startTime = timing == null ? -1 : timing.requestTime;
|
|
324
|
-
const endTime = firstPositive([loadEndTime, actResRcvdTime]) || startTime;
|
|
220
|
+
return null;
|
|
221
|
+
};
|
|
222
|
+
const roundMilliSecs = (value: number): number => {
|
|
223
|
+
return Math.floor(value * 1000) / 1000;
|
|
224
|
+
};
|
|
325
225
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
calculateDiffInMs('total', start, end);
|
|
332
|
-
calculateDiffInMs('blocked', start, middle);
|
|
333
|
-
calculateDiffInMs('receive', middle, end);
|
|
334
|
-
// Check if the request is blocked/stalled for the whole timeframe and
|
|
335
|
-
// calculate timings appropriately for that request
|
|
336
|
-
if (!isFinite(result['blocked'])) {
|
|
337
|
-
result['blocked'] = result['total'];
|
|
226
|
+
if (timing.startTime === 0) {
|
|
227
|
+
// Convert to milliseconds before round off
|
|
228
|
+
const total = roundMilliSecs((loadEndTime - requestSentTime) * 1000);
|
|
229
|
+
networkEntry.timings.total = total;
|
|
230
|
+
return;
|
|
338
231
|
}
|
|
339
|
-
return result;
|
|
340
|
-
}
|
|
341
|
-
calculateDiffInMs(
|
|
342
|
-
'total',
|
|
343
|
-
issueTime < startTime ? issueTime : startTime,
|
|
344
|
-
endTime
|
|
345
|
-
);
|
|
346
|
-
if (issueTime < startTime) {
|
|
347
|
-
calculateDiffInMs('queueing', issueTime, startTime);
|
|
348
|
-
}
|
|
349
|
-
const responseReceived = toMilliseconds(actResRcvdTime - startTime);
|
|
350
232
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
timing.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
233
|
+
const blocked =
|
|
234
|
+
roundMilliSecs(
|
|
235
|
+
firstPositive([
|
|
236
|
+
timing.domainLookupStart,
|
|
237
|
+
timing.connectStart,
|
|
238
|
+
timing.requestStart,
|
|
239
|
+
])
|
|
240
|
+
) || -1;
|
|
241
|
+
const dns =
|
|
242
|
+
timing.domainLookupEnd !== -1
|
|
243
|
+
? roundMilliSecs(timing.domainLookupEnd - timing.domainLookupStart)
|
|
244
|
+
: -1;
|
|
245
|
+
const connect =
|
|
246
|
+
timing.connectEnd !== -1
|
|
247
|
+
? roundMilliSecs(timing.connectEnd - timing.connectStart)
|
|
248
|
+
: -1;
|
|
249
|
+
const ssl =
|
|
250
|
+
timing.secureConnectionStart !== -1
|
|
251
|
+
? roundMilliSecs(timing.connectEnd - timing.secureConnectionStart)
|
|
252
|
+
: -1;
|
|
253
|
+
const wait =
|
|
254
|
+
timing.responseStart !== -1
|
|
255
|
+
? roundMilliSecs(timing.responseStart - timing.requestStart)
|
|
256
|
+
: -1;
|
|
257
|
+
const receive =
|
|
258
|
+
timing.responseEnd !== -1
|
|
259
|
+
? roundMilliSecs(timing.responseEnd - timing.responseStart)
|
|
260
|
+
: -1;
|
|
261
|
+
const total = [blocked, dns, connect, wait, receive].reduce(
|
|
262
|
+
(pre, cur) => (cur > 0 ? cur + pre : pre),
|
|
263
|
+
0
|
|
264
|
+
);
|
|
265
|
+
networkEntry.timings = {
|
|
266
|
+
blocked,
|
|
267
|
+
dns,
|
|
268
|
+
connect,
|
|
269
|
+
ssl,
|
|
270
|
+
wait,
|
|
271
|
+
send: 0, // not exposed via RT api
|
|
272
|
+
receive,
|
|
273
|
+
total,
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const page = request.frame().page();
|
|
277
|
+
// For aborted/failed requests sizes will not be present
|
|
278
|
+
this._addBarrier(
|
|
279
|
+
page,
|
|
280
|
+
request.sizes().then(sizes => {
|
|
281
|
+
networkEntry.request.bytes =
|
|
282
|
+
sizes.requestHeadersSize + sizes.requestBodySize;
|
|
283
|
+
networkEntry.request.body = {
|
|
284
|
+
bytes: sizes.requestBodySize,
|
|
285
|
+
};
|
|
286
|
+
networkEntry.response.bytes =
|
|
287
|
+
sizes.responseHeadersSize + sizes.responseBodySize;
|
|
288
|
+
networkEntry.response.body = {
|
|
289
|
+
bytes: sizes.responseBodySize,
|
|
290
|
+
};
|
|
291
|
+
networkEntry.transferSize = sizes.responseBodySize;
|
|
292
|
+
})
|
|
378
293
|
);
|
|
379
294
|
}
|
|
380
|
-
|
|
381
|
-
|
|
295
|
+
|
|
296
|
+
async stop() {
|
|
297
|
+
await Promise.all(this._barrierPromises);
|
|
298
|
+
const context = this.driver.context;
|
|
299
|
+
context.off('request', this._onRequest.bind(this));
|
|
300
|
+
context.off('response', this._onResponse.bind(this));
|
|
301
|
+
context.off('requestfinished', this._onRequestCompleted.bind(this));
|
|
302
|
+
context.off('requestfailed', this._onRequestCompleted.bind(this));
|
|
303
|
+
this._barrierPromises.clear();
|
|
304
|
+
return this.results;
|
|
305
|
+
}
|
|
382
306
|
}
|
|
@@ -102,11 +102,11 @@ export class PluginManager {
|
|
|
102
102
|
(this.get('network') as NetworkManager)._currentStep = step;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
output() {
|
|
105
|
+
async output() {
|
|
106
106
|
const data: PluginOutput = {};
|
|
107
107
|
for (const [, plugin] of this.plugins) {
|
|
108
108
|
if (plugin instanceof NetworkManager) {
|
|
109
|
-
data.networkinfo = plugin.stop();
|
|
109
|
+
data.networkinfo = await plugin.stop();
|
|
110
110
|
} else if (plugin instanceof BrowserConsole) {
|
|
111
111
|
data.browserconsole = plugin.stop();
|
|
112
112
|
}
|
package/src/reporters/json.ts
CHANGED
|
@@ -128,23 +128,8 @@ function getMetadata() {
|
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
function formatVersion(protocol: string | undefined) {
|
|
132
|
-
if (!protocol) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (protocol === 'h2') {
|
|
136
|
-
return 2;
|
|
137
|
-
} else if (protocol === 'http/1.1') {
|
|
138
|
-
return 1.1;
|
|
139
|
-
} else if (protocol === 'http/1.0') {
|
|
140
|
-
return 1.0;
|
|
141
|
-
} else if (protocol.startsWith('h3')) {
|
|
142
|
-
return 3;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
131
|
function formatTLS(tls: SecurityDetails) {
|
|
147
|
-
if (!tls) {
|
|
132
|
+
if (!tls || !tls.protocol) {
|
|
148
133
|
return;
|
|
149
134
|
}
|
|
150
135
|
const [name, version] = tls.protocol.toLowerCase().split(' ');
|
|
@@ -177,7 +162,6 @@ export function formatNetworkFields(network: NetworkInfo) {
|
|
|
177
162
|
original: request.headers?.['User-Agent'],
|
|
178
163
|
},
|
|
179
164
|
http: {
|
|
180
|
-
version: formatVersion(response?.protocol),
|
|
181
165
|
request,
|
|
182
166
|
response,
|
|
183
167
|
},
|