@appium/base-driver 8.1.1 → 8.2.2

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.
Files changed (75) hide show
  1. package/build/lib/basedriver/capabilities.js +6 -6
  2. package/build/lib/basedriver/commands/find.js +1 -1
  3. package/build/lib/basedriver/commands/index.js +2 -4
  4. package/build/lib/basedriver/commands/log.js +1 -1
  5. package/build/lib/basedriver/commands/session.js +1 -1
  6. package/build/lib/basedriver/commands/timeout.js +1 -1
  7. package/build/lib/basedriver/desired-caps.js +1 -1
  8. package/build/lib/basedriver/device-settings.js +1 -1
  9. package/build/lib/basedriver/driver.js +5 -7
  10. package/build/lib/basedriver/helpers.js +5 -3
  11. package/build/lib/constants.js +1 -1
  12. package/build/lib/express/crash.js +1 -1
  13. package/build/lib/express/middleware.js +3 -3
  14. package/build/lib/express/server.js +1 -1
  15. package/build/lib/express/static.js +2 -2
  16. package/build/lib/express/websocket.js +3 -3
  17. package/build/lib/index.js +124 -0
  18. package/build/lib/jsonwp-status/status.js +1 -1
  19. package/build/lib/protocol/errors.js +6 -5
  20. package/build/lib/protocol/helpers.js +3 -3
  21. package/build/lib/protocol/index.js +31 -19
  22. package/build/lib/protocol/protocol.js +22 -11
  23. package/build/lib/protocol/routes.js +6 -12
  24. package/build/test/basedriver/capability-specs.js +10 -10
  25. package/build/test/basedriver/commands/event-specs.js +10 -10
  26. package/build/test/basedriver/driver-e2e-specs.js +3 -3
  27. package/build/test/basedriver/driver-e2e-tests.js +53 -256
  28. package/build/test/basedriver/driver-specs.js +3 -3
  29. package/build/test/basedriver/driver-tests.js +6 -6
  30. package/build/test/basedriver/helpers-e2e-specs.js +10 -4
  31. package/build/test/basedriver/index.js +4 -4
  32. package/build/test/basedriver/timeout-specs.js +7 -7
  33. package/build/test/basedriver/websockets-e2e-specs.js +11 -11
  34. package/build/test/express/server-e2e-specs.js +156 -0
  35. package/build/test/express/server-specs.js +151 -0
  36. package/build/test/express/static-specs.js +23 -0
  37. package/build/test/helpers.js +57 -0
  38. package/build/test/jsonwp-proxy/mock-request.js +93 -0
  39. package/build/test/jsonwp-proxy/protocol-converter-specs.js +173 -0
  40. package/build/test/jsonwp-proxy/proxy-e2e-specs.js +62 -0
  41. package/build/test/jsonwp-proxy/proxy-specs.js +299 -0
  42. package/build/test/jsonwp-proxy/url-specs.js +167 -0
  43. package/build/test/jsonwp-status/status-specs.js +36 -0
  44. package/build/test/protocol/errors-specs.js +388 -0
  45. package/build/test/protocol/fake-driver.js +168 -0
  46. package/build/test/protocol/helpers.js +27 -0
  47. package/build/test/protocol/protocol-e2e-specs.js +1242 -0
  48. package/build/test/protocol/routes-specs.js +82 -0
  49. package/build/test/protocol/validator-specs.js +151 -0
  50. package/index.d.ts +309 -44
  51. package/index.js +1 -62
  52. package/lib/basedriver/commands/index.js +0 -2
  53. package/lib/basedriver/driver.js +2 -22
  54. package/lib/basedriver/helpers.js +5 -4
  55. package/lib/index.js +62 -0
  56. package/lib/protocol/index.js +3 -1
  57. package/lib/protocol/protocol.js +18 -7
  58. package/lib/protocol/routes.js +1 -4
  59. package/package.json +8 -16
  60. package/test/basedriver/capability-specs.js +1 -1
  61. package/test/basedriver/commands/event-specs.js +1 -1
  62. package/test/basedriver/driver-e2e-specs.js +1 -1
  63. package/test/basedriver/driver-e2e-tests.js +66 -213
  64. package/test/basedriver/driver-specs.js +1 -1
  65. package/test/basedriver/driver-tests.js +3 -3
  66. package/test/basedriver/helpers-e2e-specs.js +9 -4
  67. package/test/basedriver/timeout-specs.js +1 -1
  68. package/test/basedriver/websockets-e2e-specs.js +7 -7
  69. package/build/index.js +0 -118
  70. package/build/lib/basedriver/commands/execute-child.js +0 -137
  71. package/build/lib/basedriver/commands/execute.js +0 -119
  72. package/build/test/basedriver/fixtures/custom-element-finder-bad.js +0 -12
  73. package/build/test/basedriver/fixtures/custom-element-finder.js +0 -36
  74. package/lib/basedriver/commands/execute-child.js +0 -132
  75. package/lib/basedriver/commands/execute.js +0 -126
