appium 2.0.0-beta.35 → 2.0.0-beta.37
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/build/lib/appium.d.ts +41 -52
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +32 -15
- package/build/lib/cli/args.d.ts +1 -1
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +1 -1
- package/build/lib/cli/driver-command.d.ts +3 -3
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +1 -1
- package/build/lib/cli/extension-command.d.ts +60 -38
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +115 -59
- package/build/lib/cli/extension.d.ts +9 -5
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js +5 -7
- package/build/lib/cli/parser.d.ts +3 -3
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +1 -1
- package/build/lib/cli/plugin-command.d.ts +1 -1
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +1 -1
- package/build/lib/cli/utils.js +1 -1
- package/build/lib/config-file.d.ts.map +1 -1
- package/build/lib/config-file.js +1 -1
- package/build/lib/config.d.ts +4 -4
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +1 -1
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +1 -1
- package/build/lib/extension/driver-config.d.ts +29 -32
- package/build/lib/extension/driver-config.d.ts.map +1 -1
- package/build/lib/extension/driver-config.js +7 -20
- package/build/lib/extension/extension-config.d.ts +108 -36
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +199 -60
- package/build/lib/extension/index.d.ts +16 -7
- package/build/lib/extension/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +15 -18
- package/build/lib/extension/manifest.d.ts +12 -12
- package/build/lib/extension/manifest.d.ts.map +1 -1
- package/build/lib/extension/manifest.js +13 -3
- package/build/lib/extension/package-changed.d.ts.map +1 -1
- package/build/lib/extension/package-changed.js +1 -1
- package/build/lib/extension/plugin-config.d.ts +19 -24
- package/build/lib/extension/plugin-config.d.ts.map +1 -1
- package/build/lib/extension/plugin-config.js +9 -18
- package/build/lib/grid-register.d.ts.map +1 -1
- package/build/lib/grid-register.js +1 -1
- package/build/lib/logger.d.ts +1 -1
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +1 -1
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +3 -2
- package/build/lib/main.d.ts +13 -12
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +4 -4
- package/build/lib/schema/arg-spec.d.ts +4 -4
- package/build/lib/schema/arg-spec.d.ts.map +1 -1
- package/build/lib/schema/arg-spec.js +1 -1
- package/build/lib/schema/cli-args.d.ts.map +1 -1
- package/build/lib/schema/cli-args.js +1 -1
- package/build/lib/schema/cli-transformers.d.ts.map +1 -1
- package/build/lib/schema/cli-transformers.js +1 -1
- package/build/lib/schema/keywords.d.ts.map +1 -1
- package/build/lib/schema/keywords.js +1 -1
- package/build/lib/schema/schema.d.ts +2 -2
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/appium-manifest.d.ts +23 -4
- package/build/types/appium-manifest.d.ts.map +1 -1
- package/build/types/cli.d.ts.map +1 -1
- package/build/types/{external-manifest.d.ts → extension-manifest.d.ts} +15 -7
- package/build/types/extension-manifest.d.ts.map +1 -0
- package/build/types/index.d.ts +6 -5
- package/build/types/index.d.ts.map +1 -1
- package/driver.d.ts +1 -0
- package/driver.js +14 -0
- package/lib/appium.js +208 -124
- package/lib/cli/args.js +143 -93
- package/lib/cli/driver-command.js +10 -15
- package/lib/cli/extension-command.js +226 -175
- package/lib/cli/extension.js +15 -19
- package/lib/cli/parser.js +19 -31
- package/lib/cli/plugin-command.js +8 -8
- package/lib/cli/utils.js +8 -14
- package/lib/config-file.js +21 -25
- package/lib/config.js +82 -64
- package/lib/constants.js +4 -13
- package/lib/extension/driver-config.js +171 -171
- package/lib/extension/extension-config.js +347 -126
- package/lib/extension/index.js +72 -58
- package/lib/extension/manifest.js +48 -57
- package/lib/extension/package-changed.js +9 -8
- package/lib/extension/plugin-config.js +62 -62
- package/lib/grid-register.js +29 -18
- package/lib/logger.js +1 -2
- package/lib/logsink.js +29 -31
- package/lib/main.js +111 -73
- package/lib/schema/arg-spec.js +10 -13
- package/lib/schema/cli-args.js +14 -37
- package/lib/schema/cli-transformers.js +7 -14
- package/lib/schema/keywords.js +15 -13
- package/lib/schema/schema.js +58 -75
- package/lib/utils.js +50 -25
- package/package.json +25 -18
- package/plugin.d.ts +1 -0
- package/plugin.js +13 -0
- package/scripts/autoinstall-extensions.js +177 -0
- package/support.d.ts +1 -0
- package/support.js +13 -0
- package/types/appium-manifest.ts +27 -15
- package/types/cli.ts +2 -9
- package/types/{external-manifest.ts → extension-manifest.ts} +21 -15
- package/types/index.ts +12 -5
- package/build/types/extension.d.ts +0 -43
- package/build/types/extension.d.ts.map +0 -1
- package/build/types/external-manifest.d.ts.map +0 -1
- package/scripts/postinstall.js +0 -71
- package/types/extension.ts +0 -56
package/lib/appium.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
/* eslint-disable no-unused-vars */
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import {getBuildInfo, updateBuildInfo, APPIUM_VER} from './config';
|
|
4
|
+
import {
|
|
5
|
+
BaseDriver,
|
|
6
|
+
DriverCore,
|
|
7
|
+
errors,
|
|
8
|
+
isSessionCommand,
|
|
9
|
+
CREATE_SESSION_COMMAND,
|
|
10
|
+
DELETE_SESSION_COMMAND,
|
|
11
|
+
GET_STATUS_COMMAND,
|
|
6
12
|
} from '@appium/base-driver';
|
|
7
13
|
import AsyncLock from 'async-lock';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
14
|
+
import {parseCapsForInnerDriver, pullSettings} from './utils';
|
|
15
|
+
import {util, node, logger} from '@appium/support';
|
|
16
|
+
import {getDefaultsForExtension} from './schema';
|
|
17
|
+
import {DRIVER_TYPE, PLUGIN_TYPE} from './constants';
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Invariant set of base constraints
|
|
@@ -56,9 +63,9 @@ class AppiumDriver extends DriverCore {
|
|
|
56
63
|
|
|
57
64
|
/**
|
|
58
65
|
* List of active plugins
|
|
59
|
-
* @type {PluginClass
|
|
66
|
+
* @type {Map<PluginClass,string>}
|
|
60
67
|
*/
|
|
61
|
-
pluginClasses
|
|
68
|
+
pluginClasses;
|
|
62
69
|
|
|
63
70
|
/**
|
|
64
71
|
* map of sessions to actual plugin instances per session
|
|
@@ -70,7 +77,7 @@ class AppiumDriver extends DriverCore {
|
|
|
70
77
|
* some commands are sessionless, so we need a set of plugins for them
|
|
71
78
|
* @type {InstanceType<PluginClass>[]}
|
|
72
79
|
*/
|
|
73
|
-
sessionlessPlugins = []
|
|
80
|
+
sessionlessPlugins = [];
|
|
74
81
|
|
|
75
82
|
/** @type {DriverConfig} */
|
|
76
83
|
driverConfig;
|
|
@@ -78,10 +85,15 @@ class AppiumDriver extends DriverCore {
|
|
|
78
85
|
/** @type {AppiumServer} */
|
|
79
86
|
server;
|
|
80
87
|
|
|
88
|
+
desiredCapConstraints = desiredCapabilityConstraints;
|
|
89
|
+
|
|
90
|
+
/** @type {DriverOpts} */
|
|
91
|
+
args;
|
|
92
|
+
|
|
81
93
|
/**
|
|
82
94
|
* @param {DriverOpts} opts
|
|
83
95
|
*/
|
|
84
|
-
constructor
|
|
96
|
+
constructor(opts) {
|
|
85
97
|
// It is necessary to set `--tmp` here since it should be set to
|
|
86
98
|
// process.env.APPIUM_TMP_DIR once at an initial point in the Appium lifecycle.
|
|
87
99
|
// The process argument will be referenced by BaseDriver.
|
|
@@ -92,8 +104,6 @@ class AppiumDriver extends DriverCore {
|
|
|
92
104
|
|
|
93
105
|
super(opts);
|
|
94
106
|
|
|
95
|
-
this.desiredCapConstraints = desiredCapabilityConstraints;
|
|
96
|
-
|
|
97
107
|
this.args = {...opts};
|
|
98
108
|
|
|
99
109
|
// allow this to happen in the background, so no `await`
|
|
@@ -107,7 +117,7 @@ class AppiumDriver extends DriverCore {
|
|
|
107
117
|
/**
|
|
108
118
|
* Retrieves logger instance for the current umbrella driver instance
|
|
109
119
|
*/
|
|
110
|
-
get log
|
|
120
|
+
get log() {
|
|
111
121
|
if (!this._log) {
|
|
112
122
|
const instanceName = `${this.constructor.name}@${node.getObjectId(this).substring(0, 4)}`;
|
|
113
123
|
this._log = logger.getLogger(instanceName);
|
|
@@ -118,65 +128,83 @@ class AppiumDriver extends DriverCore {
|
|
|
118
128
|
/**
|
|
119
129
|
* Cancel commands queueing for the umbrella Appium driver
|
|
120
130
|
*/
|
|
121
|
-
get isCommandsQueueEnabled
|
|
131
|
+
get isCommandsQueueEnabled() {
|
|
122
132
|
return false;
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
sessionExists
|
|
135
|
+
sessionExists(sessionId) {
|
|
126
136
|
const dstSession = this.sessions[sessionId];
|
|
127
137
|
return dstSession && dstSession.sessionId !== null;
|
|
128
138
|
}
|
|
129
139
|
|
|
130
|
-
driverForSession
|
|
140
|
+
driverForSession(sessionId) {
|
|
131
141
|
return this.sessions[sessionId];
|
|
132
142
|
}
|
|
133
143
|
|
|
134
|
-
|
|
144
|
+
// eslint-disable-next-line require-await
|
|
145
|
+
async getStatus() {
|
|
135
146
|
return {
|
|
136
147
|
build: _.clone(getBuildInfo()),
|
|
137
148
|
};
|
|
138
149
|
}
|
|
139
150
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
151
|
+
// eslint-disable-next-line require-await
|
|
152
|
+
async getSessions() {
|
|
153
|
+
return _.toPairs(this.sessions).map(([id, driver]) => ({
|
|
154
|
+
id,
|
|
155
|
+
capabilities: driver.caps,
|
|
156
|
+
}));
|
|
143
157
|
}
|
|
144
158
|
|
|
145
|
-
printNewSessionAnnouncement
|
|
146
|
-
this.log.info(
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
printNewSessionAnnouncement(driverName, driverVersion, driverBaseVersion) {
|
|
160
|
+
this.log.info(
|
|
161
|
+
driverVersion
|
|
162
|
+
? `Appium v${APPIUM_VER} creating new ${driverName} (v${driverVersion}) session`
|
|
163
|
+
: `Appium v${APPIUM_VER} creating new ${driverName} session`
|
|
149
164
|
);
|
|
150
165
|
this.log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
|
|
151
|
-
this.log.info(
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
this.log.info(
|
|
167
|
+
AppiumDriver.baseVersion
|
|
168
|
+
? `Appium's BaseDriver version is ${AppiumDriver.baseVersion}`
|
|
169
|
+
: `Could not determine Appium's BaseDriver version`
|
|
154
170
|
);
|
|
155
|
-
this.log.info(
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
this.log.info(
|
|
172
|
+
driverBaseVersion
|
|
173
|
+
? `${driverName}'s BaseDriver version is ${driverBaseVersion}`
|
|
174
|
+
: `Could not determine ${driverName}'s BaseDriver version`
|
|
158
175
|
);
|
|
159
176
|
}
|
|
160
177
|
|
|
161
178
|
/**
|
|
162
|
-
*
|
|
179
|
+
* Retrieves all CLI arguments for a specific plugin.
|
|
180
|
+
* @param {string} extName - Plugin name
|
|
181
|
+
* @returns {Record<string,unknown>} Arguments object. If none, an empty object.
|
|
182
|
+
*/
|
|
183
|
+
getCliArgsForPlugin(extName) {
|
|
184
|
+
return /** @type {Record<string,unknown>} */ (this.args.plugin?.[extName] ?? {});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Retrieves CLI args for a specific driver.
|
|
163
189
|
*
|
|
164
|
-
*
|
|
190
|
+
* _Any arg which is equal to its default value will not be present in the returned object._
|
|
165
191
|
*
|
|
166
|
-
*
|
|
167
|
-
* @param {
|
|
168
|
-
* @
|
|
169
|
-
* @param {Object} extInstance the driver or plugin instance
|
|
192
|
+
* _Note that this behavior currently (May 18 2022) differs from how plugins are handled_ (see {@linkcode AppiumDriver.getCliArgsForPlugin}).
|
|
193
|
+
* @param {string} extName - Driver name
|
|
194
|
+
* @returns {Record<string,unknown>|undefined} Arguments object. If none, `undefined`
|
|
170
195
|
*/
|
|
171
|
-
|
|
172
|
-
const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */(
|
|
196
|
+
getCliArgsForDriver(extName) {
|
|
197
|
+
const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */ (
|
|
198
|
+
this.args.driver?.[extName]
|
|
199
|
+
);
|
|
200
|
+
|
|
173
201
|
if (!_.isEmpty(allCliArgsForExt)) {
|
|
174
|
-
const defaults = getDefaultsForExtension(
|
|
202
|
+
const defaults = getDefaultsForExtension(DRIVER_TYPE, extName);
|
|
175
203
|
const cliArgs = _.isEmpty(defaults)
|
|
176
204
|
? allCliArgsForExt
|
|
177
205
|
: _.omitBy(allCliArgsForExt, (value, key) => _.isEqual(defaults[key], value));
|
|
178
206
|
if (!_.isEmpty(cliArgs)) {
|
|
179
|
-
|
|
207
|
+
return cliArgs;
|
|
180
208
|
}
|
|
181
209
|
}
|
|
182
210
|
}
|
|
@@ -186,9 +214,9 @@ class AppiumDriver extends DriverCore {
|
|
|
186
214
|
* @param {W3CCapabilities} jsonwpCaps JSONWP formatted desired capabilities
|
|
187
215
|
* @param {W3CCapabilities} reqCaps Required capabilities (JSONWP standard)
|
|
188
216
|
* @param {W3CCapabilities} w3cCapabilities W3C capabilities
|
|
189
|
-
* @param {
|
|
217
|
+
* @param {DriverData[]} [driverData]
|
|
190
218
|
*/
|
|
191
|
-
async createSession
|
|
219
|
+
async createSession(jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
|
|
192
220
|
const defaultCapabilities = _.cloneDeep(this.args.defaultCapabilities);
|
|
193
221
|
const defaultSettings = pullSettings(defaultCapabilities);
|
|
194
222
|
jsonwpCaps = _.cloneDeep(jsonwpCaps);
|
|
@@ -200,9 +228,9 @@ class AppiumDriver extends DriverCore {
|
|
|
200
228
|
// JSONWP caps to W3C caps
|
|
201
229
|
const w3cSettings = {
|
|
202
230
|
...jwpSettings,
|
|
203
|
-
...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {})
|
|
231
|
+
...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {}),
|
|
204
232
|
};
|
|
205
|
-
for (const firstMatchEntry of (
|
|
233
|
+
for (const firstMatchEntry of (w3cCapabilities ?? {}).firstMatch ?? []) {
|
|
206
234
|
Object.assign(w3cSettings, pullSettings(firstMatchEntry));
|
|
207
235
|
}
|
|
208
236
|
|
|
@@ -217,9 +245,10 @@ class AppiumDriver extends DriverCore {
|
|
|
217
245
|
defaultCapabilities
|
|
218
246
|
);
|
|
219
247
|
|
|
220
|
-
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} =
|
|
248
|
+
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} =
|
|
249
|
+
/** @type {import('./utils').ParsedDriverCaps} */ (parsedCaps);
|
|
221
250
|
protocol = parsedCaps.protocol;
|
|
222
|
-
const error = /** @type {import('./utils').InvalidCaps} */(parsedCaps).error;
|
|
251
|
+
const error = /** @type {import('./utils').InvalidCaps} */ (parsedCaps).error;
|
|
223
252
|
// If the parsing of the caps produced an error, throw it in here
|
|
224
253
|
if (error) {
|
|
225
254
|
throw error;
|
|
@@ -228,7 +257,7 @@ class AppiumDriver extends DriverCore {
|
|
|
228
257
|
const {
|
|
229
258
|
driver: InnerDriver,
|
|
230
259
|
version: driverVersion,
|
|
231
|
-
driverName
|
|
260
|
+
driverName,
|
|
232
261
|
} = this.driverConfig.findMatchingDriver(desiredCaps);
|
|
233
262
|
this.printNewSessionAnnouncement(InnerDriver.name, driverVersion, InnerDriver.baseVersion);
|
|
234
263
|
|
|
@@ -252,9 +281,11 @@ class AppiumDriver extends DriverCore {
|
|
|
252
281
|
// could have been set by a malicious user via capabilities, whereas we
|
|
253
282
|
// want a guarantee the values were set by the appium server admin
|
|
254
283
|
if (this.args.relaxedSecurityEnabled) {
|
|
255
|
-
this.log.info(
|
|
256
|
-
`
|
|
257
|
-
|
|
284
|
+
this.log.info(
|
|
285
|
+
`Applying relaxed security to '${InnerDriver.name}' as per ` +
|
|
286
|
+
`server command line argument. All insecure features will be ` +
|
|
287
|
+
`enabled unless explicitly disabled by --deny-insecure`
|
|
288
|
+
);
|
|
258
289
|
driverInstance.relaxedSecurityEnabled = true;
|
|
259
290
|
}
|
|
260
291
|
|
|
@@ -272,7 +303,10 @@ class AppiumDriver extends DriverCore {
|
|
|
272
303
|
|
|
273
304
|
// Likewise, any driver-specific CLI args that were passed in should be assigned directly to
|
|
274
305
|
// the driver so that they cannot be mimicked by a malicious user sending in capabilities
|
|
275
|
-
this.
|
|
306
|
+
const cliArgs = this.getCliArgsForDriver(driverName);
|
|
307
|
+
if (!_.isEmpty(cliArgs)) {
|
|
308
|
+
driverInstance.cliArgs = cliArgs;
|
|
309
|
+
}
|
|
276
310
|
|
|
277
311
|
// This assignment is required for correct web sockets functionality inside the driver
|
|
278
312
|
// Drivers/plugins might also want to know where they are hosted
|
|
@@ -284,13 +318,15 @@ class AppiumDriver extends DriverCore {
|
|
|
284
318
|
driverInstance.serverPath = this.args.basePath;
|
|
285
319
|
|
|
286
320
|
try {
|
|
287
|
-
runningDriversData = await this.curSessionDataForDriver(InnerDriver) ?? [];
|
|
321
|
+
runningDriversData = (await this.curSessionDataForDriver(InnerDriver)) ?? [];
|
|
288
322
|
} catch (e) {
|
|
289
323
|
throw new errors.SessionNotCreatedError(e.message);
|
|
290
324
|
}
|
|
291
325
|
await pendingDriversGuard.acquire(AppiumDriver.name, () => {
|
|
292
326
|
this.pendingDrivers[InnerDriver.name] = this.pendingDrivers[InnerDriver.name] || [];
|
|
293
|
-
otherPendingDriversData = _.compact(
|
|
327
|
+
otherPendingDriversData = _.compact(
|
|
328
|
+
this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData)
|
|
329
|
+
);
|
|
294
330
|
this.pendingDrivers[InnerDriver.name].push(driverInstance);
|
|
295
331
|
});
|
|
296
332
|
|
|
@@ -311,20 +347,26 @@ class AppiumDriver extends DriverCore {
|
|
|
311
347
|
|
|
312
348
|
this.attachUnexpectedShutdownHandler(driverInstance, innerSessionId);
|
|
313
349
|
|
|
314
|
-
this.log.info(
|
|
315
|
-
|
|
350
|
+
this.log.info(
|
|
351
|
+
`New ${InnerDriver.name} session created successfully, session ` +
|
|
352
|
+
`${innerSessionId} added to master session list`
|
|
353
|
+
);
|
|
316
354
|
|
|
317
355
|
// set the New Command Timeout for the inner driver
|
|
318
356
|
driverInstance.startNewCommandTimeout();
|
|
319
357
|
|
|
320
358
|
// apply initial values to Appium settings (if provided)
|
|
321
359
|
if (driverInstance.isW3CProtocol() && !_.isEmpty(w3cSettings)) {
|
|
322
|
-
this.log.info(
|
|
323
|
-
|
|
360
|
+
this.log.info(
|
|
361
|
+
`Applying the initial values to Appium settings parsed from W3C caps: ` +
|
|
362
|
+
JSON.stringify(w3cSettings)
|
|
363
|
+
);
|
|
324
364
|
await driverInstance.updateSettings(w3cSettings);
|
|
325
365
|
} else if (driverInstance.isMjsonwpProtocol() && !_.isEmpty(jwpSettings)) {
|
|
326
|
-
this.log.info(
|
|
327
|
-
|
|
366
|
+
this.log.info(
|
|
367
|
+
`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
|
|
368
|
+
JSON.stringify(jwpSettings)
|
|
369
|
+
);
|
|
328
370
|
await driverInstance.updateSettings(jwpSettings);
|
|
329
371
|
}
|
|
330
372
|
} catch (error) {
|
|
@@ -336,22 +378,31 @@ class AppiumDriver extends DriverCore {
|
|
|
336
378
|
|
|
337
379
|
return {
|
|
338
380
|
protocol,
|
|
339
|
-
value: [innerSessionId, dCaps, protocol]
|
|
381
|
+
value: [innerSessionId, dCaps, protocol],
|
|
340
382
|
};
|
|
341
383
|
}
|
|
342
384
|
|
|
343
|
-
|
|
385
|
+
/**
|
|
386
|
+
*
|
|
387
|
+
* @param {Driver} driver
|
|
388
|
+
* @param {string} innerSessionId
|
|
389
|
+
*/
|
|
390
|
+
attachUnexpectedShutdownHandler(driver, innerSessionId) {
|
|
344
391
|
const onShutdown = (cause = new Error('Unknown error')) => {
|
|
345
392
|
this.log.warn(`Ending session, cause was '${cause.message}'`);
|
|
346
393
|
|
|
347
394
|
if (this.sessionPlugins[innerSessionId]) {
|
|
348
395
|
for (const plugin of this.sessionPlugins[innerSessionId]) {
|
|
349
396
|
if (_.isFunction(plugin.onUnexpectedShutdown)) {
|
|
350
|
-
this.log.debug(
|
|
397
|
+
this.log.debug(
|
|
398
|
+
`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`
|
|
399
|
+
);
|
|
351
400
|
try {
|
|
352
401
|
plugin.onUnexpectedShutdown(driver, cause);
|
|
353
402
|
} catch (e) {
|
|
354
|
-
this.log.warn(
|
|
403
|
+
this.log.warn(
|
|
404
|
+
`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`
|
|
405
|
+
);
|
|
355
406
|
}
|
|
356
407
|
} else {
|
|
357
408
|
this.log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
|
|
@@ -367,24 +418,31 @@ class AppiumDriver extends DriverCore {
|
|
|
367
418
|
if (_.isFunction(driver.onUnexpectedShutdown)) {
|
|
368
419
|
driver.onUnexpectedShutdown(onShutdown);
|
|
369
420
|
} else {
|
|
370
|
-
this.log.warn(
|
|
371
|
-
`
|
|
421
|
+
this.log.warn(
|
|
422
|
+
`Failed to attach the unexpected shutdown listener. ` +
|
|
423
|
+
`Is 'onUnexpectedShutdown' method available for '${driver.constructor.name}'?`
|
|
424
|
+
);
|
|
372
425
|
}
|
|
373
426
|
}
|
|
374
427
|
|
|
375
428
|
/**
|
|
376
429
|
*
|
|
377
|
-
* @param {
|
|
430
|
+
* @param {DriverClass} InnerDriver
|
|
378
431
|
* @returns {Promise<DriverData[]>}}
|
|
379
432
|
*/
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
.
|
|
433
|
+
// eslint-disable-next-line require-await
|
|
434
|
+
async curSessionDataForDriver(InnerDriver) {
|
|
435
|
+
const data = _.compact(
|
|
436
|
+
_.values(this.sessions)
|
|
437
|
+
.filter((s) => s.constructor.name === InnerDriver.name)
|
|
438
|
+
.map((s) => s.driverData)
|
|
439
|
+
);
|
|
384
440
|
for (const datum of data) {
|
|
385
441
|
if (!datum) {
|
|
386
|
-
throw new Error(
|
|
387
|
-
|
|
442
|
+
throw new Error(
|
|
443
|
+
`Problem getting session data for driver type ` +
|
|
444
|
+
`${InnerDriver.name}; does it implement 'get driverData'?`
|
|
445
|
+
);
|
|
388
446
|
}
|
|
389
447
|
}
|
|
390
448
|
return data;
|
|
@@ -393,7 +451,7 @@ class AppiumDriver extends DriverCore {
|
|
|
393
451
|
/**
|
|
394
452
|
* @param {string} sessionId
|
|
395
453
|
*/
|
|
396
|
-
async deleteSession
|
|
454
|
+
async deleteSession(sessionId) {
|
|
397
455
|
let protocol;
|
|
398
456
|
try {
|
|
399
457
|
let otherSessionsData;
|
|
@@ -403,8 +461,10 @@ class AppiumDriver extends DriverCore {
|
|
|
403
461
|
}
|
|
404
462
|
const curConstructorName = this.sessions[sessionId].constructor.name;
|
|
405
463
|
otherSessionsData = _.toPairs(this.sessions)
|
|
406
|
-
|
|
407
|
-
|
|
464
|
+
.filter(
|
|
465
|
+
([key, value]) => value.constructor.name === curConstructorName && key !== sessionId
|
|
466
|
+
)
|
|
467
|
+
.map(([, value]) => value.driverData);
|
|
408
468
|
const dstSession = this.sessions[sessionId];
|
|
409
469
|
protocol = dstSession.protocol;
|
|
410
470
|
this.log.info(`Removing session ${sessionId} from our master session list`);
|
|
@@ -433,20 +493,19 @@ class AppiumDriver extends DriverCore {
|
|
|
433
493
|
}
|
|
434
494
|
}
|
|
435
495
|
|
|
436
|
-
async deleteAllSessions
|
|
496
|
+
async deleteAllSessions(opts = {}) {
|
|
437
497
|
const sessionsCount = _.size(this.sessions);
|
|
438
498
|
if (0 === sessionsCount) {
|
|
439
499
|
this.log.debug('There are no active sessions for cleanup');
|
|
440
500
|
return;
|
|
441
501
|
}
|
|
442
502
|
|
|
443
|
-
const {
|
|
444
|
-
force = false,
|
|
445
|
-
reason,
|
|
446
|
-
} = opts;
|
|
503
|
+
const {force = false, reason} = opts;
|
|
447
504
|
this.log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
|
|
448
505
|
const cleanupPromises = force
|
|
449
|
-
? _.values(this.sessions).map((drv) =>
|
|
506
|
+
? _.values(this.sessions).map((drv) =>
|
|
507
|
+
drv.startUnexpectedShutdown(reason && new Error(reason))
|
|
508
|
+
)
|
|
450
509
|
: _.keys(this.sessions).map((id) => this.deleteSession(id));
|
|
451
510
|
for (const cleanupPromise of cleanupPromises) {
|
|
452
511
|
try {
|
|
@@ -463,7 +522,7 @@ class AppiumDriver extends DriverCore {
|
|
|
463
522
|
* @param {?string} sessionId - the sessionId (or null) to use to find plugins
|
|
464
523
|
* @returns {Array} - array of plugin instances
|
|
465
524
|
*/
|
|
466
|
-
pluginsForSession
|
|
525
|
+
pluginsForSession(sessionId = null) {
|
|
467
526
|
if (sessionId) {
|
|
468
527
|
if (!this.sessionPlugins[sessionId]) {
|
|
469
528
|
this.sessionPlugins[sessionId] = this.createPluginInstances();
|
|
@@ -487,29 +546,36 @@ class AppiumDriver extends DriverCore {
|
|
|
487
546
|
* @param {?string} sessionId - the particular session for which to find a plugin, or null if
|
|
488
547
|
* sessionless
|
|
489
548
|
*/
|
|
490
|
-
pluginsToHandleCmd
|
|
549
|
+
pluginsToHandleCmd(cmd, sessionId = null) {
|
|
491
550
|
// to handle a given command, a plugin should either implement that command as a plugin
|
|
492
551
|
// instance method or it should implement a generic 'handle' method
|
|
493
|
-
return this.pluginsForSession(sessionId)
|
|
494
|
-
|
|
552
|
+
return this.pluginsForSession(sessionId).filter(
|
|
553
|
+
(p) => _.isFunction(p[cmd]) || _.isFunction(p.handle)
|
|
554
|
+
);
|
|
495
555
|
}
|
|
496
556
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
557
|
+
/**
|
|
558
|
+
* Creates instances of all of the enabled Plugin classes
|
|
559
|
+
* @returns {Plugin[]}
|
|
560
|
+
*/
|
|
561
|
+
createPluginInstances() {
|
|
562
|
+
/** @type {Plugin[]} */
|
|
563
|
+
const pluginInstances = [];
|
|
564
|
+
for (const [PluginClass, name] of this.pluginClasses.entries()) {
|
|
565
|
+
const cliArgs = this.getCliArgsForPlugin(name);
|
|
566
|
+
const plugin = new PluginClass(name, cliArgs);
|
|
567
|
+
pluginInstances.push(plugin);
|
|
568
|
+
}
|
|
569
|
+
return pluginInstances;
|
|
504
570
|
}
|
|
505
571
|
|
|
506
572
|
/**
|
|
507
573
|
*
|
|
508
574
|
* @param {string} cmd
|
|
509
575
|
* @param {...any} args
|
|
510
|
-
* @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<
|
|
576
|
+
* @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<Driver['executeCommand']>>}
|
|
511
577
|
*/
|
|
512
|
-
async executeCommand
|
|
578
|
+
async executeCommand(cmd, ...args) {
|
|
513
579
|
// We have basically three cases for how to handle commands:
|
|
514
580
|
// 1. handle getStatus (we do this as a special out of band case so it doesn't get added to an
|
|
515
581
|
// execution queue, and can be called while e.g. createSession is in progress)
|
|
@@ -531,7 +597,6 @@ class AppiumDriver extends DriverCore {
|
|
|
531
597
|
args.pop();
|
|
532
598
|
}
|
|
533
599
|
|
|
534
|
-
|
|
535
600
|
// first do some error checking. If we're requesting a session command execution, then make
|
|
536
601
|
// sure that session actually exists on the session driver, and set the session driver itself
|
|
537
602
|
let sessionId = null;
|
|
@@ -584,8 +649,11 @@ class AppiumDriver extends DriverCore {
|
|
|
584
649
|
if (!dstSession.proxyCommand) {
|
|
585
650
|
throw new NoDriverProxyCommandError();
|
|
586
651
|
}
|
|
587
|
-
return await dstSession.proxyCommand(
|
|
588
|
-
reqForProxy.
|
|
652
|
+
return await dstSession.proxyCommand(
|
|
653
|
+
reqForProxy.originalUrl,
|
|
654
|
+
reqForProxy.method,
|
|
655
|
+
reqForProxy.body
|
|
656
|
+
);
|
|
589
657
|
}
|
|
590
658
|
|
|
591
659
|
if (isGetStatus) {
|
|
@@ -604,7 +672,12 @@ class AppiumDriver extends DriverCore {
|
|
|
604
672
|
|
|
605
673
|
// now take our default behavior, wrap it with any number of plugin behaviors, and run it
|
|
606
674
|
const wrappedCmd = this.wrapCommandWithPlugins({
|
|
607
|
-
driver,
|
|
675
|
+
driver,
|
|
676
|
+
cmd,
|
|
677
|
+
args,
|
|
678
|
+
plugins,
|
|
679
|
+
cmdHandledBy,
|
|
680
|
+
next: defaultBehavior,
|
|
608
681
|
});
|
|
609
682
|
const res = await this.executeWrappedCommand({wrappedCmd, protocol});
|
|
610
683
|
|
|
@@ -617,8 +690,10 @@ class AppiumDriver extends DriverCore {
|
|
|
617
690
|
// their createSession method and other instance methods
|
|
618
691
|
if (cmd === CREATE_SESSION_COMMAND && this.sessionlessPlugins.length && !res.error) {
|
|
619
692
|
const sessionId = _.first(res.value);
|
|
620
|
-
this.log.info(
|
|
621
|
-
`to
|
|
693
|
+
this.log.info(
|
|
694
|
+
`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
|
|
695
|
+
`to session ID ${sessionId}`
|
|
696
|
+
);
|
|
622
697
|
this.sessionPlugins[sessionId] = this.sessionlessPlugins;
|
|
623
698
|
this.sessionlessPlugins = [];
|
|
624
699
|
}
|
|
@@ -626,8 +701,9 @@ class AppiumDriver extends DriverCore {
|
|
|
626
701
|
return res;
|
|
627
702
|
}
|
|
628
703
|
|
|
629
|
-
wrapCommandWithPlugins
|
|
630
|
-
plugins.length &&
|
|
704
|
+
wrapCommandWithPlugins({driver, cmd, args, next, cmdHandledBy, plugins}) {
|
|
705
|
+
plugins.length &&
|
|
706
|
+
this.log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
|
|
631
707
|
|
|
632
708
|
// now we can go through each plugin and wrap `next` around its own handler, passing the *old*
|
|
633
709
|
// next in so that it can call it if it wants to
|
|
@@ -651,7 +727,7 @@ class AppiumDriver extends DriverCore {
|
|
|
651
727
|
return next;
|
|
652
728
|
}
|
|
653
729
|
|
|
654
|
-
logPluginHandlerReport
|
|
730
|
+
logPluginHandlerReport(plugins, {cmd, cmdHandledBy}) {
|
|
655
731
|
if (!plugins.length) {
|
|
656
732
|
return;
|
|
657
733
|
}
|
|
@@ -665,14 +741,18 @@ class AppiumDriver extends DriverCore {
|
|
|
665
741
|
const didHandle = Object.keys(cmdHandledBy).filter((k) => cmdHandledBy[k]);
|
|
666
742
|
const didntHandle = Object.keys(cmdHandledBy).filter((k) => !cmdHandledBy[k]);
|
|
667
743
|
if (didntHandle.length > 0) {
|
|
668
|
-
this.log.info(
|
|
669
|
-
`
|
|
670
|
-
|
|
744
|
+
this.log.info(
|
|
745
|
+
`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
|
|
746
|
+
`though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
|
|
747
|
+
`command *was* handled by these: ${JSON.stringify(didHandle)}.`
|
|
748
|
+
);
|
|
671
749
|
}
|
|
672
750
|
}
|
|
673
751
|
|
|
674
|
-
async executeWrappedCommand
|
|
675
|
-
let cmdRes,
|
|
752
|
+
async executeWrappedCommand({wrappedCmd, protocol}) {
|
|
753
|
+
let cmdRes,
|
|
754
|
+
cmdErr,
|
|
755
|
+
res = {};
|
|
676
756
|
try {
|
|
677
757
|
// At this point, `wrappedCmd` defines a whole sequence of plugin handlers, culminating in
|
|
678
758
|
// our default handler. Whatever it returns is what we're going to want to send back to the
|
|
@@ -695,17 +775,17 @@ class AppiumDriver extends DriverCore {
|
|
|
695
775
|
return res;
|
|
696
776
|
}
|
|
697
777
|
|
|
698
|
-
proxyActive
|
|
778
|
+
proxyActive(sessionId) {
|
|
699
779
|
const dstSession = this.sessions[sessionId];
|
|
700
780
|
return dstSession && _.isFunction(dstSession.proxyActive) && dstSession.proxyActive(sessionId);
|
|
701
781
|
}
|
|
702
782
|
|
|
703
|
-
getProxyAvoidList
|
|
783
|
+
getProxyAvoidList(sessionId) {
|
|
704
784
|
const dstSession = this.sessions[sessionId];
|
|
705
785
|
return dstSession ? dstSession.getProxyAvoidList() : [];
|
|
706
786
|
}
|
|
707
787
|
|
|
708
|
-
canProxy
|
|
788
|
+
canProxy(sessionId) {
|
|
709
789
|
const dstSession = this.sessions[sessionId];
|
|
710
790
|
return dstSession && dstSession.canProxy(sessionId);
|
|
711
791
|
}
|
|
@@ -713,7 +793,7 @@ class AppiumDriver extends DriverCore {
|
|
|
713
793
|
|
|
714
794
|
// help decide which commands should be proxied to sub-drivers and which
|
|
715
795
|
// should be handled by this, our umbrella driver
|
|
716
|
-
function isAppiumDriverCommand
|
|
796
|
+
function isAppiumDriverCommand(cmd) {
|
|
717
797
|
return !isSessionCommand(cmd) || cmd === DELETE_SESSION_COMMAND;
|
|
718
798
|
}
|
|
719
799
|
|
|
@@ -727,26 +807,34 @@ export class NoDriverProxyCommandError extends Error {
|
|
|
727
807
|
*/
|
|
728
808
|
code = 'APPIUMERR_NO_DRIVER_PROXYCOMMAND';
|
|
729
809
|
|
|
730
|
-
constructor
|
|
731
|
-
super(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
810
|
+
constructor() {
|
|
811
|
+
super(
|
|
812
|
+
`The default behavior for this command was to proxy, but the driver ` +
|
|
813
|
+
`did not have the 'proxyCommand' method defined. To fully support ` +
|
|
814
|
+
`plugins, drivers should have 'proxyCommand' set to a jwpProxy object's ` +
|
|
815
|
+
`'command()' method, in addition to the normal 'proxyReqRes'`
|
|
816
|
+
);
|
|
735
817
|
}
|
|
736
818
|
}
|
|
737
819
|
|
|
738
|
-
export {
|
|
820
|
+
export {AppiumDriver};
|
|
739
821
|
|
|
740
822
|
/**
|
|
741
823
|
* @typedef {import('@appium/types').ExternalDriver} ExternalDriver
|
|
824
|
+
* @typedef {import('@appium/types').Driver} Driver
|
|
825
|
+
* @typedef {import('@appium/types').DriverClass} DriverClass
|
|
742
826
|
* @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
|
|
743
827
|
* @typedef {import('@appium/types').DriverData} DriverData
|
|
744
828
|
* @typedef {import('@appium/types').ServerArgs} DriverOpts
|
|
745
829
|
* @typedef {import('@appium/types').Constraints} Constraints
|
|
746
830
|
* @typedef {import('@appium/types').AppiumServer} AppiumServer
|
|
747
|
-
* @typedef {import('
|
|
748
|
-
* @typedef {import('../types/extension').PluginClass} PluginClass
|
|
831
|
+
* @typedef {import('@appium/types').ExtensionType} ExtensionType
|
|
749
832
|
* @typedef {import('./extension/driver-config').DriverConfig} DriverConfig
|
|
833
|
+
* @typedef {import('@appium/types').Plugin} Plugin
|
|
834
|
+
* @typedef {import('@appium/types').PluginClass} PluginClass
|
|
835
|
+
* @typedef {import('@appium/types').PluginType} PluginType
|
|
836
|
+
* @typedef {import('@appium/types').DriverType} DriverType
|
|
837
|
+
* @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
|
|
750
838
|
*/
|
|
751
839
|
|
|
752
840
|
/**
|
|
@@ -758,7 +846,3 @@ export { AppiumDriver };
|
|
|
758
846
|
* @property {Error} [error]
|
|
759
847
|
* @property {string} [protocol]
|
|
760
848
|
*/
|
|
761
|
-
|
|
762
|
-
/**
|
|
763
|
-
* @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
|
|
764
|
-
*/
|