@appium/base-driver 8.2.4 → 8.4.0
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/basedriver/capabilities.d.ts +80 -0
- package/build/lib/basedriver/capabilities.d.ts.map +1 -0
- package/build/lib/basedriver/capabilities.js +12 -13
- package/build/lib/basedriver/commands/event.d.ts +9 -0
- package/build/lib/basedriver/commands/event.d.ts.map +1 -0
- package/build/lib/basedriver/commands/event.js +21 -23
- package/build/lib/basedriver/commands/find.d.ts +11 -0
- package/build/lib/basedriver/commands/find.d.ts.map +1 -0
- package/build/lib/basedriver/commands/find.js +41 -43
- package/build/lib/basedriver/commands/index.d.ts +8 -0
- package/build/lib/basedriver/commands/index.d.ts.map +1 -0
- package/build/lib/basedriver/commands/index.js +17 -16
- package/build/lib/basedriver/commands/log.d.ts +12 -0
- package/build/lib/basedriver/commands/log.d.ts.map +1 -0
- package/build/lib/basedriver/commands/log.js +23 -30
- package/build/lib/basedriver/commands/session.d.ts +11 -0
- package/build/lib/basedriver/commands/session.d.ts.map +1 -0
- package/build/lib/basedriver/commands/session.js +21 -158
- package/build/lib/basedriver/commands/settings.d.ts +10 -0
- package/build/lib/basedriver/commands/settings.d.ts.map +1 -0
- package/build/lib/basedriver/commands/settings.js +18 -22
- package/build/lib/basedriver/commands/timeout.d.ts +8 -0
- package/build/lib/basedriver/commands/timeout.d.ts.map +1 -0
- package/build/lib/basedriver/commands/timeout.js +118 -144
- package/build/lib/basedriver/core.d.ts +235 -0
- package/build/lib/basedriver/core.d.ts.map +1 -0
- package/build/lib/basedriver/core.js +283 -0
- package/build/lib/basedriver/desired-caps.d.ts +5 -0
- package/build/lib/basedriver/desired-caps.d.ts.map +1 -0
- package/build/lib/basedriver/desired-caps.js +2 -4
- package/build/lib/basedriver/device-settings.d.ts +32 -0
- package/build/lib/basedriver/device-settings.d.ts.map +1 -0
- package/build/lib/basedriver/device-settings.js +33 -15
- package/build/lib/basedriver/driver.d.ts +83 -0
- package/build/lib/basedriver/driver.d.ts.map +1 -0
- package/build/lib/basedriver/driver.js +104 -257
- package/build/lib/basedriver/helpers.d.ts +132 -0
- package/build/lib/basedriver/helpers.d.ts.map +1 -0
- package/build/lib/basedriver/helpers.js +24 -10
- package/build/lib/basedriver/logger.d.ts +3 -0
- package/build/lib/basedriver/logger.d.ts.map +1 -0
- package/build/lib/basedriver/logger.js +2 -4
- package/build/lib/constants.d.ts +9 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +2 -4
- package/build/lib/express/crash.d.ts +3 -0
- package/build/lib/express/crash.d.ts.map +1 -0
- package/build/lib/express/crash.js +2 -4
- package/build/lib/express/express-logging.d.ts +3 -0
- package/build/lib/express/express-logging.d.ts.map +1 -0
- package/build/lib/express/express-logging.js +3 -5
- package/build/lib/express/idempotency.d.ts +2 -0
- package/build/lib/express/idempotency.d.ts.map +1 -0
- package/build/lib/express/idempotency.js +3 -5
- package/build/lib/express/logger.d.ts +3 -0
- package/build/lib/express/logger.d.ts.map +1 -0
- package/build/lib/express/logger.js +2 -4
- package/build/lib/express/middleware.d.ts +9 -0
- package/build/lib/express/middleware.d.ts.map +1 -0
- package/build/lib/express/middleware.js +2 -4
- package/build/lib/express/server.d.ts +10 -0
- package/build/lib/express/server.d.ts.map +1 -0
- package/build/lib/express/server.js +2 -4
- package/build/lib/express/static.d.ts +6 -0
- package/build/lib/express/static.d.ts.map +1 -0
- package/build/lib/express/static.js +2 -4
- package/build/lib/express/websocket.d.ts +64 -0
- package/build/lib/express/websocket.d.ts.map +1 -0
- package/build/lib/express/websocket.js +2 -4
- package/build/lib/helpers/capabilities.d.ts +13 -0
- package/build/lib/helpers/capabilities.d.ts.map +1 -0
- package/build/lib/helpers/capabilities.js +77 -0
- package/build/lib/index.d.ts +183 -0
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/index.js +41 -25
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts +48 -0
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -0
- package/build/lib/jsonwp-proxy/protocol-converter.js +19 -15
- package/build/lib/jsonwp-proxy/proxy.d.ts +41 -0
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -0
- package/build/lib/jsonwp-proxy/proxy.js +20 -15
- package/build/lib/jsonwp-status/status.d.ts +159 -0
- package/build/lib/jsonwp-status/status.d.ts.map +1 -0
- package/build/lib/jsonwp-status/status.js +2 -4
- package/build/lib/protocol/errors.d.ts +310 -0
- package/build/lib/protocol/errors.d.ts.map +1 -0
- package/build/lib/protocol/errors.js +82 -5
- package/build/lib/protocol/helpers.d.ts +22 -0
- package/build/lib/protocol/helpers.d.ts.map +1 -0
- package/build/lib/protocol/helpers.js +2 -4
- package/build/lib/protocol/index.d.ts +16 -0
- package/build/lib/protocol/index.d.ts.map +1 -0
- package/build/lib/protocol/index.js +8 -10
- package/build/lib/protocol/protocol.d.ts +11 -0
- package/build/lib/protocol/protocol.d.ts.map +1 -0
- package/build/lib/protocol/protocol.js +38 -35
- package/build/lib/protocol/routes.d.ts +6 -0
- package/build/lib/protocol/routes.d.ts.map +1 -0
- package/build/lib/protocol/routes.js +84 -4
- package/build/lib/protocol/validators.d.ts +8 -0
- package/build/lib/protocol/validators.d.ts.map +1 -0
- package/build/lib/protocol/validators.js +2 -4
- package/build/test/basedriver/README.md +5 -0
- package/build/test/basedriver/driver-e2e-tests.js +2 -4
- package/build/test/basedriver/driver-tests.js +41 -19
- package/build/test/basedriver/index.js +2 -4
- package/build/test/e2e/basedriver/driver.e2e.spec.js +15 -0
- package/build/test/e2e/basedriver/helpers.e2e.spec.js +192 -0
- package/build/test/e2e/basedriver/websockets.e2e.spec.js +82 -0
- package/build/test/e2e/express/server.e2e.spec.js +159 -0
- package/build/test/e2e/jsonwp-proxy/proxy.e2e.spec.js +59 -0
- package/build/test/e2e/protocol/fake-driver.js +163 -0
- package/build/test/e2e/protocol/helpers.js +25 -0
- package/build/test/e2e/protocol/protocol.e2e.spec.js +1186 -0
- package/build/test/helpers.js +2 -4
- package/build/test/unit/basedriver/capabilities.spec.js +672 -0
- package/build/test/unit/basedriver/capability.spec.js +353 -0
- package/build/test/unit/basedriver/commands/event.spec.js +110 -0
- package/build/test/unit/basedriver/commands/log.spec.js +92 -0
- package/build/test/unit/basedriver/driver.spec.js +15 -0
- package/build/test/unit/basedriver/helpers.spec.js +151 -0
- package/build/test/unit/basedriver/timeout.spec.js +135 -0
- package/build/test/unit/express/server.spec.js +155 -0
- package/build/test/unit/express/static.spec.js +26 -0
- package/build/test/unit/jsonwp-proxy/mock-request.js +91 -0
- package/build/test/unit/jsonwp-proxy/protocol-converter.spec.js +171 -0
- package/build/test/unit/jsonwp-proxy/proxy.spec.js +292 -0
- package/build/test/unit/jsonwp-proxy/url.spec.js +165 -0
- package/build/test/unit/jsonwp-status/status.spec.js +34 -0
- package/build/test/unit/protocol/errors.spec.js +390 -0
- package/build/test/unit/protocol/routes.spec.js +80 -0
- package/build/test/unit/protocol/validator.spec.js +149 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/lib/basedriver/capabilities.js +49 -10
- package/lib/basedriver/commands/event.js +49 -31
- package/lib/basedriver/commands/find.js +107 -45
- package/lib/basedriver/commands/index.js +25 -19
- package/lib/basedriver/commands/log.js +59 -34
- package/lib/basedriver/commands/session.js +39 -142
- package/lib/basedriver/commands/settings.js +32 -14
- package/lib/basedriver/commands/timeout.js +153 -154
- package/lib/basedriver/core.js +497 -0
- package/lib/basedriver/desired-caps.js +1 -1
- package/lib/basedriver/device-settings.js +57 -13
- package/lib/basedriver/driver.js +277 -375
- package/lib/basedriver/helpers.js +31 -13
- package/lib/express/express-logging.js +1 -1
- package/lib/express/idempotency.js +1 -1
- package/lib/helpers/capabilities.js +84 -0
- package/lib/index.js +17 -13
- package/lib/jsonwp-proxy/protocol-converter.js +14 -13
- package/lib/jsonwp-proxy/proxy.js +16 -12
- package/lib/protocol/errors.js +42 -42
- package/lib/protocol/index.js +4 -4
- package/lib/protocol/protocol.js +35 -32
- package/lib/protocol/routes.js +69 -1
- package/package.json +37 -24
- package/test/basedriver/README.md +5 -0
- package/test/basedriver/driver-e2e-tests.js +1 -1
- package/test/basedriver/driver-tests.js +43 -9
- package/build/lib/protocol/sessions-cache.js +0 -88
- package/build/test/basedriver/capabilities-specs.js +0 -632
- package/build/test/basedriver/capability-specs.js +0 -396
- package/build/test/basedriver/commands/event-specs.js +0 -112
- package/build/test/basedriver/commands/log-specs.js +0 -80
- package/build/test/basedriver/driver-e2e-specs.js +0 -17
- package/build/test/basedriver/driver-specs.js +0 -17
- package/build/test/basedriver/helpers-e2e-specs.js +0 -194
- package/build/test/basedriver/helpers-specs.js +0 -153
- package/build/test/basedriver/timeout-specs.js +0 -139
- package/build/test/basedriver/websockets-e2e-specs.js +0 -84
- package/build/test/express/server-e2e-specs.js +0 -156
- package/build/test/express/server-specs.js +0 -151
- package/build/test/express/static-specs.js +0 -23
- package/build/test/jsonwp-proxy/mock-request.js +0 -93
- package/build/test/jsonwp-proxy/protocol-converter-specs.js +0 -173
- package/build/test/jsonwp-proxy/proxy-e2e-specs.js +0 -61
- package/build/test/jsonwp-proxy/proxy-specs.js +0 -294
- package/build/test/jsonwp-proxy/url-specs.js +0 -167
- package/build/test/jsonwp-status/status-specs.js +0 -36
- package/build/test/protocol/errors-specs.js +0 -388
- package/build/test/protocol/fake-driver.js +0 -168
- package/build/test/protocol/helpers.js +0 -27
- package/build/test/protocol/protocol-e2e-specs.js +0 -1182
- package/build/test/protocol/routes-specs.js +0 -82
- package/build/test/protocol/validator-specs.js +0 -151
- package/index.d.ts +0 -386
- package/lib/protocol/sessions-cache.js +0 -74
- package/test/basedriver/capabilities-specs.js +0 -505
- package/test/basedriver/capability-specs.js +0 -409
- package/test/basedriver/commands/event-specs.js +0 -74
- package/test/basedriver/commands/log-specs.js +0 -70
- package/test/basedriver/driver-e2e-specs.js +0 -8
- package/test/basedriver/driver-specs.js +0 -8
- package/test/basedriver/fixtures/BadZippedApp.zip +0 -1
- package/test/basedriver/fixtures/FakeAndroidApp.apk +0 -1
- package/test/basedriver/fixtures/FakeAndroidApp.asd +0 -0
- package/test/basedriver/fixtures/FakeIOSApp.app +0 -1
- package/test/basedriver/fixtures/FakeIOSApp.app.zip +0 -0
- package/test/basedriver/fixtures/FakeIOSApp.ipa +0 -0
- package/test/basedriver/fixtures/custom-element-finder-bad.js +0 -5
- package/test/basedriver/fixtures/custom-element-finder.js +0 -29
- package/test/basedriver/helpers-e2e-specs.js +0 -187
- package/test/basedriver/helpers-specs.js +0 -137
- package/test/basedriver/timeout-specs.js +0 -133
- package/test/basedriver/websockets-e2e-specs.js +0 -75
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import url from 'url';
|
|
4
4
|
import logger from './logger';
|
|
5
|
-
import { tempDir, fs, util, zip, net, timing } from '@appium/support';
|
|
5
|
+
import { tempDir, fs, util, zip, net, timing, node } from '@appium/support';
|
|
6
6
|
import LRU from 'lru-cache';
|
|
7
7
|
import AsyncLock from 'async-lock';
|
|
8
8
|
import axios from 'axios';
|
|
@@ -15,17 +15,17 @@ const ZIP_MIME_TYPES = [
|
|
|
15
15
|
'multipart/x-zip',
|
|
16
16
|
];
|
|
17
17
|
const CACHED_APPS_MAX_AGE = 1000 * 60 * 60 * 24; // ms
|
|
18
|
+
const MAX_CACHED_APPS = 1024;
|
|
18
19
|
const APPLICATIONS_CACHE = new LRU({
|
|
19
|
-
|
|
20
|
+
max: MAX_CACHED_APPS,
|
|
21
|
+
ttl: CACHED_APPS_MAX_AGE, // expire after 24 hours
|
|
20
22
|
updateAgeOnGet: true,
|
|
21
23
|
dispose: (app, {fullPath}) => {
|
|
22
24
|
logger.info(`The application '${app}' cached at '${fullPath}' has ` +
|
|
23
25
|
`expired after ${CACHED_APPS_MAX_AGE}ms`);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
});
|
|
26
|
+
if (fullPath) {
|
|
27
|
+
fs.rimraf(fullPath);
|
|
28
|
+
}
|
|
29
29
|
},
|
|
30
30
|
noDisposeOnSet: true,
|
|
31
31
|
});
|
|
@@ -35,11 +35,11 @@ const DEFAULT_BASENAME = 'appium-app';
|
|
|
35
35
|
const APP_DOWNLOAD_TIMEOUT_MS = 120 * 1000;
|
|
36
36
|
|
|
37
37
|
process.on('exit', () => {
|
|
38
|
-
if (APPLICATIONS_CACHE.
|
|
38
|
+
if (APPLICATIONS_CACHE.size === 0) {
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const appPaths = APPLICATIONS_CACHE.values()
|
|
42
|
+
const appPaths = [...APPLICATIONS_CACHE.values()]
|
|
43
43
|
.map(({fullPath}) => fullPath);
|
|
44
44
|
logger.debug(`Performing cleanup of ${appPaths.length} cached ` +
|
|
45
45
|
util.pluralize('application', appPaths.length));
|
|
@@ -151,7 +151,7 @@ async function isAppIntegrityOk (currentPath, expectedIntegrity = {}) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* @typedef
|
|
154
|
+
* @typedef PostProcessOptions
|
|
155
155
|
* @property {?Object} cachedAppInfo The information about the previously cached app instance (if exists):
|
|
156
156
|
* - packageHash: SHA1 hash of the package if it is a file and not a folder
|
|
157
157
|
* - lastModified: Optional Date instance, the value of file's `Last-Modified` header
|
|
@@ -171,13 +171,13 @@ async function isAppIntegrityOk (currentPath, expectedIntegrity = {}) {
|
|
|
171
171
|
*/
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* @typedef
|
|
174
|
+
* @typedef PostProcessResult
|
|
175
175
|
* @property {string} appPath The full past to the post-processed application package on the
|
|
176
176
|
* local file system (might be a file or a folder path)
|
|
177
177
|
*/
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
|
-
* @typedef
|
|
180
|
+
* @typedef ConfigureAppOptions
|
|
181
181
|
* @property {(obj: PostProcessOptions) => (Promise<PostProcessResult|undefined>|PostProcessResult|undefined)} onPostProcess
|
|
182
182
|
* Optional function, which should be applied
|
|
183
183
|
* to the application after it is downloaded/preprocessed. This function may be async
|
|
@@ -193,6 +193,8 @@ async function isAppIntegrityOk (currentPath, expectedIntegrity = {}) {
|
|
|
193
193
|
/**
|
|
194
194
|
* Prepares an app to be used in an automated test. The app gets cached automatically
|
|
195
195
|
* if it is an archive or if it is downloaded from an URL.
|
|
196
|
+
* If the downloaded app has `.zip` extension, this method will unzip it.
|
|
197
|
+
* The unzip does not work when `onPostProcess` is provided.
|
|
196
198
|
*
|
|
197
199
|
* @param {string} app Either a full path to the app or a remote URL
|
|
198
200
|
* @param {string|string[]|ConfigureAppOptions} options
|
|
@@ -544,6 +546,22 @@ function parseCapsArray (cap) {
|
|
|
544
546
|
throw new Error(`must provide a string or JSON Array; received ${cap}`);
|
|
545
547
|
}
|
|
546
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Generate a string that uniquely describes driver instance
|
|
551
|
+
*
|
|
552
|
+
* @param {import('@appium/types').Core} obj driver instance
|
|
553
|
+
* @param {string?} sessionId session identifier (if exists)
|
|
554
|
+
* @returns {string}
|
|
555
|
+
*/
|
|
556
|
+
function generateDriverLogPrefix (obj, sessionId = null) {
|
|
557
|
+
const instanceName = `${obj.constructor.name}@${node.getObjectId(obj).substring(0, 4)}`;
|
|
558
|
+
return sessionId ? `${instanceName} (${sessionId.substring(0, 8)})` : instanceName;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** @type {import('@appium/types').DriverHelpers} */
|
|
562
|
+
export default {
|
|
563
|
+
configureApp, isPackageOrBundle, duplicateKeys, parseCapsArray, generateDriverLogPrefix
|
|
564
|
+
};
|
|
547
565
|
export {
|
|
548
|
-
configureApp, isPackageOrBundle, duplicateKeys, parseCapsArray
|
|
566
|
+
configureApp, isPackageOrBundle, duplicateKeys, parseCapsArray, generateDriverLogPrefix
|
|
549
567
|
};
|
|
@@ -20,7 +20,7 @@ const MONITORED_METHODS = ['POST', 'PATCH'];
|
|
|
20
20
|
const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
|
|
21
21
|
|
|
22
22
|
process.on('exit', () => {
|
|
23
|
-
const resPaths = IDEMPOTENT_RESPONSES.values()
|
|
23
|
+
const resPaths = [...IDEMPOTENT_RESPONSES.values()]
|
|
24
24
|
.map(({response}) => response)
|
|
25
25
|
.filter(Boolean);
|
|
26
26
|
for (const resPath of resPaths) {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
|
|
5
|
+
function isW3cCaps (caps) {
|
|
6
|
+
if (!_.isPlainObject(caps)) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const isFirstMatchValid = () => _.isArray(caps.firstMatch)
|
|
11
|
+
&& !_.isEmpty(caps.firstMatch) && _.every(caps.firstMatch, _.isPlainObject);
|
|
12
|
+
const isAlwaysMatchValid = () => _.isPlainObject(caps.alwaysMatch);
|
|
13
|
+
if (_.has(caps, 'firstMatch') && _.has(caps, 'alwaysMatch')) {
|
|
14
|
+
return isFirstMatchValid() && isAlwaysMatchValid();
|
|
15
|
+
}
|
|
16
|
+
if (_.has(caps, 'firstMatch')) {
|
|
17
|
+
return isFirstMatchValid();
|
|
18
|
+
}
|
|
19
|
+
if (_.has(caps, 'alwaysMatch')) {
|
|
20
|
+
return isAlwaysMatchValid();
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param {Capabilities} originalCaps
|
|
28
|
+
* @param {Constraints} desiredCapConstraints
|
|
29
|
+
* @param {AppiumLogger} log
|
|
30
|
+
* @returns {Capabilities}
|
|
31
|
+
*/
|
|
32
|
+
function fixCaps (originalCaps, desiredCapConstraints, log) {
|
|
33
|
+
let caps = _.clone(originalCaps);
|
|
34
|
+
|
|
35
|
+
// boolean capabilities can be passed in as strings 'false' and 'true'
|
|
36
|
+
// which we want to translate into boolean values
|
|
37
|
+
let booleanCaps = _.keys(
|
|
38
|
+
_.pickBy(desiredCapConstraints, (k) => k.isBoolean === true),
|
|
39
|
+
);
|
|
40
|
+
for (let cap of booleanCaps) {
|
|
41
|
+
let value = originalCaps[cap];
|
|
42
|
+
if (_.isString(value)) {
|
|
43
|
+
value = value.toLowerCase();
|
|
44
|
+
if (value === 'true' || value === 'false') {
|
|
45
|
+
log.warn(
|
|
46
|
+
`Capability '${cap}' changed from string to boolean. This may cause unexpected behavior`,
|
|
47
|
+
);
|
|
48
|
+
caps[cap] = value === 'true';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// int capabilities are often sent in as strings by frameworks
|
|
54
|
+
let intCaps = _.keys(
|
|
55
|
+
_.pickBy(desiredCapConstraints, (k) => k.isNumber === true),
|
|
56
|
+
);
|
|
57
|
+
for (let cap of intCaps) {
|
|
58
|
+
let value = originalCaps[cap];
|
|
59
|
+
if (_.isString(value)) {
|
|
60
|
+
value = value.trim();
|
|
61
|
+
let newValue = parseInt(value, 10);
|
|
62
|
+
if (value !== `${newValue}`) {
|
|
63
|
+
newValue = parseFloat(value);
|
|
64
|
+
}
|
|
65
|
+
log.warn(
|
|
66
|
+
`Capability '${cap}' changed from string ('${value}') to integer (${newValue}). This may cause unexpected behavior`,
|
|
67
|
+
);
|
|
68
|
+
caps[cap] = newValue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return caps;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
isW3cCaps,
|
|
77
|
+
fixCaps
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @typedef {import('@appium/types').Capabilities} Capabilities
|
|
82
|
+
* @typedef {import('@appium/types').Constraints} Constraints
|
|
83
|
+
* @typedef {import('@appium/types').AppiumLogger} AppiumLogger
|
|
84
|
+
*/
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
//
|
|
1
|
+
// @ts-check
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import B from 'bluebird';
|
|
4
|
+
|
|
5
|
+
B.config({
|
|
6
|
+
cancellation: true,
|
|
7
|
+
});
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
// BaseDriver exports
|
|
10
|
+
import { BaseDriver } from './basedriver/driver';
|
|
11
|
+
export { DriverCore } from './basedriver/core';
|
|
12
|
+
import { DeviceSettings } from './basedriver/device-settings';
|
|
9
13
|
|
|
10
|
-
export { BaseDriver, DeviceSettings
|
|
14
|
+
export { BaseDriver, DeviceSettings };
|
|
11
15
|
export default BaseDriver;
|
|
12
16
|
|
|
13
17
|
|
|
@@ -18,19 +22,19 @@ import {
|
|
|
18
22
|
} from './constants';
|
|
19
23
|
|
|
20
24
|
const {
|
|
21
|
-
|
|
25
|
+
routeConfiguringFunction, errors, isErrorType,
|
|
22
26
|
errorFromMJSONWPStatusCode, errorFromW3CJsonCode, ALL_COMMANDS, METHOD_MAP,
|
|
23
27
|
routeToCommandName, NO_SESSION_ID_COMMANDS, isSessionCommand,
|
|
24
|
-
|
|
28
|
+
determineProtocol, CREATE_SESSION_COMMAND,
|
|
25
29
|
DELETE_SESSION_COMMAND, GET_STATUS_COMMAND,
|
|
26
30
|
} = protocol;
|
|
27
31
|
|
|
28
32
|
export {
|
|
29
|
-
|
|
33
|
+
routeConfiguringFunction, errors, isErrorType, PROTOCOLS,
|
|
30
34
|
errorFromMJSONWPStatusCode, errorFromW3CJsonCode, determineProtocol,
|
|
31
35
|
errorFromMJSONWPStatusCode as errorFromCode, ALL_COMMANDS, METHOD_MAP,
|
|
32
36
|
routeToCommandName, NO_SESSION_ID_COMMANDS, isSessionCommand,
|
|
33
|
-
DEFAULT_BASE_PATH,
|
|
37
|
+
DEFAULT_BASE_PATH, CREATE_SESSION_COMMAND,
|
|
34
38
|
DELETE_SESSION_COMMAND, GET_STATUS_COMMAND,
|
|
35
39
|
};
|
|
36
40
|
|
|
@@ -40,8 +44,8 @@ const { STATIC_DIR } = staticIndex;
|
|
|
40
44
|
export { STATIC_DIR };
|
|
41
45
|
|
|
42
46
|
import * as serverIndex from './express/server';
|
|
43
|
-
const { server } = serverIndex;
|
|
44
|
-
export { server };
|
|
47
|
+
const { server, normalizeBasePath } = serverIndex;
|
|
48
|
+
export { server, normalizeBasePath };
|
|
45
49
|
|
|
46
50
|
// jsonwp-proxy exports
|
|
47
51
|
import * as proxyIndex from './jsonwp-proxy/proxy';
|
|
@@ -5,9 +5,6 @@ import {
|
|
|
5
5
|
MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY, PROTOCOLS
|
|
6
6
|
} from '../constants';
|
|
7
7
|
|
|
8
|
-
const log = logger.getLogger('Protocol Converter');
|
|
9
|
-
|
|
10
|
-
|
|
11
8
|
export const COMMAND_URLS_CONFLICTS = [
|
|
12
9
|
{
|
|
13
10
|
commandNames: ['execute', 'executeAsync'],
|
|
@@ -41,20 +38,24 @@ export const COMMAND_URLS_CONFLICTS = [
|
|
|
41
38
|
jsonwpConverter: (w3cUrl) => {
|
|
42
39
|
const w3cPropertyRegex = /\/element\/([^/]+)\/property\/([^/]+)/;
|
|
43
40
|
const jsonwpUrl = w3cUrl.replace(w3cPropertyRegex, '/element/$1/attribute/$2');
|
|
44
|
-
log.info(`Converting W3C '${w3cUrl}' to '${jsonwpUrl}'`);
|
|
45
41
|
return jsonwpUrl;
|
|
46
42
|
},
|
|
47
43
|
w3cConverter: (jsonwpUrl) => jsonwpUrl // Don't convert JSONWP URL to W3C. W3C accepts /attribute and /property
|
|
48
44
|
}
|
|
49
45
|
];
|
|
50
|
-
|
|
51
46
|
const {MJSONWP, W3C} = PROTOCOLS;
|
|
47
|
+
const DEFAULT_LOG = logger.getLogger('Protocol Converter');
|
|
52
48
|
|
|
53
49
|
|
|
54
50
|
class ProtocolConverter {
|
|
55
|
-
constructor (proxyFunc) {
|
|
51
|
+
constructor (proxyFunc, log = null) {
|
|
56
52
|
this.proxyFunc = proxyFunc;
|
|
57
53
|
this._downstreamProtocol = null;
|
|
54
|
+
this._log = log;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get log () {
|
|
58
|
+
return this._log ?? DEFAULT_LOG;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
set downstreamProtocol (value) {
|
|
@@ -107,7 +108,7 @@ class ProtocolConverter {
|
|
|
107
108
|
let response, resBody;
|
|
108
109
|
|
|
109
110
|
const timeoutRequestObjects = this.getTimeoutRequestObjects(body);
|
|
110
|
-
log.debug(`Will send the following request bodies to /timeouts: ${JSON.stringify(timeoutRequestObjects)}`);
|
|
111
|
+
this.log.debug(`Will send the following request bodies to /timeouts: ${JSON.stringify(timeoutRequestObjects)}`);
|
|
111
112
|
for (const timeoutObj of timeoutRequestObjects) {
|
|
112
113
|
[response, resBody] = await this.proxyFunc(url, method, timeoutObj);
|
|
113
114
|
|
|
@@ -130,14 +131,14 @@ class ProtocolConverter {
|
|
|
130
131
|
const bodyObj = util.safeJsonParse(body);
|
|
131
132
|
if (_.isPlainObject(bodyObj)) {
|
|
132
133
|
if (this.downstreamProtocol === W3C && _.has(bodyObj, 'name') && !_.has(bodyObj, 'handle')) {
|
|
133
|
-
log.debug(`Copied 'name' value '${bodyObj.name}' to 'handle' as per W3C spec`);
|
|
134
|
+
this.log.debug(`Copied 'name' value '${bodyObj.name}' to 'handle' as per W3C spec`);
|
|
134
135
|
return await this.proxyFunc(url, method, {
|
|
135
136
|
...bodyObj,
|
|
136
137
|
handle: bodyObj.name,
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
if (this.downstreamProtocol === MJSONWP && _.has(bodyObj, 'handle') && !_.has(bodyObj, 'name')) {
|
|
140
|
-
log.debug(`Copied 'handle' value '${bodyObj.handle}' to 'name' as per JSONWP spec`);
|
|
141
|
+
this.log.debug(`Copied 'handle' value '${bodyObj.handle}' to 'name' as per JSONWP spec`);
|
|
141
142
|
return await this.proxyFunc(url, method, {
|
|
142
143
|
...bodyObj,
|
|
143
144
|
name: bodyObj.handle,
|
|
@@ -156,12 +157,12 @@ class ProtocolConverter {
|
|
|
156
157
|
value = _.isString(text)
|
|
157
158
|
? [...text]
|
|
158
159
|
: (_.isArray(text) ? text : []);
|
|
159
|
-
log.debug(`Added 'value' property ${JSON.stringify(value)} to 'setValue' request body`);
|
|
160
|
+
this.log.debug(`Added 'value' property ${JSON.stringify(value)} to 'setValue' request body`);
|
|
160
161
|
} else if (!util.hasValue(text) && util.hasValue(value)) {
|
|
161
162
|
text = _.isArray(value)
|
|
162
163
|
? value.join('')
|
|
163
164
|
: (_.isString(value) ? value : '');
|
|
164
|
-
log.debug(`Added 'text' property ${JSON.stringify(text)} to 'setValue' request body`);
|
|
165
|
+
this.log.debug(`Added 'text' property ${JSON.stringify(text)} to 'setValue' request body`);
|
|
165
166
|
}
|
|
166
167
|
return await this.proxyFunc(url, method, Object.assign({}, bodyObj, {
|
|
167
168
|
text,
|
|
@@ -236,11 +237,11 @@ class ProtocolConverter {
|
|
|
236
237
|
? jsonwpConverter(url)
|
|
237
238
|
: w3cConverter(url);
|
|
238
239
|
if (rewrittenUrl === url) {
|
|
239
|
-
log.debug(`Did not know how to rewrite the original URL '${url}' ` +
|
|
240
|
+
this.log.debug(`Did not know how to rewrite the original URL '${url}' ` +
|
|
240
241
|
`for ${this.downstreamProtocol} protocol`);
|
|
241
242
|
break;
|
|
242
243
|
}
|
|
243
|
-
log.info(`Rewrote the original URL '${url}' to '${rewrittenUrl}' ` +
|
|
244
|
+
this.log.info(`Rewrote the original URL '${url}' to '${rewrittenUrl}' ` +
|
|
244
245
|
`for ${this.downstreamProtocol} protocol`);
|
|
245
246
|
return await this.proxyFunc(rewrittenUrl, method, body);
|
|
246
247
|
}
|
|
@@ -12,8 +12,7 @@ import { formatResponseValue, formatStatus } from '../protocol/helpers';
|
|
|
12
12
|
import http from 'http';
|
|
13
13
|
import https from 'https';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
const log = logger.getLogger('WD Proxy');
|
|
15
|
+
const DEFAULT_LOG = logger.getLogger('WD Proxy');
|
|
17
16
|
const DEFAULT_REQUEST_TIMEOUT = 240000;
|
|
18
17
|
const COMPACT_ERROR_PATTERNS = [
|
|
19
18
|
/\bECONNREFUSED\b/,
|
|
@@ -43,7 +42,12 @@ class JWProxy {
|
|
|
43
42
|
};
|
|
44
43
|
this.httpAgent = new http.Agent(agentOpts);
|
|
45
44
|
this.httpsAgent = new https.Agent(agentOpts);
|
|
46
|
-
this.protocolConverter = new ProtocolConverter(this.proxy.bind(this));
|
|
45
|
+
this.protocolConverter = new ProtocolConverter(this.proxy.bind(this), opts.log);
|
|
46
|
+
this._log = opts.log;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get log () {
|
|
50
|
+
return this._log ?? DEFAULT_LOG;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
@@ -166,7 +170,7 @@ class JWProxy {
|
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
172
|
|
|
169
|
-
log.debug(`Proxying [${method} ${url || '/'}] to [${method} ${newUrl}] ` +
|
|
173
|
+
this.log.debug(`Proxying [${method} ${url || '/'}] to [${method} ${newUrl}] ` +
|
|
170
174
|
(reqOpts.data ? `with body: ${truncateBody(reqOpts.data)}` : 'with no body'));
|
|
171
175
|
|
|
172
176
|
const throwProxyError = (error) => {
|
|
@@ -187,7 +191,7 @@ class JWProxy {
|
|
|
187
191
|
// If it cannot be coerced to an object then the response is wrong
|
|
188
192
|
throwProxyError(data);
|
|
189
193
|
}
|
|
190
|
-
log.debug(`Got response with status ${status}: ${truncateBody(data)}`);
|
|
194
|
+
this.log.debug(`Got response with status ${status}: ${truncateBody(data)}`);
|
|
191
195
|
isResponseLogged = true;
|
|
192
196
|
const isSessionCreationRequest = /\/session$/.test(url) && method === 'POST';
|
|
193
197
|
if (isSessionCreationRequest) {
|
|
@@ -195,7 +199,7 @@ class JWProxy {
|
|
|
195
199
|
this.sessionId = data.sessionId || (data.value || {}).sessionId;
|
|
196
200
|
}
|
|
197
201
|
this.downstreamProtocol = this.getProtocolFromResBody(data);
|
|
198
|
-
log.info(`Determined the downstream protocol as '${this.downstreamProtocol}'`);
|
|
202
|
+
this.log.info(`Determined the downstream protocol as '${this.downstreamProtocol}'`);
|
|
199
203
|
}
|
|
200
204
|
if (_.has(data, 'status') && parseInt(data.status, 10) !== 0) {
|
|
201
205
|
// Some servers, like chromedriver may return response code 200 for non-zero JSONWP statuses
|
|
@@ -211,16 +215,16 @@ class JWProxy {
|
|
|
211
215
|
if (util.hasValue(e.response)) {
|
|
212
216
|
if (!isResponseLogged) {
|
|
213
217
|
const error = truncateBody(e.response.data);
|
|
214
|
-
log.info(util.hasValue(e.response.status)
|
|
218
|
+
this.log.info(util.hasValue(e.response.status)
|
|
215
219
|
? `Got response with status ${e.response.status}: ${error}`
|
|
216
220
|
: `Got response with unknown status: ${error}`);
|
|
217
221
|
}
|
|
218
222
|
} else {
|
|
219
223
|
proxyErrorMsg = `Could not proxy command to the remote server. Original error: ${e.message}`;
|
|
220
224
|
if (COMPACT_ERROR_PATTERNS.some((p) => p.test(e.message))) {
|
|
221
|
-
log.info(e.message);
|
|
225
|
+
this.log.info(e.message);
|
|
222
226
|
} else {
|
|
223
|
-
log.info(e.stack);
|
|
227
|
+
this.log.info(e.stack);
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
throw new errors.ProxyRequestError(proxyErrorMsg, e.response?.data, e.response?.status);
|
|
@@ -256,7 +260,7 @@ class JWProxy {
|
|
|
256
260
|
if (!commandName) {
|
|
257
261
|
return await this.proxy(url, method, body);
|
|
258
262
|
}
|
|
259
|
-
log.debug(`Matched '${url}' to command name '${commandName}'`);
|
|
263
|
+
this.log.debug(`Matched '${url}' to command name '${commandName}'`);
|
|
260
264
|
|
|
261
265
|
return await this.protocolConverter.convertAndProxy(commandName, url, method, body);
|
|
262
266
|
}
|
|
@@ -318,10 +322,10 @@ class JWProxy {
|
|
|
318
322
|
const reqSessionId = this.getSessionIdFromUrl(req.originalUrl);
|
|
319
323
|
if (_.has(resBodyObj, 'sessionId')) {
|
|
320
324
|
if (reqSessionId) {
|
|
321
|
-
log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${reqSessionId}`);
|
|
325
|
+
this.log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${reqSessionId}`);
|
|
322
326
|
resBodyObj.sessionId = reqSessionId;
|
|
323
327
|
} else if (this.sessionId) {
|
|
324
|
-
log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${this.sessionId}`);
|
|
328
|
+
this.log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${this.sessionId}`);
|
|
325
329
|
resBodyObj.sessionId = this.sessionId;
|
|
326
330
|
}
|
|
327
331
|
}
|