@@ -239,9 +239,17 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
239
239
  // this command should never be proxied (which is useful for plugin developers who add
240
240
  // commands and generally would not want that command to be proxied instead of handled by the
241
241
  // plugin)
242
+ let didPluginOverrideProxy = false;
242
243
  if (isSessCmd && !spec.neverProxy && driverShouldDoJwpProxy(driver, req, spec.command)) {
243
- await doJwpProxy(driver, req, res);
244
- return;
244
+ if (!driver.pluginsToHandleCmd ||
245
+ driver.pluginsToHandleCmd(spec.command, req.params.sessionId).length === 0) {
246
+ await doJwpProxy(driver, req, res);
247
+ return;
248
+ }
249
+ SESSIONS_CACHE.getLogger(req.params.sessionId, currentProtocol).debug(`Would have proxied ` +
250
+ `command directly, but a plugin exists which might require its value, so will let ` +
251
+ `its value be collected internally and made part of plugin chain`);
252
+ didPluginOverrideProxy = true;
245
253
  }
246
254
 
247
255
  // if a command is not in our method map, it's because we
@@ -283,12 +291,15 @@ function buildHandler (app, method, path, spec, driver, isSessCmd) {
283
291
  `${driver.constructor.name}.${spec.command}() with args: ` +
284
292
  _.truncate(JSON.stringify(args), {length: MAX_LOG_BODY_LENGTH}));
285
293
 
