@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.
- package/build/lib/basedriver/capabilities.js +6 -6
- package/build/lib/basedriver/commands/find.js +1 -1
- package/build/lib/basedriver/commands/index.js +2 -4
- package/build/lib/basedriver/commands/log.js +1 -1
- package/build/lib/basedriver/commands/session.js +1 -1
- package/build/lib/basedriver/commands/timeout.js +1 -1
- package/build/lib/basedriver/desired-caps.js +1 -1
- package/build/lib/basedriver/device-settings.js +1 -1
- package/build/lib/basedriver/driver.js +5 -7
- package/build/lib/basedriver/helpers.js +5 -3
- package/build/lib/constants.js +1 -1
- package/build/lib/express/crash.js +1 -1
- package/build/lib/express/middleware.js +3 -3
- package/build/lib/express/server.js +1 -1
- package/build/lib/express/static.js +2 -2
- package/build/lib/express/websocket.js +3 -3
- package/build/lib/index.js +124 -0
- package/build/lib/jsonwp-status/status.js +1 -1
- package/build/lib/protocol/errors.js +6 -5
- package/build/lib/protocol/helpers.js +3 -3
- package/build/lib/protocol/index.js +31 -19
- package/build/lib/protocol/protocol.js +22 -11
- package/build/lib/protocol/routes.js +6 -12
- package/build/test/basedriver/capability-specs.js +10 -10
- package/build/test/basedriver/commands/event-specs.js +10 -10
- package/build/test/basedriver/driver-e2e-specs.js +3 -3
- package/build/test/basedriver/driver-e2e-tests.js +53 -256
- package/build/test/basedriver/driver-specs.js +3 -3
- package/build/test/basedriver/driver-tests.js +6 -6
- package/build/test/basedriver/helpers-e2e-specs.js +10 -4
- package/build/test/basedriver/index.js +4 -4
- package/build/test/basedriver/timeout-specs.js +7 -7
- package/build/test/basedriver/websockets-e2e-specs.js +11 -11
- package/build/test/express/server-e2e-specs.js +156 -0
- package/build/test/express/server-specs.js +151 -0
- package/build/test/express/static-specs.js +23 -0
- package/build/test/helpers.js +57 -0
- package/build/test/jsonwp-proxy/mock-request.js +93 -0
- package/build/test/jsonwp-proxy/protocol-converter-specs.js +173 -0
- package/build/test/jsonwp-proxy/proxy-e2e-specs.js +62 -0
- package/build/test/jsonwp-proxy/proxy-specs.js +299 -0
- package/build/test/jsonwp-proxy/url-specs.js +167 -0
- package/build/test/jsonwp-status/status-specs.js +36 -0
- package/build/test/protocol/errors-specs.js +388 -0
- package/build/test/protocol/fake-driver.js +168 -0
- package/build/test/protocol/helpers.js +27 -0
- package/build/test/protocol/protocol-e2e-specs.js +1242 -0
- package/build/test/protocol/routes-specs.js +82 -0
- package/build/test/protocol/validator-specs.js +151 -0
- package/index.d.ts +309 -44
- package/index.js +1 -62
- package/lib/basedriver/commands/index.js +0 -2
- package/lib/basedriver/driver.js +2 -22
- package/lib/basedriver/helpers.js +5 -4
- package/lib/index.js +62 -0
- package/lib/protocol/index.js +3 -1
- package/lib/protocol/protocol.js +18 -7
- package/lib/protocol/routes.js +1 -4
- package/package.json +8 -16
- package/test/basedriver/capability-specs.js +1 -1
- package/test/basedriver/commands/event-specs.js +1 -1
- package/test/basedriver/driver-e2e-specs.js +1 -1
- package/test/basedriver/driver-e2e-tests.js +66 -213
- package/test/basedriver/driver-specs.js +1 -1
- package/test/basedriver/driver-tests.js +3 -3
- package/test/basedriver/helpers-e2e-specs.js +9 -4
- package/test/basedriver/timeout-specs.js +1 -1
- package/test/basedriver/websockets-e2e-specs.js +7 -7
- package/build/index.js +0 -118
- package/build/lib/basedriver/commands/execute-child.js +0 -137
- package/build/lib/basedriver/commands/execute.js +0 -119
- package/build/test/basedriver/fixtures/custom-element-finder-bad.js +0 -12
- package/build/test/basedriver/fixtures/custom-element-finder.js +0 -36
- package/lib/basedriver/commands/execute-child.js +0 -132
- package/lib/basedriver/commands/execute.js +0 -126
package/lib/protocol/protocol.js
CHANGED
|
@@ -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
|
-
|
|
244
|
-
|
|
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 (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
};
|
package/lib/protocol/routes.js
CHANGED
|
@@ -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.
|
|
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
|
|
40
|
-
"build/lib",
|
|
41
|
-
"build/test/basedriver",
|
|
38
|
+
"build",
|
|
42
39
|
"!build/test/basedriver/fixtures"
|
|
43
40
|
],
|
|
44
41
|
"dependencies": {
|
|
45
|
-
"@appium/support": "^2.
|
|
46
|
-
"@babel/runtime": "7.
|
|
42
|
+
"@appium/support": "^2.55.2",
|
|
43
|
+
"@babel/runtime": "7.16.3",
|
|
47
44
|
"async-lock": "1.3.0",
|
|
48
|
-
"asyncbox": "2.9.
|
|
49
|
-
"axios": "0.
|
|
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.
|
|
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": "
|
|
66
|
+
"gitHead": "280d409df6c02d36b4ffc4d02a95ab3f4649b08c"
|
|
75
67
|
}
|
|
@@ -1,52 +1,74 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
|
-
import { BaseDriver, server, routeConfiguringFunction, DeviceSettings
|
|
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
|
|
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'] ??
|
|
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
|
|
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:
|
|
34
|
-
method:
|
|
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:
|
|
42
|
-
method:
|
|
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:
|
|
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:
|
|
81
|
+
url: newSessionURL,
|
|
60
82
|
headers: {
|
|
61
83
|
'X-Idempotency-Key': '123456',
|
|
62
84
|
},
|
|
63
|
-
method:
|
|
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:
|
|
76
|
-
method:
|
|
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:
|
|
109
|
+
url: newSessionURL,
|
|
88
110
|
headers: {
|
|
89
111
|
'X-Idempotency-Key': '12345',
|
|
90
112
|
},
|
|
91
|
-
method:
|
|
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:
|
|
101
|
-
method:
|
|
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:
|
|
110
|
-
method:
|
|
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:
|
|
121
|
-
method:
|
|
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:
|
|
171
|
-
method:
|
|
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:
|
|
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:
|
|
190
|
-
method:
|
|
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:
|
|
204
|
-
method:
|
|
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:
|
|
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:
|
|
222
|
-
method:
|
|
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:
|
|
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:
|
|
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
|
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
|
|
339
|
-
d.canProxy(sessId).should.be.
|
|
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
|
-
|
|
58
|
-
|
|
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(
|
|
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 () {
|