@appium/base-driver 9.5.4 → 9.7.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/desired-caps.js +2 -1
- package/build/lib/basedriver/desired-caps.js.map +1 -1
- package/build/lib/basedriver/helpers.d.ts +30 -26
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +67 -27
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/express/middleware.d.ts +46 -7
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +65 -2
- package/build/lib/express/middleware.js.map +1 -1
- package/build/lib/express/server.d.ts +2 -1
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +5 -2
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/express/websocket.d.ts +0 -3
- package/build/lib/express/websocket.d.ts.map +1 -1
- package/build/lib/express/websocket.js +0 -27
- package/build/lib/express/websocket.js.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.js +6 -6
- package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
- package/lib/basedriver/desired-caps.js +4 -1
- package/lib/basedriver/helpers.js +72 -39
- package/lib/express/middleware.js +70 -16
- package/lib/express/server.js +6 -1
- package/lib/express/websocket.js +0 -27
- package/lib/jsonwp-proxy/protocol-converter.js +10 -6
- package/package.json +8 -8
|
@@ -2,8 +2,16 @@ import _ from 'lodash';
|
|
|
2
2
|
import log from './logger';
|
|
3
3
|
import {errors} from '../protocol';
|
|
4
4
|
import {handleIdempotency} from './idempotency';
|
|
5
|
+
import {pathToRegexp} from 'path-to-regexp';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param {import('express').Request} req
|
|
10
|
+
* @param {import('express').Response} res
|
|
11
|
+
* @param {import('express').NextFunction} next
|
|
12
|
+
* @returns {any}
|
|
13
|
+
*/
|
|
14
|
+
export function allowCrossDomain(req, res, next) {
|
|
7
15
|
try {
|
|
8
16
|
res.header('Access-Control-Allow-Origin', '*');
|
|
9
17
|
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS, DELETE');
|
|
@@ -22,7 +30,11 @@ function allowCrossDomain(req, res, next) {
|
|
|
22
30
|
next();
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} basePath
|
|
35
|
+
* @returns {import('express').RequestHandler}
|
|
36
|
+
*/
|
|
37
|
+
export function allowCrossDomainAsyncExecute(basePath) {
|
|
26
38
|
return (req, res, next) => {
|
|
27
39
|
// there are two paths for async responses, so cover both
|
|
28
40
|
// https://regex101.com/r/txYiEz/1
|
|
@@ -36,12 +48,17 @@ function allowCrossDomainAsyncExecute(basePath) {
|
|
|
36
48
|
};
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @param {string} basePath
|
|
54
|
+
* @returns {import('express').RequestHandler}
|
|
55
|
+
*/
|
|
56
|
+
export function fixPythonContentType(basePath) {
|
|
40
57
|
return (req, res, next) => {
|
|
41
58
|
// hack because python client library gives us wrong content-type
|
|
42
59
|
if (
|
|
43
60
|
new RegExp(`^${_.escapeRegExp(basePath)}`).test(req.path) &&
|
|
44
|
-
/^Python/.test(req.headers['user-agent'])
|
|
61
|
+
/^Python/.test(req.headers['user-agent'] ?? '')
|
|
45
62
|
) {
|
|
46
63
|
if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
|
47
64
|
req.headers['content-type'] = 'application/json; charset=utf-8';
|
|
@@ -51,14 +68,55 @@ function fixPythonContentType(basePath) {
|
|
|
51
68
|
};
|
|
52
69
|
}
|
|
53
70
|
|
|
54
|
-
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* @param {import('express').Request} req
|
|
74
|
+
* @param {import('express').Response} res
|
|
75
|
+
* @param {import('express').NextFunction} next
|
|
76
|
+
* @returns {any}
|
|
77
|
+
*/
|
|
78
|
+
export function defaultToJSONContentType(req, res, next) {
|
|
55
79
|
if (!req.headers['content-type']) {
|
|
56
80
|
req.headers['content-type'] = 'application/json; charset=utf-8';
|
|
57
81
|
}
|
|
58
82
|
next();
|
|
59
83
|
}
|
|
60
84
|
|
|
61
|
-
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @param {import('@appium/types').StringRecord<import('@appium/types').WSServer>} webSocketsMapping
|
|
88
|
+
* @returns {import('express').RequestHandler}
|
|
89
|
+
*/
|
|
90
|
+
export function handleUpgrade(webSocketsMapping) {
|
|
91
|
+
return (req, res, next) => {
|
|
92
|
+
if (!req.headers?.upgrade || _.toLower(req.headers.upgrade) !== 'websocket') {
|
|
93
|
+
return next();
|
|
94
|
+
}
|
|
95
|
+
let currentPathname;
|
|
96
|
+
try {
|
|
97
|
+
currentPathname = new URL(req.url ?? '').pathname;
|
|
98
|
+
} catch {
|
|
99
|
+
currentPathname = req.url ?? '';
|
|
100
|
+
}
|
|
101
|
+
for (const [pathname, wsServer] of _.toPairs(webSocketsMapping)) {
|
|
102
|
+
if (pathToRegexp(pathname).test(currentPathname)) {
|
|
103
|
+
return wsServer.handleUpgrade(req, req.socket, Buffer.from(''), (ws) => {
|
|
104
|
+
wsServer.emit('connection', ws, req);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
log.info(`Did not match the websocket upgrade request at ${currentPathname} to any known route`);
|
|
109
|
+
next();
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {Error} err
|
|
115
|
+
* @param {import('express').Request} req
|
|
116
|
+
* @param {import('express').Response} res
|
|
117
|
+
* @param {import('express').NextFunction} next
|
|
118
|
+
*/
|
|
119
|
+
export function catchAllHandler(err, req, res, next) {
|
|
62
120
|
if (res.headersSent) {
|
|
63
121
|
return next(err);
|
|
64
122
|
}
|
|
@@ -79,7 +137,11 @@ function catchAllHandler(err, req, res, next) {
|
|
|
79
137
|
log.error(err);
|
|
80
138
|
}
|
|
81
139
|
|
|
82
|
-
|
|
140
|
+
/**
|
|
141
|
+
* @param {import('express').Request} req
|
|
142
|
+
* @param {import('express').Response} res
|
|
143
|
+
*/
|
|
144
|
+
export function catch404Handler(req, res) {
|
|
83
145
|
log.debug(`No route found for ${req.url}`);
|
|
84
146
|
const error = errors.UnknownCommandError;
|
|
85
147
|
res.status(error.w3cStatus()).json(
|
|
@@ -107,12 +169,4 @@ function patchWithSessionId(req, body) {
|
|
|
107
169
|
return body;
|
|
108
170
|
}
|
|
109
171
|
|
|
110
|
-
export {
|
|
111
|
-
allowCrossDomain,
|
|
112
|
-
fixPythonContentType,
|
|
113
|
-
defaultToJSONContentType,
|
|
114
|
-
catchAllHandler,
|
|
115
|
-
allowCrossDomainAsyncExecute,
|
|
116
|
-
handleIdempotency,
|
|
117
|
-
catch404Handler,
|
|
118
|
-
};
|
|
172
|
+
export { handleIdempotency };
|
package/lib/express/server.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
catchAllHandler,
|
|
15
15
|
allowCrossDomainAsyncExecute,
|
|
16
16
|
handleIdempotency,
|
|
17
|
+
handleUpgrade,
|
|
17
18
|
catch404Handler,
|
|
18
19
|
} from './middleware';
|
|
19
20
|
import {guineaPig, guineaPigScrollable, guineaPigAppBanner, welcome, STATIC_DIR} from './static';
|
|
@@ -109,6 +110,7 @@ async function server(opts) {
|
|
|
109
110
|
allowCors,
|
|
110
111
|
basePath,
|
|
111
112
|
extraMethodMap,
|
|
113
|
+
webSocketsMapping: appiumServer.webSocketsMapping,
|
|
112
114
|
});
|
|
113
115
|
// allow extensions to update the app and http server objects
|
|
114
116
|
for (const updater of serverUpdaters) {
|
|
@@ -139,6 +141,7 @@ function configureServer({
|
|
|
139
141
|
allowCors = true,
|
|
140
142
|
basePath = DEFAULT_BASE_PATH,
|
|
141
143
|
extraMethodMap = {},
|
|
144
|
+
webSocketsMapping = {},
|
|
142
145
|
}) {
|
|
143
146
|
basePath = normalizeBasePath(basePath);
|
|
144
147
|
|
|
@@ -152,7 +155,7 @@ function configureServer({
|
|
|
152
155
|
app.use(`${basePath}/produce_error`, produceError);
|
|
153
156
|
app.use(`${basePath}/crash`, produceCrash);
|
|
154
157
|
|
|
155
|
-
|
|
158
|
+
app.use(handleUpgrade(webSocketsMapping));
|
|
156
159
|
if (allowCors) {
|
|
157
160
|
app.use(allowCrossDomain);
|
|
158
161
|
} else {
|
|
@@ -195,6 +198,7 @@ function configureHttp({httpServer, reject, keepAliveTimeout}) {
|
|
|
195
198
|
* @type {AppiumServer}
|
|
196
199
|
*/
|
|
197
200
|
const appiumServer = /** @type {any} */ (httpServer);
|
|
201
|
+
appiumServer.webSocketsMapping = {};
|
|
198
202
|
appiumServer.addWebSocketHandler = addWebSocketHandler;
|
|
199
203
|
appiumServer.removeWebSocketHandler = removeWebSocketHandler;
|
|
200
204
|
appiumServer.removeAllWebSocketHandlers = removeAllWebSocketHandlers;
|
|
@@ -370,4 +374,5 @@ export {server, configureServer, normalizeBasePath};
|
|
|
370
374
|
* @property {boolean} [allowCors]
|
|
371
375
|
* @property {string} [basePath]
|
|
372
376
|
* @property {MethodMap} [extraMethodMap]
|
|
377
|
+
* @property {import('@appium/types').StringRecord} [webSocketsMapping={}]
|
|
373
378
|
*/
|
package/lib/express/websocket.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* eslint-disable require-await */
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {URL} from 'url';
|
|
4
3
|
import B from 'bluebird';
|
|
5
|
-
import { pathToRegexp } from 'path-to-regexp';
|
|
6
4
|
|
|
7
5
|
const DEFAULT_WS_PATHNAME_PREFIX = '/ws';
|
|
8
6
|
|
|
@@ -11,27 +9,6 @@ const DEFAULT_WS_PATHNAME_PREFIX = '/ws';
|
|
|
11
9
|
* @type {AppiumServer['addWebSocketHandler']}
|
|
12
10
|
*/
|
|
13
11
|
async function addWebSocketHandler(handlerPathname, handlerServer) {
|
|
14
|
-
if (_.isUndefined(this.webSocketsMapping)) {
|
|
15
|
-
this.webSocketsMapping = {};
|
|
16
|
-
// https://github.com/websockets/ws/pull/885
|
|
17
|
-
this.on('upgrade', (request, socket, head) => {
|
|
18
|
-
let currentPathname;
|
|
19
|
-
try {
|
|
20
|
-
currentPathname = new URL(request.url ?? '').pathname;
|
|
21
|
-
} catch {
|
|
22
|
-
currentPathname = request.url ?? '';
|
|
23
|
-
}
|
|
24
|
-
for (const [pathname, wsServer] of _.toPairs(this.webSocketsMapping)) {
|
|
25
|
-
if (pathToRegexp(pathname).test(currentPathname)) {
|
|
26
|
-
wsServer.handleUpgrade(request, socket, head, (ws) => {
|
|
27
|
-
wsServer.emit('connection', ws, request);
|
|
28
|
-
});
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
socket.destroy();
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
12
|
this.webSocketsMapping[handlerPathname] = handlerServer;
|
|
36
13
|
}
|
|
37
14
|
|
|
@@ -40,10 +17,6 @@ async function addWebSocketHandler(handlerPathname, handlerServer) {
|
|
|
40
17
|
* @type {AppiumServer['getWebSocketHandlers']}
|
|
41
18
|
*/
|
|
42
19
|
async function getWebSocketHandlers(keysFilter = null) {
|
|
43
|
-
if (_.isEmpty(this.webSocketsMapping)) {
|
|
44
|
-
return {};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
20
|
return _.toPairs(this.webSocketsMapping).reduce((acc, [pathname, wsServer]) => {
|
|
48
21
|
if (!_.isString(keysFilter) || pathname.includes(keysFilter)) {
|
|
49
22
|
acc[pathname] = wsServer;
|
|
@@ -134,10 +134,12 @@ class ProtocolConverter {
|
|
|
134
134
|
const bodyObj = util.safeJsonParse(body);
|
|
135
135
|
if (_.isPlainObject(bodyObj)) {
|
|
136
136
|
if (this.downstreamProtocol === W3C && _.has(bodyObj, 'name') && !_.has(bodyObj, 'handle')) {
|
|
137
|
-
this.log.debug(
|
|
137
|
+
this.log.debug(
|
|
138
|
+
`Copied 'name' value '${/** @type {import('@appium/types').StringRecord} */ (bodyObj).name}' to 'handle' as per W3C spec`
|
|
139
|
+
);
|
|
138
140
|
return await this.proxyFunc(url, method, {
|
|
139
|
-
|
|
140
|
-
handle: bodyObj.name,
|
|
141
|
+
.../** @type {import('@appium/types').StringRecord} */ (bodyObj),
|
|
142
|
+
handle: /** @type {import('@appium/types').StringRecord} */ (bodyObj).name,
|
|
141
143
|
});
|
|
142
144
|
}
|
|
143
145
|
if (
|
|
@@ -145,10 +147,12 @@ class ProtocolConverter {
|
|
|
145
147
|
_.has(bodyObj, 'handle') &&
|
|
146
148
|
!_.has(bodyObj, 'name')
|
|
147
149
|
) {
|
|
148
|
-
this.log.debug(
|
|
150
|
+
this.log.debug(
|
|
151
|
+
`Copied 'handle' value '${/** @type {import('@appium/types').StringRecord} */ (bodyObj).handle}' to 'name' as per JSONWP spec`
|
|
152
|
+
);
|
|
149
153
|
return await this.proxyFunc(url, method, {
|
|
150
|
-
|
|
151
|
-
name: bodyObj.handle,
|
|
154
|
+
.../** @type {import('@appium/types').StringRecord} */ (bodyObj),
|
|
155
|
+
name: /** @type {import('@appium/types').StringRecord} */ (bodyObj).handle,
|
|
152
156
|
});
|
|
153
157
|
}
|
|
154
158
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appium/base-driver",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.7.0",
|
|
4
4
|
"description": "Base driver class for Appium drivers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -44,30 +44,30 @@
|
|
|
44
44
|
"test:types": "tsd"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@appium/support": "^4.2.
|
|
48
|
-
"@appium/types": "^0.
|
|
47
|
+
"@appium/support": "^4.2.6",
|
|
48
|
+
"@appium/types": "^0.18.0",
|
|
49
49
|
"@colors/colors": "1.6.0",
|
|
50
50
|
"@types/async-lock": "1.4.2",
|
|
51
51
|
"@types/bluebird": "3.5.42",
|
|
52
52
|
"@types/express": "4.17.21",
|
|
53
|
-
"@types/lodash": "4.17.
|
|
53
|
+
"@types/lodash": "4.17.4",
|
|
54
54
|
"@types/method-override": "0.0.35",
|
|
55
55
|
"@types/serve-favicon": "2.5.7",
|
|
56
56
|
"async-lock": "1.4.1",
|
|
57
57
|
"asyncbox": "3.0.0",
|
|
58
|
-
"axios": "1.
|
|
58
|
+
"axios": "1.7.2",
|
|
59
59
|
"bluebird": "3.7.2",
|
|
60
60
|
"body-parser": "1.20.2",
|
|
61
61
|
"express": "4.19.2",
|
|
62
62
|
"http-status-codes": "2.3.0",
|
|
63
63
|
"lodash": "4.17.21",
|
|
64
|
-
"lru-cache": "10.2.
|
|
64
|
+
"lru-cache": "10.2.2",
|
|
65
65
|
"method-override": "3.0.0",
|
|
66
66
|
"morgan": "1.10.0",
|
|
67
67
|
"path-to-regexp": "6.2.2",
|
|
68
68
|
"serve-favicon": "2.5.0",
|
|
69
69
|
"source-map-support": "0.5.21",
|
|
70
|
-
"type-fest": "4.
|
|
70
|
+
"type-fest": "4.18.3",
|
|
71
71
|
"validate.js": "0.13.1"
|
|
72
72
|
},
|
|
73
73
|
"optionalDependencies": {
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "a4138c6ec9524594519f29938008500b7cdcc0b8",
|
|
84
84
|
"tsd": {
|
|
85
85
|
"directory": "test/types"
|
|
86
86
|
}
|