@mablhq/mabl-cli 1.12.33 → 1.13.19
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/api/basicApiClient.js +63 -26
- package/api/mablApiClientFactory.js +1 -0
- package/browserLauncher/browserLauncherFactory.js +7 -3
- package/browserLauncher/playwrightBrowserLauncher/playwrightBrowser.js +4 -0
- package/browserLauncher/playwrightBrowserLauncher/playwrightBrowserLauncher.js +1 -0
- package/browserLauncher/playwrightBrowserLauncher/playwrightDom.js +38 -12
- package/browserLauncher/playwrightBrowserLauncher/playwrightFrame.js +10 -0
- package/browserLauncher/playwrightBrowserLauncher/playwrightHttpResponse.js +3 -0
- package/browserLauncher/playwrightBrowserLauncher/playwrightPage.js +61 -57
- package/browserLauncher/puppeteerBrowserLauncher/puppeteerBrowser.js +4 -0
- package/browserLauncher/puppeteerBrowserLauncher/puppeteerElementHandle.js +7 -1
- package/browserLauncher/puppeteerBrowserLauncher/puppeteerHttpResponse.js +3 -0
- package/browserLauncher/types.js +6 -1
- package/commands/tests/testsUtil.js +6 -3
- package/commands/tests/tests_cmds/run-cloud.js +1 -1
- package/commands/tests/tests_cmds/run.js +20 -2
- package/execution/index.js +1 -1
- package/execution/index.js.LICENSE.txt +12 -0
- package/index.d.ts +7 -0
- package/mablscript/steps/SendHttpRequestStep.js +9 -1
- package/package.json +3 -2
- package/popupDismissal/index.js +29 -23
- package/resources/popupDismissal.js +1 -1
- package/util/actionabilityUtil.js +55 -7
- package/util/asyncUtil.js +45 -0
- package/util/logUtils.js +2 -2
- package/util/resourceUtil.js +4 -0
package/api/basicApiClient.js
CHANGED
|
@@ -28,8 +28,12 @@ const httpUtil_1 = require("../util/httpUtil");
|
|
|
28
28
|
const axios_1 = __importDefault(require("axios"));
|
|
29
29
|
const os = __importStar(require("os"));
|
|
30
30
|
const async_retry_1 = __importDefault(require("async-retry"));
|
|
31
|
+
const logUtils_1 = require("../util/logUtils");
|
|
32
|
+
const asyncUtil_1 = require("../util/asyncUtil");
|
|
31
33
|
const MABL_ENTITY_VERSION_HEADER = 'x-mabl-entity-version';
|
|
32
|
-
const
|
|
34
|
+
const DEFAULT_REQUEST_TIMEOUT_MILLISECONDS = 60000;
|
|
35
|
+
const DEFAULT_RETRIES = 5;
|
|
36
|
+
const DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS = DEFAULT_REQUEST_TIMEOUT_MILLISECONDS * DEFAULT_RETRIES;
|
|
33
37
|
const DEFAULT_MIN_RETRY_TIMEOUT_MILLISECONDS = 100;
|
|
34
38
|
const DEFAULT_MAX_RETRY_TIMEOUT_MILLISECONDS = 1000;
|
|
35
39
|
var AuthType;
|
|
@@ -39,10 +43,12 @@ var AuthType;
|
|
|
39
43
|
})(AuthType = exports.AuthType || (exports.AuthType = {}));
|
|
40
44
|
class BasicApiClient {
|
|
41
45
|
constructor(options) {
|
|
46
|
+
var _a, _b;
|
|
42
47
|
const config = httpUtil_1.axiosProxyConfig({
|
|
43
48
|
sslVerify: options.sslVerify,
|
|
44
49
|
proxyHost: options.proxyUrl,
|
|
45
50
|
});
|
|
51
|
+
config.timeout = (_a = options.requestTimeoutMillis) !== null && _a !== void 0 ? _a : DEFAULT_REQUEST_TIMEOUT_MILLISECONDS;
|
|
46
52
|
switch (options.authType) {
|
|
47
53
|
case AuthType.ApiKey:
|
|
48
54
|
config.auth = {
|
|
@@ -64,23 +70,27 @@ class BasicApiClient {
|
|
|
64
70
|
'x-mabl-user-platform': `${os.platform()}-${os.release()}`,
|
|
65
71
|
},
|
|
66
72
|
};
|
|
73
|
+
if (options.userAgentOverride) {
|
|
74
|
+
config.headers[httpUtil_1.USER_AGENT_HEADER] = options.userAgentOverride;
|
|
75
|
+
}
|
|
67
76
|
this.httpClient = axios_1.default.create(config);
|
|
68
77
|
this.retryConfig = options.retryConfig;
|
|
78
|
+
this.debugLogger = (_b = options.debugLogger) !== null && _b !== void 0 ? _b : logUtils_1.logInternal;
|
|
69
79
|
}
|
|
70
|
-
|
|
71
|
-
return this.retryWrappedRequest(
|
|
80
|
+
makeGetRequest(path) {
|
|
81
|
+
return this.retryWrappedRequest(`makeGetRequest('${path}')`, () => this.getRequest(path));
|
|
72
82
|
}
|
|
73
83
|
async getRequest(path) {
|
|
74
|
-
const response = await this.httpClient.get(path);
|
|
84
|
+
const response = await this.debugRequest('GET', path, () => this.httpClient.get(path));
|
|
75
85
|
BasicApiClient.checkResponseStatusCode(response);
|
|
76
86
|
return response.data;
|
|
77
87
|
}
|
|
78
|
-
|
|
79
|
-
return this.retryWrappedRequest(
|
|
88
|
+
makeGetRequestWithETag(path) {
|
|
89
|
+
return this.retryWrappedRequest(`makeGetRequestWithETag('${path}')`, () => this.getRequestWithETag(path));
|
|
80
90
|
}
|
|
81
91
|
async getRequestWithETag(path) {
|
|
82
92
|
var _a;
|
|
83
|
-
const response = await this.httpClient.get(path);
|
|
93
|
+
const response = await this.debugRequest('GET', path, () => this.httpClient.get(path));
|
|
84
94
|
BasicApiClient.checkResponseStatusCode(response);
|
|
85
95
|
const headers = response.headers;
|
|
86
96
|
const result = response.data;
|
|
@@ -91,58 +101,85 @@ class BasicApiClient {
|
|
|
91
101
|
return { ...result, entity_version: versionHeader };
|
|
92
102
|
}
|
|
93
103
|
async makePostRequest(path, requestBody, requestConfig) {
|
|
94
|
-
const response = await this.httpClient.post(path, requestBody, requestConfig);
|
|
104
|
+
const response = await this.debugRequest('POST', path, () => this.httpClient.post(path, requestBody, requestConfig));
|
|
95
105
|
BasicApiClient.checkResponseStatusCode(response);
|
|
96
106
|
return response.data;
|
|
97
107
|
}
|
|
98
108
|
async makePutRequest(path, requestBody) {
|
|
99
|
-
const response = await this.httpClient.put(path, requestBody);
|
|
109
|
+
const response = await this.debugRequest('PUT', path, () => this.httpClient.put(path, requestBody));
|
|
100
110
|
BasicApiClient.checkResponseStatusCode(response);
|
|
101
111
|
return response.data;
|
|
102
112
|
}
|
|
103
|
-
|
|
104
|
-
return this.retryWrappedRequest(
|
|
113
|
+
makeDeleteRequest(path) {
|
|
114
|
+
return this.retryWrappedRequest(`makeDeleteRequest('${path}')`, () => this.deleteRequest(path));
|
|
105
115
|
}
|
|
106
116
|
async deleteRequest(path) {
|
|
107
|
-
const response = await this.
|
|
117
|
+
const response = await this.debugRequest('DELETE', path, () => this.deleteRequest(path));
|
|
108
118
|
BasicApiClient.checkResponseStatusCode(response);
|
|
109
119
|
return response.data;
|
|
110
120
|
}
|
|
111
121
|
async makePatchRequest(path, requestBody, ifMatch) {
|
|
112
122
|
const extraConfig = ifMatch ? { headers: { 'If-Match': ifMatch } } : {};
|
|
113
|
-
const response = await this.httpClient.patch(path, requestBody, extraConfig);
|
|
123
|
+
const response = await this.debugRequest('PATCH', path, () => this.httpClient.patch(path, requestBody, extraConfig));
|
|
114
124
|
BasicApiClient.checkResponseStatusCode(response);
|
|
115
125
|
return response.data;
|
|
116
126
|
}
|
|
127
|
+
async debugRequest(method, path, request) {
|
|
128
|
+
const startTimeMillis = Date.now();
|
|
129
|
+
let responseCode;
|
|
130
|
+
let error;
|
|
131
|
+
try {
|
|
132
|
+
this.debugLogger(`API Client: Sending ${method} ${path}`);
|
|
133
|
+
const response = await request();
|
|
134
|
+
responseCode = response.status;
|
|
135
|
+
return response;
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
error = e;
|
|
139
|
+
throw e;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
this.debugLogger(`API Client: ${method} ${path} ${error ? 'failed' : 'completed'} in ${Date.now() - startTimeMillis}ms with ${responseCode !== null && responseCode !== void 0 ? responseCode : error}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
117
145
|
static checkResponseStatusCode(response) {
|
|
118
146
|
const statusCode = response.status;
|
|
119
147
|
if (!statusCode || statusCode >= 400) {
|
|
120
148
|
throw new ApiError_1.ApiError(`[${statusCode} - ${response.statusText}]`, statusCode);
|
|
121
149
|
}
|
|
122
150
|
}
|
|
123
|
-
retryWrappedRequest(requestFunc) {
|
|
151
|
+
retryWrappedRequest(description, requestFunc) {
|
|
124
152
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
125
153
|
const retryOptions = {
|
|
126
|
-
retries: (_b = (_a = this.retryConfig) === null || _a === void 0 ? void 0 : _a.retryCount) !== null && _b !== void 0 ? _b :
|
|
154
|
+
retries: (_b = (_a = this.retryConfig) === null || _a === void 0 ? void 0 : _a.retryCount) !== null && _b !== void 0 ? _b : DEFAULT_RETRIES,
|
|
127
155
|
minTimeout: (_d = (_c = this.retryConfig) === null || _c === void 0 ? void 0 : _c.minTimeoutMillis) !== null && _d !== void 0 ? _d : DEFAULT_MIN_RETRY_TIMEOUT_MILLISECONDS,
|
|
128
156
|
maxTimeout: (_f = (_e = this.retryConfig) === null || _e === void 0 ? void 0 : _e.maxTimeoutMillis) !== null && _f !== void 0 ? _f : DEFAULT_MAX_RETRY_TIMEOUT_MILLISECONDS,
|
|
129
157
|
maxRetryTime: (_h = (_g = this.retryConfig) === null || _g === void 0 ? void 0 : _g.maxRetryTimeMillis) !== null && _h !== void 0 ? _h : DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS,
|
|
158
|
+
onRetry: (error) => {
|
|
159
|
+
this.debugLogger(`Retrying failed API request "${description}"`, error);
|
|
160
|
+
},
|
|
130
161
|
forever: false,
|
|
131
162
|
};
|
|
132
|
-
return async_retry_1.default(async (bail) =>
|
|
163
|
+
return asyncUtil_1.promiseWithTimeout(async_retry_1.default(async (bail) => {
|
|
133
164
|
var _a, _b;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
statusCode === 502 ||
|
|
137
|
-
statusCode === 503 ||
|
|
138
|
-
statusCode === 504) {
|
|
139
|
-
throw error;
|
|
165
|
+
try {
|
|
166
|
+
return await requestFunc();
|
|
140
167
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
catch (error) {
|
|
169
|
+
const axiosError = error;
|
|
170
|
+
const statusCode = (_a = axiosError.code) !== null && _a !== void 0 ? _a : (_b = axiosError.response) === null || _b === void 0 ? void 0 : _b.status;
|
|
171
|
+
if (statusCode === 429 ||
|
|
172
|
+
statusCode === 502 ||
|
|
173
|
+
statusCode === 503 ||
|
|
174
|
+
statusCode === 504) {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
bail(error);
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
144
181
|
}
|
|
145
|
-
}), retryOptions);
|
|
182
|
+
}, retryOptions), retryOptions.maxRetryTime + retryOptions.maxTimeout, 'Retryable API request');
|
|
146
183
|
}
|
|
147
184
|
}
|
|
148
185
|
exports.BasicApiClient = BasicApiClient;
|
|
@@ -45,6 +45,7 @@ class MablApiClientFactory {
|
|
|
45
45
|
proxyUrl: httpConfig.proxyHost,
|
|
46
46
|
sslVerify: httpConfig.sslVerify,
|
|
47
47
|
retryConfig: RETRY_CONFIG,
|
|
48
|
+
userAgentOverride: opts.userAgentOverride,
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
const authProvider = new authenticationProvider_1.AuthenticationProvider();
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.BrowserLauncherFactory = void 0;
|
|
4
7
|
const puppeteerBrowserLauncher_1 = require("./puppeteerBrowserLauncher/puppeteerBrowserLauncher");
|
|
@@ -6,20 +9,21 @@ const playwrightBrowserLauncher_1 = require("./playwrightBrowserLauncher/playwri
|
|
|
6
9
|
const runnerType_1 = require("./runnerType");
|
|
7
10
|
const logUtils_1 = require("../util/logUtils");
|
|
8
11
|
const loggingProvider_1 = require("../providers/logging/loggingProvider");
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
13
|
class BrowserLauncherFactory {
|
|
10
14
|
static getRunnerFromEnvironment() {
|
|
11
15
|
var _a;
|
|
12
16
|
return (_a = process.env.MABL_RUNNER) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
13
17
|
}
|
|
14
|
-
static createRunner(runnerType = runnerType_1.RunnerType.
|
|
18
|
+
static createRunner(runnerType = runnerType_1.RunnerType.Playwright, loggerFunc) {
|
|
15
19
|
const runnerFromEnv = BrowserLauncherFactory.getRunnerFromEnvironment();
|
|
16
20
|
const runner = runnerFromEnv ? runnerFromEnv : runnerType;
|
|
17
21
|
loggerFunc = loggerFunc !== null && loggerFunc !== void 0 ? loggerFunc : ((line) => logUtils_1.logCliOutput(loggingProvider_1.LogLevel.Info, line));
|
|
18
22
|
if (runner === runnerType_1.RunnerType.Playwright) {
|
|
19
|
-
loggerFunc(
|
|
23
|
+
loggerFunc(chalk_1.default.cyan(`Browser launcher:`, chalk_1.default.magenta('Playwright')));
|
|
20
24
|
return new playwrightBrowserLauncher_1.PlaywrightBrowserLauncher();
|
|
21
25
|
}
|
|
22
|
-
loggerFunc(
|
|
26
|
+
loggerFunc(chalk_1.default.cyan(`Browser launcher:`, chalk_1.default.magenta('Puppeteer')));
|
|
23
27
|
return new puppeteerBrowserLauncher_1.PuppeteerBrowserLauncher();
|
|
24
28
|
}
|
|
25
29
|
}
|
|
@@ -29,6 +29,7 @@ const browserLauncher_1 = require("../browserLauncher");
|
|
|
29
29
|
const playwrightPage_1 = require("./playwrightPage");
|
|
30
30
|
const path_1 = __importDefault(require("path"));
|
|
31
31
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
32
|
+
const runnerType_1 = require("../runnerType");
|
|
32
33
|
class PlaywrightBrowser extends events_1.default {
|
|
33
34
|
constructor(defaultContext, downloadDirectory, browserWSEndpoint) {
|
|
34
35
|
super();
|
|
@@ -49,6 +50,9 @@ class PlaywrightBrowser extends events_1.default {
|
|
|
49
50
|
fs_extra_1.default.mkdirSync(path_1.default.join(this.downloadDirectory));
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
getRunnerType() {
|
|
54
|
+
return runnerType_1.RunnerType.Playwright;
|
|
55
|
+
}
|
|
52
56
|
makeCdpCall(method, paramArgs) {
|
|
53
57
|
return this.cdpSession.send(method, paramArgs);
|
|
54
58
|
}
|
|
@@ -31,6 +31,7 @@ class PlaywrightBrowserLauncher {
|
|
|
31
31
|
viewport,
|
|
32
32
|
acceptDownloads: true,
|
|
33
33
|
httpCredentials: options.credentials,
|
|
34
|
+
extraHTTPHeaders: options.extraHttpHeaders,
|
|
34
35
|
isMobile: (_a = options.defaultDeviceDescriptor) === null || _a === void 0 ? void 0 : _a.isMobile,
|
|
35
36
|
deviceScaleFactor: (_b = options.defaultDeviceDescriptor) === null || _b === void 0 ? void 0 : _b.deviceScaleFactor,
|
|
36
37
|
hasTouch: (_c = options.defaultDeviceDescriptor) === null || _c === void 0 ? void 0 : _c.hasTouch,
|
|
@@ -19,13 +19,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.PlaywrightElementHandle = exports.PlaywrightJsHandle = exports.
|
|
22
|
+
exports.PlaywrightElementHandle = exports.PlaywrightJsHandle = exports.NAVIGATION_ERROR_MESSAGE = void 0;
|
|
23
23
|
const playwright = __importStar(require("@playwright/test"));
|
|
24
|
+
const types_1 = require("../types");
|
|
24
25
|
const utils_1 = require("../utils");
|
|
25
26
|
const logUtils_1 = require("../../util/logUtils");
|
|
26
27
|
const elementHandle_1 = require("../elementHandle");
|
|
27
28
|
const testsUtil_1 = require("../../commands/tests/testsUtil");
|
|
28
|
-
exports.
|
|
29
|
+
exports.NAVIGATION_ERROR_MESSAGE = 'waiting for scheduled navigations to finish';
|
|
29
30
|
class PlaywrightJsHandle {
|
|
30
31
|
constructor(handle, page) {
|
|
31
32
|
this.handle = handle;
|
|
@@ -125,15 +126,40 @@ class PlaywrightElementHandle extends PlaywrightJsHandle {
|
|
|
125
126
|
async boundingBox() {
|
|
126
127
|
return utils_1.mapIfNotNull(await this.element.boundingBox(), (boundingBox) => boundingBox);
|
|
127
128
|
}
|
|
128
|
-
click(options) {
|
|
129
|
-
var _a, _b;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
async click(options) {
|
|
130
|
+
var _a, _b, _c, _d;
|
|
131
|
+
const trial = (_a = options === null || options === void 0 ? void 0 : options.trial) !== null && _a !== void 0 ? _a : false;
|
|
132
|
+
try {
|
|
133
|
+
await this.element.click({
|
|
134
|
+
clickCount: (_b = options === null || options === void 0 ? void 0 : options.clickCount) !== null && _b !== void 0 ? _b : 1,
|
|
135
|
+
force: (_c = options === null || options === void 0 ? void 0 : options.force) !== null && _c !== void 0 ? _c : !trial,
|
|
136
|
+
timeout: (_d = options === null || options === void 0 ? void 0 : options.timeout) !== null && _d !== void 0 ? _d : types_1.DefaultTimeouts.quickActionTimeoutMs,
|
|
137
|
+
trial,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (error.message.includes(exports.NAVIGATION_ERROR_MESSAGE)) {
|
|
142
|
+
logUtils_1.logInternal(`Action timed out due to navigation timeout. ${error.toString()}`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
134
147
|
}
|
|
135
|
-
doubleClick() {
|
|
136
|
-
|
|
148
|
+
async doubleClick(options) {
|
|
149
|
+
var _a, _b, _c;
|
|
150
|
+
try {
|
|
151
|
+
const trial = (_a = options === null || options === void 0 ? void 0 : options.trial) !== null && _a !== void 0 ? _a : false;
|
|
152
|
+
return this.element.dblclick({
|
|
153
|
+
force: (_b = options === null || options === void 0 ? void 0 : options.force) !== null && _b !== void 0 ? _b : !trial,
|
|
154
|
+
timeout: (_c = options === null || options === void 0 ? void 0 : options.timeout) !== null && _c !== void 0 ? _c : types_1.DefaultTimeouts.quickActionTimeoutMs,
|
|
155
|
+
trial,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error.message.includes(exports.NAVIGATION_ERROR_MESSAGE)) {
|
|
160
|
+
logUtils_1.logInternal(`Action timed out due to navigation timeout. ${error.toString()}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
137
163
|
}
|
|
138
164
|
async clickablePoint() {
|
|
139
165
|
var _a;
|
|
@@ -175,7 +201,7 @@ class PlaywrightElementHandle extends PlaywrightJsHandle {
|
|
|
175
201
|
var _a;
|
|
176
202
|
let timeout;
|
|
177
203
|
const newTimeout = text.length * ((_a = options === null || options === void 0 ? void 0 : options.delay) !== null && _a !== void 0 ? _a : 1) * 2;
|
|
178
|
-
if (newTimeout >
|
|
204
|
+
if (newTimeout > types_1.DefaultTimeouts.defaultTextInputTimeoutMs) {
|
|
179
205
|
timeout = newTimeout;
|
|
180
206
|
}
|
|
181
207
|
return timeout;
|
|
@@ -239,7 +265,7 @@ class PlaywrightElementHandle extends PlaywrightJsHandle {
|
|
|
239
265
|
}
|
|
240
266
|
async makeCdpCall(method, paramArgs) {
|
|
241
267
|
var _a;
|
|
242
|
-
return ((_a = this.cdpSession) !== null && _a !== void 0 ? _a :
|
|
268
|
+
return ((_a = this.cdpSession) !== null && _a !== void 0 ? _a : this.page.getCdpSession()).send(method, paramArgs);
|
|
243
269
|
}
|
|
244
270
|
}
|
|
245
271
|
exports.PlaywrightElementHandle = PlaywrightElementHandle;
|
|
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
exports.PlaywrightFrame = void 0;
|
|
23
23
|
const browserLauncher_1 = require("../browserLauncher");
|
|
24
24
|
const playwright = __importStar(require("@playwright/test"));
|
|
25
|
+
const types_1 = require("../types");
|
|
25
26
|
const utils_1 = require("../utils");
|
|
26
27
|
const playwrightHttpResponse_1 = require("./playwrightHttpResponse");
|
|
27
28
|
const playwrightDom_1 = require("./playwrightDom");
|
|
@@ -117,7 +118,16 @@ class PlaywrightFrame extends browserLauncher_1.Frame {
|
|
|
117
118
|
}
|
|
118
119
|
async goto(url, options) {
|
|
119
120
|
try {
|
|
121
|
+
const waitForNetworkIdle = (options === null || options === void 0 ? void 0 : options.waitUntil) === types_1.LifecycleEvent.NetworkIdle;
|
|
122
|
+
if (options && waitForNetworkIdle) {
|
|
123
|
+
options.waitUntil = types_1.LifecycleEvent.Load;
|
|
124
|
+
}
|
|
120
125
|
const response = await this.frame.goto(url, options);
|
|
126
|
+
if (waitForNetworkIdle) {
|
|
127
|
+
await this.frame.waitForLoadState('networkidle', {
|
|
128
|
+
timeout: types_1.DefaultTimeouts.quickActionTimeoutMs,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
121
131
|
return utils_1.mapIfNotNull(response, (response) => new playwrightHttpResponse_1.PlaywrightHttpResponse(this.parentPage, response));
|
|
122
132
|
}
|
|
123
133
|
catch (e) {
|
|
@@ -69,6 +69,7 @@ class PlaywrightPage extends events_1.default {
|
|
|
69
69
|
}
|
|
70
70
|
async waitForInitialization() {
|
|
71
71
|
this.openerPage = await utils_1.mapIfNotNull(await this.page.opener(), (page) => this.browser.getOrCreatePage(page));
|
|
72
|
+
this.fallbackCdpSession = await this.createFallbackCdpSession();
|
|
72
73
|
}
|
|
73
74
|
on(event, listener) {
|
|
74
75
|
this.wireEvents(event);
|
|
@@ -81,56 +82,62 @@ class PlaywrightPage extends events_1.default {
|
|
|
81
82
|
return this;
|
|
82
83
|
}
|
|
83
84
|
wireEvents(event) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
this.
|
|
128
|
-
|
|
85
|
+
try {
|
|
86
|
+
if (event === browserLauncher_1.PageEvent.RequestWillBeSentExtraInfo &&
|
|
87
|
+
!this.listenerCount(event)) {
|
|
88
|
+
this.getCdpSession().on('Network.requestWillBeSentExtraInfo', (event) => {
|
|
89
|
+
this.emit(browserLauncher_1.PageEvent.RequestWillBeSentExtraInfo, event);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (event === browserLauncher_1.PageEvent.Response && !this.listenerCount(event)) {
|
|
93
|
+
this.page.on('response', (event) => {
|
|
94
|
+
this.emit(browserLauncher_1.PageEvent.Response, new playwrightHttpResponse_1.PlaywrightHttpResponse(this, event));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (event === browserLauncher_1.PageEvent.Request && !this.listenerCount(event)) {
|
|
98
|
+
void this.page.route('**/*', (route) => {
|
|
99
|
+
this.emit(browserLauncher_1.PageEvent.Request, new playwrightHttpRequest_1.PlaywrightHttpRequest(this, route.request(), route));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (event === browserLauncher_1.PageEvent.FrameNavigated && !this.listenerCount(event)) {
|
|
103
|
+
this.page.on('framenavigated', (frame) => {
|
|
104
|
+
this.emit(browserLauncher_1.PageEvent.FrameNavigated, this.getOrCreateFrame(frame));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (event === browserLauncher_1.PageEvent.FrameAttached && !this.listenerCount(event)) {
|
|
108
|
+
this.page.on('frameattached', (frame) => {
|
|
109
|
+
this.emit(browserLauncher_1.PageEvent.FrameAttached, this.getOrCreateFrame(frame));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (event === browserLauncher_1.PageEvent.Console && !this.listenerCount(event)) {
|
|
113
|
+
this.page.on('console', (console) => {
|
|
114
|
+
this.emit(browserLauncher_1.PageEvent.Console, new wrappers_1.PlaywrightWrappedConsoleMessage(console, this));
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (event === browserLauncher_1.PageEvent.PageError && !this.listenerCount(event)) {
|
|
118
|
+
this.page.on('pageerror', (error) => {
|
|
119
|
+
this.emit(browserLauncher_1.PageEvent.PageError, error);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (event === browserLauncher_1.PageEvent.Error && !this.listenerCount(event)) {
|
|
123
|
+
this.page.on('crash', (error) => {
|
|
124
|
+
this.emit(browserLauncher_1.PageEvent.Error, error);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (event === browserLauncher_1.PageEvent.TracingBufferUsage &&
|
|
128
|
+
!this.listenerCount(event)) {
|
|
129
|
+
this.getCdpSession().on('Tracing.bufferUsage', (tracing) => {
|
|
130
|
+
this.emit(browserLauncher_1.PageEvent.TracingBufferUsage, tracing);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (event === browserLauncher_1.PageEvent.TracingComplete && !this.listenerCount(event)) {
|
|
134
|
+
this.getCdpSession().on('Tracing.tracingComplete', (tracingComplete) => {
|
|
135
|
+
this.emit(browserLauncher_1.PageEvent.TracingComplete, tracingComplete);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
129
138
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.emit(browserLauncher_1.PageEvent.TracingComplete, tracingComplete);
|
|
133
|
-
}));
|
|
139
|
+
catch (error) {
|
|
140
|
+
logUtils_1.logInternal(`Unable to register event ${event.toString()}. Error: ${error}`);
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
async screenshot(clip) {
|
|
@@ -329,9 +336,9 @@ class PlaywrightPage extends events_1.default {
|
|
|
329
336
|
throw new Error('PlaywrightPage.setExtraHTTPHeaders not implemented');
|
|
330
337
|
}
|
|
331
338
|
makeCdpCall(method, paramArgs) {
|
|
332
|
-
return this.getCdpSession().
|
|
339
|
+
return this.getCdpSession().send(method, paramArgs);
|
|
333
340
|
}
|
|
334
|
-
|
|
341
|
+
getCdpSession() {
|
|
335
342
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
336
343
|
if (((_c = (_b = (_a = this.getPageImpl()) === null || _a === void 0 ? void 0 : _a._delegate) === null || _b === void 0 ? void 0 : _b._mainFrameSession) === null || _c === void 0 ? void 0 : _c._client) === undefined) {
|
|
337
344
|
const undefinedField = ((_e = (_d = this.getPageImpl()) === null || _d === void 0 ? void 0 : _d._delegate) === null || _e === void 0 ? void 0 : _e._mainFrameSession) !== undefined
|
|
@@ -342,13 +349,10 @@ class PlaywrightPage extends events_1.default {
|
|
|
342
349
|
logUtils_1.logInternal(`Unable to get the CDP Session of the page (${undefinedField} is undefined).
|
|
343
350
|
Creating a fallback session. Some functionality might not work as expected.`);
|
|
344
351
|
}
|
|
345
|
-
return ((_k = (_j = (_h = (_g = this.getPageImpl()) === null || _g === void 0 ? void 0 : _g._delegate) === null || _h === void 0 ? void 0 : _h._mainFrameSession) === null || _j === void 0 ? void 0 : _j._client) !== null && _k !== void 0 ? _k : this.
|
|
352
|
+
return ((_k = (_j = (_h = (_g = this.getPageImpl()) === null || _g === void 0 ? void 0 : _g._delegate) === null || _h === void 0 ? void 0 : _h._mainFrameSession) === null || _j === void 0 ? void 0 : _j._client) !== null && _k !== void 0 ? _k : this.fallbackCdpSession);
|
|
346
353
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
this.fallbackCdpSession = await this.browser.defaultContext.newCDPSession(this.page);
|
|
350
|
-
}
|
|
351
|
-
return this.fallbackCdpSession;
|
|
354
|
+
createFallbackCdpSession() {
|
|
355
|
+
return this.browser.defaultContext.newCDPSession(this.page);
|
|
352
356
|
}
|
|
353
357
|
async getWindowInfo() {
|
|
354
358
|
return this.makeCdpCall('Browser.getWindowForTarget', { targetId: this.getPageId() });
|
|
@@ -9,6 +9,7 @@ const puppeteer_core_1 = __importDefault(require("puppeteer-core"));
|
|
|
9
9
|
const events_1 = __importDefault(require("events"));
|
|
10
10
|
const puppeteerBrowserLauncher_1 = require("./puppeteerBrowserLauncher");
|
|
11
11
|
const puppeteerPage_1 = require("./puppeteerPage");
|
|
12
|
+
const runnerType_1 = require("../runnerType");
|
|
12
13
|
class PuppeteerBrowser extends events_1.default {
|
|
13
14
|
constructor(browser, downloadDirectory, credentials) {
|
|
14
15
|
var _a;
|
|
@@ -38,6 +39,9 @@ class PuppeteerBrowser extends events_1.default {
|
|
|
38
39
|
state: event.state,
|
|
39
40
|
}));
|
|
40
41
|
}
|
|
42
|
+
getRunnerType() {
|
|
43
|
+
return runnerType_1.RunnerType.Puppeteer;
|
|
44
|
+
}
|
|
41
45
|
getDownloadDirectory() {
|
|
42
46
|
return this.downloadDirectory;
|
|
43
47
|
}
|
|
@@ -35,9 +35,15 @@ class PuppeteerElementHandle extends puppeteerJsHandle_1.PuppeteerJsHandle {
|
|
|
35
35
|
return this.element.hover();
|
|
36
36
|
}
|
|
37
37
|
click(options) {
|
|
38
|
+
if (options === null || options === void 0 ? void 0 : options.trial) {
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
}
|
|
38
41
|
return this.element.click(options);
|
|
39
42
|
}
|
|
40
|
-
async doubleClick() {
|
|
43
|
+
async doubleClick(options) {
|
|
44
|
+
if (options === null || options === void 0 ? void 0 : options.trial) {
|
|
45
|
+
return Promise.resolve();
|
|
46
|
+
}
|
|
41
47
|
await this.element.click();
|
|
42
48
|
await testsUtil_1.sleep(msBetweenClicks);
|
|
43
49
|
return this.element.click({ clickCount: 2 });
|
|
@@ -20,5 +20,8 @@ class PuppeteerHttpResponse {
|
|
|
20
20
|
request() {
|
|
21
21
|
return new puppeteerHttpRequest_1.PuppeteerHttpRequest(this.response.request(), this.parentPage);
|
|
22
22
|
}
|
|
23
|
+
json() {
|
|
24
|
+
return this.response.json();
|
|
25
|
+
}
|
|
23
26
|
}
|
|
24
27
|
exports.PuppeteerHttpResponse = PuppeteerHttpResponse;
|
package/browserLauncher/types.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WaitForOptions = exports.LifecycleEvent = void 0;
|
|
3
|
+
exports.WaitForOptions = exports.LifecycleEvent = exports.DefaultTimeouts = void 0;
|
|
4
|
+
class DefaultTimeouts {
|
|
5
|
+
}
|
|
6
|
+
exports.DefaultTimeouts = DefaultTimeouts;
|
|
7
|
+
DefaultTimeouts.quickActionTimeoutMs = 5000;
|
|
8
|
+
DefaultTimeouts.defaultTextInputTimeoutMs = 30000;
|
|
4
9
|
var LifecycleEvent;
|
|
5
10
|
(function (LifecycleEvent) {
|
|
6
11
|
LifecycleEvent["DomContentLoaded"] = "domcontentloaded";
|
|
@@ -134,11 +134,12 @@ async function createBrowserWithAuthedExtension(accessToken, browserWidth, brows
|
|
|
134
134
|
}
|
|
135
135
|
exports.createBrowserWithAuthedExtension = createBrowserWithAuthedExtension;
|
|
136
136
|
async function launchBrowserInstance(chromePath, launchArgs, userDataDir, headless, credentials, options) {
|
|
137
|
-
const { defaultDeviceDescriptor, ignoreDefaultArgs, runnerType, loggerFunc } = options || {};
|
|
137
|
+
const { defaultDeviceDescriptor, extraHttpHeaders, ignoreDefaultArgs, runnerType, loggerFunc, } = options || {};
|
|
138
138
|
let browser;
|
|
139
139
|
try {
|
|
140
140
|
browser = await maybeLaunchBrowser(chromePath, launchArgs, userDataDir, headless, credentials, {
|
|
141
141
|
defaultDeviceDescriptor,
|
|
142
|
+
extraHttpHeaders,
|
|
142
143
|
ignoreDefaultArgs,
|
|
143
144
|
runnerType,
|
|
144
145
|
loggerFunc,
|
|
@@ -161,10 +162,11 @@ async function launchBrowserInstance(chromePath, launchArgs, userDataDir, headle
|
|
|
161
162
|
return browser;
|
|
162
163
|
}
|
|
163
164
|
function maybeLaunchBrowser(chromePath, launchArgs, userDataDir, headless, credentials, options) {
|
|
164
|
-
const { defaultDeviceDescriptor, ignoreDefaultArgs, runnerType, loggerFunc } = options || {};
|
|
165
|
+
const { defaultDeviceDescriptor, extraHttpHeaders, ignoreDefaultArgs, runnerType, loggerFunc, } = options || {};
|
|
165
166
|
return browserLauncher_1.BrowserLauncherFactory.createRunner(runnerType, loggerFunc).launch({
|
|
166
167
|
defaultDeviceDescriptor,
|
|
167
168
|
executablePath: chromePath,
|
|
169
|
+
extraHttpHeaders,
|
|
168
170
|
headless,
|
|
169
171
|
args: launchArgs,
|
|
170
172
|
ignoreDefaultArgs,
|
|
@@ -195,7 +197,7 @@ function removeTempBrowserPreferencesDirectory(tempDirPath) {
|
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
199
|
async function createBrowser(browserWidth, browserHeight, headless, containerTesting, tempBrowserPreferencesDirectory, options) {
|
|
198
|
-
const { credentials, browserPath, disableIsolation, ignoreCertificateErrors, emulationConfig, enableExtensions, runnerType, loggerFunc, } = options || {};
|
|
200
|
+
const { credentials, browserPath, disableIsolation, extraHttpHeaders, ignoreCertificateErrors, emulationConfig, enableExtensions, runnerType, loggerFunc, } = options || {};
|
|
199
201
|
const chromePath = browserPath !== null && browserPath !== void 0 ? browserPath : findChrome();
|
|
200
202
|
if (!chromePath.length) {
|
|
201
203
|
messaging_1.mablEventEmitter.log(chalk.yellow('Could not find a local install of Chrome to use, please ensure you have it installed and try again'));
|
|
@@ -220,6 +222,7 @@ async function createBrowser(browserWidth, browserHeight, headless, containerTes
|
|
|
220
222
|
}
|
|
221
223
|
const maybeBrowser = await launchBrowserInstance(chromePath, launchArgs, tempBrowserPreferencesDirectory, headless, credentials, {
|
|
222
224
|
defaultDeviceDescriptor,
|
|
225
|
+
extraHttpHeaders,
|
|
223
226
|
ignoreDefaultArgs,
|
|
224
227
|
runnerType,
|
|
225
228
|
loggerFunc,
|
|
@@ -237,7 +237,7 @@ async function getJourneysForLabels(workspaceId, branchName, branchChangesOnly,
|
|
|
237
237
|
organization_id: workspaceId,
|
|
238
238
|
include_labels: labelsInclude,
|
|
239
239
|
exclude_labels: labelsExclude,
|
|
240
|
-
|
|
240
|
+
branch: branchName,
|
|
241
241
|
branch_changes_only: branchChangesOnly,
|
|
242
242
|
});
|
|
243
243
|
switch (journeys.length) {
|