@checkly/playwright-core 1.51.11 → 1.51.12
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/lib/common/socksProxy.js +569 -0
- package/lib/common/timeoutSettings.js +73 -0
- package/lib/common/types.js +5 -0
- package/lib/generated/recorderSource.js +7 -0
- package/lib/image_tools/colorUtils.js +98 -0
- package/lib/image_tools/compare.js +108 -0
- package/lib/image_tools/imageChannel.js +70 -0
- package/lib/image_tools/stats.js +102 -0
- package/lib/protocol/transport.js +82 -0
- package/lib/server/fetch.js +4 -3
- package/lib/server/recorder/codeGenerator.js +154 -0
- package/lib/server/recorder/csharp.js +311 -0
- package/lib/server/recorder/java.js +249 -0
- package/lib/server/recorder/javascript.js +230 -0
- package/lib/server/recorder/jsonl.js +48 -0
- package/lib/server/recorder/language.js +45 -0
- package/lib/server/recorder/python.js +276 -0
- package/lib/server/recorder/recorderActions.js +6 -0
- package/lib/server/recorder/utils.js +46 -0
- package/lib/server/utils/happyEyeballs.js +9 -7
- package/lib/third_party/diff_match_patch.js +2222 -0
- package/lib/utils/ascii.js +31 -0
- package/lib/utils/comparators.js +171 -0
- package/lib/utils/crypto.js +174 -0
- package/lib/utils/debug.js +46 -0
- package/lib/utils/debugLogger.js +91 -0
- package/lib/utils/env.js +49 -0
- package/lib/utils/eventsHelper.js +38 -0
- package/lib/utils/glob.js +84 -0
- package/lib/utils/happy-eyeballs.js +210 -0
- package/lib/utils/headers.js +52 -0
- package/lib/utils/hostPlatform.js +133 -0
- package/lib/utils/httpServer.js +237 -0
- package/lib/utils/linuxUtils.js +78 -0
- package/lib/utils/manualPromise.js +109 -0
- package/lib/utils/mimeType.js +30 -0
- package/lib/utils/multimap.js +75 -0
- package/lib/utils/network.js +160 -0
- package/lib/utils/processLauncher.js +248 -0
- package/lib/utils/profiler.js +53 -0
- package/lib/utils/rtti.js +44 -0
- package/lib/utils/semaphore.js +51 -0
- package/lib/utils/spawnAsync.js +45 -0
- package/lib/utils/task.js +58 -0
- package/lib/utils/time.js +37 -0
- package/lib/utils/traceUtils.js +44 -0
- package/lib/utils/userAgent.js +105 -0
- package/lib/utils/wsServer.js +127 -0
- package/lib/utils/zipFile.js +75 -0
- package/lib/vite/traceViewer/sw.bundle.js +7888 -0
- package/package.json +1 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PythonLanguageGenerator = void 0;
|
|
7
|
+
var _language = require("./language");
|
|
8
|
+
var _utils = require("./utils");
|
|
9
|
+
var _stringUtils = require("../../utils/isomorphic/stringUtils");
|
|
10
|
+
var _locatorGenerators = require("../../utils/isomorphic/locatorGenerators");
|
|
11
|
+
/**
|
|
12
|
+
* Copyright (c) Microsoft Corporation.
|
|
13
|
+
*
|
|
14
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
* you may not use this file except in compliance with the License.
|
|
16
|
+
* You may obtain a copy of the License at
|
|
17
|
+
*
|
|
18
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
*
|
|
20
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
* See the License for the specific language governing permissions and
|
|
24
|
+
* limitations under the License.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const deviceDescriptors = require('../deviceDescriptorsSource.json');
|
|
28
|
+
class PythonLanguageGenerator {
|
|
29
|
+
constructor(isAsync, isPyTest) {
|
|
30
|
+
this.id = void 0;
|
|
31
|
+
this.groupName = 'Python';
|
|
32
|
+
this.name = void 0;
|
|
33
|
+
this.highlighter = 'python';
|
|
34
|
+
this._awaitPrefix = void 0;
|
|
35
|
+
this._asyncPrefix = void 0;
|
|
36
|
+
this._isAsync = void 0;
|
|
37
|
+
this._isPyTest = void 0;
|
|
38
|
+
this.id = isPyTest ? 'python-pytest' : isAsync ? 'python-async' : 'python';
|
|
39
|
+
this.name = isPyTest ? 'Pytest' : isAsync ? 'Library Async' : 'Library';
|
|
40
|
+
this._isAsync = isAsync;
|
|
41
|
+
this._isPyTest = isPyTest;
|
|
42
|
+
this._awaitPrefix = isAsync ? 'await ' : '';
|
|
43
|
+
this._asyncPrefix = isAsync ? 'async ' : '';
|
|
44
|
+
}
|
|
45
|
+
generateAction(actionInContext) {
|
|
46
|
+
const action = actionInContext.action;
|
|
47
|
+
if (this._isPyTest && (action.name === 'openPage' || action.name === 'closePage')) return '';
|
|
48
|
+
const pageAlias = actionInContext.frame.pageAlias;
|
|
49
|
+
const formatter = new PythonFormatter(4);
|
|
50
|
+
if (action.name === 'openPage') {
|
|
51
|
+
formatter.add(`${pageAlias} = ${this._awaitPrefix}context.new_page()`);
|
|
52
|
+
if (action.url && action.url !== 'about:blank' && action.url !== 'chrome://newtab/') formatter.add(`${this._awaitPrefix}${pageAlias}.goto(${quote(action.url)})`);
|
|
53
|
+
return formatter.format();
|
|
54
|
+
}
|
|
55
|
+
let subject;
|
|
56
|
+
if (actionInContext.frame.isMainFrame) {
|
|
57
|
+
subject = pageAlias;
|
|
58
|
+
} else {
|
|
59
|
+
const locators = actionInContext.frame.selectorsChain.map(selector => `.frame_locator(${quote(selector)})`);
|
|
60
|
+
subject = `${pageAlias}${locators.join('')}`;
|
|
61
|
+
}
|
|
62
|
+
const signals = (0, _language.toSignalMap)(action);
|
|
63
|
+
if (signals.dialog) formatter.add(` ${pageAlias}.once("dialog", lambda dialog: dialog.dismiss())`);
|
|
64
|
+
let code = `${this._awaitPrefix}${this._generateActionCall(subject, action)}`;
|
|
65
|
+
if (signals.popup) {
|
|
66
|
+
code = `${this._asyncPrefix}with ${pageAlias}.expect_popup() as ${signals.popup.popupAlias}_info {
|
|
67
|
+
${code}
|
|
68
|
+
}
|
|
69
|
+
${signals.popup.popupAlias} = ${this._awaitPrefix}${signals.popup.popupAlias}_info.value`;
|
|
70
|
+
}
|
|
71
|
+
if (signals.download) {
|
|
72
|
+
code = `${this._asyncPrefix}with ${pageAlias}.expect_download() as download${signals.download.downloadAlias}_info {
|
|
73
|
+
${code}
|
|
74
|
+
}
|
|
75
|
+
download${signals.download.downloadAlias} = ${this._awaitPrefix}download${signals.download.downloadAlias}_info.value`;
|
|
76
|
+
}
|
|
77
|
+
formatter.add(code);
|
|
78
|
+
return formatter.format();
|
|
79
|
+
}
|
|
80
|
+
_generateActionCall(subject, action) {
|
|
81
|
+
switch (action.name) {
|
|
82
|
+
case 'openPage':
|
|
83
|
+
throw Error('Not reached');
|
|
84
|
+
case 'closePage':
|
|
85
|
+
return `${subject}.close()`;
|
|
86
|
+
case 'click':
|
|
87
|
+
{
|
|
88
|
+
let method = 'click';
|
|
89
|
+
if (action.clickCount === 2) method = 'dblclick';
|
|
90
|
+
const modifiers = (0, _utils.toModifiers)(action.modifiers);
|
|
91
|
+
const options = {};
|
|
92
|
+
if (action.button !== 'left') options.button = action.button;
|
|
93
|
+
if (modifiers.length) options.modifiers = modifiers;
|
|
94
|
+
if (action.clickCount > 2) options.clickCount = action.clickCount;
|
|
95
|
+
if (action.position) options.position = action.position;
|
|
96
|
+
const optionsString = formatOptions(options, false);
|
|
97
|
+
return `${subject}.${this._asLocator(action.selector)}.${method}(${optionsString})`;
|
|
98
|
+
}
|
|
99
|
+
case 'check':
|
|
100
|
+
return `${subject}.${this._asLocator(action.selector)}.check()`;
|
|
101
|
+
case 'uncheck':
|
|
102
|
+
return `${subject}.${this._asLocator(action.selector)}.uncheck()`;
|
|
103
|
+
case 'fill':
|
|
104
|
+
return `${subject}.${this._asLocator(action.selector)}.fill(${quote(action.text)})`;
|
|
105
|
+
case 'setInputFiles':
|
|
106
|
+
return `${subject}.${this._asLocator(action.selector)}.set_input_files(${formatValue(action.files.length === 1 ? action.files[0] : action.files)})`;
|
|
107
|
+
case 'press':
|
|
108
|
+
{
|
|
109
|
+
const modifiers = (0, _utils.toModifiers)(action.modifiers);
|
|
110
|
+
const shortcut = [...modifiers, action.key].join('+');
|
|
111
|
+
return `${subject}.${this._asLocator(action.selector)}.press(${quote(shortcut)})`;
|
|
112
|
+
}
|
|
113
|
+
case 'navigate':
|
|
114
|
+
return `${subject}.goto(${quote(action.url)})`;
|
|
115
|
+
case 'select':
|
|
116
|
+
return `${subject}.${this._asLocator(action.selector)}.select_option(${formatValue(action.options.length === 1 ? action.options[0] : action.options)})`;
|
|
117
|
+
case 'assertText':
|
|
118
|
+
return `expect(${subject}.${this._asLocator(action.selector)}).${action.substring ? 'to_contain_text' : 'to_have_text'}(${quote(action.text)})`;
|
|
119
|
+
case 'assertChecked':
|
|
120
|
+
return `expect(${subject}.${this._asLocator(action.selector)}).${action.checked ? 'to_be_checked()' : 'not_to_be_checked()'}`;
|
|
121
|
+
case 'assertVisible':
|
|
122
|
+
return `expect(${subject}.${this._asLocator(action.selector)}).to_be_visible()`;
|
|
123
|
+
case 'assertValue':
|
|
124
|
+
{
|
|
125
|
+
const assertion = action.value ? `to_have_value(${quote(action.value)})` : `to_be_empty()`;
|
|
126
|
+
return `expect(${subject}.${this._asLocator(action.selector)}).${assertion};`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
_asLocator(selector) {
|
|
131
|
+
return (0, _locatorGenerators.asLocator)('python', selector);
|
|
132
|
+
}
|
|
133
|
+
generateHeader(options) {
|
|
134
|
+
const formatter = new PythonFormatter();
|
|
135
|
+
if (this._isPyTest) {
|
|
136
|
+
const contextOptions = formatContextOptions(options.contextOptions, options.deviceName, true /* asDict */);
|
|
137
|
+
const fixture = contextOptions ? `
|
|
138
|
+
|
|
139
|
+
@pytest.fixture(scope="session")
|
|
140
|
+
def browser_context_args(browser_context_args, playwright) {
|
|
141
|
+
return {${contextOptions}}
|
|
142
|
+
}
|
|
143
|
+
` : '';
|
|
144
|
+
formatter.add(`${options.deviceName ? 'import pytest\n' : ''}
|
|
145
|
+
from playwright.sync_api import Page, expect
|
|
146
|
+
${fixture}
|
|
147
|
+
|
|
148
|
+
def test_example(page: Page) -> None {`);
|
|
149
|
+
} else if (this._isAsync) {
|
|
150
|
+
formatter.add(`
|
|
151
|
+
import asyncio
|
|
152
|
+
|
|
153
|
+
from playwright.async_api import Playwright, async_playwright, expect
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
async def run(playwright: Playwright) -> None {
|
|
157
|
+
browser = await playwright.${options.browserName}.launch(${formatOptions(options.launchOptions, false)})
|
|
158
|
+
context = await browser.new_context(${formatContextOptions(options.contextOptions, options.deviceName)})`);
|
|
159
|
+
} else {
|
|
160
|
+
formatter.add(`
|
|
161
|
+
from playwright.sync_api import Playwright, sync_playwright, expect
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def run(playwright: Playwright) -> None {
|
|
165
|
+
browser = playwright.${options.browserName}.launch(${formatOptions(options.launchOptions, false)})
|
|
166
|
+
context = browser.new_context(${formatContextOptions(options.contextOptions, options.deviceName)})`);
|
|
167
|
+
}
|
|
168
|
+
return formatter.format();
|
|
169
|
+
}
|
|
170
|
+
generateFooter(saveStorage) {
|
|
171
|
+
if (this._isPyTest) {
|
|
172
|
+
return '';
|
|
173
|
+
} else if (this._isAsync) {
|
|
174
|
+
const storageStateLine = saveStorage ? `\n await context.storage_state(path=${quote(saveStorage)})` : '';
|
|
175
|
+
return `\n # ---------------------${storageStateLine}
|
|
176
|
+
await context.close()
|
|
177
|
+
await browser.close()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def main() -> None:
|
|
181
|
+
async with async_playwright() as playwright:
|
|
182
|
+
await run(playwright)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
asyncio.run(main())
|
|
186
|
+
`;
|
|
187
|
+
} else {
|
|
188
|
+
const storageStateLine = saveStorage ? `\n context.storage_state(path=${quote(saveStorage)})` : '';
|
|
189
|
+
return `\n # ---------------------${storageStateLine}
|
|
190
|
+
context.close()
|
|
191
|
+
browser.close()
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
with sync_playwright() as playwright:
|
|
195
|
+
run(playwright)
|
|
196
|
+
`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
exports.PythonLanguageGenerator = PythonLanguageGenerator;
|
|
201
|
+
function formatValue(value) {
|
|
202
|
+
if (value === false) return 'False';
|
|
203
|
+
if (value === true) return 'True';
|
|
204
|
+
if (value === undefined) return 'None';
|
|
205
|
+
if (Array.isArray(value)) return `[${value.map(formatValue).join(', ')}]`;
|
|
206
|
+
if (typeof value === 'string') return quote(value);
|
|
207
|
+
if (typeof value === 'object') return JSON.stringify(value);
|
|
208
|
+
return String(value);
|
|
209
|
+
}
|
|
210
|
+
function formatOptions(value, hasArguments, asDict) {
|
|
211
|
+
const keys = Object.keys(value).filter(key => value[key] !== undefined).sort();
|
|
212
|
+
if (!keys.length) return '';
|
|
213
|
+
return (hasArguments ? ', ' : '') + keys.map(key => {
|
|
214
|
+
if (asDict) return `"${(0, _stringUtils.toSnakeCase)(key)}": ${formatValue(value[key])}`;
|
|
215
|
+
return `${(0, _stringUtils.toSnakeCase)(key)}=${formatValue(value[key])}`;
|
|
216
|
+
}).join(', ');
|
|
217
|
+
}
|
|
218
|
+
function convertContextOptions(options) {
|
|
219
|
+
const result = {
|
|
220
|
+
...options
|
|
221
|
+
};
|
|
222
|
+
if (options.recordHar) {
|
|
223
|
+
result['record_har_path'] = options.recordHar.path;
|
|
224
|
+
result['record_har_content'] = options.recordHar.content;
|
|
225
|
+
result['record_har_mode'] = options.recordHar.mode;
|
|
226
|
+
result['record_har_omit_content'] = options.recordHar.omitContent;
|
|
227
|
+
result['record_har_url_filter'] = options.recordHar.urlFilter;
|
|
228
|
+
delete result.recordHar;
|
|
229
|
+
}
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
function formatContextOptions(options, deviceName, asDict) {
|
|
233
|
+
const device = deviceName && deviceDescriptors[deviceName];
|
|
234
|
+
if (!device) return formatOptions(convertContextOptions(options), false, asDict);
|
|
235
|
+
return `**playwright.devices[${quote(deviceName)}]` + formatOptions(convertContextOptions((0, _language.sanitizeDeviceOptions)(device, options)), true, asDict);
|
|
236
|
+
}
|
|
237
|
+
class PythonFormatter {
|
|
238
|
+
constructor(offset = 0) {
|
|
239
|
+
this._baseIndent = void 0;
|
|
240
|
+
this._baseOffset = void 0;
|
|
241
|
+
this._lines = [];
|
|
242
|
+
this._baseIndent = ' '.repeat(4);
|
|
243
|
+
this._baseOffset = ' '.repeat(offset);
|
|
244
|
+
}
|
|
245
|
+
prepend(text) {
|
|
246
|
+
this._lines = text.trim().split('\n').map(line => line.trim()).concat(this._lines);
|
|
247
|
+
}
|
|
248
|
+
add(text) {
|
|
249
|
+
this._lines.push(...text.trim().split('\n').map(line => line.trim()));
|
|
250
|
+
}
|
|
251
|
+
newLine() {
|
|
252
|
+
this._lines.push('');
|
|
253
|
+
}
|
|
254
|
+
format() {
|
|
255
|
+
let spaces = '';
|
|
256
|
+
const lines = [];
|
|
257
|
+
this._lines.forEach(line => {
|
|
258
|
+
if (line === '') return lines.push(line);
|
|
259
|
+
if (line === '}') {
|
|
260
|
+
spaces = spaces.substring(this._baseIndent.length);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
line = spaces + line;
|
|
264
|
+
if (line.endsWith('{')) {
|
|
265
|
+
spaces += this._baseIndent;
|
|
266
|
+
line = line.substring(0, line.length - 1).trimEnd() + ':';
|
|
267
|
+
}
|
|
268
|
+
return lines.push(this._baseOffset + line);
|
|
269
|
+
});
|
|
270
|
+
return lines.join('\n');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function quote(text) {
|
|
274
|
+
return (0, _stringUtils.escapeWithQuotes)(text, '\"');
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=python.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.toClickOptions = toClickOptions;
|
|
7
|
+
exports.toModifiers = toModifiers;
|
|
8
|
+
/**
|
|
9
|
+
* Copyright (c) Microsoft Corporation.
|
|
10
|
+
*
|
|
11
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
* you may not use this file except in compliance with the License.
|
|
13
|
+
* You may obtain a copy of the License at
|
|
14
|
+
*
|
|
15
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
* See the License for the specific language governing permissions and
|
|
21
|
+
* limitations under the License.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
function toClickOptions(action) {
|
|
25
|
+
let method = 'click';
|
|
26
|
+
if (action.clickCount === 2) method = 'dblclick';
|
|
27
|
+
const modifiers = toModifiers(action.modifiers);
|
|
28
|
+
const options = {};
|
|
29
|
+
if (action.button !== 'left') options.button = action.button;
|
|
30
|
+
if (modifiers.length) options.modifiers = modifiers;
|
|
31
|
+
if (action.clickCount > 2) options.clickCount = action.clickCount;
|
|
32
|
+
if (action.position) options.position = action.position;
|
|
33
|
+
return {
|
|
34
|
+
method,
|
|
35
|
+
options
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function toModifiers(modifiers) {
|
|
39
|
+
const result = [];
|
|
40
|
+
if (modifiers & 1) result.push('Alt');
|
|
41
|
+
if (modifiers & 2) result.push('Control');
|
|
42
|
+
if (modifiers & 4) result.push('Meta');
|
|
43
|
+
if (modifiers & 8) result.push('Shift');
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.createConnectionAsync = createConnectionAsync;
|
|
7
7
|
exports.createSocket = createSocket;
|
|
8
8
|
exports.createTLSSocket = createTLSSocket;
|
|
9
|
-
exports.httpsHappyEyeballsAgent = exports.httpHappyEyeballsAgent = void 0;
|
|
9
|
+
exports.httpsHappyEyeballsAgent = exports.httpHappyEyeballsTimings = exports.httpHappyEyeballsAgent = void 0;
|
|
10
10
|
exports.timingForSocket = timingForSocket;
|
|
11
11
|
var _dns = _interopRequireDefault(require("dns"));
|
|
12
12
|
var _http = _interopRequireDefault(require("http"));
|
|
@@ -38,7 +38,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
38
38
|
|
|
39
39
|
// Same as in Chromium (https://source.chromium.org/chromium/chromium/src/+/5666ff4f5077a7e2f72902f3a95f5d553ea0d88d:net/socket/transport_connect_job.cc;l=102)
|
|
40
40
|
const connectionAttemptDelayMs = 300;
|
|
41
|
-
const
|
|
41
|
+
const checklyTimings = {
|
|
42
42
|
values: {
|
|
43
43
|
startTimeNow: 0,
|
|
44
44
|
socket: 0,
|
|
@@ -58,8 +58,8 @@ class HttpHappyEyeballsAgent extends _http.default.Agent {
|
|
|
58
58
|
}
|
|
59
59
|
class HttpsHappyEyeballsAgent extends _https.default.Agent {
|
|
60
60
|
createConnection(options, oncreate) {
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
checklyTimings.values.startTimeNow = performance.now();
|
|
62
|
+
checklyTimings.agent = true;
|
|
63
63
|
// There is no ambiguity in case of IP address.
|
|
64
64
|
if (_net.default.isIP(clientRequestArgsToHostName(options))) return _tls.default.connect(options);
|
|
65
65
|
createConnectionAsync(options, oncreate, /* useTLS */true).catch(err => oncreate === null || oncreate === void 0 ? void 0 : oncreate(err));
|
|
@@ -73,6 +73,7 @@ const httpsHappyEyeballsAgent = exports.httpsHappyEyeballsAgent = new HttpsHappy
|
|
|
73
73
|
const httpHappyEyeballsAgent = exports.httpHappyEyeballsAgent = new HttpHappyEyeballsAgent({
|
|
74
74
|
keepAlive: true
|
|
75
75
|
});
|
|
76
|
+
const httpHappyEyeballsTimings = exports.httpHappyEyeballsTimings = checklyTimings;
|
|
76
77
|
async function createSocket(host, port) {
|
|
77
78
|
return new Promise((resolve, reject) => {
|
|
78
79
|
if (_net.default.isIP(host)) {
|
|
@@ -139,15 +140,16 @@ async function createConnectionAsync(options, oncreate, useTLS) {
|
|
|
139
140
|
port: options.port,
|
|
140
141
|
host: address
|
|
141
142
|
});
|
|
143
|
+
|
|
142
144
|
// Socket created
|
|
143
|
-
|
|
144
|
-
socket[kDNSLookupAt] = dnsLookupAt;
|
|
145
|
+
checklyTimings.values.socket = performance.now() - checklyTimings.values.startTimeNow;
|
|
145
146
|
socket[kDNSLookupAt] = dnsLookupAt;
|
|
146
147
|
|
|
147
148
|
// Each socket may fire only one of 'connect', 'timeout' or 'error' events.
|
|
148
149
|
// None of these events are fired after socket.destroy() is called.
|
|
149
150
|
socket.on('connect', () => {
|
|
150
151
|
socket[kTCPConnectionAt] = (0, _time.monotonicTime)();
|
|
152
|
+
checklyTimings.values.connect = performance.now() - checklyTimings.values.startTimeNow;
|
|
151
153
|
connected.resolve();
|
|
152
154
|
oncreate === null || oncreate === void 0 || oncreate(null, socket);
|
|
153
155
|
// TODO: Cache the result?
|
|
@@ -173,7 +175,7 @@ async function lookupAddresses(hostname) {
|
|
|
173
175
|
family: 0,
|
|
174
176
|
verbatim: true
|
|
175
177
|
});
|
|
176
|
-
|
|
178
|
+
checklyTimings.values.lookup = performance.now() - checklyTimings.values.startTimeNow;
|
|
177
179
|
let firstFamily = addresses.filter(({
|
|
178
180
|
family
|
|
179
181
|
}) => family === 6);
|