appium-android-driver 5.14.7 → 6.0.1
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 +7 -0
- package/build/lib/commands/actions.d.ts +6 -224
- package/build/lib/commands/actions.d.ts.map +1 -1
- package/build/lib/commands/actions.js +306 -405
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +7 -9
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +24 -18
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +7 -313
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +135 -293
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.d.ts +8 -92
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +381 -439
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/element.d.ts +8 -35
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +153 -136
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/emu-console.d.ts +6 -48
- package/build/lib/commands/emu-console.d.ts.map +1 -1
- package/build/lib/commands/emu-console.js +19 -34
- package/build/lib/commands/emu-console.js.map +1 -1
- package/build/lib/commands/execute.d.ts +6 -5
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +77 -66
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +7 -128
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +183 -219
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +8 -12
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +19 -23
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +9 -132
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +281 -312
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.d.ts +7 -10
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +47 -35
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/index.d.ts +27 -2
- package/build/lib/commands/index.d.ts.map +1 -1
- package/build/lib/commands/index.js +41 -19
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/intent.d.ts +7 -417
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +104 -216
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +6 -5
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +16 -8
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/log.d.ts +7 -44
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +146 -108
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +7 -143
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +113 -140
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/mixins.d.ts +740 -0
- package/build/lib/commands/mixins.d.ts.map +1 -0
- package/build/lib/commands/mixins.js +19 -0
- package/build/lib/commands/mixins.js.map +1 -0
- package/build/lib/commands/network.d.ts +7 -138
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +212 -254
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +24 -70
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +144 -100
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +8 -92
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +75 -87
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +7 -193
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +151 -182
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.d.ts +7 -7
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +40 -33
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +9 -103
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +261 -218
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +22 -90
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +76 -74
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.d.ts +10 -29
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +301 -285
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/types.d.ts +978 -0
- package/build/lib/commands/types.d.ts.map +1 -0
- package/build/lib/commands/types.js +3 -0
- package/build/lib/commands/types.js.map +1 -0
- package/build/lib/constraints.d.ts +291 -0
- package/build/lib/constraints.d.ts.map +1 -0
- package/build/lib/{desired-caps.js → constraints.js} +103 -102
- package/build/lib/constraints.js.map +1 -0
- package/build/lib/driver.d.ts +68 -37
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +123 -80
- package/build/lib/driver.js.map +1 -1
- package/build/lib/helpers/android.d.ts +164 -0
- package/build/lib/helpers/android.d.ts.map +1 -0
- package/build/lib/helpers/android.js +819 -0
- package/build/lib/helpers/android.js.map +1 -0
- package/build/lib/helpers/index.d.ts +7 -0
- package/build/lib/helpers/index.d.ts.map +1 -0
- package/build/lib/helpers/index.js +29 -0
- package/build/lib/helpers/index.js.map +1 -0
- package/build/lib/helpers/types.d.ts +121 -0
- package/build/lib/helpers/types.d.ts.map +1 -0
- package/build/lib/helpers/types.js +3 -0
- package/build/lib/helpers/types.js.map +1 -0
- package/build/lib/helpers/unlock.d.ts +32 -0
- package/build/lib/helpers/unlock.d.ts.map +1 -0
- package/build/lib/helpers/unlock.js +273 -0
- package/build/lib/helpers/unlock.js.map +1 -0
- package/build/lib/helpers/webview.d.ts +74 -0
- package/build/lib/helpers/webview.d.ts.map +1 -0
- package/build/lib/helpers/webview.js +421 -0
- package/build/lib/helpers/webview.js.map +1 -0
- package/build/lib/index.d.ts +9 -0
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/index.js +37 -0
- package/build/lib/index.js.map +1 -0
- package/build/lib/method-map.d.ts +0 -8
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +63 -74
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/stubs.d.ts +0 -1
- package/build/lib/stubs.d.ts.map +1 -1
- package/build/lib/stubs.js +1 -0
- package/build/lib/stubs.js.map +1 -1
- package/build/lib/utils.d.ts +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/lib/commands/actions.js +351 -464
- package/lib/commands/alert.js +27 -17
- package/lib/commands/app-management.js +156 -314
- package/lib/commands/context.js +457 -441
- package/lib/commands/element.js +201 -157
- package/lib/commands/emu-console.js +25 -45
- package/lib/commands/execute.js +106 -90
- package/lib/commands/file-actions.js +222 -240
- package/lib/commands/find.ts +103 -0
- package/lib/commands/general.js +327 -339
- package/lib/commands/ime.js +50 -34
- package/lib/commands/{index.js → index.ts} +20 -24
- package/lib/commands/intent.js +108 -249
- package/lib/commands/keyboard.js +20 -8
- package/lib/commands/log.js +172 -116
- package/lib/commands/media-projection.js +134 -161
- package/lib/commands/mixins.ts +966 -0
- package/lib/commands/network.js +252 -281
- package/lib/commands/performance.js +203 -132
- package/lib/commands/permissions.js +108 -109
- package/lib/commands/recordscreen.js +212 -209
- package/lib/commands/shell.js +51 -40
- package/lib/commands/streamscreen.js +355 -289
- package/lib/commands/system-bars.js +92 -83
- package/lib/commands/touch.js +357 -294
- package/lib/commands/types.ts +1097 -0
- package/lib/{desired-caps.js → constraints.ts} +106 -103
- package/lib/{driver.js → driver.ts} +278 -132
- package/lib/helpers/android.ts +1143 -0
- package/lib/helpers/index.ts +6 -0
- package/lib/helpers/types.ts +134 -0
- package/lib/helpers/unlock.ts +329 -0
- package/lib/helpers/webview.ts +582 -0
- package/lib/index.ts +18 -0
- package/lib/method-map.js +87 -98
- package/lib/stubs.ts +0 -1
- package/package.json +26 -19
- package/build/index.js +0 -51
- package/build/lib/android-helpers.d.ts +0 -136
- package/build/lib/android-helpers.d.ts.map +0 -1
- package/build/lib/android-helpers.js +0 -855
- package/build/lib/android-helpers.js.map +0 -1
- package/build/lib/commands/coverage.d.ts +0 -5
- package/build/lib/commands/coverage.d.ts.map +0 -1
- package/build/lib/commands/coverage.js +0 -19
- package/build/lib/commands/coverage.js.map +0 -1
- package/build/lib/desired-caps.d.ts +0 -353
- package/build/lib/desired-caps.d.ts.map +0 -1
- package/build/lib/desired-caps.js.map +0 -1
- package/build/lib/unlock-helpers.d.ts +0 -38
- package/build/lib/unlock-helpers.d.ts.map +0 -1
- package/build/lib/unlock-helpers.js +0 -266
- package/build/lib/unlock-helpers.js.map +0 -1
- package/build/lib/webview-helpers.d.ts +0 -224
- package/build/lib/webview-helpers.d.ts.map +0 -1
- package/build/lib/webview-helpers.js +0 -528
- package/build/lib/webview-helpers.js.map +0 -1
- package/index.js +0 -24
- package/lib/android-helpers.js +0 -983
- package/lib/commands/coverage.js +0 -18
- package/lib/commands/find.js +0 -82
- package/lib/unlock-helpers.js +0 -278
- package/lib/webview-helpers.js +0 -602
|
@@ -1,472 +1,414 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.setupNewChromedriver =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const portfinder_1 = __importDefault(require("portfinder"));
|
|
33
|
-
const bluebird_1 = __importDefault(require("bluebird"));
|
|
6
|
+
exports.setupNewChromedriver = void 0;
|
|
7
|
+
/* eslint-disable require-await */
|
|
8
|
+
// @ts-check
|
|
34
9
|
const support_1 = require("@appium/support");
|
|
10
|
+
const appium_chromedriver_1 = __importDefault(require("appium-chromedriver"));
|
|
35
11
|
const driver_1 = require("appium/driver");
|
|
36
|
-
const
|
|
37
|
-
const
|
|
12
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
13
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
14
|
+
const portfinder_1 = __importDefault(require("portfinder"));
|
|
15
|
+
const helpers_1 = require("../helpers");
|
|
16
|
+
const mixins_1 = require("./mixins");
|
|
38
17
|
const CHROMEDRIVER_AUTODOWNLOAD_FEATURE = 'chromedriver_autodownload';
|
|
39
|
-
let commands = {}, helpers = {}, extensions = {};
|
|
40
|
-
exports.commands = commands;
|
|
41
|
-
exports.helpers = helpers;
|
|
42
|
-
/* -------------------------------
|
|
43
|
-
* Actual MJSONWP command handlers
|
|
44
|
-
* ------------------------------- */
|
|
45
|
-
commands.getCurrentContext = async function getCurrentContext() {
|
|
46
|
-
// if the current context is `null`, indicating no context
|
|
47
|
-
// explicitly set, it is the default context
|
|
48
|
-
return this.curContext || this.defaultContextName();
|
|
49
|
-
};
|
|
50
|
-
commands.getContexts = async function getContexts() {
|
|
51
|
-
const webviewsMapping = await webview_helpers_1.default.getWebViewsMapping(this.adb, this.opts);
|
|
52
|
-
return this.assignContexts(webviewsMapping);
|
|
53
|
-
};
|
|
54
|
-
commands.setContext = async function setContext(name) {
|
|
55
|
-
if (!support_1.util.hasValue(name)) {
|
|
56
|
-
name = this.defaultContextName();
|
|
57
|
-
}
|
|
58
|
-
else if (name === webview_helpers_1.WEBVIEW_WIN) {
|
|
59
|
-
// handle setContext "WEBVIEW"
|
|
60
|
-
name = this.defaultWebviewName();
|
|
61
|
-
}
|
|
62
|
-
// if we're already in the context we want, do nothing
|
|
63
|
-
if (name === this.curContext) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const webviewsMapping = await webview_helpers_1.default.getWebViewsMapping(this.adb, this.opts);
|
|
67
|
-
const contexts = this.assignContexts(webviewsMapping);
|
|
68
|
-
// if the context we want doesn't exist, fail
|
|
69
|
-
if (!lodash_1.default.includes(contexts, name)) {
|
|
70
|
-
throw new driver_1.errors.NoSuchContextError();
|
|
71
|
-
}
|
|
72
|
-
await this.switchContext(name, webviewsMapping);
|
|
73
|
-
this.curContext = name;
|
|
74
|
-
};
|
|
75
18
|
/**
|
|
76
|
-
* @
|
|
77
|
-
* @
|
|
78
|
-
* @property {string} webview The web view alias. Looks like `WEBVIEW_`
|
|
79
|
-
* prefix plus PID or package name
|
|
80
|
-
* @property {?Object} info Webview information as it is retrieved by
|
|
81
|
-
* /json/version CDP endpoint
|
|
82
|
-
* @property {?Array<Object>} pages Webview pages list as it is retrieved by
|
|
83
|
-
* /json/list CDP endpoint
|
|
84
|
-
* @propery {?string} webviewName An actual webview name for switching context.
|
|
85
|
-
* This value becomes null when failing to find a PID for a webview.
|
|
86
|
-
*
|
|
87
|
-
* The following json demonstrates the example of WebviewsMapping object.
|
|
88
|
-
* Note that `description` in `page` can be an empty string most likely when it comes to Mobile Chrome)
|
|
89
|
-
* {
|
|
90
|
-
* "proc": "@webview_devtools_remote_22138",
|
|
91
|
-
* "webview": "WEBVIEW_22138",
|
|
92
|
-
* "info": {
|
|
93
|
-
* "Android-Package": "io.appium.settings",
|
|
94
|
-
* "Browser": "Chrome/74.0.3729.185",
|
|
95
|
-
* "Protocol-Version": "1.3",
|
|
96
|
-
* "User-Agent": "Mozilla/5.0 (Linux; Android 10; Android SDK built for x86 Build/QSR1.190920.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36",
|
|
97
|
-
* "V8-Version": "7.4.288.28",
|
|
98
|
-
* "WebKit-Version": "537.36 (@22955682f94ce09336197bfb8dffea991fa32f0d)",
|
|
99
|
-
* "webSocketDebuggerUrl": "ws://127.0.0.1:10900/devtools/browser"
|
|
100
|
-
* },
|
|
101
|
-
* "pages": [
|
|
102
|
-
* {
|
|
103
|
-
* "description": "{\"attached\":true,\"empty\":false,\"height\":1458,\"screenX\":0,\"screenY\":336,\"visible\":true,\"width\":1080}",
|
|
104
|
-
* "devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@22955682f94ce09336197bfb8dffea991fa32f0d/inspector.html?ws=127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F",
|
|
105
|
-
* "id": "27325CC50B600D31B233F45E09487B1F",
|
|
106
|
-
* "title": "Releases · appium/appium · GitHub",
|
|
107
|
-
* "type": "page",
|
|
108
|
-
* "url": "https://github.com/appium/appium/releases",
|
|
109
|
-
* "webSocketDebuggerUrl": "ws://127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F"
|
|
110
|
-
* }
|
|
111
|
-
* ],
|
|
112
|
-
* "webviewName": "WEBVIEW_com.io.appium.setting"
|
|
113
|
-
* }
|
|
19
|
+
* @type {import('./mixins').ContextMixin & ThisType<import('../driver').AndroidDriver>}
|
|
20
|
+
* @satisfies {import('@appium/types').ExternalDriver}
|
|
114
21
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.contexts = [webview_helpers_1.NATIVE_WIN, ...webviews];
|
|
133
|
-
this.log.debug(`Available contexts: ${JSON.stringify(this.contexts)}`);
|
|
134
|
-
return this.contexts;
|
|
135
|
-
};
|
|
136
|
-
helpers.switchContext = async function switchContext(name, webviewsMapping) {
|
|
137
|
-
// We have some options when it comes to webviews. If we want a
|
|
138
|
-
// Chromedriver webview, we can only control one at a time.
|
|
139
|
-
if (this.isChromedriverContext(name)) {
|
|
140
|
-
// start proxying commands directly to chromedriver
|
|
141
|
-
await this.startChromedriverProxy(name, webviewsMapping);
|
|
142
|
-
}
|
|
143
|
-
else if (this.isChromedriverContext(this.curContext)) {
|
|
144
|
-
// if we're moving to a non-chromedriver webview, and our current context
|
|
145
|
-
// _is_ a chromedriver webview, if caps recreateChromeDriverSessions is set
|
|
146
|
-
// to true then kill chromedriver session using stopChromedriverProxies or
|
|
147
|
-
// else simply suspend proxying to the latter
|
|
148
|
-
if (this.opts.recreateChromeDriverSessions) {
|
|
149
|
-
this.log.debug('recreateChromeDriverSessions set to true; killing existing chromedrivers');
|
|
150
|
-
await this.stopChromedriverProxies();
|
|
22
|
+
const ContextMixin = {
|
|
23
|
+
/* -------------------------------
|
|
24
|
+
* Actual MJSONWP command handlers
|
|
25
|
+
* ------------------------------- */
|
|
26
|
+
async getCurrentContext() {
|
|
27
|
+
// if the current context is `null`, indicating no context
|
|
28
|
+
// explicitly set, it is the default context
|
|
29
|
+
return this.curContext || this.defaultContextName();
|
|
30
|
+
},
|
|
31
|
+
async getContexts() {
|
|
32
|
+
const webviewsMapping = await helpers_1.WebviewHelpers.getWebViewsMapping(
|
|
33
|
+
/** @type {ADB} */ (this.adb), this.opts);
|
|
34
|
+
return this.assignContexts(webviewsMapping);
|
|
35
|
+
},
|
|
36
|
+
async setContext(name) {
|
|
37
|
+
if (!support_1.util.hasValue(name)) {
|
|
38
|
+
name = this.defaultContextName();
|
|
151
39
|
}
|
|
152
|
-
else {
|
|
153
|
-
|
|
40
|
+
else if (name === helpers_1.WEBVIEW_WIN) {
|
|
41
|
+
// handle setContext "WEBVIEW"
|
|
42
|
+
name = this.defaultWebviewName();
|
|
154
43
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
this.log.debug(`
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
44
|
+
// if we're already in the context we want, do nothing
|
|
45
|
+
if (name === this.curContext) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const webviewsMapping = await helpers_1.WebviewHelpers.getWebViewsMapping(
|
|
49
|
+
/** @type {ADB} */ (this.adb), this.opts);
|
|
50
|
+
const contexts = this.assignContexts(webviewsMapping);
|
|
51
|
+
// if the context we want doesn't exist, fail
|
|
52
|
+
if (!lodash_1.default.includes(contexts, name)) {
|
|
53
|
+
throw new driver_1.errors.NoSuchContextError();
|
|
54
|
+
}
|
|
55
|
+
await this.switchContext(name, webviewsMapping);
|
|
56
|
+
this.curContext = name;
|
|
57
|
+
},
|
|
58
|
+
async mobileGetContexts() {
|
|
59
|
+
const opts = {
|
|
60
|
+
androidDeviceSocket: this.opts.androidDeviceSocket,
|
|
61
|
+
ensureWebviewsHavePages: true,
|
|
62
|
+
webviewDevtoolsPort: this.opts.webviewDevtoolsPort,
|
|
63
|
+
enableWebviewDetailsCollection: true,
|
|
64
|
+
};
|
|
65
|
+
return await helpers_1.WebviewHelpers.getWebViewsMapping(/** @type {ADB} */ (this.adb), opts);
|
|
66
|
+
},
|
|
67
|
+
assignContexts(webviewsMapping) {
|
|
68
|
+
const opts = Object.assign({ isChromeSession: this.isChromeSession }, this.opts);
|
|
69
|
+
const webviews = helpers_1.WebviewHelpers.parseWebviewNames(webviewsMapping, opts);
|
|
70
|
+
this.contexts = [helpers_1.NATIVE_WIN, ...webviews];
|
|
71
|
+
this.log.debug(`Available contexts: ${JSON.stringify(this.contexts)}`);
|
|
72
|
+
return this.contexts;
|
|
73
|
+
},
|
|
74
|
+
async switchContext(name, webviewsMapping) {
|
|
75
|
+
// We have some options when it comes to webviews. If we want a
|
|
76
|
+
// Chromedriver webview, we can only control one at a time.
|
|
77
|
+
if (this.isChromedriverContext(name)) {
|
|
78
|
+
// start proxying commands directly to chromedriver
|
|
79
|
+
await this.startChromedriverProxy(name, webviewsMapping);
|
|
80
|
+
}
|
|
81
|
+
else if (this.isChromedriverContext(this.curContext)) {
|
|
82
|
+
// if we're moving to a non-chromedriver webview, and our current context
|
|
83
|
+
// _is_ a chromedriver webview, if caps recreateChromeDriverSessions is set
|
|
84
|
+
// to true then kill chromedriver session using stopChromedriverProxies or
|
|
85
|
+
// else simply suspend proxying to the latter
|
|
86
|
+
if (this.opts.recreateChromeDriverSessions) {
|
|
87
|
+
this.log.debug('recreateChromeDriverSessions set to true; killing existing chromedrivers');
|
|
88
|
+
await this.stopChromedriverProxies();
|
|
198
89
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
90
|
+
else {
|
|
91
|
+
this.suspendChromedriverProxy();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
throw new Error(`Didn't know how to handle switching to context '${name}'`);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
/* ---------------------------------
|
|
99
|
+
* On-object context-related helpers
|
|
100
|
+
* --------------------------------- */
|
|
101
|
+
// The reason this is a function and not just a constant is that both android-
|
|
102
|
+
// driver and selendroid-driver use this logic, and each one returns
|
|
103
|
+
// a different default context name
|
|
104
|
+
defaultContextName() {
|
|
105
|
+
return helpers_1.NATIVE_WIN;
|
|
106
|
+
},
|
|
107
|
+
defaultWebviewName() {
|
|
108
|
+
return helpers_1.WEBVIEW_BASE + (this.opts.autoWebviewName || this.opts.appPackage);
|
|
109
|
+
},
|
|
110
|
+
isWebContext() {
|
|
111
|
+
return this.curContext !== null && this.curContext !== helpers_1.NATIVE_WIN;
|
|
112
|
+
},
|
|
113
|
+
// Turn on proxying to an existing Chromedriver session or a new one
|
|
114
|
+
async startChromedriverProxy(context, webviewsMapping) {
|
|
115
|
+
this.log.debug(`Connecting to chrome-backed webview context '${context}'`);
|
|
116
|
+
let cd;
|
|
117
|
+
if (this.sessionChromedrivers[context]) {
|
|
118
|
+
// in the case where we've already set up a chromedriver for a context,
|
|
119
|
+
// we want to reconnect to it, not create a whole new one
|
|
120
|
+
this.log.debug(`Found existing Chromedriver for context '${context}'. Using it.`);
|
|
121
|
+
cd = this.sessionChromedrivers[context];
|
|
122
|
+
await this.setupExistingChromedriver(this.log, cd);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// XXX: this suppresses errors about putting arbitrary stuff on opts
|
|
126
|
+
const opts = /** @type {any} */ (lodash_1.default.cloneDeep(this.opts));
|
|
127
|
+
opts.chromeUseRunningApp = true;
|
|
128
|
+
// if requested, tell chromedriver to attach to the android package we have
|
|
129
|
+
// associated with the context name, rather than the package of the AUT.
|
|
130
|
+
// And turn this on by default for chrome--if chrome pops up with a webview
|
|
131
|
+
// and someone wants to switch to it, we should let chromedriver connect to
|
|
132
|
+
// chrome rather than staying stuck on the AUT
|
|
133
|
+
if (opts.extractChromeAndroidPackageFromContextName || context === `${helpers_1.WEBVIEW_BASE}chrome`) {
|
|
134
|
+
let androidPackage = context.match(`${helpers_1.WEBVIEW_BASE}(.+)`);
|
|
135
|
+
if (androidPackage && androidPackage.length > 0) {
|
|
136
|
+
opts.chromeAndroidPackage = androidPackage[1];
|
|
137
|
+
}
|
|
138
|
+
if (!opts.extractChromeAndroidPackageFromContextName) {
|
|
139
|
+
if (lodash_1.default.has(this.opts, 'enableWebviewDetailsCollection') &&
|
|
140
|
+
!this.opts.enableWebviewDetailsCollection) {
|
|
141
|
+
// When enableWebviewDetailsCollection capability is explicitly disabled, try to identify
|
|
142
|
+
// chromeAndroidPackage based on contexts, known chrome variant packages and queryAppState result
|
|
143
|
+
// since webviewsMapping does not have info object
|
|
144
|
+
const contexts = webviewsMapping.map((wm) => wm.webviewName);
|
|
145
|
+
for (const knownPackage of helpers_1.KNOWN_CHROME_PACKAGE_NAMES) {
|
|
146
|
+
if (lodash_1.default.includes(contexts, `${helpers_1.WEBVIEW_BASE}${knownPackage}`)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const appState = await this.queryAppState(knownPackage);
|
|
150
|
+
if (lodash_1.default.includes([helpers_1.APP_STATE.RUNNING_IN_BACKGROUND, helpers_1.APP_STATE.RUNNING_IN_FOREGROUND], appState)) {
|
|
151
|
+
opts.chromeAndroidPackage = knownPackage;
|
|
152
|
+
this.log.debug(`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
153
|
+
`for context '${context}' by querying states of Chrome app packages`);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
215
156
|
}
|
|
216
157
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
`
|
|
224
|
-
|
|
158
|
+
else {
|
|
159
|
+
for (const wm of webviewsMapping) {
|
|
160
|
+
if (wm.webviewName === context && lodash_1.default.has(wm?.info, 'Android-Package')) {
|
|
161
|
+
// XXX: should be a type guard here
|
|
162
|
+
opts.chromeAndroidPackage =
|
|
163
|
+
/** @type {NonNullable<import('./types').WebviewsMapping['info']>} */ (wm.info)['Android-Package'];
|
|
164
|
+
this.log.debug(`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
165
|
+
`for context '${context}' by CDP`);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
225
168
|
}
|
|
226
169
|
}
|
|
227
170
|
}
|
|
228
171
|
}
|
|
172
|
+
cd = await this.setupNewChromedriver(opts,
|
|
173
|
+
/** @type {string} */ ( /** @type {ADB} */(this.adb).curDeviceId),
|
|
174
|
+
/** @type {ADB} */ (this.adb), context);
|
|
175
|
+
// bind our stop/exit handler, passing in context so we know which
|
|
176
|
+
// one stopped unexpectedly
|
|
177
|
+
cd.on(appium_chromedriver_1.default.EVENT_CHANGED, (msg) => {
|
|
178
|
+
if (msg.state === appium_chromedriver_1.default.STATE_STOPPED) {
|
|
179
|
+
this.onChromedriverStop(context);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// save the chromedriver object under the context
|
|
183
|
+
this.sessionChromedrivers[context] = cd;
|
|
229
184
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
185
|
+
// hook up the local variables so we can proxy this biz
|
|
186
|
+
this.chromedriver = cd;
|
|
187
|
+
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
188
|
+
this.proxyCommand = /** @type {import('@appium/types').ExternalDriver['proxyCommand']} */ (this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy));
|
|
189
|
+
this.jwpProxyActive = true;
|
|
190
|
+
},
|
|
191
|
+
// Stop proxying to any Chromedriver
|
|
192
|
+
suspendChromedriverProxy() {
|
|
193
|
+
this.chromedriver = undefined;
|
|
194
|
+
this.proxyReqRes = undefined;
|
|
195
|
+
this.proxyCommand = undefined;
|
|
196
|
+
this.jwpProxyActive = false;
|
|
197
|
+
},
|
|
198
|
+
// Handle an out-of-band Chromedriver stop event
|
|
199
|
+
async onChromedriverStop(context) {
|
|
200
|
+
this.log.warn(`Chromedriver for context ${context} stopped unexpectedly`);
|
|
201
|
+
if (context === this.curContext) {
|
|
202
|
+
// we exited unexpectedly while automating the current context and so want
|
|
203
|
+
// to shut down the session and respond with an error
|
|
204
|
+
let err = new Error('Chromedriver quit unexpectedly during session');
|
|
205
|
+
await this.startUnexpectedShutdown(err);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// if a Chromedriver in the non-active context barfs, we don't really
|
|
209
|
+
// care, we'll just make a new one next time we need the context.
|
|
210
|
+
this.log.warn("Chromedriver quit unexpectedly, but it wasn't the active " + 'context, ignoring');
|
|
211
|
+
delete this.sessionChromedrivers[context];
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
// Intentionally stop all the chromedrivers currently active, and ignore
|
|
215
|
+
// their exit events
|
|
216
|
+
async stopChromedriverProxies() {
|
|
217
|
+
this.suspendChromedriverProxy(); // make sure we turn off the proxy flag
|
|
218
|
+
for (let context of lodash_1.default.keys(this.sessionChromedrivers)) {
|
|
219
|
+
let cd = this.sessionChromedrivers[context];
|
|
220
|
+
this.log.debug(`Stopping chromedriver for context ${context}`);
|
|
221
|
+
// stop listening for the stopped state event
|
|
222
|
+
cd.removeAllListeners(appium_chromedriver_1.default.EVENT_CHANGED);
|
|
223
|
+
try {
|
|
224
|
+
await cd.stop();
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
this.log.warn(`Error stopping Chromedriver: ${ /** @type {Error} */(err).message}`);
|
|
228
|
+
}
|
|
229
|
+
delete this.sessionChromedrivers[context];
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
isChromedriverContext(viewName) {
|
|
233
|
+
return lodash_1.default.includes(viewName, helpers_1.WEBVIEW_WIN) || viewName === helpers_1.CHROMIUM_WIN;
|
|
234
|
+
},
|
|
235
|
+
shouldDismissChromeWelcome() {
|
|
236
|
+
return (!!this.opts.chromeOptions &&
|
|
237
|
+
lodash_1.default.isArray(this.opts.chromeOptions.args) &&
|
|
238
|
+
this.opts.chromeOptions.args.includes('--no-first-run'));
|
|
239
|
+
},
|
|
240
|
+
async dismissChromeWelcome() {
|
|
241
|
+
this.log.info('Trying to dismiss Chrome welcome');
|
|
242
|
+
let activity = await this.getCurrentActivity();
|
|
243
|
+
if (activity !== 'org.chromium.chrome.browser.firstrun.FirstRunActivity') {
|
|
244
|
+
this.log.info('Chrome welcome dialog never showed up! Continuing');
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
let el = await this.findElOrEls('id', 'com.android.chrome:id/terms_accept', false);
|
|
248
|
+
await this.click(/** @type {string} */ (el.ELEMENT));
|
|
249
|
+
try {
|
|
250
|
+
let el = await this.findElOrEls('id', 'com.android.chrome:id/negative_button', false);
|
|
251
|
+
await this.click(/** @type {string} */ (el.ELEMENT));
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
// DO NOTHING, THIS DEVICE DIDNT LAUNCH THE SIGNIN DIALOG
|
|
255
|
+
// IT MUST BE A NON GMS DEVICE
|
|
256
|
+
this.log.warn(`This device did not show Chrome SignIn dialog, ${ /** @type {Error} */(e).message}`);
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
async startChromeSession() {
|
|
260
|
+
this.log.info('Starting a chrome-based browser session');
|
|
261
|
+
// XXX: this suppresses errors about putting arbitrary stuff on opts
|
|
262
|
+
const opts = /** @type {any} */ (lodash_1.default.cloneDeep(this.opts));
|
|
263
|
+
const knownPackages = [
|
|
264
|
+
'org.chromium.chrome.shell',
|
|
265
|
+
'com.android.chrome',
|
|
266
|
+
'com.chrome.beta',
|
|
267
|
+
'org.chromium.chrome',
|
|
268
|
+
'org.chromium.webview_shell',
|
|
269
|
+
];
|
|
270
|
+
if (lodash_1.default.includes(knownPackages, this.opts.appPackage)) {
|
|
271
|
+
opts.chromeBundleId = this.opts.appPackage;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
opts.chromeAndroidActivity = this.opts.appActivity;
|
|
275
|
+
}
|
|
276
|
+
this.chromedriver = await this.setupNewChromedriver(opts,
|
|
277
|
+
/** @type {string} */ ( /** @type {ADB} */(this.adb).curDeviceId),
|
|
278
|
+
/** @type {ADB} */ (this.adb));
|
|
279
|
+
this.chromedriver.on(appium_chromedriver_1.default.EVENT_CHANGED, (msg) => {
|
|
234
280
|
if (msg.state === appium_chromedriver_1.default.STATE_STOPPED) {
|
|
235
|
-
this.onChromedriverStop(
|
|
281
|
+
this.onChromedriverStop(helpers_1.CHROMIUM_WIN);
|
|
236
282
|
}
|
|
237
283
|
});
|
|
238
|
-
//
|
|
239
|
-
this
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
this.chromedriver = null;
|
|
250
|
-
this.proxyReqRes = null;
|
|
251
|
-
this.proxyCommand = null;
|
|
252
|
-
this.jwpProxyActive = false;
|
|
253
|
-
};
|
|
254
|
-
// Handle an out-of-band Chromedriver stop event
|
|
255
|
-
helpers.onChromedriverStop = async function onChromedriverStop(context) {
|
|
256
|
-
this.log.warn(`Chromedriver for context ${context} stopped unexpectedly`);
|
|
257
|
-
if (context === this.curContext) {
|
|
258
|
-
// we exited unexpectedly while automating the current context and so want
|
|
259
|
-
// to shut down the session and respond with an error
|
|
260
|
-
let err = new Error('Chromedriver quit unexpectedly during session');
|
|
261
|
-
await this.startUnexpectedShutdown(err);
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
// if a Chromedriver in the non-active context barfs, we don't really
|
|
265
|
-
// care, we'll just make a new one next time we need the context.
|
|
266
|
-
this.log.warn("Chromedriver quit unexpectedly, but it wasn't the active " +
|
|
267
|
-
'context, ignoring');
|
|
268
|
-
delete this.sessionChromedrivers[context];
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
// Intentionally stop all the chromedrivers currently active, and ignore
|
|
272
|
-
// their exit events
|
|
273
|
-
helpers.stopChromedriverProxies = async function stopChromedriverProxies() {
|
|
274
|
-
this.suspendChromedriverProxy(); // make sure we turn off the proxy flag
|
|
275
|
-
for (let context of lodash_1.default.keys(this.sessionChromedrivers)) {
|
|
276
|
-
let cd = this.sessionChromedrivers[context];
|
|
277
|
-
this.log.debug(`Stopping chromedriver for context ${context}`);
|
|
278
|
-
// stop listening for the stopped state event
|
|
279
|
-
cd.removeAllListeners(appium_chromedriver_1.default.EVENT_CHANGED);
|
|
280
|
-
try {
|
|
281
|
-
await cd.stop();
|
|
284
|
+
// Now that we have a Chrome session, we ensure that the context is
|
|
285
|
+
// appropriately set and that this chromedriver is added to the list
|
|
286
|
+
// of session chromedrivers so we can switch back and forth
|
|
287
|
+
this.curContext = helpers_1.CHROMIUM_WIN;
|
|
288
|
+
this.sessionChromedrivers[helpers_1.CHROMIUM_WIN] = this.chromedriver;
|
|
289
|
+
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
290
|
+
this.proxyCommand = /** @type {import('@appium/types').ExternalDriver['proxyCommand']} */ (this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy));
|
|
291
|
+
this.jwpProxyActive = true;
|
|
292
|
+
if (this.shouldDismissChromeWelcome()) {
|
|
293
|
+
// dismiss Chrome welcome dialog
|
|
294
|
+
await this.dismissChromeWelcome();
|
|
282
295
|
}
|
|
283
|
-
|
|
284
|
-
|
|
296
|
+
},
|
|
297
|
+
/* --------------------------
|
|
298
|
+
* Internal library functions
|
|
299
|
+
* -------------------------- */
|
|
300
|
+
async setupExistingChromedriver(log, chromedriver) {
|
|
301
|
+
// check the status by sending a simple window-based command to ChromeDriver
|
|
302
|
+
// if there is an error, we want to recreate the ChromeDriver session
|
|
303
|
+
if (!(await chromedriver.hasWorkingWebview())) {
|
|
304
|
+
log.debug('ChromeDriver is not associated with a window. ' + 'Re-initializing the session.');
|
|
305
|
+
await chromedriver.restart();
|
|
285
306
|
}
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
};
|
|
297
|
-
helpers.dismissChromeWelcome = async function dismissChromeWelcome() {
|
|
298
|
-
this.log.info('Trying to dismiss Chrome welcome');
|
|
299
|
-
let activity = await this.getCurrentActivity();
|
|
300
|
-
if (activity !== 'org.chromium.chrome.browser.firstrun.FirstRunActivity') {
|
|
301
|
-
this.log.info('Chrome welcome dialog never showed up! Continuing');
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
let el = await this.findElOrEls('id', 'com.android.chrome:id/terms_accept', false);
|
|
305
|
-
await this.click(el.ELEMENT);
|
|
306
|
-
try {
|
|
307
|
-
let el = await this.findElOrEls('id', 'com.android.chrome:id/negative_button', false);
|
|
308
|
-
await this.click(el.ELEMENT);
|
|
309
|
-
}
|
|
310
|
-
catch (e) {
|
|
311
|
-
// DO NOTHING, THIS DEVICE DIDNT LAUNCH THE SIGNIN DIALOG
|
|
312
|
-
// IT MUST BE A NON GMS DEVICE
|
|
313
|
-
this.log.warn(`This device did not show Chrome SignIn dialog, ${e.message}`);
|
|
314
|
-
}
|
|
315
|
-
};
|
|
316
|
-
helpers.startChromeSession = async function startChromeSession() {
|
|
317
|
-
this.log.info('Starting a chrome-based browser session');
|
|
318
|
-
let opts = lodash_1.default.cloneDeep(this.opts);
|
|
319
|
-
const knownPackages = [
|
|
320
|
-
'org.chromium.chrome.shell',
|
|
321
|
-
'com.android.chrome',
|
|
322
|
-
'com.chrome.beta',
|
|
323
|
-
'org.chromium.chrome',
|
|
324
|
-
'org.chromium.webview_shell',
|
|
325
|
-
];
|
|
326
|
-
if (lodash_1.default.includes(knownPackages, this.opts.appPackage)) {
|
|
327
|
-
opts.chromeBundleId = this.opts.appPackage;
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
opts.chromeAndroidActivity = this.opts.appActivity;
|
|
331
|
-
}
|
|
332
|
-
this.chromedriver = await this.setupNewChromedriver(opts, this.adb.curDeviceId, this.adb);
|
|
333
|
-
this.chromedriver.on(appium_chromedriver_1.default.EVENT_CHANGED, (msg) => {
|
|
334
|
-
if (msg.state === appium_chromedriver_1.default.STATE_STOPPED) {
|
|
335
|
-
this.onChromedriverStop(webview_helpers_1.CHROMIUM_WIN);
|
|
307
|
+
return chromedriver;
|
|
308
|
+
},
|
|
309
|
+
async getChromedriverPort(portSpec, log) {
|
|
310
|
+
const getPort = /** @type {(opts?: import('portfinder').PortFinderOptions) => B<number>} */ (bluebird_1.default.promisify(portfinder_1.default.getPort, { context: portfinder_1.default }));
|
|
311
|
+
// if the user didn't give us any specific information about chromedriver
|
|
312
|
+
// port ranges, just find any free port
|
|
313
|
+
if (!portSpec) {
|
|
314
|
+
const port = await getPort();
|
|
315
|
+
log?.debug(`A port was not given, using random free port: ${port}`);
|
|
316
|
+
return port;
|
|
336
317
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
await chromedriver.restart();
|
|
361
|
-
}
|
|
362
|
-
return chromedriver;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Find a free port to have Chromedriver listen on.
|
|
366
|
-
*
|
|
367
|
-
* @param {array} portSpec - Array which is a list of ports. A list item may
|
|
368
|
-
* also itself be an array of length 2 specifying a start and end port of
|
|
369
|
-
* a range. Some valid port specs:
|
|
370
|
-
* - [8000, 8001, 8002]
|
|
371
|
-
* - [[8000, 8005]]
|
|
372
|
-
* - [8000, [9000, 9100]]
|
|
373
|
-
* @param {Object?} log Logger instance
|
|
374
|
-
*
|
|
375
|
-
* @return {number} A free port
|
|
376
|
-
*/
|
|
377
|
-
async function getChromedriverPort(portSpec, log = null) {
|
|
378
|
-
const getPort = bluebird_1.default.promisify(portfinder_1.default.getPort, { context: portfinder_1.default });
|
|
379
|
-
// if the user didn't give us any specific information about chromedriver
|
|
380
|
-
// port ranges, just find any free port
|
|
381
|
-
if (!portSpec) {
|
|
382
|
-
const port = await getPort();
|
|
383
|
-
log?.debug(`A port was not given, using random free port: ${port}`);
|
|
384
|
-
return port;
|
|
385
|
-
}
|
|
386
|
-
// otherwise find the free port based on a list or range provided by the user
|
|
387
|
-
log?.debug(`Finding a free port for chromedriver using spec ${JSON.stringify(portSpec)}`);
|
|
388
|
-
let foundPort = null;
|
|
389
|
-
for (const potentialPort of portSpec) {
|
|
390
|
-
let port, stopPort;
|
|
391
|
-
if (lodash_1.default.isArray(potentialPort)) {
|
|
392
|
-
([port, stopPort] = potentialPort);
|
|
318
|
+
// otherwise find the free port based on a list or range provided by the user
|
|
319
|
+
log?.debug(`Finding a free port for chromedriver using spec ${JSON.stringify(portSpec)}`);
|
|
320
|
+
let foundPort = null;
|
|
321
|
+
for (const potentialPort of portSpec) {
|
|
322
|
+
/** @type {number} */
|
|
323
|
+
let port;
|
|
324
|
+
/** @type {number} */
|
|
325
|
+
let stopPort;
|
|
326
|
+
if (lodash_1.default.isArray(potentialPort)) {
|
|
327
|
+
[port, stopPort] = potentialPort.map((p) => parseInt(String(p), 10));
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
port = parseInt(String(potentialPort), 10); // ensure we have a number and not a string
|
|
331
|
+
stopPort = port;
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
log?.debug(`Checking port range ${port}:${stopPort}`);
|
|
335
|
+
foundPort = await getPort({ port, stopPort });
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
catch (e) {
|
|
339
|
+
log?.debug(`Nothing in port range ${port}:${stopPort} was available`);
|
|
340
|
+
}
|
|
393
341
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
342
|
+
if (foundPort === null) {
|
|
343
|
+
throw new Error(`Could not find a free port for chromedriver using ` +
|
|
344
|
+
`chromedriverPorts spec ${JSON.stringify(portSpec)}`);
|
|
397
345
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
346
|
+
log?.debug(`Using free port ${foundPort} for chromedriver`);
|
|
347
|
+
return foundPort;
|
|
348
|
+
},
|
|
349
|
+
isChromedriverAutodownloadEnabled() {
|
|
350
|
+
if (this.isFeatureEnabled(CHROMEDRIVER_AUTODOWNLOAD_FEATURE)) {
|
|
351
|
+
return true;
|
|
402
352
|
}
|
|
403
|
-
|
|
404
|
-
|
|
353
|
+
this?.log?.debug(`Automated Chromedriver download is disabled. ` +
|
|
354
|
+
`Use '${CHROMEDRIVER_AUTODOWNLOAD_FEATURE}' server feature to enable it`);
|
|
355
|
+
return false;
|
|
356
|
+
},
|
|
357
|
+
async setupNewChromedriver(opts, curDeviceId, adb, context) {
|
|
358
|
+
if (opts.chromeDriverPort) {
|
|
359
|
+
this?.log?.warn(`The 'chromeDriverPort' capability is deprecated. Please use 'chromedriverPort' instead`);
|
|
360
|
+
opts.chromedriverPort = opts.chromeDriverPort;
|
|
405
361
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return foundPort;
|
|
413
|
-
}
|
|
414
|
-
helpers.isChromedriverAutodownloadEnabled = function isChromedriverAutodownloadEnabled() {
|
|
415
|
-
if (this.isFeatureEnabled(CHROMEDRIVER_AUTODOWNLOAD_FEATURE)) {
|
|
416
|
-
return true;
|
|
417
|
-
}
|
|
418
|
-
this?.log?.debug(`Automated Chromedriver download is disabled. ` +
|
|
419
|
-
`Use '${CHROMEDRIVER_AUTODOWNLOAD_FEATURE}' server feature to enable it`);
|
|
420
|
-
return false;
|
|
421
|
-
};
|
|
422
|
-
helpers.setupNewChromedriver = async function setupNewChromedriver(opts, curDeviceId, adb, context = null) {
|
|
423
|
-
if (opts.chromeDriverPort) {
|
|
424
|
-
this?.log?.warn(`The 'chromeDriverPort' capability is deprecated. Please use 'chromedriverPort' instead`);
|
|
425
|
-
opts.chromedriverPort = opts.chromeDriverPort;
|
|
426
|
-
}
|
|
427
|
-
if (opts.chromedriverPort) {
|
|
428
|
-
this?.log?.debug(`Using user-specified port ${opts.chromedriverPort} for chromedriver`);
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
// if a single port wasn't given, we'll look for a free one
|
|
432
|
-
opts.chromedriverPort = await getChromedriverPort(opts.chromedriverPorts, this?.log);
|
|
433
|
-
}
|
|
434
|
-
const details = context ? webview_helpers_1.default.getWebviewDetails(adb, context) : undefined;
|
|
435
|
-
if (!lodash_1.default.isEmpty(details)) {
|
|
436
|
-
this?.log?.debug('Passing web view details to the Chromedriver constructor: ' +
|
|
437
|
-
JSON.stringify(details, null, 2));
|
|
438
|
-
}
|
|
439
|
-
const chromedriver = new appium_chromedriver_1.default({
|
|
440
|
-
port: opts.chromedriverPort,
|
|
441
|
-
executable: opts.chromedriverExecutable,
|
|
442
|
-
adb,
|
|
443
|
-
cmdArgs: opts.chromedriverArgs,
|
|
444
|
-
verbose: !!opts.showChromedriverLog,
|
|
445
|
-
executableDir: opts.chromedriverExecutableDir,
|
|
446
|
-
mappingPath: opts.chromedriverChromeMappingFile,
|
|
447
|
-
bundleId: opts.chromeBundleId,
|
|
448
|
-
useSystemExecutable: opts.chromedriverUseSystemExecutable,
|
|
449
|
-
disableBuildCheck: opts.chromedriverDisableBuildCheck,
|
|
450
|
-
details,
|
|
451
|
-
isAutodownloadEnabled: this?.isChromedriverAutodownloadEnabled?.()
|
|
452
|
-
});
|
|
453
|
-
// make sure there are chromeOptions
|
|
454
|
-
opts.chromeOptions = opts.chromeOptions || {};
|
|
455
|
-
// try out any prefixed chromeOptions,
|
|
456
|
-
// and strip the prefix
|
|
457
|
-
for (const opt of lodash_1.default.keys(opts)) {
|
|
458
|
-
if (opt.endsWith(':chromeOptions')) {
|
|
459
|
-
this?.log?.warn(`Merging '${opt}' into 'chromeOptions'. This may cause unexpected behavior`);
|
|
460
|
-
lodash_1.default.merge(opts.chromeOptions, opts[opt]);
|
|
362
|
+
if (opts.chromedriverPort) {
|
|
363
|
+
this?.log?.debug(`Using user-specified port ${opts.chromedriverPort} for chromedriver`);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// if a single port wasn't given, we'll look for a free one
|
|
367
|
+
opts.chromedriverPort = await this.getChromedriverPort(opts.chromedriverPorts, this?.log);
|
|
461
368
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
369
|
+
const details = context ? helpers_1.WebviewHelpers.getWebviewDetails(adb, context) : undefined;
|
|
370
|
+
if (!lodash_1.default.isEmpty(details)) {
|
|
371
|
+
this?.log?.debug('Passing web view details to the Chromedriver constructor: ' +
|
|
372
|
+
JSON.stringify(details, null, 2));
|
|
373
|
+
}
|
|
374
|
+
const chromedriver = new appium_chromedriver_1.default({
|
|
375
|
+
port: String(opts.chromedriverPort),
|
|
376
|
+
executable: opts.chromedriverExecutable,
|
|
377
|
+
// eslint-disable-next-line object-shorthand
|
|
378
|
+
adb: /** @type {any} */ (adb),
|
|
379
|
+
cmdArgs: /** @type {string[]} */ (opts.chromedriverArgs),
|
|
380
|
+
verbose: !!opts.showChromedriverLog,
|
|
381
|
+
executableDir: opts.chromedriverExecutableDir,
|
|
382
|
+
mappingPath: opts.chromedriverChromeMappingFile,
|
|
383
|
+
// @ts-expect-error arbitrary value on opts?
|
|
384
|
+
bundleId: opts.chromeBundleId,
|
|
385
|
+
useSystemExecutable: opts.chromedriverUseSystemExecutable,
|
|
386
|
+
disableBuildCheck: opts.chromedriverDisableBuildCheck,
|
|
387
|
+
// @ts-expect-error FIXME: chromedriver typing are probably too strict
|
|
388
|
+
details,
|
|
389
|
+
isAutodownloadEnabled: this?.isChromedriverAutodownloadEnabled?.(),
|
|
390
|
+
});
|
|
391
|
+
// make sure there are chromeOptions
|
|
392
|
+
opts.chromeOptions = opts.chromeOptions || {};
|
|
393
|
+
// try out any prefixed chromeOptions,
|
|
394
|
+
// and strip the prefix
|
|
395
|
+
for (const opt of lodash_1.default.keys(opts)) {
|
|
396
|
+
if (opt.endsWith(':chromeOptions')) {
|
|
397
|
+
this?.log?.warn(`Merging '${opt}' into 'chromeOptions'. This may cause unexpected behavior`);
|
|
398
|
+
// @ts-expect-error unsafe types
|
|
399
|
+
lodash_1.default.merge(opts.chromeOptions, opts[opt]);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const caps = /** @type {any} */ (helpers_1.WebviewHelpers.createChromedriverCaps(opts, curDeviceId, details));
|
|
403
|
+
this?.log?.debug(`Before starting chromedriver, androidPackage is '${caps.chromeOptions.androidPackage}'`);
|
|
404
|
+
await chromedriver.start(caps);
|
|
405
|
+
return chromedriver;
|
|
406
|
+
},
|
|
467
407
|
};
|
|
468
|
-
|
|
469
|
-
exports.
|
|
470
|
-
|
|
471
|
-
|
|
408
|
+
(0, mixins_1.mixin)(ContextMixin);
|
|
409
|
+
exports.default = ContextMixin;
|
|
410
|
+
exports.setupNewChromedriver = ContextMixin.setupNewChromedriver;
|
|
411
|
+
/**
|
|
412
|
+
* @typedef {import('appium-adb').ADB} ADB
|
|
413
|
+
*/
|
|
472
414
|
//# sourceMappingURL=context.js.map
|