@appium/test-support 1.4.0 → 2.0.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.
@@ -1,642 +0,0 @@
1
- import _ from 'lodash';
2
- import B from 'bluebird';
3
- import {DeviceSettings} from '@appium/base-driver';
4
- import {createSandbox} from 'sinon';
5
-
6
- import chai from 'chai';
7
-
8
- const should = chai.should();
9
- const {expect} = chai;
10
-
11
- // wrap these tests in a function so we can export the tests and re-use them
12
- // for actual driver implementations
13
-
14
- /**
15
- * Creates unit test suites for a driver.
16
- * @param {DriverClass} DriverClass
17
- * @param {AppiumW3CCapabilities} [defaultCaps]
18
- */
19
-
20
- export function driverUnitTestSuite(DriverClass, defaultCaps = {}) {
21
- // to display the driver under test in report
22
- const className = DriverClass.name ?? '(unknown driver)';
23
-
24
- describe(`BaseDriver unit suite (as ${className})`, function () {
25
- /** @type {InstanceType<typeof DriverClass>} */
26
- let d;
27
- /** @type {W3CCapabilities} */
28
- let w3cCaps;
29
- /** @type {import('sinon').SinonSandbox} */
30
- let sandbox;
31
-
32
- beforeEach(function () {
33
- sandbox = createSandbox();
34
- d = new DriverClass();
35
- w3cCaps = {
36
- alwaysMatch: {
37
- ...defaultCaps,
38
- platformName: 'Fake',
39
- 'appium:deviceName': 'Commodore 64',
40
- },
41
- firstMatch: [{}],
42
- };
43
- });
44
- afterEach(async function () {
45
- sandbox.restore();
46
- await d.deleteSession();
47
- });
48
-
49
- describe('static property', function () {
50
- describe('baseVersion', function () {
51
- it('should exist', function () {
52
- DriverClass.baseVersion.should.exist;
53
- });
54
- });
55
- });
56
-
57
- describe('Log prefix', function () {
58
- it('should setup log prefix', async function () {
59
- const d = new DriverClass();
60
- const previousPrefix = d.log.prefix;
61
- await d.createSession({
62
- alwaysMatch: {...defaultCaps, platformName: 'Fake', 'appium:deviceName': 'Commodore 64'},
63
- firstMatch: [{}],
64
- });
65
- try {
66
- expect(previousPrefix).not.to.eql(d.log.prefix);
67
- } finally {
68
- await d.deleteSession();
69
- expect(previousPrefix).to.eql(d.log.prefix);
70
- }
71
- });
72
- });
73
-
74
- it('should return an empty status object', async function () {
75
- let status = await d.getStatus();
76
- status.should.eql({});
77
- });
78
-
79
- it('should return a sessionId from createSession', async function () {
80
- let [sessId] = await d.createSession(w3cCaps);
81
- should.exist(sessId);
82
- sessId.should.be.a('string');
83
- sessId.length.should.be.above(5);
84
- });
85
-
86
- it('should not be able to start two sessions without closing the first', async function () {
87
- await d.createSession(_.cloneDeep(w3cCaps));
88
- await d.createSession(_.cloneDeep(w3cCaps)).should.be.rejectedWith('session');
89
- });
90
-
91
- it('should be able to delete a session', async function () {
92
- let sessionId1 = await d.createSession(_.cloneDeep(w3cCaps));
93
- await d.deleteSession();
94
- should.equal(d.sessionId, null);
95
- let sessionId2 = await d.createSession(_.cloneDeep(w3cCaps));
96
- sessionId1.should.not.eql(sessionId2);
97
- });
98
-
99
- it('should get the current session', async function () {
100
- let [, caps] = await d.createSession(w3cCaps);
101
- caps.should.equal(await d.getSession());
102
- });
103
-
104
- it('should return sessions if no session exists', async function () {
105
- let sessions = await d.getSessions();
106
- sessions.length.should.equal(0);
107
- });
108
-
109
- it('should return sessions', async function () {
110
- const caps = _.cloneDeep(w3cCaps);
111
- await d.createSession(caps);
112
- let sessions = await d.getSessions();
113
-
114
- sessions.length.should.equal(1);
115
- sessions[0].should.include({
116
- id: d.sessionId,
117
- });
118
- sessions[0].capabilities.should.include({
119
- deviceName: 'Commodore 64',
120
- platformName: 'Fake',
121
- });
122
- });
123
-
124
- it('should fulfill an unexpected driver quit promise', async function () {
125
- // make a command that will wait a bit so we can crash while it's running
126
- sandbox.stub(d, 'getStatus').callsFake(async () => {
127
- await B.delay(1000);
128
- return 'good status';
129
- });
130
- let cmdPromise = d.executeCommand('getStatus');
131
- await B.delay(10);
132
- const p = new B((resolve, reject) => {
133
- setTimeout(
134
- () =>
135
- reject(
136
- new Error(
137
- 'onUnexpectedShutdown event is expected to be fired within 5 seconds timeout'
138
- )
139
- ),
140
- 5000
141
- );
142
- d.onUnexpectedShutdown(resolve);
143
- });
144
- d.startUnexpectedShutdown(new Error('We crashed'));
145
- await cmdPromise.should.be.rejectedWith(/We crashed/);
146
- await p;
147
- });
148
-
149
- it('should not allow commands in middle of unexpected shutdown', async function () {
150
- // make a command that will wait a bit so we can crash while it's running
151
- sandbox.stub(d, 'deleteSession').callsFake(async function () {
152
- await B.delay(100);
153
- DriverClass.prototype.deleteSession.call(this);
154
- });
155
- await d.createSession(w3cCaps);
156
- const p = new B((resolve, reject) => {
157
- setTimeout(
158
- () =>
159
- reject(
160
- new Error(
161
- 'onUnexpectedShutdown event is expected to be fired within 5 seconds timeout'
162
- )
163
- ),
164
- 5000
165
- );
166
- d.onUnexpectedShutdown(resolve);
167
- });
168
- d.startUnexpectedShutdown(new Error('We crashed'));
169
- await p;
170
- await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
171
- });
172
-
173
- it('should allow new commands after done shutting down', async function () {
174
- // make a command that will wait a bit so we can crash while it's running
175
- sandbox.stub(d, 'deleteSession').callsFake(async function () {
176
- await B.delay(100);
177
- DriverClass.prototype.deleteSession.call(this);
178
- });
179
-
180
- await d.createSession(_.cloneDeep(w3cCaps));
181
- const p = new B((resolve, reject) => {
182
- setTimeout(
183
- () =>
184
- reject(
185
- new Error(
186
- 'onUnexpectedShutdown event is expected to be fired within 5 seconds timeout'
187
- )
188
- ),
189
- 5000
190
- );
191
- d.onUnexpectedShutdown(resolve);
192
- });
193
- d.startUnexpectedShutdown(new Error('We crashed'));
194
- await p;
195
-
196
- await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
197
- await B.delay(500);
198
-
199
- await d.executeCommand('createSession', null, null, _.cloneDeep(w3cCaps));
200
- await d.deleteSession();
201
- });
202
-
203
- it('should distinguish between W3C and JSONWP session', async function () {
204
- // Test W3C (leave first 2 args null because those are the JSONWP args)
205
- await d.executeCommand('createSession', null, null, {
206
- alwaysMatch: {
207
- ...defaultCaps,
208
- platformName: 'Fake',
209
- 'appium:deviceName': 'Commodore 64',
210
- },
211
- firstMatch: [{}],
212
- });
213
-
214
- expect(d.protocol).to.equal('W3C');
215
- });
216
-
217
- describe('protocol detection', function () {
218
- it('should use W3C if only W3C caps are provided', async function () {
219
- await d.createSession({
220
- alwaysMatch: _.clone(defaultCaps),
221
- firstMatch: [{}],
222
- });
223
- expect(d.protocol).to.equal('W3C');
224
- });
225
- });
226
-
227
- it('should have a method to get driver for a session', async function () {
228
- let [sessId] = await d.createSession(w3cCaps);
229
- expect(d.driverForSession(sessId)).to.eql(d);
230
- });
231
-
232
- describe('command queue', function () {
233
- /** @type {InstanceType<DriverClass>} */
234
- let d;
235
- let waitMs = 10;
236
-
237
- beforeEach(function () {
238
- d = new DriverClass();
239
- sandbox.stub(d, 'getStatus').callsFake(async () => {
240
- await B.delay(waitMs);
241
- return Date.now();
242
- });
243
- sandbox.stub(d, 'getSessions').callsFake(async () => {
244
- await B.delay(waitMs);
245
- throw new Error('multipass');
246
- });
247
- });
248
-
249
- afterEach(async function () {
250
- await d.clearNewCommandTimeout();
251
- });
252
-
253
- it('should queue commands and.executeCommand/respond in the order received', async function () {
254
- let numCmds = 10;
255
- let cmds = [];
256
- for (let i = 0; i < numCmds; i++) {
257
- cmds.push(d.executeCommand('getStatus'));
258
- }
259
- let results = await B.all(cmds);
260
- for (let i = 1; i < numCmds; i++) {
261
- if (results[i] <= results[i - 1]) {
262
- throw new Error('Got result out of order');
263
- }
264
- }
265
- });
266
-
267
- it('should handle errors correctly when queuing', async function () {
268
- let numCmds = 10;
269
- let cmds = [];
270
- for (let i = 0; i < numCmds; i++) {
271
- if (i === 5) {
272
- cmds.push(d.executeCommand('getSessions'));
273
- } else {
274
- cmds.push(d.executeCommand('getStatus'));
275
- }
276
- }
277
- let results = /** @type {PromiseFulfilledResult<any>[]} */ (
278
- // eslint-disable-next-line promise/no-native
279
- await Promise.allSettled(cmds)
280
- );
281
- for (let i = 1; i < 5; i++) {
282
- if (results[i].value <= results[i - 1].value) {
283
- throw new Error('Got result out of order');
284
- }
285
- }
286
- /** @type {PromiseRejectedResult} */ (
287
- /** @type {unknown} */ (results[5])
288
- ).reason.message.should.contain('multipass');
289
- for (let i = 7; i < numCmds; i++) {
290
- if (results[i].value <= results[i - 1].value) {
291
- throw new Error('Got result out of order');
292
- }
293
- }
294
- });
295
-
296
- it('should not care if queue empties for a bit', async function () {
297
- let numCmds = 10;
298
- let cmds = [];
299
- for (let i = 0; i < numCmds; i++) {
300
- cmds.push(d.executeCommand('getStatus'));
301
- }
302
- let results = await B.all(cmds);
303
- cmds = [];
304
- for (let i = 0; i < numCmds; i++) {
305
- cmds.push(d.executeCommand('getStatus'));
306
- }
307
- results = await B.all(cmds);
308
- for (let i = 1; i < numCmds; i++) {
309
- if (results[i] <= results[i - 1]) {
310
- throw new Error('Got result out of order');
311
- }
312
- }
313
- });
314
- });
315
-
316
- describe('timeouts', function () {
317
- before(async function () {
318
- await d.createSession(w3cCaps);
319
- });
320
- describe('command', function () {
321
- it('should exist by default', function () {
322
- d.newCommandTimeoutMs.should.equal(60000);
323
- });
324
- it('should be settable through `timeouts`', async function () {
325
- await d.timeouts('command', 20);
326
- d.newCommandTimeoutMs.should.equal(20);
327
- });
328
- });
329
- describe('implicit', function () {
330
- it('should not exist by default', function () {
331
- d.implicitWaitMs.should.equal(0);
332
- });
333
- it('should be settable through `timeouts`', async function () {
334
- await d.timeouts('implicit', 20);
335
- d.implicitWaitMs.should.equal(20);
336
- });
337
- });
338
- });
339
-
340
- describe('timeouts (W3C)', function () {
341
- beforeEach(async function () {
342
- await d.createSession(w3cCaps);
343
- });
344
- afterEach(async function () {
345
- await d.deleteSession();
346
- });
347
- it('should get timeouts that we set', async function () {
348
- // @ts-expect-error
349
- await d.timeouts(undefined, undefined, undefined, undefined, 1000);
350
- await d.getTimeouts().should.eventually.have.property('implicit', 1000);
351
- await d.timeouts('command', 2000);
352
- await d.getTimeouts().should.eventually.deep.equal({
353
- implicit: 1000,
354
- command: 2000,
355
- });
356
- // @ts-expect-error
357
- await d.timeouts(undefined, undefined, undefined, undefined, 3000);
358
- await d.getTimeouts().should.eventually.deep.equal({
359
- implicit: 3000,
360
- command: 2000,
361
- });
362
- });
363
- });
364
-
365
- describe('reset compatibility', function () {
366
- it('should not allow both fullReset and noReset to be true', async function () {
367
- const newCaps = {
368
- alwaysMatch: {
369
- ...defaultCaps,
370
- platformName: 'Fake',
371
- 'appium:deviceName': 'Commodore 64',
372
- 'appium:fullReset': true,
373
- 'appium:noReset': true,
374
- },
375
- firstMatch: [{}],
376
- };
377
- await d.createSession(newCaps).should.be.rejectedWith(/noReset.+fullReset/);
378
- });
379
- });
380
-
381
- describe('proxying', function () {
382
- let sessId;
383
- beforeEach(async function () {
384
- [sessId] = await d.createSession(w3cCaps);
385
- });
386
- describe('#proxyActive', function () {
387
- it('should exist', function () {
388
- d.proxyActive.should.be.an.instanceof(Function);
389
- });
390
- it('should return false', function () {
391
- d.proxyActive(sessId).should.be.false;
392
- });
393
- it('should throw an error when sessionId is wrong', function () {
394
- (() => {
395
- d.proxyActive('aaa');
396
- }).should.throw;
397
- });
398
- });
399
-
400
- describe('#getProxyAvoidList', function () {
401
- it('should exist', function () {
402
- d.getProxyAvoidList.should.be.an.instanceof(Function);
403
- });
404
- it('should return an array', function () {
405
- d.getProxyAvoidList(sessId).should.be.an.instanceof(Array);
406
- });
407
- it('should throw an error when sessionId is wrong', function () {
408
- (() => {
409
- d.getProxyAvoidList('aaa');
410
- }).should.throw;
411
- });
412
- });
413
-
414
- describe('#canProxy', function () {
415
- it('should have a #canProxy method', function () {
416
- d.canProxy.should.be.an.instanceof(Function);
417
- });
418
- it('should return a boolean from #canProxy', function () {
419
- d.canProxy(sessId).should.be.a('boolean');
420
- });
421
- it('should throw an error when sessionId is wrong', function () {
422
- (() => {
423
- d.canProxy();
424
- }).should.throw;
425
- });
426
- });
427
-
428
- describe('#proxyRouteIsAvoided', function () {
429
- it('should validate form of avoidance list', function () {
430
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
431
- // @ts-expect-error
432
- avoidStub.returns([['POST', /\/foo/], ['GET']]);
433
- (() => {
434
- // @ts-expect-error
435
- d.proxyRouteIsAvoided();
436
- }).should.throw;
437
- avoidStub.returns([
438
- ['POST', /\/foo/],
439
- // @ts-expect-error
440
- ['GET', /^foo/, 'bar'],
441
- ]);
442
- (() => {
443
- // @ts-expect-error
444
- d.proxyRouteIsAvoided();
445
- }).should.throw;
446
- });
447
- it('should reject bad http methods', function () {
448
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
449
- avoidStub.returns([
450
- ['POST', /^foo/],
451
- ['BAZETE', /^bar/],
452
- ]);
453
- (() => {
454
- // @ts-expect-error
455
- d.proxyRouteIsAvoided();
456
- }).should.throw;
457
- });
458
- it('should reject non-regex routes', function () {
459
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
460
- avoidStub.returns([
461
- ['POST', /^foo/],
462
- // @ts-expect-error
463
- ['GET', '/bar'],
464
- ]);
465
- (() => {
466
- // @ts-expect-error
467
- d.proxyRouteIsAvoided();
468
- }).should.throw;
469
- });
470
- it('should return true for routes in the avoid list', function () {
471
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
472
- avoidStub.returns([['POST', /^\/foo/]]);
473
- d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
474
- });
475
- it('should strip away any wd/hub prefix', function () {
476
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
477
- avoidStub.returns([['POST', /^\/foo/]]);
478
- d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
479
- });
480
- it('should return false for routes not in the avoid list', function () {
481
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
482
- avoidStub.returns([['POST', /^\/foo/]]);
483
- d.proxyRouteIsAvoided('foo', 'GET', '/foo/bar').should.be.false;
484
- d.proxyRouteIsAvoided('foo', 'POST', '/boo').should.be.false;
485
- });
486
- });
487
- });
488
-
489
- describe('event timing framework', function () {
490
- let beforeStartTime;
491
- beforeEach(async function () {
492
- beforeStartTime = Date.now();
493
- d.shouldValidateCaps = false;
494
- await d.executeCommand('createSession', null, null, {
495
- alwaysMatch: {...defaultCaps},
496
- firstMatch: [{}],
497
- });
498
- });
499
- describe('#eventHistory', function () {
500
- it('should have an eventHistory property', function () {
501
- should.exist(d.eventHistory);
502
- should.exist(d.eventHistory.commands);
503
- });
504
-
505
- it('should have a session start timing after session start', function () {
506
- let {newSessionRequested, newSessionStarted} = d.eventHistory;
507
- newSessionRequested.should.have.length(1);
508
- newSessionStarted.should.have.length(1);
509
- newSessionRequested[0].should.be.a('number');
510
- newSessionStarted[0].should.be.a('number');
511
- (newSessionRequested[0] >= beforeStartTime).should.be.true;
512
- (newSessionStarted[0] >= newSessionRequested[0]).should.be.true;
513
- });
514
-
515
- it('should include a commands list', async function () {
516
- await d.executeCommand('getStatus', []);
517
- d.eventHistory.commands.length.should.equal(2);
518
- d.eventHistory.commands[1].cmd.should.equal('getStatus');
519
- d.eventHistory.commands[1].startTime.should.be.a('number');
520
- d.eventHistory.commands[1].endTime.should.be.a('number');
521
- });
522
- });
523
- describe('#logEvent', function () {
524
- it('should allow logging arbitrary events', function () {
525
- d.logEvent('foo');
526
- d.eventHistory.foo[0].should.be.a('number');
527
- (d.eventHistory.foo[0] >= beforeStartTime).should.be.true;
528
- });
529
- it('should not allow reserved or oddly formed event names', function () {
530
- (() => {
531
- d.logEvent('commands');
532
- }).should.throw();
533
- (() => {
534
- // @ts-expect-error
535
- d.logEvent(1);
536
- }).should.throw();
537
- (() => {
538
- // @ts-expect-error
539
- d.logEvent({});
540
- }).should.throw();
541
- });
542
- });
543
- it('should allow logging the same event multiple times', function () {
544
- d.logEvent('bar');
545
- d.logEvent('bar');
546
- d.eventHistory.bar.should.have.length(2);
547
- d.eventHistory.bar[1].should.be.a('number');
548
- (d.eventHistory.bar[1] >= d.eventHistory.bar[0]).should.be.true;
549
- });
550
- describe('getSession decoration', function () {
551
- it('should decorate getSession response if opt-in cap is provided', async function () {
552
- let res = await d.getSession();
553
- should.not.exist(res.events);
554
-
555
- _.set(d, 'caps.eventTimings', true);
556
- res = await d.getSession();
557
- should.exist(res.events);
558
- should.exist(res.events?.newSessionRequested);
559
- expect(res.events?.newSessionRequested[0]).to.be.a('number');
560
- });
561
- });
562
- });
563
- describe('.reset', function () {
564
- it('should reset as W3C if the original session was W3C', async function () {
565
- const caps = {
566
- alwaysMatch: {
567
- 'appium:app': 'Fake',
568
- 'appium:deviceName': 'Fake',
569
- 'appium:automationName': 'Fake',
570
- platformName: 'Fake',
571
- ...defaultCaps,
572
- },
573
-
574
- firstMatch: [{}],
575
- };
576
- await d.createSession(caps);
577
- expect(d.protocol).to.equal('W3C');
578
- await d.reset();
579
- expect(d.protocol).to.equal('W3C');
580
- });
581
- });
582
- });
583
-
584
- describe('DeviceSettings', function () {
585
- it('should not hold on to reference of defaults in constructor', function () {
586
- let obj = {foo: 'bar'};
587
- let d1 = new DeviceSettings(obj);
588
- let d2 = new DeviceSettings(obj);
589
- d1.getSettings().foo = 'baz';
590
- d1.getSettings().should.not.eql(d2.getSettings());
591
- });
592
- });
593
-
594
- describe('.isFeatureEnabled', function () {
595
- let d;
596
-
597
- beforeEach(function () {
598
- d = new DriverClass();
599
- });
600
-
601
- it('should say a feature is enabled when it is explicitly allowed', function () {
602
- d.allowInsecure = ['foo', 'bar'];
603
- d.isFeatureEnabled('foo').should.be.true;
604
- d.isFeatureEnabled('bar').should.be.true;
605
- d.isFeatureEnabled('baz').should.be.false;
606
- });
607
-
608
- it('should say a feature is not enabled if it is not enabled', function () {
609
- d.allowInsecure = [];
610
- d.isFeatureEnabled('foo').should.be.false;
611
- });
612
-
613
- it('should prefer denyInsecure to allowInsecure', function () {
614
- d.allowInsecure = ['foo', 'bar'];
615
- d.denyInsecure = ['foo'];
616
- d.isFeatureEnabled('foo').should.be.false;
617
- d.isFeatureEnabled('bar').should.be.true;
618
- d.isFeatureEnabled('baz').should.be.false;
619
- });
620
-
621
- it('should allow global setting for insecurity', function () {
622
- d.relaxedSecurityEnabled = true;
623
- d.isFeatureEnabled('foo').should.be.true;
624
- d.isFeatureEnabled('bar').should.be.true;
625
- d.isFeatureEnabled('baz').should.be.true;
626
- });
627
-
628
- it('global setting should be overrideable', function () {
629
- d.relaxedSecurityEnabled = true;
630
- d.denyInsecure = ['foo', 'bar'];
631
- d.isFeatureEnabled('foo').should.be.false;
632
- d.isFeatureEnabled('bar').should.be.false;
633
- d.isFeatureEnabled('baz').should.be.true;
634
- });
635
- });
636
- }
637
-
638
- /**
639
- * @typedef {import('@appium/types').DriverClass} DriverClass
640
- * @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
641
- * @typedef {import('@appium/types').AppiumW3CCapabilities} AppiumW3CCapabilities
642
- */
package/lib/helpers.js DELETED
@@ -1,68 +0,0 @@
1
- import getPort from 'get-port';
2
- import {curry} from 'lodash';
3
-
4
- /**
5
- * Default test host
6
- */
7
- const TEST_HOST = '127.0.0.1';
8
-
9
- let testPort;
10
-
11
- /**
12
- * Returns a free port; one per process
13
- * @param {boolean} [force] - If true, do not reuse the port (if it already exists)
14
- * @returns {Promise<number>} a free port
15
- */
16
- async function getTestPort(force = false) {
17
- if (force || !testPort) {
18
- let 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
- */
34
- const createAppiumURL = curry(
35
- /**
36
- * @param {string} address - Base address (w/ optional protocol)
37
- * @param {string|number} port - Port number
38
- * @param {string?} session - Session ID
39
- * @param {string} pathname - Extra path
40
- * @returns {string} New URL
41
- * @example
42
- *
43
- * import _ from 'lodash';
44
- *
45
- * // http://127.0.0.1:31337/session
46
- * createAppiumURL('127.0.0.1', 31337, '', 'session')
47
- *
48
- * // http://127.0.0.1:31337/session/asdfgjkl
49
- * const createSessionURL = createAppiumURL('127.0.0.1', 31337, _, 'session')
50
- * createSessionURL('asdfgjkl')
51
- *
52
- * // http://127.0.0.1:31337/session/asdfgjkl/appium/execute
53
- * const createURLWithPath = createAppiumURL('127.0.0.1', 31337, 'asdfgjkl');
54
- * createURLWithPath('appium/execute')
55
- */
56
- (address, port, session, pathname) => {
57
- if (!/^https?:\/\//.test(address)) {
58
- address = `http://${address}`;
59
- }
60
- let path = session ? `session/${session}` : '';
61
- if (pathname) {
62
- path = `${path}/${pathname}`;
63
- }
64
- return new URL(path, `${address}:${port}`).href;
65
- }
66
- );
67
-
68
- export {TEST_HOST, getTestPort, createAppiumURL};