@appium/base-driver 8.2.3 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/basedriver/capabilities.js +2 -4
- package/build/lib/basedriver/commands/event.js +2 -4
- package/build/lib/basedriver/commands/find.js +5 -14
- package/build/lib/basedriver/commands/index.js +2 -4
- package/build/lib/basedriver/commands/log.js +4 -9
- package/build/lib/basedriver/commands/session.js +19 -30
- package/build/lib/basedriver/commands/settings.js +5 -11
- package/build/lib/basedriver/commands/timeout.js +11 -18
- package/build/lib/basedriver/desired-caps.js +2 -4
- package/build/lib/basedriver/device-settings.js +15 -5
- package/build/lib/basedriver/driver.js +36 -23
- package/build/lib/basedriver/helpers.js +10 -12
- package/build/lib/basedriver/logger.js +2 -4
- package/build/lib/constants.js +2 -4
- package/build/lib/express/crash.js +2 -4
- package/build/lib/express/express-logging.js +3 -5
- package/build/lib/express/idempotency.js +3 -5
- package/build/lib/express/logger.js +2 -4
- package/build/lib/express/middleware.js +2 -4
- package/build/lib/express/server.js +2 -4
- package/build/lib/express/static.js +2 -4
- package/build/lib/express/websocket.js +2 -4
- package/build/lib/helpers/capabilities.js +37 -0
- package/build/lib/index.js +4 -8
- package/build/lib/jsonwp-proxy/protocol-converter.js +19 -15
- package/build/lib/jsonwp-proxy/proxy.js +20 -15
- package/build/lib/jsonwp-status/status.js +2 -4
- package/build/lib/protocol/errors.js +2 -4
- package/build/lib/protocol/helpers.js +2 -4
- package/build/lib/protocol/index.js +2 -4
- package/build/lib/protocol/protocol.js +37 -30
- package/build/lib/protocol/routes.js +68 -4
- 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 +12 -17
- 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 +85 -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/lib/basedriver/commands/find.js +3 -6
- package/lib/basedriver/commands/log.js +2 -4
- package/lib/basedriver/commands/session.js +21 -22
- package/lib/basedriver/commands/settings.js +3 -5
- package/lib/basedriver/commands/timeout.js +9 -10
- package/lib/basedriver/device-settings.js +10 -1
- package/lib/basedriver/driver.js +36 -12
- package/lib/basedriver/helpers.js +13 -11
- package/lib/express/express-logging.js +1 -1
- package/lib/express/idempotency.js +1 -1
- package/lib/helpers/capabilities.js +25 -0
- package/lib/index.js +2 -2
- package/lib/jsonwp-proxy/protocol-converter.js +14 -13
- package/lib/jsonwp-proxy/proxy.js +16 -12
- package/lib/protocol/protocol.js +34 -29
- package/lib/protocol/routes.js +60 -1
- package/package.json +36 -24
- package/test/basedriver/README.md +5 -0
- package/test/basedriver/driver-e2e-tests.js +1 -1
- package/test/basedriver/driver-tests.js +12 -7
- 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/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
package/lib/index.js
CHANGED
|
@@ -5,9 +5,9 @@ import * as driver from './basedriver/driver';
|
|
|
5
5
|
import * as deviceSettings from './basedriver/device-settings';
|
|
6
6
|
|
|
7
7
|
const { BaseDriver } = driver;
|
|
8
|
-
const { DeviceSettings
|
|
8
|
+
const { DeviceSettings } = deviceSettings;
|
|
9
9
|
|
|
10
|
-
export { BaseDriver, DeviceSettings
|
|
10
|
+
export { BaseDriver, DeviceSettings };
|
|
11
11
|
export default BaseDriver;
|
|
12
12
|
|
|
13
13
|
|
|
@@ -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
|
}
|
package/lib/protocol/protocol.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import { util } from '@appium/support';
|
|
2
|
+
import { util, logger, node } from '@appium/support';
|
|
3
3
|
import { validators } from './validators';
|
|
4
4
|
import {
|
|
5
5
|
errors, isErrorType, getResponseForW3CError,
|
|
@@ -7,11 +7,9 @@ import {
|
|
|
7
7
|
} from './errors';
|
|
8
8
|
import { METHOD_MAP, NO_SESSION_ID_COMMANDS } from './routes';
|
|
9
9
|
import B from 'bluebird';
|
|
10
|
-
import {
|
|
11
|
-
formatResponseValue, formatStatus,
|
|
12
|
-
} from './helpers';
|
|
10
|
+
import { formatResponseValue, formatStatus } from './helpers';
|
|
13
11
|
import { MAX_LOG_BODY_LENGTH, PROTOCOLS, DEFAULT_BASE_PATH } from '../constants';
|
|
14
|
-
import
|
|
12
|
+
import { isW3cCaps } from '../helpers/capabilities';
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
const CREATE_SESSION_COMMAND = 'createSession';
|
|
@@ -20,10 +18,8 @@ const GET_STATUS_COMMAND = 'getStatus';
|
|
|
20
18
|
|
|
21
19
|
class Protocol {}
|
|
22
20
|
|
|
23
|
-
function determineProtocol (
|
|
24
|
-
return _.
|
|
25
|
-
PROTOCOLS.W3C :
|
|
26
|
-
PROTOCOLS.MJSONWP;
|
|
21
|
+
function determineProtocol (createSessionArgs) {
|
|
22
|
+
return _.some(createSessionArgs, isW3cCaps) ? PROTOCOLS.W3C : PROTOCOLS.MJSONWP;
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
function extractProtocol (driver, sessionId = null) {
|
|
@@ -38,13 +34,30 @@ function extractProtocol (driver, sessionId = null) {
|
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
// Extract the protocol for the current session if the given driver is the umbrella one
|
|
41
|
-
return dstDriver
|
|
37
|
+
return dstDriver?.protocol ?? PROTOCOLS.W3C;
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
function isSessionCommand (command) {
|
|
45
41
|
return !_.includes(NO_SESSION_ID_COMMANDS, command);
|
|
46
42
|
}
|
|
47
43
|
|
|
44
|
+
function getLogger (driver, sessionId = null) {
|
|
45
|
+
const dstDriver = sessionId && _.isFunction(driver.driverForSession)
|
|
46
|
+
? (driver.driverForSession(sessionId) ?? driver)
|
|
47
|
+
: driver;
|
|
48
|
+
if (_.isFunction(dstDriver.log?.info)) {
|
|
49
|
+
return dstDriver.log;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let logPrefix = dstDriver.constructor
|
|
53
|
+
? `${dstDriver.constructor.name}@${node.getObjectId(dstDriver).substring(0, 8)}`
|
|
54
|
+
: 'AppiumDriver';
|
|
55
|
+
if (sessionId) {
|
|
56
|
+
logPrefix += ` (${sessionId.substring(0, 8)})`;
|
|
57
|
+
}
|
|
58
|
+
return logger.getLogger(logPrefix);
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
function wrapParams (paramSets, jsonObj) {
|
|
49
62
|
/* There are commands like performTouch which take a single parameter (primitive type or array).
|
|
50
63
|
* Some drivers choose to pass this parameter as a value (eg. [action1, action2...]) while others to
|
|
@@ -192,11 +205,11 @@ function makeArgs (requestParams, jsonObj, payloadParams, protocol) {
|
|
|
192
205
|
|
|
193
206
|
function routeConfiguringFunction (driver) {
|
|
194
207
|
if (!driver.sessionExists) {
|
|
195
|
-
throw new Error('Drivers
|
|
208
|
+
throw new Error('Drivers must implement `sessionExists` property');
|
|
196
209
|
}
|
|
197
210
|
|
|
198
211
|
if (!(driver.executeCommand || driver.execute)) {
|
|
199
|
-
throw new Error('Drivers
|
|
212
|
+
throw new Error('Drivers must implement `executeCommand` or `execute` method');
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
// return a function which will add all the routes to the driver. Here extraMethods might be
|
|
@@ -247,7 +260,7 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
247
260
|
await doJwpProxy(driver, req, res);
|
|
248
261
|
return;
|
|
249
262
|
}
|
|
250
|
-
|
|
263
|
+
getLogger(driver, req.params.sessionId).debug(`Would have proxied ` +
|
|
251
264
|
`command directly, but a plugin exists which might require its value, so will let ` +
|
|
252
265
|
`its value be collected internally and made part of plugin chain`);
|
|
253
266
|
didPluginOverrideProxy = true;
|
|
@@ -272,7 +285,7 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
272
285
|
if (spec.command === CREATE_SESSION_COMMAND) {
|
|
273
286
|
// try to determine protocol by session creation args, so we can throw a
|
|
274
287
|
// properly formatted error if arguments validation fails
|
|
275
|
-
currentProtocol = determineProtocol(
|
|
288
|
+
currentProtocol = determineProtocol(makeArgs(req.params, jsonObj, spec.payloadParams || {}));
|
|
276
289
|
}
|
|
277
290
|
|
|
278
291
|
// ensure that the json payload conforms to the spec
|
|
@@ -288,7 +301,7 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
288
301
|
}
|
|
289
302
|
|
|
290
303
|
// run the driver command wrapped inside the argument validators
|
|
291
|
-
|
|
304
|
+
getLogger(driver, req.params.sessionId).debug(`Calling ` +
|
|
292
305
|
`${driver.constructor.name}.${spec.command}() with args: ` +
|
|
293
306
|
_.truncate(JSON.stringify(args), {length: MAX_LOG_BODY_LENGTH}));
|
|
294
307
|
|
|
@@ -317,8 +330,7 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
317
330
|
// unpack createSession response
|
|
318
331
|
if (spec.command === CREATE_SESSION_COMMAND) {
|
|
319
332
|
newSessionId = driverRes[0];
|
|
320
|
-
|
|
321
|
-
SESSIONS_CACHE.getLogger(newSessionId, currentProtocol)
|
|
333
|
+
getLogger(driver, newSessionId)
|
|
322
334
|
.debug(`Cached the protocol value '${currentProtocol}' for the new session ${newSessionId}`);
|
|
323
335
|
if (currentProtocol === PROTOCOLS.MJSONWP) {
|
|
324
336
|
driverRes = driverRes[1];
|
|
@@ -333,9 +345,9 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
333
345
|
|
|
334
346
|
// delete should not return anything even if successful
|
|
335
347
|
if (spec.command === DELETE_SESSION_COMMAND) {
|
|
336
|
-
|
|
348
|
+
getLogger(driver, req.params.sessionId)
|
|
337
349
|
.debug(`Received response: ${_.truncate(JSON.stringify(driverRes), {length: MAX_LOG_BODY_LENGTH})}`);
|
|
338
|
-
|
|
350
|
+
getLogger(driver, req.params.sessionId).debug('But deleting session, so not returning');
|
|
339
351
|
driverRes = null;
|
|
340
352
|
}
|
|
341
353
|
|
|
@@ -349,15 +361,8 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
349
361
|
}
|
|
350
362
|
|
|
351
363
|
httpResBody.value = driverRes;
|
|
352
|
-
|
|
364
|
+
getLogger(driver, req.params.sessionId || newSessionId).debug(`Responding ` +
|
|
353
365
|
`to client with driver.${spec.command}() result: ${_.truncate(JSON.stringify(driverRes), {length: MAX_LOG_BODY_LENGTH})}`);
|
|
354
|
-
|
|
355
|
-
if (spec.command === DELETE_SESSION_COMMAND) {
|
|
356
|
-
// We don't want to keep the logger instance in the cache
|
|
357
|
-
// after the session is deleted, because it contains the logging history
|
|
358
|
-
// and consumes the memory
|
|
359
|
-
SESSIONS_CACHE.resetLogger(req.params.sessionId);
|
|
360
|
-
}
|
|
361
366
|
} catch (err) {
|
|
362
367
|
// if anything goes wrong, figure out what our response should be
|
|
363
368
|
// based on the type of error that we encountered
|
|
@@ -374,7 +379,7 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
|
|
|
374
379
|
if (isErrorType(err, errors.ProxyRequestError)) {
|
|
375
380
|
actualErr = err.getActualError();
|
|
376
381
|
} else {
|
|
377
|
-
|
|
382
|
+
getLogger(driver, req.params.sessionId || newSessionId)
|
|
378
383
|
.debug(`Encountered internal error running command: ${errMsg}`);
|
|
379
384
|
}
|
|
380
385
|
|
|
@@ -431,7 +436,7 @@ function driverShouldDoJwpProxy (driver, req, command) {
|
|
|
431
436
|
}
|
|
432
437
|
|
|
433
438
|
async function doJwpProxy (driver, req, res) {
|
|
434
|
-
|
|
439
|
+
getLogger(driver, req.params.sessionId)
|
|
435
440
|
.info('Driver proxy active, passing request on via HTTP proxy');
|
|
436
441
|
|
|
437
442
|
// check that the inner driver has a proxy function
|
package/lib/protocol/routes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { util } from '@appium/support';
|
|
3
|
-
import { DEFAULT_BASE_PATH } from '../constants';
|
|
3
|
+
import { PROTOCOLS, DEFAULT_BASE_PATH } from '../constants';
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
const SET_ALERT_TEXT_PAYLOAD_PARAMS = {
|
|
@@ -33,6 +33,18 @@ const METHOD_MAP = {
|
|
|
33
33
|
'/session/:sessionId/timeouts': {
|
|
34
34
|
GET: {command: 'getTimeouts'}, // W3C route
|
|
35
35
|
POST: {command: 'timeouts', payloadParams: {
|
|
36
|
+
validate: (jsonObj, protocolName) => {
|
|
37
|
+
if (protocolName === PROTOCOLS.W3C) {
|
|
38
|
+
if (!util.hasValue(jsonObj.script) && !util.hasValue(jsonObj.pageLoad) && !util.hasValue(jsonObj.implicit)) {
|
|
39
|
+
return 'W3C protocol expects any of script, pageLoad or implicit to be set';
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
// MJSONWP
|
|
43
|
+
if (!util.hasValue(jsonObj.type) || !util.hasValue(jsonObj.ms)) {
|
|
44
|
+
return 'MJSONWP protocol requires type and ms';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
36
48
|
optional: ['type', 'ms', 'script', 'pageLoad', 'implicit'],
|
|
37
49
|
}}
|
|
38
50
|
},
|
|
@@ -42,9 +54,19 @@ const METHOD_MAP = {
|
|
|
42
54
|
'/session/:sessionId/timeouts/implicit_wait': {
|
|
43
55
|
POST: {command: 'implicitWait', payloadParams: {required: ['ms']}}
|
|
44
56
|
},
|
|
57
|
+
// JSONWP
|
|
58
|
+
'/session/:sessionId/window_handle': {
|
|
59
|
+
GET: {command: 'getWindowHandle'}
|
|
60
|
+
},
|
|
61
|
+
// W3C
|
|
45
62
|
'/session/:sessionId/window/handle': {
|
|
46
63
|
GET: {command: 'getWindowHandle'}
|
|
47
64
|
},
|
|
65
|
+
// JSONWP
|
|
66
|
+
'/session/:sessionId/window_handles': {
|
|
67
|
+
GET: {command: 'getWindowHandles'}
|
|
68
|
+
},
|
|
69
|
+
// W3C
|
|
48
70
|
'/session/:sessionId/window/handles': {
|
|
49
71
|
GET: {command: 'getWindowHandles'}
|
|
50
72
|
},
|
|
@@ -61,6 +83,14 @@ const METHOD_MAP = {
|
|
|
61
83
|
'/session/:sessionId/refresh': {
|
|
62
84
|
POST: {command: 'refresh'}
|
|
63
85
|
},
|
|
86
|
+
// MJSONWP
|
|
87
|
+
'/session/:sessionId/execute': {
|
|
88
|
+
POST: {command: 'execute', payloadParams: {required: ['script', 'args']}}
|
|
89
|
+
},
|
|
90
|
+
// MJSONWP
|
|
91
|
+
'/session/:sessionId/execute_async': {
|
|
92
|
+
POST: {command: 'executeAsync', payloadParams: {required: ['script', 'args']}}
|
|
93
|
+
},
|
|
64
94
|
'/session/:sessionId/screenshot': {
|
|
65
95
|
GET: {command: 'getScreenshot'}
|
|
66
96
|
},
|
|
@@ -207,6 +237,9 @@ const METHOD_MAP = {
|
|
|
207
237
|
'/session/:sessionId/element/:elementId/size': {
|
|
208
238
|
GET: {command: 'getSize'}
|
|
209
239
|
},
|
|
240
|
+
'/session/:sessionId/element/:elementId/shadow': {
|
|
241
|
+
GET: {command: 'elementShadowRoot'}
|
|
242
|
+
},
|
|
210
243
|
'/session/:sessionId/element/:elementId/css/:propertyName': {
|
|
211
244
|
GET: {command: 'getCssProperty'}
|
|
212
245
|
},
|
|
@@ -582,6 +615,28 @@ const METHOD_MAP = {
|
|
|
582
615
|
POST: {command: 'logCustomEvent', payloadParams: {required: ['vendor', 'event']}}
|
|
583
616
|
},
|
|
584
617
|
|
|
618
|
+
/*
|
|
619
|
+
* The W3C spec has some changes to the wire protocol.
|
|
620
|
+
* https://w3c.github.io/webdriver/webdriver-spec.html
|
|
621
|
+
* Begin to add those changes here, keeping the old version
|
|
622
|
+
* since clients still implement them.
|
|
623
|
+
*/
|
|
624
|
+
// MJSONWP
|
|
625
|
+
'/session/:sessionId/alert_text': {
|
|
626
|
+
GET: {command: 'getAlertText'},
|
|
627
|
+
POST: {
|
|
628
|
+
command: 'setAlertText',
|
|
629
|
+
payloadParams: SET_ALERT_TEXT_PAYLOAD_PARAMS,
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
// MJSONWP
|
|
633
|
+
'/session/:sessionId/accept_alert': {
|
|
634
|
+
POST: {command: 'postAcceptAlert'}
|
|
635
|
+
},
|
|
636
|
+
// MJSONWP
|
|
637
|
+
'/session/:sessionId/dismiss_alert': {
|
|
638
|
+
POST: {command: 'postDismissAlert'}
|
|
639
|
+
},
|
|
585
640
|
// https://w3c.github.io/webdriver/webdriver-spec.html#user-prompts
|
|
586
641
|
'/session/:sessionId/alert/text': {
|
|
587
642
|
GET: {command: 'getAlertText'},
|
|
@@ -606,6 +661,10 @@ const METHOD_MAP = {
|
|
|
606
661
|
'/session/:sessionId/execute/async': {
|
|
607
662
|
POST: {command: 'executeAsync', payloadParams: {required: ['script', 'args']}}
|
|
608
663
|
},
|
|
664
|
+
// Pre-W3C endpoint for element screenshot
|
|
665
|
+
'/session/:sessionId/screenshot/:elementId': {
|
|
666
|
+
GET: {command: 'getElementScreenshot'}
|
|
667
|
+
},
|
|
609
668
|
'/session/:sessionId/element/:elementId/screenshot': {
|
|
610
669
|
GET: {command: 'getElementScreenshot'}
|
|
611
670
|
},
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appium/base-driver",
|
|
3
|
+
"version": "8.3.1",
|
|
3
4
|
"description": "Base driver class for Appium drivers",
|
|
4
5
|
"keywords": [
|
|
5
6
|
"automation",
|
|
@@ -11,20 +12,17 @@
|
|
|
11
12
|
"firefoxos",
|
|
12
13
|
"testing"
|
|
13
14
|
],
|
|
14
|
-
"
|
|
15
|
-
"author": "https://github.com/appium",
|
|
16
|
-
"license": "Apache-2.0",
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "https://github.com/appium/appium.git"
|
|
20
|
-
},
|
|
15
|
+
"homepage": "https://appium.io",
|
|
21
16
|
"bugs": {
|
|
22
17
|
"url": "https://github.com/appium/appium/issues"
|
|
23
18
|
},
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/appium/appium.git",
|
|
22
|
+
"directory": "packages/base-driver"
|
|
27
23
|
},
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"author": "https://github.com/appium",
|
|
28
26
|
"directories": {
|
|
29
27
|
"lib": "lib"
|
|
30
28
|
},
|
|
@@ -34,34 +32,48 @@
|
|
|
34
32
|
"lib",
|
|
35
33
|
"static",
|
|
36
34
|
"test/basedriver",
|
|
37
|
-
"!test/
|
|
35
|
+
"!test/e2e/fixtures",
|
|
38
36
|
"build",
|
|
39
|
-
"!build/test/
|
|
37
|
+
"!build/test/e2e/fixtures"
|
|
40
38
|
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "npm run build:sources && npm run build:test",
|
|
41
|
+
"build:sources": "babel lib --root-mode=upward --out-dir=build/lib",
|
|
42
|
+
"build:test": "babel test --root-mode=upward --out-dir=build/test --copy-files",
|
|
43
|
+
"dev": "npm run build -- --watch",
|
|
44
|
+
"fix": "npm run lint -- --fix",
|
|
45
|
+
"lint": "eslint -c ../../.eslintrc --ignore-path ../../.eslintignore .",
|
|
46
|
+
"test": "npm run test:unit",
|
|
47
|
+
"test:e2e": "mocha --require ../../test/setup-babel.js --timeout 20s --slow 10s \"./test/e2e/**/*.spec.js\"",
|
|
48
|
+
"test:unit": "mocha --require ../../test/setup-babel.js \"./test/unit/**/*.spec.js\""
|
|
49
|
+
},
|
|
41
50
|
"dependencies": {
|
|
42
|
-
"@appium/support": "^2.
|
|
43
|
-
"@babel/runtime": "7.
|
|
44
|
-
"@
|
|
45
|
-
"async-lock": "1.3.
|
|
51
|
+
"@appium/support": "^2.56.1",
|
|
52
|
+
"@babel/runtime": "7.17.8",
|
|
53
|
+
"@colors/colors": "1.5.0",
|
|
54
|
+
"async-lock": "1.3.1",
|
|
46
55
|
"asyncbox": "2.9.2",
|
|
47
|
-
"axios": "0.
|
|
56
|
+
"axios": "0.26.1",
|
|
48
57
|
"bluebird": "3.7.2",
|
|
49
|
-
"body-parser": "1.19.
|
|
58
|
+
"body-parser": "1.19.2",
|
|
50
59
|
"es6-error": "4.1.1",
|
|
51
|
-
"express": "4.17.
|
|
52
|
-
"http-status-codes": "2.
|
|
60
|
+
"express": "4.17.3",
|
|
61
|
+
"http-status-codes": "2.2.0",
|
|
53
62
|
"lodash": "4.17.21",
|
|
54
|
-
"lru-cache": "
|
|
63
|
+
"lru-cache": "7.7.1",
|
|
55
64
|
"method-override": "3.0.0",
|
|
56
65
|
"morgan": "1.10.0",
|
|
57
66
|
"serve-favicon": "2.5.0",
|
|
58
67
|
"source-map-support": "0.5.21",
|
|
59
68
|
"validate.js": "0.13.1",
|
|
60
|
-
"ws": "7.5.
|
|
69
|
+
"ws": "7.5.7"
|
|
70
|
+
},
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=12",
|
|
73
|
+
"npm": ">=6"
|
|
61
74
|
},
|
|
62
75
|
"publishConfig": {
|
|
63
76
|
"access": "public"
|
|
64
77
|
},
|
|
65
|
-
"
|
|
66
|
-
"gitHead": "ca90a11813546ab4851e5b1f0406f420a53227e6"
|
|
78
|
+
"gitHead": "6d35def9ed754121fee691cdaf7b30e3a7ac3e8b"
|
|
67
79
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Driver Test Helpers
|
|
2
|
+
|
|
3
|
+
This directory contains modules which expose test suites that an external driver can use to test against the base implementation. They are published in the `@appium/base-driver` package.
|
|
4
|
+
|
|
5
|
+
Drivers wanting to leverage these suites will want to add `@appium/base-driver` to their `devDependencies`.
|
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import { BaseDriver, server, routeConfiguringFunction, DeviceSettings } from '../../lib';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import B from 'bluebird';
|
|
5
|
-
import {TEST_HOST, getTestPort, createAppiumURL, METHODS} from '../helpers';
|
|
5
|
+
import { TEST_HOST, getTestPort, createAppiumURL, METHODS } from '../helpers';
|
|
6
6
|
import { PREFIXED_APPIUM_OPTS_CAP } from '../../lib/basedriver/capabilities';
|
|
7
7
|
const {POST, DELETE} = METHODS;
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import B from 'bluebird';
|
|
3
3
|
import { DeviceSettings } from '../../lib';
|
|
4
|
-
import
|
|
4
|
+
import { createSandbox } from 'sinon';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
// wrap these tests in a function so we can export the tests and re-use them
|
|
@@ -10,10 +10,14 @@ function baseDriverUnitTests (DriverClass, defaultCaps = {}) {
|
|
|
10
10
|
// to display the driver under test in report
|
|
11
11
|
const className = DriverClass.name || '(unknown driver)';
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
describe(`BaseDriver (as ${className})`, function () {
|
|
14
15
|
let d, w3cCaps;
|
|
15
16
|
|
|
17
|
+
let sandbox;
|
|
18
|
+
|
|
16
19
|
beforeEach(function () {
|
|
20
|
+
sandbox = createSandbox();
|
|
17
21
|
d = new DriverClass();
|
|
18
22
|
w3cCaps = {
|
|
19
23
|
alwaysMatch: Object.assign({}, defaultCaps, {
|
|
@@ -25,6 +29,7 @@ function baseDriverUnitTests (DriverClass, defaultCaps = {}) {
|
|
|
25
29
|
});
|
|
26
30
|
afterEach(async function () {
|
|
27
31
|
await d.deleteSession();
|
|
32
|
+
sandbox.restore();
|
|
28
33
|
});
|
|
29
34
|
|
|
30
35
|
it('should report the version of BaseDriver used', function () {
|
|
@@ -345,7 +350,7 @@ function baseDriverUnitTests (DriverClass, defaultCaps = {}) {
|
|
|
345
350
|
|
|
346
351
|
describe('#proxyRouteIsAvoided', function () {
|
|
347
352
|
it('should validate form of avoidance list', function () {
|
|
348
|
-
const avoidStub =
|
|
353
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
349
354
|
avoidStub.returns([['POST', /\/foo/], ['GET']]);
|
|
350
355
|
(() => { d.proxyRouteIsAvoided(); }).should.throw;
|
|
351
356
|
avoidStub.returns([['POST', /\/foo/], ['GET', /^foo/, 'bar']]);
|
|
@@ -353,31 +358,31 @@ function baseDriverUnitTests (DriverClass, defaultCaps = {}) {
|
|
|
353
358
|
avoidStub.restore();
|
|
354
359
|
});
|
|
355
360
|
it('should reject bad http methods', function () {
|
|
356
|
-
const avoidStub =
|
|
361
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
357
362
|
avoidStub.returns([['POST', /^foo/], ['BAZETE', /^bar/]]);
|
|
358
363
|
(() => { d.proxyRouteIsAvoided(); }).should.throw;
|
|
359
364
|
avoidStub.restore();
|
|
360
365
|
});
|
|
361
366
|
it('should reject non-regex routes', function () {
|
|
362
|
-
const avoidStub =
|
|
367
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
363
368
|
avoidStub.returns([['POST', /^foo/], ['GET', '/bar']]);
|
|
364
369
|
(() => { d.proxyRouteIsAvoided(); }).should.throw;
|
|
365
370
|
avoidStub.restore();
|
|
366
371
|
});
|
|
367
372
|
it('should return true for routes in the avoid list', function () {
|
|
368
|
-
const avoidStub =
|
|
373
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
369
374
|
avoidStub.returns([['POST', /^\/foo/]]);
|
|
370
375
|
d.proxyRouteIsAvoided(null, 'POST', '/foo/bar').should.be.true;
|
|
371
376
|
avoidStub.restore();
|
|
372
377
|
});
|
|
373
378
|
it('should strip away any wd/hub prefix', function () {
|
|
374
|
-
const avoidStub =
|
|
379
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
375
380
|
avoidStub.returns([['POST', /^\/foo/]]);
|
|
376
381
|
d.proxyRouteIsAvoided(null, 'POST', '/foo/bar').should.be.true;
|
|
377
382
|
avoidStub.restore();
|
|
378
383
|
});
|
|
379
384
|
it('should return false for routes not in the avoid list', function () {
|
|
380
|
-
const avoidStub =
|
|
385
|
+
const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
|
|
381
386
|
avoidStub.returns([['POST', /^\/foo/]]);
|
|
382
387
|
d.proxyRouteIsAvoided(null, 'GET', '/foo/bar').should.be.false;
|
|
383
388
|
d.proxyRouteIsAvoided(null, 'POST', '/boo').should.be.false;
|