286
- if (driver.executeCommand) {
287
- driverRes = await driver.executeCommand(spec.command, ...args);
288
- } else {
289
- driverRes = await driver.execute(spec.command, ...args);
294
+ if (didPluginOverrideProxy) {
295
+ // TODO for now we add this information on the args list, but that's mixing purposes here.
296
+ // We really should add another 'options' parameter to 'executeCommand', but this would be
297
+ // a breaking change for all drivers so would need to be handled carefully.
298
+ args.push({reqForProxy: req});
290
299
  }
291
300
 
301
+ driverRes = await driver.executeCommand(spec.command, ...args);
302
+
292
303
  // Get the protocol after executeCommand
293
304
  currentProtocol = extractProtocol(driver, req.params.sessionId) || currentProtocol;
294
305
 
@@ -458,5 +469,5 @@ async function doJwpProxy (driver, req, res) {
458
469
 
459
470
  export {
460
471
  Protocol, routeConfiguringFunction, isSessionCommand,
461
- driverShouldDoJwpProxy, determineProtocol
472
+ driverShouldDoJwpProxy, determineProtocol, CREATE_SESSION_COMMAND, DELETE_SESSION_COMMAND,
462
473
  };
@@ -575,9 +575,6 @@ const METHOD_MAP = {
575
575
  '/session/:sessionId/appium/receive_async_response': {
576
576
  POST: {command: 'receiveAsyncResponse', payloadParams: {required: ['response']}}
577
577
  },
578
- '/session/:sessionId/appium/execute_driver': {
579
- POST: {command: 'executeDriverScript', payloadParams: {required: ['script'], optional: ['type', 'timeout']}}
580
- },
581
578
  '/session/:sessionId/appium/events': {
582
579
  POST: {command: 'getLogEvents', payloadParams: {optional: ['type']}}
583
580
  },
@@ -614,7 +611,7 @@ const METHOD_MAP = {
614
611
  },
615
612
  '/session/:sessionId/window/rect': {
616
613
  GET: {command: 'getWindowRect'},
617
- POST: {command: 'setWindowRect'},
614
+ POST: {command: 'setWindowRect', payloadParams: {required: ['x', 'y', 'width', 'height']}},
618
615
  },
619
616
  '/session/:sessionId/window/maximize': {
620
617
  POST: {command: 'maximizeWindow'}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "firefoxos",
12
12
  "testing"
13
13
  ],
14
- "version": "8.1.1",
14
+ "version": "8.2.2",
15
15
  "author": "https://github.com/appium",
16
16
  "license": "Apache-2.0",
17
17
  "repository": {
@@ -25,7 +25,6 @@
25
25
  "node": ">=12",
26
26
  "npm": ">=6"
27
27
  },
28
- "main": "./build/index.js",
29
28
  "directories": {
30
29
  "lib": "lib"
31
30
  },
@@ -36,17 +35,15 @@
36
35
  "static",
37
36
  "test/basedriver",
38
37
  "!test/basedriver/fixtures",
39
- "build/index.js",
40
- "build/lib",
41
- "build/test/basedriver",
38
+ "build",
42
39
  "!build/test/basedriver/fixtures"
43
40
  ],
44
41
  "dependencies": {
45
- "@appium/support": "^2.54.2",
46
- "@babel/runtime": "7.15.4",
42
+ "@appium/support": "^2.55.2",
43
+ "@babel/runtime": "7.16.3",
47
44
  "async-lock": "1.3.0",
48
- "asyncbox": "2.9.1",
49
- "axios": "0.21.4",
45
+ "asyncbox": "2.9.2",
46
+ "axios": "0.24.0",
50
47
  "bluebird": "3.7.2",
51
48
  "body-parser": "1.19.0",
52
49
  "colors": "1.4.0",
@@ -58,18 +55,13 @@
58
55
  "method-override": "3.0.0",
59
56
  "morgan": "1.10.0",
60
57
  "serve-favicon": "2.5.0",
61
- "source-map-support": "0.5.20",
58
+ "source-map-support": "0.5.21",
62
59
  "validate.js": "0.13.1",
63
- "webdriverio": "6.12.1",
64
60
  "ws": "7.5.5"
65
61
  },
66
- "devDependencies": {
67
- "@appium/eslint-config-appium": "^4.7.2",
68
- "@appium/gulp-plugins": "^5.5.3"
69
- },
70
62
  "publishConfig": {
71
63
  "access": "public"
72
64
  },
73
65
  "homepage": "https://appium.io",
74
- "gitHead": "01dd42ee1778509664d422a0c26e7061bae8402e"
66
+ "gitHead": "280d409df6c02d36b4ffc4d02a95ab3f4649b08c"
75
67
  }
@@ -1,4 +1,4 @@
1
- import { default as BaseDriver, errors } from '../..';
1
+ import { default as BaseDriver, errors } from '../../lib';
2
2
  import logger from '../../lib/basedriver/logger';
3
3
  import sinon from 'sinon';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import _ from 'lodash';
2
- import { BaseDriver } from '../../..';
2
+ import { BaseDriver } from '../../../lib';
3
3
 
4
4
 
5
5
 
@@ -1,6 +1,6 @@
1
1
  // transpile:mocha
2
2
 
3
- import BaseDriver from '../..';
3
+ import BaseDriver from '../../lib';
4
4
  import baseDriverE2ETests from './driver-e2e-tests';
5
5
  baseDriverE2ETests(BaseDriver, {
6
6
  platformName: 'iOS',
@@ -1,52 +1,74 @@
1
1
  import _ from 'lodash';
2
- import { BaseDriver, server, routeConfiguringFunction, DeviceSettings, errors } from '../..';
3
- import {
4
- MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY
5
- } from '../../lib/constants';
2
+ import { BaseDriver, server, routeConfiguringFunction, DeviceSettings } from '../../lib';
6
3
  import axios from 'axios';
7
4
  import B from 'bluebird';
8
- import getPort from 'get-port';
5
+ import {TEST_HOST, getTestPort, createAppiumURL, METHODS} from '../helpers';
9
6
  import { PREFIXED_APPIUM_OPTS_CAP } from '../../lib/basedriver/capabilities';
7
+ const {POST, DELETE} = METHODS;
10
8
 
11
9
  function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
12
- let address = defaultCaps['appium:address'] ?? '127.0.0.1';
10
+ let address = defaultCaps['appium:address'] ?? TEST_HOST;
13
11
  let port = defaultCaps['appium:port'];
14
12
  const className = DriverClass.name || '(unknown driver)';
15
13
 
16
14
  describe(`BaseDriver E2E (as ${className})`, function () {
17
15
  let baseServer, d;
16
+ /**
17
+ * This URL creates a new session
18
+ * @type {string}
19
+ **/
20
+ let newSessionURL;
21
+
22
+ /**
23
+ * Creates a URL with base host/port. Supply `session` and `pathname`
24
+ * @type {_.CurriedFunction2<string,string,string>}
25
+ */
26
+ let createAppiumTestURL;
27
+
28
+ /**
29
+ * Creates a URL with the given session ID and a blank pathname;
30
+ * e.g., `http://foo.bar:123/session/<session-id>`
31
+ * @type {_.CurriedFunction1<string,string>}
32
+ */
33
+ let createSessionURL;
34
+
18
35
  before(async function () {
19
- port = port ?? await getPort();
36
+ port = port ?? await getTestPort();
20
37
  defaultCaps = {...defaultCaps, 'appium:port': port};
21
38
  d = new DriverClass({port, address});
22
39
  baseServer = await server({
23
40
  routeConfiguringFunction: routeConfiguringFunction(d),
24
- port
41
+ port,
42
+ hostname: TEST_HOST
25
43
  });
44
+ createAppiumTestURL = createAppiumURL(address, port);
45
+ newSessionURL = createAppiumTestURL('', 'session');
46
+ createSessionURL = createAppiumTestURL(_, '');
26
47
  });
48
+
27
49
  after(async function () {
28
50
  await baseServer.close();
29
51
  });
30
52
 
31
53
  async function startSession (caps) {
32
54
  return (await axios({
33
- url: `http://${address}:${port}/session`,
34
- method: 'POST',
55
+ url: newSessionURL,
56
+ method: POST,
35
57
  data: {capabilities: {alwaysMatch: caps, firstMatch: [{}]}},
36
58
  })).data.value;
37
59
  }
38
60
 
39
61
  async function endSession (id) {
40
62
  return (await axios({
41
- url: `http://${address}:${port}/session/${id}`,
42
- method: 'DELETE',
63
+ url: createSessionURL(id),
64
+ method: DELETE,
43
65
  validateStatus: null,
44
66
  })).data.value;
45
67
  }
46
68
 
47
69
  async function getSession (id) {
48
70
  return (await axios({
49
- url: `http://${address}:${port}/session/${id}`,
71
+ url: createSessionURL(id),
50
72
  })).data.value;
51
73
  }
52
74
 
@@ -56,11 +78,11 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
56
78
  let times = 0;
57
79
  do {
58
80
  const {sessionId} = (await axios({
59
- url: `http://${address}:${port}/session`,
81
+ url: newSessionURL,
60
82
  headers: {
61
83
  'X-Idempotency-Key': '123456',
62
84
  },
63
- method: 'POST',
85
+ method: POST,
64
86
  data: {capabilities: {alwaysMatch: defaultCaps, firstMatch: [{}]}},
65
87
  simple: false,
66
88
  resolveWithFullResponse: true
@@ -72,8 +94,8 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
72
94
  _.uniq(sessionIds).length.should.equal(1);
73
95
 
74
96
  const {status, data} = await axios({
75
- url: `http://${address}:${port}/session/${sessionIds[0]}`,
76
- method: 'DELETE',
97
+ url: createSessionURL(sessionIds[0]),
98
+ method: DELETE,
77
99
  });
78
100
  status.should.equal(200);
79
101
  should.equal(data.value, null);
@@ -84,11 +106,11 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
84
106
  let times = 0;
85
107
  do {
86
108
  reqs.push(axios({
87
- url: `http://${address}:${port}/session`,
109
+ url: newSessionURL,
88
110
  headers: {
89
111
  'X-Idempotency-Key': '12345',
90
112
  },
91
- method: 'POST',
113
+ method: POST,
92
114
  data: {capabilities: {alwaysMatch: defaultCaps, firstMatch: [{}]}},
93
115
  }));
94
116
  times++;
@@ -97,8 +119,8 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
97
119
  _.uniq(sessionIds).length.should.equal(1);
98
120
 
99
121
  const {status, data} = await axios({
100
- url: `http://${address}:${port}/session/${sessionIds[0]}`,
101
- method: 'DELETE',
122
+ url: createSessionURL(sessionIds[0]),
123
+ method: DELETE,
102
124
  });
103
125
  status.should.equal(200);
104
126
  should.equal(data.value, null);
@@ -106,8 +128,8 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
106
128
 
107
129
  it('should create session and retrieve a session id, then delete it', async function () {
108
130
  let {status, data} = await axios({
109
- url: `http://${address}:${port}/session`,
110
- method: 'POST',
131
+ url: newSessionURL,
132
+ method: POST,
111
133
  data: {capabilities: {alwaysMatch: defaultCaps, firstMatch: [{}]}},
112
134
  });
113
135
 
@@ -117,8 +139,8 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
117
139
  data.value.capabilities.deviceName.should.equal(defaultCaps['appium:deviceName']);
118
140
 
119
141
  ({status, data} = await axios({
120
- url: `http://${address}:${port}/session/${d.sessionId}`,
121
- method: 'DELETE',
142
+ url: createSessionURL(d.sessionId),
143
+ method: DELETE,
122
144
  }));
123
145
 
124
146
  status.should.equal(200);
@@ -132,6 +154,7 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
132
154
 
133
155
  describe('command timeouts', function () {
134
156
  let originalFindElement, originalFindElements;
157
+
135
158
  async function startTimeoutSession (timeout) {
136
159
  const caps = _.cloneDeep(defaultCaps);
137
160
  caps['appium:newCommandTimeout'] = timeout;
@@ -165,15 +188,17 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
165
188
 
166
189
  it('should timeout on commands using commandTimeout cap', async function () {
167
190
  let newSession = await startTimeoutSession(0.25);
168
-
191
+ // XXX: race condition: we must build this URL before ...something happens...
192
+ // which causes `d.sessionId` to be missing
193
+ let sessionURL = createSessionURL(d.sessionId);
169
194
  await axios({
170
- url: `http://${address}:${port}/session/${d.sessionId}/element`,
171
- method: 'POST',
195
+ url: createAppiumTestURL(d.sessionId, 'element'),
196
+ method: POST,
172
197
  data: {using: 'name', value: 'foo'},
173
198
  });
174
199
  await B.delay(400);
175
200
  const {data} = await axios({
176
- url: `http://${address}:${port}/session/${d.sessionId}`,
201
+ url: sessionURL,
177
202
  validateStatus: null,
178
203
  });
179
204
  should.equal(data.value.error, 'invalid session id');
@@ -186,8 +211,8 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
186
211
  let newSession = await startTimeoutSession(0.1);
187
212
  let start = Date.now();
188
213
  const {value} = (await axios({
189
- url: `http://${address}:${port}/session/${d.sessionId}/elements`,
190
- method: 'POST',
214
+ url: createAppiumTestURL(d.sessionId, 'elements'),
215
+ method: POST,
191
216
  data: {using: 'name', value: 'foo'},
192
217
  })).data;
193
218
  (Date.now() - start).should.be.above(150);
@@ -200,13 +225,13 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
200
225
  let newSession = await startTimeoutSession(0);
201
226
 
202
227
  await axios({
203
- url: `http://${address}:${port}/session/${d.sessionId}/element`,
204
- method: 'POST',
228
+ url: createAppiumTestURL(d.sessionId, 'element'),
229
+ method: POST,
205
230
  data: {using: 'name', value: 'foo'},
206
231
  });
207
232
  await B.delay(400);
208
233
  const {value} = (await axios({
209
- url: `http://${address}:${port}/session/${d.sessionId}`,
234
+ url: createSessionURL(d.sessionId),
210
235
  })).data;
211
236
  value.platformName.should.equal(defaultCaps.platformName);
212
237
  const resp = await endSession(newSession.sessionId);
@@ -217,14 +242,17 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
217
242
 
218
243
  it('should not timeout if its just the command taking awhile', async function () {
219
244
  let newSession = await startTimeoutSession(0.25);
245
+ // XXX: race condition: we must build this URL before ...something happens...
246
+ // which causes `d.sessionId` to be missing
247
+ let sessionURL = createSessionURL(d.sessionId);
220
248
  await axios({
221
- url: `http://${address}:${port}/session/${d.sessionId}/element`,
222
- method: 'POST',
249
+ url: createAppiumTestURL(d.sessionId, 'element'),
250
+ method: POST,
223
251
  data: {using: 'name', value: 'foo'},
224
252
  });
225
253
  await B.delay(400);
226
254
  const {value} = (await axios({
227
- url: `http://${address}:${port}/session/${d.sessionId}`,
255
+ url: sessionURL,
228
256
  validateStatus: null,
229
257
  })).data;
230
258
  value.error.should.equal('invalid session id');
@@ -269,7 +297,7 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
269
297
  await B.delay(5000);
270
298
  }.bind(d);
271
299
  const reqPromise = axios({
272
- url: `http://${address}:${port}/status`,
300
+ url: createAppiumTestURL('', 'status'),
273
301
  validateStatus: null,
274
302
  });
275
303
  // make sure that the request gets to the server before our shutdown
@@ -308,181 +336,6 @@ function baseDriverE2ETests (DriverClass, defaultCaps = {}) {
308
336
  });
309
337
  });
310
338
 
311
- describe('execute driver script', function () {
312
- // mock some methods on BaseDriver that aren't normally there except in
313
- // a fully blown driver
314
- let originalFindElement, sessionId;
315
- before(function () {
316
- d.allowInsecure = ['execute_driver_script'];
317
- originalFindElement = d.findElement;
318
- d.findElement = (function (strategy, selector) {
319
- if (strategy === 'accessibility id' && selector === 'amazing') {
320
- return {[W3C_ELEMENT_KEY]: 'element-id-1'};
321
- }
322
-
323
- throw new errors.NoSuchElementError('not found');
324
- }).bind(d);
325
- });
326
-
327
- beforeEach(async function () {
328
- ({sessionId} = await startSession(defaultCaps));
329
- });
330
-
331
- after(function () {
332
- d.findElement = originalFindElement;
333
- });
334
-
335
- afterEach(async function () {
336
- await endSession(sessionId);
337
- });
338
-
339
- it('should not work unless the allowInsecure feature flag is set', async function () {
340
- d._allowInsecure = d.allowInsecure;
341
- try {
342
- d.allowInsecure = [];
343
- const script = `return 'foo'`;
344
- await axios({
345
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
346
- method: 'POST',
347
- data: {script, type: 'wd'},
348
- }).should.eventually.be.rejected;
349
- await endSession(sessionId);
350
- } finally {
351
- d.allowInsecure = d._allowInsecure;
352
- }
353
- });
354
-
355
- it('should execute a webdriverio script in the context of session', async function () {
356
- const script = `
357
- const timeouts = await driver.getTimeouts();
358
- const status = await driver.status();
359
- return [timeouts, status];
360
- `;
361
- const {value} = (await axios({
362
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
363
- method: 'POST',
364
- data: {script, type: 'webdriverio'},
365
- })).data;
366
- const expectedTimeouts = {command: 250, implicit: 0};
367
- const expectedStatus = {};
368
- value.result.should.eql([expectedTimeouts, expectedStatus]);
369
- });
370
-
371
- it('should fail with any script type other than webdriverio currently', async function () {
372
- const script = `return 'foo'`;
373
- await axios({
374
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
375
- method: 'POST',
376
- data: {script, type: 'wd'},
377
- }).should.eventually.be.rejected;
378
- });
379
-
380
- it('should execute a webdriverio script that returns elements correctly', async function () {
381
- const script = `
382
- return await driver.$("~amazing");
383
- `;
384
- const {value} = (await axios({
385
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
386
- method: 'POST',
387
- data: {script},
388
- })).data;
389
- value.result.should.eql({
390
- [W3C_ELEMENT_KEY]: 'element-id-1',
391
- [MJSONWP_ELEMENT_KEY]: 'element-id-1'
392
- });
393
- });
394
-
395
- it('should execute a webdriverio script that returns elements in deep structure', async function () {
396
- const script = `
397
- const el = await driver.$("~amazing");
398
- return {element: el, elements: [el, el]};
399
- `;
400
- const {value} = (await axios({
401
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
402
- method: 'POST',
403
- data: {script},
404
- })).data;
405
- const elObj = {
406
- [W3C_ELEMENT_KEY]: 'element-id-1',
407
- [MJSONWP_ELEMENT_KEY]: 'element-id-1'
408
- };
409
- value.result.should.eql({element: elObj, elements: [elObj, elObj]});
410
- });
411
-
412
- it('should store and return logs to the user', async function () {
413
- const script = `
414
- console.log("foo");
415
- console.log("foo2");
416
- console.warn("bar");
417
- console.error("baz");
418
- return null;
419
- `;
420
- const {value} = (await axios({
421
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
422
- method: 'POST',
423
- data: {script},
424
- })).data;
425
- value.logs.should.eql({log: ['foo', 'foo2'], warn: ['bar'], error: ['baz']});
426
- });
427
-
428
- it('should have appium specific commands available', async function () {
429
- const script = `
430
- return typeof driver.lock;
431
- `;
432
- const {value} = (await axios({
433
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
434
- method: 'POST',
435
- data: {script},
436
- })).data;
437
- value.result.should.eql('function');
438
- });
439
-
440
- it('should correctly handle errors that happen in a webdriverio script', async function () {
441
- const script = `
442
- return await driver.$("~notfound");
443
- `;
444
- const {data} = await axios({
445
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
446
- method: 'POST',
447
- validateStatus: null,
448
- data: {script},
449
- });
450
- data.value.result.error.error.should.equal('no such element');
451
- data.value.result.error.message.should.equal('not found');
452
- data.value.result.error.stacktrace.should.includes('NoSuchElementError:');
453
- data.value.result.selector.should.equal('~notfound');
454
- data.value.result.sessionId.should.equal(sessionId);
455
- });
456
-
457
- it('should correctly handle errors that happen when a script cannot be compiled', async function () {
458
- const script = `
459
- return {;
460
- `;
461
- const {data} = await axios({
462
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
463
- method: 'POST',
464
- validateStatus: null,
465
- data: {script},
466
- });
467
- data.value.should.have.property('message');
468
- data.value.message.should.match(/An unknown server-side error occurred while processing the command. Original error: Could not execute driver script. Original error was: Error: Unexpected token '?;'?/);
469
- });
470
-
471
- it('should be able to set a timeout on a driver script', async function () {
472
- const script = `
473
- await Promise.delay(1000);
474
- return true;
475
- `;
476
- const {value} = (await axios({
477
- url: `http://${address}:${port}/session/${sessionId}/appium/execute_driver`,
478
- method: 'POST',
479
- validateStatus: null,
480
- data: {script, timeout: 50},
481
- })).data;
482
- value.message.should.match(/.+50.+timeout.+/);
483
- });
484
- });
485
-
486
339
  if (DriverClass === BaseDriver) {
487
340
  // only run this test on basedriver, not other drivers which also use these tests, since we
488
341
  // don't want them to try and start sessions with these random capabilities that are
@@ -1,6 +1,6 @@
1
1
  // transpile:mocha
2
2
 
3
- import BaseDriver from '../..';
3
+ import BaseDriver from '../../lib';
4
4
  import baseDriverUnitTests from './driver-tests';
5
5
  baseDriverUnitTests(BaseDriver, {
6
6
  platformName: 'iOS',
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import B from 'bluebird';
3
- import { DeviceSettings } from '../..';
3
+ import { DeviceSettings } from '../../lib';
4
4
  import sinon from 'sinon';
5
5
 
6
6
 
@@ -335,8 +335,8 @@ function baseDriverUnitTests (DriverClass, defaultCaps = {}) {
335
335
  it('should have a #canProxy method', function () {
336
336
  d.canProxy.should.be.an.instanceof(Function);
337
337
  });
338
- it('should return false from #canProxy', function () {
339
- d.canProxy(sessId).should.be.false;
338
+ it('should return a boolean from #canProxy', function () {
339
+ d.canProxy(sessId).should.be.a('boolean');
340
340
  });
341
341
  it('should throw an error when sessionId is wrong', function () {
342
342
  (() => { d.canProxy(); }).should.throw;
@@ -7,7 +7,7 @@ import finalhandler from 'finalhandler';
7
7
  import serveStatic from 'serve-static';
8
8
  import contentDisposition from 'content-disposition';
9
9
  import B from 'bluebird';
10
-
10
+ import {TEST_HOST, getTestPort} from '../helpers';
11
11
 
12
12
 
13
13
  function getFixture (file) {
@@ -54,8 +54,13 @@ describe('app download and configuration', function () {
54
54
  .should.be.rejectedWith(/did not have extension/);
55
55
  });
56
56
  describe('should download an app from the web', function () {
57
- const port = 8000;
58
- const serverUrl = `http://localhost:${port}`;
57
+ let port;
58
+ let serverUrl;
59
+
60
+ before(async function () {
61
+ port = await getTestPort(true);
62
+ serverUrl = `http://${TEST_HOST}:${port}`;
63
+ });
59
64
 
60
65
  describe('server not available', function () {
61
66
  it('should handle server not available', async function () {
@@ -142,7 +147,7 @@ describe('app download and configuration', function () {
142
147
  it('should handle invalid protocol', async function () {
143
148
  await configureApp('file://C:/missing/FakeIOSApp.app.zip', '.app')
144
149
  .should.eventually.be.rejectedWith(/is not supported/);
145
- await configureApp('ftp://localhost:8000/missing/FakeIOSApp.app.zip', '.app')
150
+ await configureApp(`ftp://${TEST_HOST}:${port}/missing/FakeIOSApp.app.zip`, '.app')
146
151
  .should.eventually.be.rejectedWith(/is not supported/);
147
152
  });
148
153
  it('should handle missing file in Windows path format', async function () {
@@ -1,4 +1,4 @@
1
- import BaseDriver from '../..';
1
+ import BaseDriver from '../../lib';
2
2
  import sinon from 'sinon';
3
3
 
4
4