@elastic/synthetics 1.0.0-beta.22 → 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/CHANGELOG.md +23 -0
- package/NOTICE.txt +0 -29
- package/dist/cli.js +55 -184
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +43 -36
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/gatherer.d.ts +2 -3
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +17 -9
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -9
- package/dist/core/index.js.map +1 -1
- package/dist/core/runner.d.ts +1 -8
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +2 -3
- package/dist/core/runner.js.map +1 -1
- package/dist/dsl/journey.d.ts +4 -3
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +4 -3
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/step.d.ts +3 -2
- package/dist/dsl/step.d.ts.map +1 -1
- package/dist/dsl/step.js +2 -1
- package/dist/dsl/step.js.map +1 -1
- package/dist/formatter/javascript.d.ts +31 -6
- package/dist/formatter/javascript.d.ts.map +1 -1
- package/dist/formatter/javascript.js +45 -24
- package/dist/formatter/javascript.js.map +1 -1
- package/dist/helpers.d.ts +2 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +30 -1
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -17
- package/dist/index.js.map +1 -1
- package/dist/{parse_args.d.ts → loader.d.ts} +2 -5
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +144 -0
- package/dist/loader.js.map +1 -0
- package/dist/options.d.ts +27 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +108 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/network.d.ts +17 -33
- 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 +5 -24
- package/dist/reporters/json.js.map +1 -1
- package/dist/sdk/trace-metrics.js +3 -4
- package/dist/sdk/trace-metrics.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/src/cli.ts +114 -188
- package/src/common_types.ts +47 -36
- package/src/core/gatherer.ts +17 -10
- package/src/core/index.ts +22 -16
- package/src/core/runner.ts +3 -23
- package/src/dsl/journey.ts +10 -4
- package/src/dsl/step.ts +9 -2
- package/src/formatter/javascript.ts +59 -22
- package/src/helpers.ts +40 -1
- package/src/index.ts +10 -16
- package/src/loader.ts +162 -0
- package/src/options.ts +116 -0
- package/src/plugins/network.ts +218 -293
- package/src/plugins/plugin-manager.ts +2 -2
- package/src/reporters/json.ts +1 -17
- package/dist/parse_args.d.ts.map +0 -1
- package/dist/parse_args.js +0 -103
- package/dist/parse_args.js.map +0 -1
- package/src/parse_args.ts +0 -158
package/src/plugins/network.ts
CHANGED
|
@@ -23,359 +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
|
-
});
|
|
91
|
-
this._onResponseReceived(data);
|
|
92
|
-
this._onLoadingFinished(data);
|
|
93
|
-
} else {
|
|
94
|
-
/**
|
|
95
|
-
* Edge case, we handle it to proceed with next navigation
|
|
96
|
-
*/
|
|
97
|
-
this._onLoadingFailed(
|
|
98
|
-
Object.assign(event, {
|
|
99
|
-
type: event.type,
|
|
100
|
-
errorText: 'redirectResponse data is not available',
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
const redirectedRecord = this._findNetworkRecord(requestId);
|
|
105
|
-
/**
|
|
106
|
-
* Rewrite the map with new redirect id to not reset
|
|
107
|
-
* the redirect request with original request
|
|
108
|
-
*/
|
|
109
|
-
this._InflightRequestMap.delete(requestId);
|
|
110
|
-
this._InflightRequestMap.set(
|
|
111
|
-
`redirect:${timestamp}:${requestId}`,
|
|
112
|
-
redirectedRecord
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
108
|
|
|
116
|
-
|
|
109
|
+
const timestamp = getTimestamp();
|
|
110
|
+
const networkEntry: NetworkInfo = {
|
|
117
111
|
browser: this._browser,
|
|
118
112
|
step: this._currentStep,
|
|
119
|
-
timestamp
|
|
113
|
+
timestamp,
|
|
120
114
|
url,
|
|
121
|
-
type,
|
|
115
|
+
type: request.resourceType(),
|
|
122
116
|
request: {
|
|
123
117
|
url,
|
|
124
|
-
method,
|
|
125
|
-
headers,
|
|
126
|
-
|
|
118
|
+
method: request.method(),
|
|
119
|
+
headers: {},
|
|
120
|
+
body: {
|
|
121
|
+
bytes: request.postDataBuffer()?.length || 0,
|
|
122
|
+
},
|
|
127
123
|
},
|
|
128
124
|
response: {
|
|
129
125
|
status: -1,
|
|
130
|
-
mimeType: 'x-unknown',
|
|
131
126
|
headers: {},
|
|
132
|
-
|
|
127
|
+
mimeType: 'x-unknown',
|
|
128
|
+
redirectURL: '',
|
|
133
129
|
},
|
|
134
|
-
isNavigationRequest,
|
|
135
|
-
requestSentTime:
|
|
136
|
-
responseReceivedTime: -1,
|
|
130
|
+
isNavigationRequest: request.isNavigationRequest(),
|
|
131
|
+
requestSentTime: epochTimeInSeconds(),
|
|
137
132
|
loadEndTime: -1,
|
|
133
|
+
responseReceivedTime: -1,
|
|
138
134
|
resourceSize: 0,
|
|
139
135
|
transferSize: 0,
|
|
140
136
|
timings: null,
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
_onRequestWillBeSentExtraInfo(
|
|
145
|
-
event: Protocol.Network.requestWillBeSentExtraInfoPayload
|
|
146
|
-
) {
|
|
147
|
-
const { requestId, headers } = event;
|
|
148
|
-
const record = this._findNetworkRecord(requestId);
|
|
149
|
-
if (!record) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Enhance request headers with additional information
|
|
154
|
-
*/
|
|
155
|
-
record.request.headers = {
|
|
156
|
-
...record.request.headers,
|
|
157
|
-
...headers,
|
|
158
137
|
};
|
|
159
|
-
record.request.referrer = record.request.headers?.Referer;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
_onDataReceived(event: Protocol.Network.dataReceivedPayload) {
|
|
163
|
-
const { requestId, dataLength, encodedDataLength } = event;
|
|
164
|
-
const record = this._findNetworkRecord(requestId);
|
|
165
|
-
if (!record) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
record.resourceSize += dataLength;
|
|
169
|
-
if (encodedDataLength >= 0) record.transferSize += encodedDataLength;
|
|
170
|
-
}
|
|
171
138
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!record) {
|
|
176
|
-
return;
|
|
139
|
+
if (request.redirectedFrom()) {
|
|
140
|
+
const fromEntry = this._findNetworkEntry(request.redirectedFrom());
|
|
141
|
+
if (fromEntry) fromEntry.response.redirectURL = request.url();
|
|
177
142
|
}
|
|
178
143
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
record.response = {
|
|
182
|
-
url: response.url,
|
|
183
|
-
status: response.status,
|
|
184
|
-
protocol: response.protocol,
|
|
185
|
-
statusText: response.statusText,
|
|
186
|
-
headers: response.headers,
|
|
187
|
-
mimeType: response.mimeType,
|
|
188
|
-
remoteIPAddress: response.remoteIPAddress,
|
|
189
|
-
remotePort: response.remotePort,
|
|
190
|
-
fromServiceWorker: response.fromServiceWorker,
|
|
191
|
-
redirectURL: record.response.redirectURL,
|
|
192
|
-
timing: response.timing,
|
|
193
|
-
};
|
|
194
|
-
if (response.securityDetails) {
|
|
195
|
-
record.response.securityDetails = {
|
|
196
|
-
protocol: response.securityDetails.protocol,
|
|
197
|
-
subjectName: response.securityDetails.subjectName,
|
|
198
|
-
issuer: response.securityDetails.issuer,
|
|
199
|
-
validFrom: response.securityDetails.validFrom,
|
|
200
|
-
validTo: response.securityDetails.validTo,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
_onLoadingFinished(event: Protocol.Network.loadingFinishedPayload) {
|
|
206
|
-
const { requestId, timestamp, encodedDataLength } = event;
|
|
207
|
-
this._requestCompleted(requestId, timestamp, encodedDataLength);
|
|
144
|
+
request[NETWORK_ENTRY_SUMBOL] = networkEntry;
|
|
145
|
+
this.results.push(networkEntry);
|
|
208
146
|
}
|
|
209
147
|
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
this.
|
|
213
|
-
|
|
148
|
+
private async _onResponse(response: Response) {
|
|
149
|
+
const request = response.request();
|
|
150
|
+
const networkEntry = this._findNetworkEntry(request);
|
|
151
|
+
if (!networkEntry) return;
|
|
214
152
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
if (encodedDataLength >= 0) {
|
|
225
|
-
record.transferSize = encodedDataLength;
|
|
226
|
-
record.response.body = {
|
|
227
|
-
bytes: encodedDataLength,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
record.loadEndTime = endTime;
|
|
231
|
-
record.timings = calculateTimings(record);
|
|
232
|
-
this.results.push(record);
|
|
233
|
-
/**
|
|
234
|
-
* When there is DNS failure, browsers keeps retrying requests which
|
|
235
|
-
* might result in incorrect timings so we get remove them to measure only once
|
|
236
|
-
*/
|
|
237
|
-
this._InflightRequestMap.delete(requestId);
|
|
238
|
-
}
|
|
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
|
+
};
|
|
239
162
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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;
|
|
244
188
|
|
|
245
|
-
|
|
246
|
-
|
|
189
|
+
const contentType = resHeaders['content-type'];
|
|
190
|
+
if (contentType)
|
|
191
|
+
networkEntry.response.mimeType = contentType.split(';')[0];
|
|
192
|
+
})
|
|
193
|
+
);
|
|
247
194
|
}
|
|
248
|
-
}
|
|
249
195
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
) {
|
|
254
|
-
if (timing == null) {
|
|
255
|
-
return responseReceivedTime;
|
|
256
|
-
}
|
|
257
|
-
const startTime = timing.requestTime;
|
|
258
|
-
const headersReceivedTime = startTime + timing.receiveHeadersEnd / 1000;
|
|
259
|
-
if (responseReceivedTime < 0 || responseReceivedTime > headersReceivedTime) {
|
|
260
|
-
responseReceivedTime = headersReceivedTime;
|
|
261
|
-
}
|
|
262
|
-
if (startTime > responseReceivedTime) {
|
|
263
|
-
responseReceivedTime = startTime;
|
|
264
|
-
}
|
|
265
|
-
return responseReceivedTime;
|
|
266
|
-
}
|
|
196
|
+
private async _onRequestCompleted(request: Request) {
|
|
197
|
+
const networkEntry = this._findNetworkEntry(request);
|
|
198
|
+
if (!networkEntry) return;
|
|
267
199
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
wait: -1,
|
|
282
|
-
receive: -1,
|
|
283
|
-
total: -1,
|
|
284
|
-
};
|
|
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
|
+
};
|
|
285
213
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
) => {
|
|
292
|
-
if (start < Number.MAX_VALUE && start <= end) {
|
|
293
|
-
result[name] = toMilliseconds(end - start);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
const firstPositive = (numbers: number[]) => {
|
|
297
|
-
for (let i = 0; i < numbers.length; ++i) {
|
|
298
|
-
if (numbers[i] > 0) {
|
|
299
|
-
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
|
+
}
|
|
300
219
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* from the requestTime, so we calculate the offset from that
|
|
307
|
-
*/
|
|
308
|
-
const addOffsetRange = (
|
|
309
|
-
name: keyof NetworkInfo['timings'],
|
|
310
|
-
start: number,
|
|
311
|
-
end: number
|
|
312
|
-
) => {
|
|
313
|
-
if (start >= 0 && end >= 0) {
|
|
314
|
-
calculateDiffInMs(name, startTime + start / 1000, startTime + end / 1000);
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
const { requestSentTime, loadEndTime, responseReceivedTime, response } =
|
|
318
|
-
record;
|
|
319
|
-
const timing = response.timing;
|
|
320
|
-
const actResRcvdTime = getResponseReceivedTime(timing, responseReceivedTime);
|
|
321
|
-
const issueTime = requestSentTime;
|
|
322
|
-
const startTime = timing == null ? -1 : timing.requestTime;
|
|
323
|
-
const endTime = firstPositive([loadEndTime, actResRcvdTime]) || startTime;
|
|
220
|
+
return null;
|
|
221
|
+
};
|
|
222
|
+
const roundMilliSecs = (value: number): number => {
|
|
223
|
+
return Math.floor(value * 1000) / 1000;
|
|
224
|
+
};
|
|
324
225
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
calculateDiffInMs('total', start, end);
|
|
331
|
-
calculateDiffInMs('blocked', start, middle);
|
|
332
|
-
calculateDiffInMs('receive', middle, end);
|
|
333
|
-
// Check if the request is blocked/stalled for the whole timeframe and
|
|
334
|
-
// calculate timings appropriately for that request
|
|
335
|
-
if (!isFinite(result['blocked'])) {
|
|
336
|
-
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;
|
|
337
231
|
}
|
|
338
|
-
return result;
|
|
339
|
-
}
|
|
340
|
-
calculateDiffInMs(
|
|
341
|
-
'total',
|
|
342
|
-
issueTime < startTime ? issueTime : startTime,
|
|
343
|
-
endTime
|
|
344
|
-
);
|
|
345
|
-
if (issueTime < startTime) {
|
|
346
|
-
calculateDiffInMs('queueing', issueTime, startTime);
|
|
347
|
-
}
|
|
348
|
-
const responseReceived = toMilliseconds(actResRcvdTime - startTime);
|
|
349
232
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
timing.
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
+
})
|
|
377
293
|
);
|
|
378
294
|
}
|
|
379
|
-
|
|
380
|
-
|
|
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
|
+
}
|
|
381
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
|
},
|
package/dist/parse_args.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parse_args.d.ts","sourceRoot":"","sources":["../src/parse_args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAuFzC,QAAA,MAAM,OAAO,6BAA8B,CAAC;AAC5C,QAAA,MAAM,OAAO,SAA4B,CAAC;AA0C1C,OAAO,EAAE,OAAO,EAAE,CAAC;AACnB,eAAe,OAAO,CAAC"}
|