appium 2.0.0-beta.25 → 2.0.0-beta.28
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 +215 -0
- package/build/lib/appium.d.ts.map +1 -0
- package/build/lib/appium.js +94 -101
- package/build/lib/cli/args.d.ts +20 -0
- package/build/lib/cli/args.d.ts.map +1 -0
- package/build/lib/cli/args.js +19 -39
- package/build/lib/cli/driver-command.d.ts +36 -0
- package/build/lib/cli/driver-command.d.ts.map +1 -0
- package/build/lib/cli/driver-command.js +10 -13
- package/build/lib/cli/extension-command.d.ts +345 -0
- package/build/lib/cli/extension-command.d.ts.map +1 -0
- package/build/lib/cli/extension-command.js +117 -94
- package/build/lib/cli/extension.d.ts +14 -0
- package/build/lib/cli/extension.d.ts.map +1 -0
- package/build/lib/cli/extension.js +14 -22
- package/build/lib/cli/parser.d.ts +79 -0
- package/build/lib/cli/parser.d.ts.map +1 -0
- package/build/lib/cli/parser.js +9 -19
- package/build/lib/cli/plugin-command.d.ts +39 -0
- package/build/lib/cli/plugin-command.d.ts.map +1 -0
- package/build/lib/cli/plugin-command.js +9 -14
- package/build/lib/cli/utils.d.ts +29 -0
- package/build/lib/cli/utils.d.ts.map +1 -0
- package/build/lib/cli/utils.js +2 -4
- package/build/lib/config-file.d.ts +100 -0
- package/build/lib/config-file.d.ts.map +1 -0
- package/build/lib/config-file.js +2 -4
- package/build/lib/config.d.ts +40 -0
- package/build/lib/config.d.ts.map +1 -0
- package/build/lib/config.js +8 -7
- package/build/lib/constants.d.ts +48 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +60 -0
- package/build/lib/extension/driver-config.d.ts +84 -0
- package/build/lib/extension/driver-config.d.ts.map +1 -0
- package/build/lib/extension/driver-config.js +190 -0
- package/build/lib/extension/extension-config.d.ts +170 -0
- package/build/lib/extension/extension-config.d.ts.map +1 -0
- package/build/lib/extension/extension-config.js +297 -0
- package/build/lib/extension/index.d.ts +39 -0
- package/build/lib/extension/index.d.ts.map +1 -0
- package/build/lib/extension/index.js +77 -0
- package/build/lib/extension/manifest.d.ts +174 -0
- package/build/lib/extension/manifest.d.ts.map +1 -0
- package/build/lib/extension/manifest.js +246 -0
- package/build/lib/extension/package-changed.d.ts +11 -0
- package/build/lib/extension/package-changed.d.ts.map +1 -0
- package/build/lib/extension/package-changed.js +68 -0
- package/build/lib/extension/plugin-config.d.ts +62 -0
- package/build/lib/extension/plugin-config.d.ts.map +1 -0
- package/build/lib/extension/plugin-config.js +87 -0
- package/build/lib/grid-register.d.ts +10 -0
- package/build/lib/grid-register.d.ts.map +1 -0
- package/build/lib/grid-register.js +2 -4
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +2 -4
- package/build/lib/logsink.d.ts +4 -0
- package/build/lib/logsink.d.ts.map +1 -0
- package/build/lib/logsink.js +2 -4
- package/build/lib/main.d.ts +51 -0
- package/build/lib/main.d.ts.map +1 -0
- package/build/lib/main.js +40 -68
- package/build/lib/schema/arg-spec.d.ts +143 -0
- package/build/lib/schema/arg-spec.d.ts.map +1 -0
- package/build/lib/schema/arg-spec.js +11 -14
- package/build/lib/schema/cli-args.d.ts +19 -0
- package/build/lib/schema/cli-args.d.ts.map +1 -0
- package/build/lib/schema/cli-args.js +2 -4
- package/build/lib/schema/cli-transformers.d.ts +5 -0
- package/build/lib/schema/cli-transformers.d.ts.map +1 -0
- package/build/lib/schema/cli-transformers.js +2 -4
- package/build/lib/schema/index.d.ts +3 -0
- package/build/lib/schema/index.d.ts.map +1 -0
- package/build/lib/schema/index.js +2 -4
- package/build/lib/schema/keywords.d.ts +24 -0
- package/build/lib/schema/keywords.d.ts.map +1 -0
- package/build/lib/schema/keywords.js +2 -4
- package/build/lib/schema/schema.d.ts +259 -0
- package/build/lib/schema/schema.d.ts.map +1 -0
- package/build/lib/schema/schema.js +57 -39
- package/build/lib/utils.d.ts +66 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +6 -35
- package/build/tsconfig.tsbuildinfo +1 -0
- package/lib/appium.js +188 -117
- package/lib/cli/args.js +19 -24
- package/lib/cli/driver-command.js +19 -8
- package/lib/cli/extension-command.js +314 -184
- package/lib/cli/extension.js +18 -16
- package/lib/cli/parser.js +7 -16
- package/lib/cli/plugin-command.js +16 -7
- package/lib/cli/utils.js +1 -1
- package/lib/config-file.js +6 -7
- package/lib/config.js +17 -12
- package/lib/constants.js +78 -0
- package/lib/extension/driver-config.js +249 -0
- package/lib/extension/extension-config.js +458 -0
- package/lib/extension/index.js +102 -0
- package/lib/extension/manifest.js +486 -0
- package/lib/extension/package-changed.js +63 -0
- package/lib/extension/plugin-config.js +113 -0
- package/lib/grid-register.js +4 -4
- package/lib/logsink.js +4 -0
- package/lib/main.js +54 -92
- package/lib/schema/arg-spec.js +11 -7
- package/lib/schema/cli-args.js +1 -1
- package/lib/schema/cli-transformers.js +0 -1
- package/lib/schema/keywords.js +1 -2
- package/lib/schema/schema.js +62 -31
- package/lib/utils.js +48 -45
- package/package.json +30 -24
- package/{postinstall.js → scripts/postinstall.js} +1 -1
- package/types/appium-manifest.d.ts +61 -0
- package/types/cli.d.ts +134 -0
- package/types/extension.d.ts +56 -0
- package/types/external-manifest.d.ts +58 -0
- package/types/index.d.ts +7 -0
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/check-npm-pack-files.js +0 -23
- package/build/commands-yml/parse.js +0 -319
- package/build/commands-yml/validator.js +0 -130
- package/build/index.js +0 -19
- package/build/lib/appium-config.schema.json +0 -0
- package/build/lib/cli/npm.js +0 -220
- package/build/lib/driver-config.js +0 -100
- package/build/lib/drivers.js +0 -100
- package/build/lib/ext-config-io.js +0 -165
- package/build/lib/extension-config.js +0 -320
- package/build/lib/plugin-config.js +0 -69
- package/build/lib/plugins.js +0 -18
- package/build/lib/schema/appium-config-schema.js +0 -253
- package/build/postinstall.js +0 -90
- package/build/test/cli/cli-e2e-specs.js +0 -221
- package/build/test/cli/cli-helpers.js +0 -86
- package/build/test/cli/cli-specs.js +0 -71
- package/build/test/cli/fixtures/test-driver/package.json +0 -27
- package/build/test/cli/schema-args-specs.js +0 -48
- package/build/test/cli/schema-e2e-specs.js +0 -47
- package/build/test/config-e2e-specs.js +0 -112
- package/build/test/config-file-e2e-specs.js +0 -191
- package/build/test/config-file-specs.js +0 -281
- package/build/test/config-specs.js +0 -258
- package/build/test/driver-e2e-specs.js +0 -435
- package/build/test/driver-specs.js +0 -386
- package/build/test/ext-config-io-specs.js +0 -181
- package/build/test/extension-config-specs.js +0 -365
- package/build/test/fixtures/allow-feat.txt +0 -5
- package/build/test/fixtures/caps.json +0 -3
- package/build/test/fixtures/config/allow-insecure.txt +0 -3
- package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
- package/build/test/fixtures/config/appium.config.bad.json +0 -32
- package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
- package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
- package/build/test/fixtures/config/appium.config.good.js +0 -40
- package/build/test/fixtures/config/appium.config.good.json +0 -33
- package/build/test/fixtures/config/appium.config.good.yaml +0 -30
- package/build/test/fixtures/config/appium.config.invalid.json +0 -31
- package/build/test/fixtures/config/appium.config.security-array.json +0 -5
- package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
- package/build/test/fixtures/config/appium.config.security-path.json +0 -5
- package/build/test/fixtures/config/driver-fake.config.json +0 -8
- package/build/test/fixtures/config/nodeconfig.json +0 -3
- package/build/test/fixtures/config/plugin-fake.config.json +0 -0
- package/build/test/fixtures/default-args.js +0 -35
- package/build/test/fixtures/deny-feat.txt +0 -5
- package/build/test/fixtures/driver.schema.js +0 -20
- package/build/test/fixtures/extensions.yaml +0 -27
- package/build/test/fixtures/flattened-schema.js +0 -532
- package/build/test/fixtures/plugin.schema.js +0 -20
- package/build/test/fixtures/schema-with-extensions.js +0 -28
- package/build/test/grid-register-specs.js +0 -74
- package/build/test/helpers.js +0 -75
- package/build/test/logger-specs.js +0 -76
- package/build/test/npm-specs.js +0 -20
- package/build/test/parser-specs.js +0 -319
- package/build/test/plugin-e2e-specs.js +0 -316
- package/build/test/schema/arg-spec-specs.js +0 -70
- package/build/test/schema/cli-args-specs.js +0 -408
- package/build/test/schema/schema-specs.js +0 -407
- package/build/test/utils-specs.js +0 -288
- package/lib/cli/npm.js +0 -251
- package/lib/driver-config.js +0 -101
- package/lib/drivers.js +0 -84
- package/lib/ext-config-io.js +0 -287
- package/lib/extension-config.js +0 -366
- package/lib/plugin-config.js +0 -63
- package/lib/plugins.js +0 -13
- package/lib/schema/appium-config-schema.js +0 -287
- package/types/appium-config.d.ts +0 -197
- package/types/types.d.ts +0 -206
package/lib/appium.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
1
2
|
import _ from 'lodash';
|
|
2
|
-
import log from './logger';
|
|
3
3
|
import { getBuildInfo, updateBuildInfo, APPIUM_VER } from './config';
|
|
4
|
-
import {
|
|
5
|
-
import { BaseDriver, errors, isSessionCommand,
|
|
4
|
+
import { BaseDriver, DriverCore, errors, isSessionCommand,
|
|
6
5
|
CREATE_SESSION_COMMAND, DELETE_SESSION_COMMAND, GET_STATUS_COMMAND
|
|
7
6
|
} from '@appium/base-driver';
|
|
8
7
|
import AsyncLock from 'async-lock';
|
|
9
8
|
import { parseCapsForInnerDriver, pullSettings } from './utils';
|
|
10
|
-
import { util } from '@appium/support';
|
|
9
|
+
import { util, node, logger } from '@appium/support';
|
|
11
10
|
import { getDefaultsForExtension } from './schema';
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Invariant set of base constraints
|
|
14
|
+
* @type {Readonly<Constraints>}
|
|
15
|
+
*/
|
|
16
|
+
const desiredCapabilityConstraints = Object.freeze({
|
|
14
17
|
automationName: {
|
|
15
18
|
presence: true,
|
|
16
19
|
isString: true,
|
|
@@ -19,54 +22,99 @@ const desiredCapabilityConstraints = {
|
|
|
19
22
|
presence: true,
|
|
20
23
|
isString: true,
|
|
21
24
|
},
|
|
22
|
-
};
|
|
25
|
+
});
|
|
23
26
|
|
|
24
27
|
const sessionsListGuard = new AsyncLock();
|
|
25
28
|
const pendingDriversGuard = new AsyncLock();
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
/**
|
|
31
|
+
* @implements {SessionHandler}
|
|
32
|
+
*/
|
|
33
|
+
class AppiumDriver extends DriverCore {
|
|
34
|
+
/**
|
|
35
|
+
* Access to sessions list must be guarded with a Semaphore, because
|
|
36
|
+
* it might be changed by other async calls at any time
|
|
37
|
+
* It is not recommended to access this property directly from the outside
|
|
38
|
+
* @type {Record<string,ExternalDriver>}
|
|
39
|
+
*/
|
|
40
|
+
sessions = {};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Access to pending drivers list must be guarded with a Semaphore, because
|
|
44
|
+
* it might be changed by other async calls at any time
|
|
45
|
+
* It is not recommended to access this property directly from the outside
|
|
46
|
+
* @type {Record<string,ExternalDriver[]>}
|
|
47
|
+
*/
|
|
48
|
+
pendingDrivers = {};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Note that {@linkcode AppiumDriver} has no `newCommandTimeout` method.
|
|
52
|
+
* `AppiumDriver` does not set and observe its own timeouts; individual
|
|
53
|
+
* sessions (managed drivers) do instead.
|
|
54
|
+
*/
|
|
55
|
+
newCommandTimeoutMs = 0;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* List of active plugins
|
|
59
|
+
* @type {PluginClass[]}
|
|
60
|
+
*/
|
|
61
|
+
pluginClasses = [];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* map of sessions to actual plugin instances per session
|
|
65
|
+
* @type {Record<string,InstanceType<PluginClass>[]>}
|
|
66
|
+
*/
|
|
67
|
+
sessionPlugins = {};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* some commands are sessionless, so we need a set of plugins for them
|
|
71
|
+
* @type {InstanceType<PluginClass>[]}
|
|
72
|
+
*/
|
|
73
|
+
sessionlessPlugins = [];;
|
|
74
|
+
|
|
75
|
+
/** @type {DriverConfig} */
|
|
76
|
+
driverConfig;
|
|
77
|
+
|
|
78
|
+
/** @type {AppiumServer} */
|
|
79
|
+
server;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {DriverOpts} opts
|
|
83
|
+
*/
|
|
84
|
+
constructor (opts) {
|
|
29
85
|
// It is necessary to set `--tmp` here since it should be set to
|
|
30
86
|
// process.env.APPIUM_TMP_DIR once at an initial point in the Appium lifecycle.
|
|
31
87
|
// The process argument will be referenced by BaseDriver.
|
|
32
88
|
// Please call @appium/support.tempDir module to apply this benefit.
|
|
33
|
-
if (
|
|
34
|
-
process.env.APPIUM_TMP_DIR =
|
|
89
|
+
if (opts.tmpDir) {
|
|
90
|
+
process.env.APPIUM_TMP_DIR = opts.tmpDir;
|
|
35
91
|
}
|
|
36
92
|
|
|
37
|
-
super(
|
|
93
|
+
super(opts);
|
|
38
94
|
|
|
39
95
|
this.desiredCapConstraints = desiredCapabilityConstraints;
|
|
40
96
|
|
|
41
|
-
|
|
42
|
-
this.newCommandTimeoutMs = 0;
|
|
43
|
-
|
|
44
|
-
this.args = {...args};
|
|
45
|
-
|
|
46
|
-
// Access to sessions list must be guarded with a Semaphore, because
|
|
47
|
-
// it might be changed by other async calls at any time
|
|
48
|
-
// It is not recommended to access this property directly from the outside
|
|
49
|
-
this.sessions = {};
|
|
50
|
-
|
|
51
|
-
// Access to pending drivers list must be guarded with a Semaphore, because
|
|
52
|
-
// it might be changed by other async calls at any time
|
|
53
|
-
// It is not recommended to access this property directly from the outside
|
|
54
|
-
this.pendingDrivers = {};
|
|
55
|
-
|
|
56
|
-
/** @type {PluginExtensionClass[]} */
|
|
57
|
-
this.pluginClasses = []; // list of which plugins are active
|
|
58
|
-
this.sessionPlugins = {}; // map of sessions to actual plugin instances per session
|
|
59
|
-
this.sessionlessPlugins = []; // some commands are sessionless, so we need a set of plugins for them
|
|
97
|
+
this.args = {...opts};
|
|
60
98
|
|
|
61
99
|
// allow this to happen in the background, so no `await`
|
|
62
|
-
|
|
100
|
+
// catch this to avoid an unhandled rejection
|
|
101
|
+
// eslint-disable-next-line promise/prefer-await-to-then,promise/prefer-await-to-callbacks
|
|
102
|
+
updateBuildInfo().catch((err) => {
|
|
103
|
+
this.log.debug(err);
|
|
104
|
+
});
|
|
63
105
|
}
|
|
64
106
|
|
|
65
|
-
/**
|
|
66
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves logger instance for the current umbrella driver instance
|
|
109
|
+
*/
|
|
110
|
+
get log () {
|
|
111
|
+
if (!this._log) {
|
|
112
|
+
const instanceName = `${this.constructor.name}@${node.getObjectId(this).substring(0, 4)}`;
|
|
113
|
+
this._log = logger.getLogger(instanceName);
|
|
114
|
+
}
|
|
115
|
+
return this._log;
|
|
116
|
+
}
|
|
67
117
|
|
|
68
|
-
/** @type {import('express').Express|undefined} */
|
|
69
|
-
server;
|
|
70
118
|
|
|
71
119
|
/**
|
|
72
120
|
* Cancel commands queueing for the umbrella Appium driver
|
|
@@ -97,41 +145,33 @@ class AppiumDriver extends BaseDriver {
|
|
|
97
145
|
}
|
|
98
146
|
|
|
99
147
|
printNewSessionAnnouncement (driverName, driverVersion, driverBaseVersion) {
|
|
100
|
-
log.info(driverVersion
|
|
148
|
+
this.log.info(driverVersion
|
|
101
149
|
? `Appium v${APPIUM_VER} creating new ${driverName} (v${driverVersion}) session`
|
|
102
150
|
: `Appium v${APPIUM_VER} creating new ${driverName} session`
|
|
103
151
|
);
|
|
104
|
-
log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
|
|
105
|
-
log.info(AppiumDriver.baseVersion
|
|
152
|
+
this.log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
|
|
153
|
+
this.log.info(AppiumDriver.baseVersion
|
|
106
154
|
? `Appium's BaseDriver version is ${AppiumDriver.baseVersion}`
|
|
107
155
|
: `Could not determine Appium's BaseDriver version`
|
|
108
156
|
);
|
|
109
|
-
log.info(driverBaseVersion
|
|
157
|
+
this.log.info(driverBaseVersion
|
|
110
158
|
? `${driverName}'s BaseDriver version is ${driverBaseVersion}`
|
|
111
159
|
: `Could not determine ${driverName}'s BaseDriver version`
|
|
112
160
|
);
|
|
113
161
|
}
|
|
114
162
|
|
|
115
|
-
/**
|
|
116
|
-
* This is just an alias for driver.js's method, which is necessary for
|
|
117
|
-
* mocking in the test suite
|
|
118
|
-
*/
|
|
119
|
-
_findMatchingDriver (...args) {
|
|
120
|
-
return findMatchingDriver(...args);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
163
|
/**
|
|
124
164
|
* Validate and assign CLI args for a driver or plugin
|
|
125
165
|
*
|
|
126
166
|
* If the extension has provided a schema, validation has already happened.
|
|
127
167
|
*
|
|
128
168
|
* Any arg which is equal to its default value will not be assigned to the extension.
|
|
129
|
-
* @param {
|
|
169
|
+
* @param {ExtensionType} extType 'driver' or 'plugin'
|
|
130
170
|
* @param {string} extName the name of the extension
|
|
131
171
|
* @param {Object} extInstance the driver or plugin instance
|
|
132
172
|
*/
|
|
133
173
|
assignCliArgsToExtension (extType, extName, extInstance) {
|
|
134
|
-
const allCliArgsForExt = this.args[extType]?.[extName];
|
|
174
|
+
const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */(this.args[extType]?.[extName]);
|
|
135
175
|
if (!_.isEmpty(allCliArgsForExt)) {
|
|
136
176
|
const defaults = getDefaultsForExtension(extType, extName);
|
|
137
177
|
const cliArgs = _.isEmpty(defaults)
|
|
@@ -145,24 +185,26 @@ class AppiumDriver extends BaseDriver {
|
|
|
145
185
|
|
|
146
186
|
/**
|
|
147
187
|
* Create a new session
|
|
148
|
-
* @param {
|
|
149
|
-
* @param {
|
|
150
|
-
* @param {
|
|
151
|
-
* @
|
|
188
|
+
* @param {W3CCapabilities} jsonwpCaps JSONWP formatted desired capabilities
|
|
189
|
+
* @param {W3CCapabilities} reqCaps Required capabilities (JSONWP standard)
|
|
190
|
+
* @param {W3CCapabilities} w3cCapabilities W3C capabilities
|
|
191
|
+
* @param {import('@appium/types').DriverData[]} [driverData]
|
|
152
192
|
*/
|
|
153
|
-
async createSession (jsonwpCaps, reqCaps, w3cCapabilities) {
|
|
193
|
+
async createSession (jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
|
|
154
194
|
const defaultCapabilities = _.cloneDeep(this.args.defaultCapabilities);
|
|
155
195
|
const defaultSettings = pullSettings(defaultCapabilities);
|
|
156
196
|
jsonwpCaps = _.cloneDeep(jsonwpCaps);
|
|
157
|
-
const jwpSettings =
|
|
197
|
+
const jwpSettings = {...defaultSettings, ...pullSettings(jsonwpCaps)};
|
|
158
198
|
w3cCapabilities = _.cloneDeep(w3cCapabilities);
|
|
159
199
|
// It is possible that the client only provides caps using JSONWP standard,
|
|
160
200
|
// although firstMatch/alwaysMatch properties are still present.
|
|
161
201
|
// In such case we assume the client understands W3C protocol and merge the given
|
|
162
202
|
// JSONWP caps to W3C caps
|
|
163
|
-
const w3cSettings =
|
|
164
|
-
|
|
165
|
-
|
|
203
|
+
const w3cSettings = {
|
|
204
|
+
...jwpSettings,
|
|
205
|
+
...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {})
|
|
206
|
+
};
|
|
207
|
+
for (const firstMatchEntry of ((w3cCapabilities ?? {}).firstMatch ?? [])) {
|
|
166
208
|
Object.assign(w3cSettings, pullSettings(firstMatchEntry));
|
|
167
209
|
}
|
|
168
210
|
|
|
@@ -177,9 +219,9 @@ class AppiumDriver extends BaseDriver {
|
|
|
177
219
|
defaultCapabilities
|
|
178
220
|
);
|
|
179
221
|
|
|
180
|
-
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities
|
|
222
|
+
const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = /** @type {import('./utils').ParsedDriverCaps} */(parsedCaps);
|
|
181
223
|
protocol = parsedCaps.protocol;
|
|
182
|
-
|
|
224
|
+
const error = /** @type {import('./utils').InvalidCaps} */(parsedCaps).error;
|
|
183
225
|
// If the parsing of the caps produced an error, throw it in here
|
|
184
226
|
if (error) {
|
|
185
227
|
throw error;
|
|
@@ -189,14 +231,21 @@ class AppiumDriver extends BaseDriver {
|
|
|
189
231
|
driver: InnerDriver,
|
|
190
232
|
version: driverVersion,
|
|
191
233
|
driverName
|
|
192
|
-
} = this.
|
|
234
|
+
} = this.driverConfig.findMatchingDriver(desiredCaps);
|
|
193
235
|
this.printNewSessionAnnouncement(InnerDriver.name, driverVersion, InnerDriver.baseVersion);
|
|
194
236
|
|
|
195
237
|
if (this.args.sessionOverride) {
|
|
196
238
|
await this.deleteAllSessions();
|
|
197
239
|
}
|
|
198
240
|
|
|
199
|
-
|
|
241
|
+
/**
|
|
242
|
+
* @type {DriverData[]}
|
|
243
|
+
*/
|
|
244
|
+
let runningDriversData = [];
|
|
245
|
+
/**
|
|
246
|
+
* @type {DriverData[]}
|
|
247
|
+
*/
|
|
248
|
+
let otherPendingDriversData = [];
|
|
200
249
|
|
|
201
250
|
const driverInstance = new InnerDriver(this.args, true);
|
|
202
251
|
|
|
@@ -205,21 +254,21 @@ class AppiumDriver extends BaseDriver {
|
|
|
205
254
|
// could have been set by a malicious user via capabilities, whereas we
|
|
206
255
|
// want a guarantee the values were set by the appium server admin
|
|
207
256
|
if (this.args.relaxedSecurityEnabled) {
|
|
208
|
-
log.info(`Applying relaxed security to '${InnerDriver.name}' as per ` +
|
|
209
|
-
|
|
210
|
-
|
|
257
|
+
this.log.info(`Applying relaxed security to '${InnerDriver.name}' as per ` +
|
|
258
|
+
`server command line argument. All insecure features will be ` +
|
|
259
|
+
`enabled unless explicitly disabled by --deny-insecure`);
|
|
211
260
|
driverInstance.relaxedSecurityEnabled = true;
|
|
212
261
|
}
|
|
213
262
|
|
|
214
263
|
if (!_.isEmpty(this.args.denyInsecure)) {
|
|
215
|
-
log.info('Explicitly preventing use of insecure features:');
|
|
216
|
-
this.args.denyInsecure.map((a) => log.info(` ${a}`));
|
|
264
|
+
this.log.info('Explicitly preventing use of insecure features:');
|
|
265
|
+
this.args.denyInsecure.map((a) => this.log.info(` ${a}`));
|
|
217
266
|
driverInstance.denyInsecure = this.args.denyInsecure;
|
|
218
267
|
}
|
|
219
268
|
|
|
220
269
|
if (!_.isEmpty(this.args.allowInsecure)) {
|
|
221
|
-
log.info('Explicitly enabling use of insecure features:');
|
|
222
|
-
this.args.allowInsecure.map((a) => log.info(` ${a}`));
|
|
270
|
+
this.log.info('Explicitly enabling use of insecure features:');
|
|
271
|
+
this.args.allowInsecure.map((a) => this.log.info(` ${a}`));
|
|
223
272
|
driverInstance.allowInsecure = this.args.allowInsecure;
|
|
224
273
|
}
|
|
225
274
|
|
|
@@ -229,21 +278,17 @@ class AppiumDriver extends BaseDriver {
|
|
|
229
278
|
|
|
230
279
|
|
|
231
280
|
// This assignment is required for correct web sockets functionality inside the driver
|
|
232
|
-
driverInstance.server = this.server;
|
|
233
|
-
|
|
234
281
|
// Drivers/plugins might also want to know where they are hosted
|
|
235
|
-
driverInstance.
|
|
236
|
-
driverInstance.serverPort = this.args.port;
|
|
237
|
-
driverInstance.serverPath = this.args.basePath;
|
|
282
|
+
driverInstance.assignServer(this.server, this.args.address, this.args.port, this.args.basePath);
|
|
238
283
|
|
|
239
284
|
try {
|
|
240
|
-
runningDriversData = await this.curSessionDataForDriver(InnerDriver);
|
|
285
|
+
runningDriversData = await this.curSessionDataForDriver(InnerDriver) ?? [];
|
|
241
286
|
} catch (e) {
|
|
242
287
|
throw new errors.SessionNotCreatedError(e.message);
|
|
243
288
|
}
|
|
244
289
|
await pendingDriversGuard.acquire(AppiumDriver.name, () => {
|
|
245
290
|
this.pendingDrivers[InnerDriver.name] = this.pendingDrivers[InnerDriver.name] || [];
|
|
246
|
-
otherPendingDriversData = this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData);
|
|
291
|
+
otherPendingDriversData = _.compact(this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData));
|
|
247
292
|
this.pendingDrivers[InnerDriver.name].push(driverInstance);
|
|
248
293
|
});
|
|
249
294
|
|
|
@@ -266,19 +311,19 @@ class AppiumDriver extends BaseDriver {
|
|
|
266
311
|
|
|
267
312
|
this.attachUnexpectedShutdownHandler(driverInstance, innerSessionId);
|
|
268
313
|
|
|
269
|
-
log.info(`New ${InnerDriver.name} session created successfully, session ` +
|
|
270
|
-
|
|
314
|
+
this.log.info(`New ${InnerDriver.name} session created successfully, session ` +
|
|
315
|
+
`${innerSessionId} added to master session list`);
|
|
271
316
|
|
|
272
317
|
// set the New Command Timeout for the inner driver
|
|
273
318
|
driverInstance.startNewCommandTimeout();
|
|
274
319
|
|
|
275
320
|
// apply initial values to Appium settings (if provided)
|
|
276
321
|
if (driverInstance.isW3CProtocol() && !_.isEmpty(w3cSettings)) {
|
|
277
|
-
log.info(`Applying the initial values to Appium settings parsed from W3C caps: ` +
|
|
322
|
+
this.log.info(`Applying the initial values to Appium settings parsed from W3C caps: ` +
|
|
278
323
|
JSON.stringify(w3cSettings));
|
|
279
324
|
await driverInstance.updateSettings(w3cSettings);
|
|
280
325
|
} else if (driverInstance.isMjsonwpProtocol() && !_.isEmpty(jwpSettings)) {
|
|
281
|
-
log.info(`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
|
|
326
|
+
this.log.info(`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
|
|
282
327
|
JSON.stringify(jwpSettings));
|
|
283
328
|
await driverInstance.updateSettings(jwpSettings);
|
|
284
329
|
}
|
|
@@ -297,24 +342,24 @@ class AppiumDriver extends BaseDriver {
|
|
|
297
342
|
|
|
298
343
|
attachUnexpectedShutdownHandler (driver, innerSessionId) {
|
|
299
344
|
const onShutdown = (cause = new Error('Unknown error')) => {
|
|
300
|
-
log.warn(`Ending session, cause was '${cause.message}'`);
|
|
345
|
+
this.log.warn(`Ending session, cause was '${cause.message}'`);
|
|
301
346
|
|
|
302
347
|
if (this.sessionPlugins[innerSessionId]) {
|
|
303
348
|
for (const plugin of this.sessionPlugins[innerSessionId]) {
|
|
304
349
|
if (_.isFunction(plugin.onUnexpectedShutdown)) {
|
|
305
|
-
log.debug(`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`);
|
|
350
|
+
this.log.debug(`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`);
|
|
306
351
|
try {
|
|
307
352
|
plugin.onUnexpectedShutdown(driver, cause);
|
|
308
353
|
} catch (e) {
|
|
309
|
-
log.warn(`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`);
|
|
354
|
+
this.log.warn(`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`);
|
|
310
355
|
}
|
|
311
356
|
} else {
|
|
312
|
-
log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
|
|
357
|
+
this.log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
|
|
313
358
|
}
|
|
314
359
|
}
|
|
315
360
|
}
|
|
316
361
|
|
|
317
|
-
log.info(`Removing session '${innerSessionId}' from our master session list`);
|
|
362
|
+
this.log.info(`Removing session '${innerSessionId}' from our master session list`);
|
|
318
363
|
delete this.sessions[innerSessionId];
|
|
319
364
|
delete this.sessionPlugins[innerSessionId];
|
|
320
365
|
};
|
|
@@ -322,16 +367,21 @@ class AppiumDriver extends BaseDriver {
|
|
|
322
367
|
if (_.isFunction(driver.onUnexpectedShutdown)) {
|
|
323
368
|
driver.onUnexpectedShutdown(onShutdown);
|
|
324
369
|
} else {
|
|
325
|
-
log.warn(`Failed to attach the unexpected shutdown listener. ` +
|
|
370
|
+
this.log.warn(`Failed to attach the unexpected shutdown listener. ` +
|
|
326
371
|
`Is 'onUnexpectedShutdown' method available for '${driver.constructor.name}'?`);
|
|
327
372
|
}
|
|
328
373
|
}
|
|
329
374
|
|
|
375
|
+
/**
|
|
376
|
+
*
|
|
377
|
+
* @param {import('../types/extension').DriverClass} InnerDriver
|
|
378
|
+
* @returns {Promise<DriverData[]>}}
|
|
379
|
+
*/
|
|
330
380
|
async curSessionDataForDriver (InnerDriver) {
|
|
331
381
|
const sessions = await sessionsListGuard.acquire(AppiumDriver.name, () => this.sessions);
|
|
332
|
-
const data = _.values(sessions)
|
|
382
|
+
const data = _.compact(_.values(sessions)
|
|
333
383
|
.filter((s) => s.constructor.name === InnerDriver.name)
|
|
334
|
-
.map((s) => s.driverData);
|
|
384
|
+
.map((s) => s.driverData));
|
|
335
385
|
for (let datum of data) {
|
|
336
386
|
if (!datum) {
|
|
337
387
|
throw new Error(`Problem getting session data for driver type ` +
|
|
@@ -342,12 +392,14 @@ class AppiumDriver extends BaseDriver {
|
|
|
342
392
|
return data;
|
|
343
393
|
}
|
|
344
394
|
|
|
395
|
+
/**
|
|
396
|
+
* @param {string} sessionId
|
|
397
|
+
*/
|
|
345
398
|
async deleteSession (sessionId) {
|
|
346
399
|
let protocol;
|
|
347
400
|
try {
|
|
348
|
-
let otherSessionsData
|
|
349
|
-
|
|
350
|
-
await sessionsListGuard.acquire(AppiumDriver.name, () => {
|
|
401
|
+
let otherSessionsData;
|
|
402
|
+
const dstSession = await sessionsListGuard.acquire(AppiumDriver.name, () => {
|
|
351
403
|
if (!this.sessions[sessionId]) {
|
|
352
404
|
return;
|
|
353
405
|
}
|
|
@@ -355,21 +407,27 @@ class AppiumDriver extends BaseDriver {
|
|
|
355
407
|
otherSessionsData = _.toPairs(this.sessions)
|
|
356
408
|
.filter(([key, value]) => value.constructor.name === curConstructorName && key !== sessionId)
|
|
357
409
|
.map(([, value]) => value.driverData);
|
|
358
|
-
dstSession = this.sessions[sessionId];
|
|
410
|
+
const dstSession = this.sessions[sessionId];
|
|
359
411
|
protocol = dstSession.protocol;
|
|
360
|
-
log.info(`Removing session ${sessionId} from our master session list`);
|
|
412
|
+
this.log.info(`Removing session ${sessionId} from our master session list`);
|
|
361
413
|
// regardless of whether the deleteSession completes successfully or not
|
|
362
414
|
// make the session unavailable, because who knows what state it might
|
|
363
415
|
// be in otherwise
|
|
364
416
|
delete this.sessions[sessionId];
|
|
365
417
|
delete this.sessionPlugins[sessionId];
|
|
418
|
+
return dstSession;
|
|
366
419
|
});
|
|
420
|
+
// this may not be correct, but if `dstSession` was falsy, the call to `deleteSession()` would
|
|
421
|
+
// throw anyway.
|
|
422
|
+
if (!dstSession) {
|
|
423
|
+
throw new Error('Session not found');
|
|
424
|
+
}
|
|
367
425
|
return {
|
|
368
426
|
protocol,
|
|
369
427
|
value: await dstSession.deleteSession(sessionId, otherSessionsData),
|
|
370
428
|
};
|
|
371
429
|
} catch (e) {
|
|
372
|
-
log.error(`Had trouble ending session ${sessionId}: ${e.message}`);
|
|
430
|
+
this.log.error(`Had trouble ending session ${sessionId}: ${e.message}`);
|
|
373
431
|
return {
|
|
374
432
|
protocol,
|
|
375
433
|
error: e,
|
|
@@ -380,7 +438,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
380
438
|
async deleteAllSessions (opts = {}) {
|
|
381
439
|
const sessionsCount = _.size(this.sessions);
|
|
382
440
|
if (0 === sessionsCount) {
|
|
383
|
-
log.debug('There are no active sessions for cleanup');
|
|
441
|
+
this.log.debug('There are no active sessions for cleanup');
|
|
384
442
|
return;
|
|
385
443
|
}
|
|
386
444
|
|
|
@@ -388,7 +446,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
388
446
|
force = false,
|
|
389
447
|
reason,
|
|
390
448
|
} = opts;
|
|
391
|
-
log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
|
|
449
|
+
this.log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
|
|
392
450
|
const cleanupPromises = force
|
|
393
451
|
? _.values(this.sessions).map((drv) => drv.startUnexpectedShutdown(reason && new Error(reason)))
|
|
394
452
|
: _.keys(this.sessions).map((id) => this.deleteSession(id));
|
|
@@ -396,7 +454,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
396
454
|
try {
|
|
397
455
|
await cleanupPromise;
|
|
398
456
|
} catch (e) {
|
|
399
|
-
log.debug(e);
|
|
457
|
+
this.log.debug(e);
|
|
400
458
|
}
|
|
401
459
|
}
|
|
402
460
|
}
|
|
@@ -447,6 +505,12 @@ class AppiumDriver extends BaseDriver {
|
|
|
447
505
|
});
|
|
448
506
|
}
|
|
449
507
|
|
|
508
|
+
/**
|
|
509
|
+
*
|
|
510
|
+
* @param {string} cmd
|
|
511
|
+
* @param {...any} args
|
|
512
|
+
* @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<import('@appium/types').Driver['executeCommand']>>}
|
|
513
|
+
*/
|
|
450
514
|
async executeCommand (cmd, ...args) {
|
|
451
515
|
// We have basically three cases for how to handle commands:
|
|
452
516
|
// 1. handle getStatus (we do this as a special out of band case so it doesn't get added to an
|
|
@@ -476,6 +540,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
476
540
|
let sessionId = null;
|
|
477
541
|
let dstSession = null;
|
|
478
542
|
let protocol = null;
|
|
543
|
+
/** @type {this | ExternalDriver} */
|
|
479
544
|
let driver = this;
|
|
480
545
|
if (isSessionCmd) {
|
|
481
546
|
sessionId = _.last(args);
|
|
@@ -509,7 +574,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
509
574
|
// if we're running with plugins, make sure we log that the default behavior is actually
|
|
510
575
|
// happening so we can tell when the plugin call chain is unwrapping to the default behavior
|
|
511
576
|
// if that's what happens
|
|
512
|
-
plugins.length && log.info(`Executing default handling behavior for command '${cmd}'`);
|
|
577
|
+
plugins.length && this.log.info(`Executing default handling behavior for command '${cmd}'`);
|
|
513
578
|
|
|
514
579
|
// if we make it here, we know that the default behavior is handled
|
|
515
580
|
cmdHandledBy.default = true;
|
|
@@ -533,7 +598,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
533
598
|
if (isUmbrellaCmd) {
|
|
534
599
|
// some commands, like deleteSession, we want to make sure to handle on *this* driver,
|
|
535
600
|
// not the platform driver
|
|
536
|
-
return await
|
|
601
|
+
return await BaseDriver.prototype.executeCommand.call(this, cmd, ...args);
|
|
537
602
|
}
|
|
538
603
|
|
|
539
604
|
// here we know that we are executing a session command, and have a valid session driver
|
|
@@ -555,8 +620,8 @@ class AppiumDriver extends BaseDriver {
|
|
|
555
620
|
// their createSession method and other instance methods
|
|
556
621
|
if (cmd === CREATE_SESSION_COMMAND && this.sessionlessPlugins.length && !res.error) {
|
|
557
622
|
const sessionId = _.first(res.value);
|
|
558
|
-
log.info(`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
|
|
559
|
-
|
|
623
|
+
this.log.info(`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
|
|
624
|
+
`to session ID ${sessionId}`);
|
|
560
625
|
this.sessionPlugins[sessionId] = this.sessionlessPlugins;
|
|
561
626
|
this.sessionlessPlugins = [];
|
|
562
627
|
}
|
|
@@ -565,7 +630,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
565
630
|
}
|
|
566
631
|
|
|
567
632
|
wrapCommandWithPlugins ({driver, cmd, args, next, cmdHandledBy, plugins}) {
|
|
568
|
-
plugins.length && log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
|
|
633
|
+
plugins.length && this.log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
|
|
569
634
|
|
|
570
635
|
// now we can go through each plugin and wrap `next` around its own handler, passing the *old*
|
|
571
636
|
// next in so that it can call it if it wants to
|
|
@@ -575,7 +640,7 @@ class AppiumDriver extends BaseDriver {
|
|
|
575
640
|
// evaluated, otherwise we end up with infinite recursion of the last `next` to be defined.
|
|
576
641
|
cmdHandledBy[plugin.name] = false; // we see a new plugin, so add it to the 'cmdHandledBy' object
|
|
577
642
|
next = ((_next) => async () => {
|
|
578
|
-
log.info(`Plugin ${plugin.name} is now handling cmd '${cmd}'`);
|
|
643
|
+
this.log.info(`Plugin ${plugin.name} is now handling cmd '${cmd}'`);
|
|
579
644
|
cmdHandledBy[plugin.name] = true; // if we make it here, this plugin has attempted to handle cmd
|
|
580
645
|
// first attempt to handle the command via a command-specific handler on the plugin
|
|
581
646
|
if (plugin[cmd]) {
|
|
@@ -603,9 +668,9 @@ class AppiumDriver extends BaseDriver {
|
|
|
603
668
|
const didHandle = Object.keys(cmdHandledBy).filter((k) => cmdHandledBy[k]);
|
|
604
669
|
const didntHandle = Object.keys(cmdHandledBy).filter((k) => !cmdHandledBy[k]);
|
|
605
670
|
if (didntHandle.length > 0) {
|
|
606
|
-
log.info(`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
|
|
607
|
-
|
|
608
|
-
|
|
671
|
+
this.log.info(`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
|
|
672
|
+
`though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
|
|
673
|
+
`command *was* handled by these: ${JSON.stringify(didHandle)}.`);
|
|
609
674
|
}
|
|
610
675
|
}
|
|
611
676
|
|
|
@@ -675,22 +740,28 @@ export class NoDriverProxyCommandError extends Error {
|
|
|
675
740
|
|
|
676
741
|
export { AppiumDriver };
|
|
677
742
|
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* @typedef {Object} StaticExtMembers
|
|
681
|
-
* @property {(app: import('express').Express, httpServer: import('http').Server) => import('type-fest').Promisable<void>} [updateServer]
|
|
682
|
-
* @property {import('@appium/base-driver').MethodMap} [newMethodMap]
|
|
683
|
-
*/
|
|
684
|
-
|
|
685
743
|
/**
|
|
686
|
-
* @typedef {
|
|
687
|
-
* @
|
|
744
|
+
* @typedef {import('@appium/types').ExternalDriver} ExternalDriver
|
|
745
|
+
* @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
|
|
746
|
+
* @typedef {import('@appium/types').DriverData} DriverData
|
|
747
|
+
* @typedef {import('@appium/types').DriverOpts} DriverOpts
|
|
748
|
+
* @typedef {import('@appium/types').Constraints} Constraints
|
|
749
|
+
* @typedef {import('@appium/types').AppiumServer} AppiumServer
|
|
750
|
+
* @typedef {import('../types').ExtensionType} ExtensionType
|
|
751
|
+
* @typedef {import('../types/extension').PluginClass} PluginClass
|
|
752
|
+
* @typedef {import('./extension/driver-config').DriverConfig} DriverConfig
|
|
688
753
|
*/
|
|
689
754
|
|
|
690
755
|
/**
|
|
691
|
-
* @
|
|
756
|
+
* Used by {@linkcode AppiumDriver.createSession} and {@linkcode AppiumDriver.deleteSession} to describe
|
|
757
|
+
* result.
|
|
758
|
+
* @template V
|
|
759
|
+
* @typedef SessionHandlerResult
|
|
760
|
+
* @property {V} [value]
|
|
761
|
+
* @property {Error} [error]
|
|
762
|
+
* @property {string} [protocol]
|
|
692
763
|
*/
|
|
693
764
|
|
|
694
765
|
/**
|
|
695
|
-
* @typedef {import('
|
|
766
|
+
* @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
|
|
696
767
|
*/
|