@appium/driver-test-support 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/e2e-suite.d.ts +4 -73
- package/build/lib/e2e-suite.d.ts.map +1 -1
- package/build/lib/e2e-suite.js +41 -140
- package/build/lib/e2e-suite.js.map +1 -1
- package/build/lib/helpers.d.ts +6 -7
- package/build/lib/helpers.d.ts.map +1 -1
- package/build/lib/helpers.js +5 -30
- package/build/lib/helpers.js.map +1 -1
- package/build/lib/index.d.ts +4 -6
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +0 -8
- package/build/lib/index.js.map +1 -1
- package/build/lib/types.d.ts +26 -0
- package/build/lib/types.d.ts.map +1 -0
- package/build/lib/types.js +3 -0
- package/build/lib/types.js.map +1 -0
- package/build/lib/unit-suite.d.ts +2 -9
- package/build/lib/unit-suite.d.ts.map +1 -1
- package/build/lib/unit-suite.js +59 -92
- package/build/lib/unit-suite.js.map +1 -1
- package/lib/{e2e-suite.js → e2e-suite.ts} +86 -185
- package/lib/helpers.ts +44 -0
- package/lib/index.ts +4 -0
- package/lib/types.ts +36 -0
- package/lib/{unit-suite.js → unit-suite.ts} +98 -134
- package/package.json +18 -19
- package/tsconfig.json +1 -2
- package/build/test/unit/index.spec.d.ts +0 -2
- package/build/test/unit/index.spec.d.ts.map +0 -1
- package/build/test/unit/index.spec.js +0 -58
- package/build/test/unit/index.spec.js.map +0 -1
- package/index.js +0 -1
- package/lib/helpers.js +0 -68
- package/lib/index.js +0 -13
|
@@ -1,68 +1,45 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import {server, routeConfiguringFunction, DeviceSettings} from 'appium/driver';
|
|
3
|
-
import axios from 'axios';
|
|
4
|
-
import
|
|
3
|
+
import axios, {type RawAxiosRequestConfig} from 'axios';
|
|
4
|
+
import {sleep} from 'asyncbox';
|
|
5
5
|
import {TEST_HOST, getTestPort, createAppiumURL} from './helpers';
|
|
6
6
|
import sinon from 'sinon';
|
|
7
7
|
import {Agent} from 'node:http';
|
|
8
|
+
import type {BaseNSCapabilities, Driver, DriverClass, SingularSessionData} from '@appium/types';
|
|
9
|
+
import type {NewSessionResponse, SessionHelpers} from './types';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Creates some helper functions for E2E tests to manage sessions.
|
|
11
|
-
* @template [CommandData=unknown]
|
|
12
|
-
* @template [ResponseData=any]
|
|
13
|
-
* @param {number} port - Port on which the server is running. Typically this will be retrieved via `get-port` beforehand
|
|
14
|
-
* @param {string} [address] - Address/host on which the server is running. Defaults to {@linkcode TEST_HOST}
|
|
15
|
-
* @returns {SessionHelpers<CommandData, ResponseData>}
|
|
16
13
|
*/
|
|
17
|
-
export function createSessionHelpers
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const createSessionURL = createAppiumTestURL(_, '');
|
|
14
|
+
export function createSessionHelpers<CommandData = unknown, ResponseData = any>(
|
|
15
|
+
port: number,
|
|
16
|
+
address: string = TEST_HOST
|
|
17
|
+
): SessionHelpers<CommandData, ResponseData> {
|
|
18
|
+
const createAppiumTestURL = createAppiumURL(address, port);
|
|
19
|
+
const createSessionURL = (sessionId: string) => createAppiumTestURL(sessionId, '');
|
|
24
20
|
const newSessionURL = createAppiumTestURL('', 'session');
|
|
25
|
-
|
|
21
|
+
|
|
22
|
+
return {
|
|
26
23
|
newSessionURL,
|
|
27
24
|
createAppiumTestURL,
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
* @param {string} sessionId
|
|
31
|
-
* @param {string} cmdName
|
|
32
|
-
* @param {any} [data]
|
|
33
|
-
* @param {RawAxiosRequestConfig} [config]
|
|
34
|
-
* @returns {Promise<any>}
|
|
35
|
-
*/
|
|
36
|
-
postCommand: async (sessionId, cmdName, data = {}, config = {}) => {
|
|
25
|
+
postCommand: async (sessionId, cmdName, data = {} as CommandData, config = {}) => {
|
|
37
26
|
const url = createAppiumTestURL(sessionId, cmdName);
|
|
38
27
|
const response = await axios.post(url, data, config);
|
|
39
28
|
return response.data?.value;
|
|
40
29
|
},
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
* @param {string} sessionIdOrCmdName
|
|
44
|
-
* @param {string|RawAxiosRequestConfig} cmdNameOrConfig
|
|
45
|
-
* @param {RawAxiosRequestConfig} [config]
|
|
46
|
-
* @returns {Promise<any>}
|
|
47
|
-
*/
|
|
48
30
|
getCommand: async (sessionIdOrCmdName, cmdNameOrConfig, config = {}) => {
|
|
49
31
|
if (!_.isString(cmdNameOrConfig)) {
|
|
50
|
-
config = cmdNameOrConfig;
|
|
32
|
+
config = cmdNameOrConfig as RawAxiosRequestConfig;
|
|
51
33
|
cmdNameOrConfig = sessionIdOrCmdName;
|
|
52
34
|
sessionIdOrCmdName = '';
|
|
53
35
|
}
|
|
54
36
|
const response = await axios({
|
|
55
|
-
url: createAppiumTestURL(sessionIdOrCmdName, cmdNameOrConfig),
|
|
37
|
+
url: createAppiumTestURL(sessionIdOrCmdName, cmdNameOrConfig as string),
|
|
56
38
|
validateStatus: null,
|
|
57
39
|
...config,
|
|
58
40
|
});
|
|
59
41
|
return response.data?.value;
|
|
60
42
|
},
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
63
|
-
* @param {NewSessionData} data
|
|
64
|
-
* @param {RawAxiosRequestConfig} [config]
|
|
65
|
-
*/
|
|
66
43
|
startSession: async (data, config = {}) => {
|
|
67
44
|
data = _.defaultsDeep(data, {
|
|
68
45
|
capabilities: {
|
|
@@ -73,18 +50,10 @@ export function createSessionHelpers(port, address = TEST_HOST) {
|
|
|
73
50
|
const response = await axios.post(newSessionURL, data, config);
|
|
74
51
|
return response.data?.value;
|
|
75
52
|
},
|
|
76
|
-
/**
|
|
77
|
-
*
|
|
78
|
-
* @param {string} sessionId
|
|
79
|
-
*/
|
|
80
53
|
endSession: async (sessionId) =>
|
|
81
54
|
await axios.delete(createSessionURL(sessionId), {
|
|
82
55
|
validateStatus: null,
|
|
83
56
|
}),
|
|
84
|
-
/**
|
|
85
|
-
* @param {string} sessionId
|
|
86
|
-
* @returns {Promise<any>}
|
|
87
|
-
*/
|
|
88
57
|
getSession: async (sessionId) => {
|
|
89
58
|
const response = await axios({
|
|
90
59
|
url: createSessionURL(sessionId),
|
|
@@ -92,59 +61,53 @@ export function createSessionHelpers(port, address = TEST_HOST) {
|
|
|
92
61
|
});
|
|
93
62
|
return response.data?.value;
|
|
94
63
|
},
|
|
95
|
-
}
|
|
64
|
+
};
|
|
96
65
|
}
|
|
97
66
|
|
|
98
67
|
/**
|
|
99
68
|
* Creates E2E test suites for a driver.
|
|
100
|
-
* @param {DriverClass} DriverClass
|
|
101
|
-
* @param {Partial<BaseNSCapabilities>} [defaultCaps]
|
|
102
69
|
*/
|
|
103
|
-
export function driverE2ETestSuite(
|
|
104
|
-
|
|
105
|
-
|
|
70
|
+
export function driverE2ETestSuite(
|
|
71
|
+
DriverClass: DriverClass<Driver>,
|
|
72
|
+
defaultCaps: Partial<BaseNSCapabilities> = {}
|
|
73
|
+
): void {
|
|
74
|
+
const address = (defaultCaps as BaseNSCapabilities)['appium:address'] ?? TEST_HOST;
|
|
75
|
+
let port: number | undefined = (defaultCaps as BaseNSCapabilities)['appium:port'];
|
|
106
76
|
const className = DriverClass.name || '(unknown driver)';
|
|
107
77
|
|
|
108
78
|
describe(`BaseDriver E2E (as ${className})`, function () {
|
|
109
|
-
let baseServer
|
|
110
|
-
|
|
111
|
-
let
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let
|
|
117
|
-
|
|
118
|
-
/** @type {SessionHelpers['startSession']} */
|
|
119
|
-
let startSession;
|
|
120
|
-
/** @type {SessionHelpers['getSession']} */
|
|
121
|
-
let getSession;
|
|
122
|
-
/** @type {SessionHelpers['endSession']} */
|
|
123
|
-
let endSession;
|
|
124
|
-
/** @type {SessionHelpers['getCommand']} */
|
|
125
|
-
let getCommand;
|
|
126
|
-
/** @type {SessionHelpers['postCommand']} */
|
|
127
|
-
let postCommand;
|
|
128
|
-
let expect;
|
|
79
|
+
let baseServer: Awaited<ReturnType<typeof server>>;
|
|
80
|
+
let d: InstanceType<typeof DriverClass>;
|
|
81
|
+
let newSessionURL: string;
|
|
82
|
+
let startSession: SessionHelpers['startSession'];
|
|
83
|
+
let getSession: SessionHelpers['getSession'];
|
|
84
|
+
let endSession: SessionHelpers['endSession'];
|
|
85
|
+
let getCommand: SessionHelpers['getCommand'];
|
|
86
|
+
let postCommand: SessionHelpers['postCommand'];
|
|
87
|
+
let expect: Chai.ExpectStatic;
|
|
129
88
|
|
|
130
89
|
before(async function () {
|
|
131
90
|
const chai = await import('chai');
|
|
132
91
|
const chaiAsPromised = await import('chai-as-promised');
|
|
133
|
-
chai.use(chaiAsPromised.default);
|
|
134
|
-
expect = chai.expect;
|
|
92
|
+
(chai as any).use((chaiAsPromised as any).default);
|
|
93
|
+
expect = (chai as any).expect;
|
|
135
94
|
|
|
136
95
|
port = port ?? (await getTestPort());
|
|
137
96
|
defaultCaps = {...defaultCaps};
|
|
138
|
-
d = new DriverClass({port, address})
|
|
97
|
+
d = new DriverClass({port, address}) as InstanceType<typeof DriverClass>;
|
|
139
98
|
baseServer = await server({
|
|
140
99
|
routeConfiguringFunction: routeConfiguringFunction(d),
|
|
141
|
-
port
|
|
100
|
+
port: port!,
|
|
142
101
|
hostname: address,
|
|
143
|
-
|
|
144
|
-
cliArgs: {},
|
|
102
|
+
cliArgs: {} as any,
|
|
145
103
|
});
|
|
146
|
-
|
|
147
|
-
|
|
104
|
+
const helpers = createSessionHelpers(port, address);
|
|
105
|
+
startSession = helpers.startSession;
|
|
106
|
+
getSession = helpers.getSession;
|
|
107
|
+
endSession = helpers.endSession;
|
|
108
|
+
getCommand = helpers.getCommand;
|
|
109
|
+
postCommand = helpers.postCommand;
|
|
110
|
+
newSessionURL = helpers.newSessionURL;
|
|
148
111
|
});
|
|
149
112
|
after(async function () {
|
|
150
113
|
await baseServer?.close();
|
|
@@ -160,7 +123,7 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
160
123
|
// workaround for https://github.com/node-fetch/node-fetch/issues/1735
|
|
161
124
|
const httpAgent = new Agent({keepAlive: true});
|
|
162
125
|
|
|
163
|
-
const sessionIds = [];
|
|
126
|
+
const sessionIds: string[] = [];
|
|
164
127
|
let times = 0;
|
|
165
128
|
do {
|
|
166
129
|
const {sessionId} = await startSession(
|
|
@@ -194,7 +157,7 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
194
157
|
// workaround for https://github.com/node-fetch/node-fetch/issues/1735
|
|
195
158
|
const httpAgent = new Agent({keepAlive: true});
|
|
196
159
|
|
|
197
|
-
const reqs = [];
|
|
160
|
+
const reqs: Promise<NewSessionResponse>[] = [];
|
|
198
161
|
let times = 0;
|
|
199
162
|
do {
|
|
200
163
|
reqs.push(
|
|
@@ -214,7 +177,7 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
214
177
|
);
|
|
215
178
|
times++;
|
|
216
179
|
} while (times < 2);
|
|
217
|
-
const sessionIds = _.map(await
|
|
180
|
+
const sessionIds = _.map(await Promise.all(reqs), 'sessionId');
|
|
218
181
|
expect(_.uniq(sessionIds)).to.have.lengthOf(1);
|
|
219
182
|
|
|
220
183
|
const {status, data} = await endSession(sessionIds[0]);
|
|
@@ -232,9 +195,11 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
232
195
|
expect(status).to.equal(200);
|
|
233
196
|
expect(data.value.sessionId).to.exist;
|
|
234
197
|
expect(data.value.capabilities.platformName).to.equal(defaultCaps.platformName);
|
|
235
|
-
expect(data.value.capabilities.deviceName).to.equal(
|
|
198
|
+
expect(data.value.capabilities.deviceName).to.equal(
|
|
199
|
+
(defaultCaps as BaseNSCapabilities)['appium:deviceName']
|
|
200
|
+
);
|
|
236
201
|
|
|
237
|
-
({status, data} = await endSession(
|
|
202
|
+
({status, data} = await endSession(d.sessionId!));
|
|
238
203
|
|
|
239
204
|
expect(status).to.equal(200);
|
|
240
205
|
expect(data.value).to.be.null;
|
|
@@ -243,26 +208,24 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
243
208
|
});
|
|
244
209
|
|
|
245
210
|
describe('command timeouts', function () {
|
|
246
|
-
let originalFindElement
|
|
211
|
+
let originalFindElement: typeof d.findElement;
|
|
212
|
+
let originalFindElements: typeof d.findElements;
|
|
247
213
|
|
|
248
|
-
|
|
249
|
-
* @param {number} [timeout]
|
|
250
|
-
*/
|
|
251
|
-
async function startTimeoutSession(timeout) {
|
|
214
|
+
async function startTimeoutSession(timeout?: number) {
|
|
252
215
|
const caps = _.cloneDeep(defaultCaps);
|
|
253
|
-
caps['appium:newCommandTimeout'] = timeout;
|
|
216
|
+
(caps as any)['appium:newCommandTimeout'] = timeout;
|
|
254
217
|
return await startSession({capabilities: {alwaysMatch: caps}});
|
|
255
218
|
}
|
|
256
219
|
|
|
257
220
|
before(function () {
|
|
258
221
|
originalFindElement = d.findElement;
|
|
259
222
|
d.findElement = function () {
|
|
260
|
-
return 'foo';
|
|
223
|
+
return 'foo' as any;
|
|
261
224
|
}.bind(d);
|
|
262
225
|
|
|
263
226
|
originalFindElements = d.findElements;
|
|
264
227
|
d.findElements = async function () {
|
|
265
|
-
await
|
|
228
|
+
await sleep(200);
|
|
266
229
|
return ['foo'];
|
|
267
230
|
}.bind(d);
|
|
268
231
|
});
|
|
@@ -273,19 +236,19 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
273
236
|
});
|
|
274
237
|
|
|
275
238
|
it('should set a default commandTimeout', async function () {
|
|
276
|
-
|
|
239
|
+
const newSession = await startTimeoutSession();
|
|
277
240
|
expect(d.newCommandTimeoutMs).to.be.above(0);
|
|
278
241
|
await endSession(newSession.sessionId);
|
|
279
242
|
});
|
|
280
243
|
|
|
281
244
|
it('should timeout on commands using commandTimeout cap', async function () {
|
|
282
|
-
|
|
283
|
-
const sessionId =
|
|
245
|
+
const newSession = await startTimeoutSession(0.25);
|
|
246
|
+
const sessionId = d.sessionId!;
|
|
284
247
|
await postCommand(sessionId, 'element', {
|
|
285
248
|
using: 'name',
|
|
286
249
|
value: 'foo',
|
|
287
250
|
});
|
|
288
|
-
await
|
|
251
|
+
await sleep(400);
|
|
289
252
|
const value = await getSession(sessionId);
|
|
290
253
|
expect(value.error).to.equal('invalid session id');
|
|
291
254
|
expect(d.sessionId).to.be.null;
|
|
@@ -294,9 +257,9 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
294
257
|
});
|
|
295
258
|
|
|
296
259
|
it('should not timeout with commandTimeout of false', async function () {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const value = await postCommand(
|
|
260
|
+
const newSession = await startTimeoutSession(0.1);
|
|
261
|
+
const start = Date.now();
|
|
262
|
+
const value = await postCommand(d.sessionId!, 'elements', {
|
|
300
263
|
using: 'name',
|
|
301
264
|
value: 'foo',
|
|
302
265
|
});
|
|
@@ -307,14 +270,14 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
307
270
|
|
|
308
271
|
it('should not timeout with commandTimeout of 0', async function () {
|
|
309
272
|
d.newCommandTimeoutMs = 2;
|
|
310
|
-
|
|
273
|
+
const newSession = await startTimeoutSession(0);
|
|
311
274
|
|
|
312
|
-
await postCommand(
|
|
275
|
+
await postCommand(d.sessionId!, 'element', {
|
|
313
276
|
using: 'name',
|
|
314
277
|
value: 'foo',
|
|
315
278
|
});
|
|
316
|
-
await
|
|
317
|
-
const value = await getSession(
|
|
279
|
+
await sleep(400);
|
|
280
|
+
const value = await getSession(d.sessionId!);
|
|
318
281
|
expect(value.platformName).to.equal(defaultCaps.platformName);
|
|
319
282
|
const resp = (await endSession(newSession.sessionId)).data.value;
|
|
320
283
|
expect(resp).to.be.null;
|
|
@@ -323,35 +286,28 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
323
286
|
});
|
|
324
287
|
|
|
325
288
|
it('should not timeout if its just the command taking awhile', async function () {
|
|
326
|
-
|
|
327
|
-
// XXX: race condition: we must build this URL before ...something happens...
|
|
328
|
-
// which causes `d.sessionId` to be missing
|
|
289
|
+
const newSession = await startTimeoutSession(0.25);
|
|
329
290
|
const {sessionId} = d;
|
|
330
291
|
|
|
331
|
-
await postCommand(
|
|
292
|
+
await postCommand(d.sessionId!, 'element', {
|
|
332
293
|
using: 'name',
|
|
333
294
|
value: 'foo',
|
|
334
295
|
});
|
|
335
|
-
await
|
|
336
|
-
const value = await getSession(
|
|
337
|
-
expect(
|
|
296
|
+
await sleep(400);
|
|
297
|
+
const value = await getSession(sessionId!);
|
|
298
|
+
expect((value as any).error).to.equal('invalid session id');
|
|
338
299
|
expect(d.sessionId).to.be.null;
|
|
339
|
-
const resp = (await endSession(newSession.sessionId)).data.value;
|
|
340
|
-
expect(
|
|
341
|
-
'invalid session id'
|
|
342
|
-
);
|
|
300
|
+
const resp = (await endSession(newSession.sessionId)).data.value as {error?: string};
|
|
301
|
+
expect(resp?.error).to.equal('invalid session id');
|
|
343
302
|
});
|
|
344
303
|
|
|
345
304
|
it('should not have a timer running before or after a session', async function () {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
let newSession = await startTimeoutSession(0.25);
|
|
305
|
+
expect((d as any).noCommandTimer).to.be.null;
|
|
306
|
+
const newSession = await startTimeoutSession(0.25);
|
|
349
307
|
expect(newSession.sessionId).to.equal(d.sessionId);
|
|
350
|
-
|
|
351
|
-
expect(d.noCommandTimer).to.exist;
|
|
308
|
+
expect((d as any).noCommandTimer).to.exist;
|
|
352
309
|
await endSession(newSession.sessionId);
|
|
353
|
-
|
|
354
|
-
expect(d.noCommandTimer).to.be.null;
|
|
310
|
+
expect((d as any).noCommandTimer).to.be.null;
|
|
355
311
|
});
|
|
356
312
|
});
|
|
357
313
|
|
|
@@ -367,15 +323,13 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
367
323
|
});
|
|
368
324
|
it('should reject for invalid update object', async function () {
|
|
369
325
|
await expect(
|
|
370
|
-
|
|
371
|
-
d.settings.update('invalid json')
|
|
326
|
+
(d.settings as any).update('invalid json')
|
|
372
327
|
).to.be.rejectedWith('JSON');
|
|
373
328
|
});
|
|
374
329
|
});
|
|
375
330
|
|
|
376
331
|
describe('unexpected exits', function () {
|
|
377
|
-
|
|
378
|
-
let sandbox;
|
|
332
|
+
let sandbox: ReturnType<typeof sinon.createSandbox>;
|
|
379
333
|
beforeEach(function () {
|
|
380
334
|
sandbox = sinon.createSandbox();
|
|
381
335
|
});
|
|
@@ -386,12 +340,11 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
386
340
|
|
|
387
341
|
it('should reject a current command when the driver crashes', async function () {
|
|
388
342
|
sandbox.stub(d, 'getStatus').callsFake(async function () {
|
|
389
|
-
await
|
|
343
|
+
await sleep(5000);
|
|
390
344
|
});
|
|
391
345
|
const reqPromise = getCommand('status', {validateStatus: null});
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const shutdownEventPromise = new B((resolve, reject) => {
|
|
346
|
+
await sleep(100);
|
|
347
|
+
const shutdownEventPromise = new Promise<void>((resolve, reject) => {
|
|
395
348
|
setTimeout(
|
|
396
349
|
() =>
|
|
397
350
|
reject(
|
|
@@ -405,16 +358,14 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
405
358
|
});
|
|
406
359
|
d.startUnexpectedShutdown(new Error('Crashytimes'));
|
|
407
360
|
const value = await reqPromise;
|
|
408
|
-
expect(value.message).to.contain('Crashytimes');
|
|
361
|
+
expect((value as any).message).to.contain('Crashytimes');
|
|
409
362
|
await shutdownEventPromise;
|
|
410
363
|
});
|
|
411
364
|
});
|
|
412
365
|
|
|
413
366
|
describe('event timings', function () {
|
|
414
|
-
|
|
415
|
-
let
|
|
416
|
-
/** @type {SingularSessionData} */
|
|
417
|
-
let res;
|
|
367
|
+
let session: NewSessionResponse | undefined;
|
|
368
|
+
let res: SingularSessionData;
|
|
418
369
|
|
|
419
370
|
describe('when not provided the eventTimings cap', function () {
|
|
420
371
|
before(async function () {
|
|
@@ -458,53 +409,3 @@ export function driverE2ETestSuite(DriverClass, defaultCaps = {}) {
|
|
|
458
409
|
});
|
|
459
410
|
});
|
|
460
411
|
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* @typedef {import('@appium/types').DriverClass} DriverClass
|
|
464
|
-
* @typedef {import('@appium/types').Driver} Driver
|
|
465
|
-
* @typedef {import('@appium/types').Constraints} Constraints
|
|
466
|
-
* @typedef {import('@appium/types').StringRecord} StringRecord
|
|
467
|
-
* @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
|
|
468
|
-
* @typedef {import('@appium/types').BaseNSCapabilities} BaseNSCapabilities
|
|
469
|
-
* @typedef {import('axios').RawAxiosRequestConfig} RawAxiosRequestConfig
|
|
470
|
-
*/
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* `Constraints` is purposefully loose here
|
|
474
|
-
* @template {Constraints} [C=Constraints]
|
|
475
|
-
* @typedef {import('@appium/types').SingularSessionData<C>} SingularSessionData
|
|
476
|
-
*/
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* @template T,D
|
|
480
|
-
* @typedef {import('axios').AxiosResponse<T, D>} AxiosResponse
|
|
481
|
-
*/
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* `Constraints` is purposefully loose here
|
|
485
|
-
* @template {Constraints} [C=Constraints]
|
|
486
|
-
* @typedef NewSessionData
|
|
487
|
-
* @property {import('type-fest').RequireAtLeastOne<import('@appium/types').W3CCapabilities<C>, 'firstMatch'|'alwaysMatch'>} capabilities
|
|
488
|
-
*/
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* `Constraints` is purposefully loose here
|
|
492
|
-
* @template {Constraints} [C=Constraints]
|
|
493
|
-
* @typedef NewSessionResponse
|
|
494
|
-
* @property {string} sessionId,
|
|
495
|
-
* @property {import('@appium/types').Capabilities<C>} capabilities
|
|
496
|
-
*/
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Some E2E helpers for making requests and managing sessions
|
|
500
|
-
* See {@linkcode createSessionHelpers}
|
|
501
|
-
* @template [CommandData=unknown]
|
|
502
|
-
* @template [ResponseData=any]
|
|
503
|
-
* @typedef SessionHelpers
|
|
504
|
-
* @property {string} newSessionURL - URL to create a new session. Can be used with raw `axios` requests to fully inspect raw response. Mostly, this will not be used.
|
|
505
|
-
* @property {(data: NewSessionData, config?: RawAxiosRequestConfig) => Promise<NewSessionResponse>} startSession - Begin a session
|
|
506
|
-
* @property {(sessionId: string) => Promise<AxiosResponse<{value: {error?: string}?}, {validateStatus: null}>>} endSession - End a session. _Note: resolves with raw response object_
|
|
507
|
-
* @property {(sessionId: string) => Promise<SingularSessionData>} getSession - Get info about a session
|
|
508
|
-
* @property {(sessionId: string, cmdName: string, data?: CommandData, config?: RawAxiosRequestConfig) => Promise<ResponseData>} postCommand - Send an arbitrary command via `POST`.
|
|
509
|
-
* @property {(sessionIdOrCmdName: string, cmdNameOrConfig: string|RawAxiosRequestConfig, config?: RawAxiosRequestConfig) => Promise<ResponseData>} getCommand - Send an arbitrary command via `GET`. Optional `sessionId`.
|
|
510
|
-
*/
|
package/lib/helpers.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import getPort from 'get-port';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Default test host
|
|
6
|
+
*/
|
|
7
|
+
export const TEST_HOST = '127.0.0.1';
|
|
8
|
+
|
|
9
|
+
let testPort: number | undefined;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns a free port; one per process
|
|
13
|
+
* @param force - If true, do not reuse the port (if it already exists)
|
|
14
|
+
* @returns a free port
|
|
15
|
+
*/
|
|
16
|
+
export async function getTestPort(force = false): Promise<number> {
|
|
17
|
+
if (force || !testPort) {
|
|
18
|
+
const port = await getPort();
|
|
19
|
+
if (!testPort) {
|
|
20
|
+
testPort = port;
|
|
21
|
+
}
|
|
22
|
+
return port;
|
|
23
|
+
}
|
|
24
|
+
return testPort;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Build an Appium URL from components.
|
|
29
|
+
*
|
|
30
|
+
* **All** parameters are required. Provide an empty string (`''`) if you don't need one.
|
|
31
|
+
* To rearrange arguments (if needed), use the placeholder from Lodash (`_`).
|
|
32
|
+
*/
|
|
33
|
+
export const createAppiumURL = _.curry(
|
|
34
|
+
(address: string, port: string | number, session: string | null, pathname: string): string => {
|
|
35
|
+
if (!/^https?:\/\//.test(address)) {
|
|
36
|
+
address = `http://${address}`;
|
|
37
|
+
}
|
|
38
|
+
let path = session ? `session/${session}` : '';
|
|
39
|
+
if (pathname) {
|
|
40
|
+
path = `${path}/${pathname}`;
|
|
41
|
+
}
|
|
42
|
+
return new URL(path, `${address}:${port}`).href;
|
|
43
|
+
}
|
|
44
|
+
);
|
package/lib/index.ts
ADDED
package/lib/types.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {AxiosResponse, RawAxiosRequestConfig} from 'axios';
|
|
2
|
+
import type {Capabilities, Constraints, SingularSessionData, W3CCapabilities} from '@appium/types';
|
|
3
|
+
import type {RequireAtLeastOne} from 'type-fest';
|
|
4
|
+
|
|
5
|
+
export interface NewSessionData<C extends Constraints = Constraints> {
|
|
6
|
+
capabilities: RequireAtLeastOne<W3CCapabilities<C>, 'firstMatch' | 'alwaysMatch'>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface NewSessionResponse<C extends Constraints = Constraints> {
|
|
10
|
+
sessionId: string;
|
|
11
|
+
capabilities: Capabilities<C>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SessionHelpers<CommandData = unknown, ResponseData = any> {
|
|
15
|
+
newSessionURL: string;
|
|
16
|
+
createAppiumTestURL: (session: string, pathname: string) => string;
|
|
17
|
+
postCommand: (
|
|
18
|
+
sessionId: string,
|
|
19
|
+
cmdName: string,
|
|
20
|
+
data?: CommandData,
|
|
21
|
+
config?: RawAxiosRequestConfig
|
|
22
|
+
) => Promise<ResponseData>;
|
|
23
|
+
getCommand: (
|
|
24
|
+
sessionIdOrCmdName: string,
|
|
25
|
+
cmdNameOrConfig: string | RawAxiosRequestConfig,
|
|
26
|
+
config?: RawAxiosRequestConfig
|
|
27
|
+
) => Promise<ResponseData>;
|
|
28
|
+
startSession: (
|
|
29
|
+
data: NewSessionData,
|
|
30
|
+
config?: RawAxiosRequestConfig
|
|
31
|
+
) => Promise<NewSessionResponse>;
|
|
32
|
+
endSession: (
|
|
33
|
+
sessionId: string
|
|
34
|
+
) => Promise<AxiosResponse<{value: {error?: string} | null}, {validateStatus: null}>>;
|
|
35
|
+
getSession: (sessionId: string) => Promise<SingularSessionData>;
|
|
36
|
+
}
|