appium-xcuitest-driver 7.6.1 → 7.7.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/CHANGELOG.md +7 -0
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +9 -17
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +2 -4
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +3 -6
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/certificate.d.ts +1 -1
- package/build/lib/commands/certificate.d.ts.map +1 -1
- package/build/lib/commands/certificate.js +3 -5
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/condition.d.ts.map +1 -1
- package/build/lib/commands/condition.js +2 -4
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +1 -2
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceInfo.d.ts.map +1 -1
- package/build/lib/commands/deviceInfo.js +1 -2
- package/build/lib/commands/deviceInfo.js.map +1 -1
- package/build/lib/commands/file-movement.d.ts.map +1 -1
- package/build/lib/commands/file-movement.js +14 -22
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +1 -2
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/gesture.d.ts.map +1 -1
- package/build/lib/commands/gesture.js +1 -2
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/keychains.js +1 -2
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +1 -3
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.d.ts.map +1 -1
- package/build/lib/commands/location.js +1 -2
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +2 -4
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +2 -2
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/notifications.d.ts +1 -1
- package/build/lib/commands/notifications.d.ts.map +1 -1
- package/build/lib/commands/notifications.js +1 -2
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +2 -4
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.d.ts.map +1 -1
- package/build/lib/commands/pcap.js +1 -2
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +4 -9
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +2 -4
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +1 -2
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/screenshots.d.ts +3 -2
- package/build/lib/commands/screenshots.d.ts.map +1 -1
- package/build/lib/commands/screenshots.js +8 -3
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/web.d.ts.map +1 -1
- package/build/lib/commands/web.js +1 -2
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
- package/build/lib/commands/xctest-record-screen.js +2 -4
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/commands/xctest.d.ts.map +1 -1
- package/build/lib/commands/xctest.js +2 -4
- package/build/lib/commands/xctest.js.map +1 -1
- package/build/lib/driver.d.ts +26 -8
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +75 -77
- package/build/lib/driver.js.map +1 -1
- package/build/lib/py-ios-device-client.d.ts +1 -1
- package/build/lib/real-device-management.d.ts +30 -27
- package/build/lib/real-device-management.d.ts.map +1 -1
- package/build/lib/real-device-management.js +34 -35
- package/build/lib/real-device-management.js.map +1 -1
- package/build/lib/real-device.d.ts +36 -9
- package/build/lib/real-device.d.ts.map +1 -1
- package/build/lib/real-device.js +46 -15
- package/build/lib/real-device.js.map +1 -1
- package/build/lib/simulator-management.d.ts +58 -68
- package/build/lib/simulator-management.d.ts.map +1 -1
- package/build/lib/simulator-management.js +74 -66
- package/build/lib/simulator-management.js.map +1 -1
- package/lib/commands/app-management.js +11 -18
- package/lib/commands/appearance.js +4 -4
- package/lib/commands/biometric.js +3 -6
- package/lib/commands/certificate.js +3 -5
- package/lib/commands/condition.js +2 -4
- package/lib/commands/context.js +1 -2
- package/lib/commands/deviceInfo.js +1 -2
- package/lib/commands/file-movement.js +14 -22
- package/lib/commands/general.js +1 -2
- package/lib/commands/gesture.js +1 -2
- package/lib/commands/keychains.js +2 -2
- package/lib/commands/localization.js +1 -4
- package/lib/commands/location.js +1 -2
- package/lib/commands/log.js +2 -4
- package/lib/commands/memory.js +2 -2
- package/lib/commands/notifications.js +1 -2
- package/lib/commands/pasteboard.js +4 -4
- package/lib/commands/pcap.js +1 -2
- package/lib/commands/performance.js +4 -8
- package/lib/commands/permissions.js +6 -4
- package/lib/commands/recordscreen.js +1 -2
- package/lib/commands/screenshots.js +8 -3
- package/lib/commands/web.js +1 -2
- package/lib/commands/xctest-record-screen.js +2 -4
- package/lib/commands/xctest.js +2 -4
- package/lib/driver.js +79 -78
- package/lib/real-device-management.js +37 -44
- package/lib/real-device.js +47 -17
- package/lib/simulator-management.js +83 -82
- package/npm-shrinkwrap.json +7 -29
- package/package.json +2 -2
package/lib/real-device.js
CHANGED
|
@@ -2,7 +2,7 @@ import {fs, timing, util} from 'appium/support';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import {services, utilities, INSTRUMENT_CHANNEL} from 'appium-ios-device';
|
|
4
4
|
import B from 'bluebird';
|
|
5
|
-
import
|
|
5
|
+
import defaultLogger from './logger';
|
|
6
6
|
import _ from 'lodash';
|
|
7
7
|
import {exec} from 'teen_process';
|
|
8
8
|
import {extractBundleId} from './app-utils';
|
|
@@ -20,12 +20,27 @@ const APP_INSTALL_STRATEGY = Object.freeze({
|
|
|
20
20
|
IOS_DEPLOY,
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
class RealDevice {
|
|
23
|
+
export class RealDevice {
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} udid
|
|
26
|
+
* @param {import('@appium/types').AppiumLogger} [logger]
|
|
27
|
+
*/
|
|
24
28
|
constructor(udid, logger) {
|
|
25
29
|
this.udid = udid;
|
|
26
|
-
this.
|
|
30
|
+
this._log = logger ?? defaultLogger;
|
|
31
|
+
this.devicectl = new Devicectl(this.udid, this._log);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @returns {import('@appium/types').AppiumLogger}
|
|
36
|
+
*/
|
|
37
|
+
get log() {
|
|
38
|
+
return this._log;
|
|
27
39
|
}
|
|
28
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} bundleId
|
|
43
|
+
*/
|
|
29
44
|
async remove(bundleId) {
|
|
30
45
|
const service = await services.startInstallationProxyService(this.udid);
|
|
31
46
|
try {
|
|
@@ -35,6 +50,9 @@ class RealDevice {
|
|
|
35
50
|
}
|
|
36
51
|
}
|
|
37
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} bundleId
|
|
55
|
+
*/
|
|
38
56
|
async removeApp(bundleId) {
|
|
39
57
|
await this.remove(bundleId);
|
|
40
58
|
}
|
|
@@ -56,7 +74,7 @@ class RealDevice {
|
|
|
56
74
|
`Only the following strategies are supported: ${_.values(APP_INSTALL_STRATEGY)}`,
|
|
57
75
|
);
|
|
58
76
|
}
|
|
59
|
-
log.debug(
|
|
77
|
+
this.log.debug(
|
|
60
78
|
`Using '${strategy ?? APP_INSTALL_STRATEGY.SERIAL}' app deployment strategy. ` +
|
|
61
79
|
`You could change it by providing another value to the 'appInstallStrategy' capability`,
|
|
62
80
|
);
|
|
@@ -94,11 +112,11 @@ class RealDevice {
|
|
|
94
112
|
await this.isAppInstalled(bundleId),
|
|
95
113
|
);
|
|
96
114
|
} catch (err) {
|
|
97
|
-
log.warn(`Error installing app '${app}': ${err.message}`);
|
|
115
|
+
this.log.warn(`Error installing app '${app}': ${err.message}`);
|
|
98
116
|
if (err instanceof B.TimeoutError) {
|
|
99
|
-
log.warn(`Consider increasing the value of 'appPushTimeout' capability`);
|
|
117
|
+
this.log.warn(`Consider increasing the value of 'appPushTimeout' capability`);
|
|
100
118
|
}
|
|
101
|
-
log.warn(`Falling back to '${IOS_DEPLOY}' usage`);
|
|
119
|
+
this.log.warn(`Falling back to '${IOS_DEPLOY}' usage`);
|
|
102
120
|
try {
|
|
103
121
|
await installWithIosDeploy();
|
|
104
122
|
} catch (err1) {
|
|
@@ -110,9 +128,13 @@ class RealDevice {
|
|
|
110
128
|
afcService.close();
|
|
111
129
|
}
|
|
112
130
|
}
|
|
113
|
-
log.info(`App installation succeeded after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
131
|
+
this.log.info(`App installation succeeded after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @param {string} bundlePathOnPhone
|
|
136
|
+
* @param {boolean} [isUpgrade=false]
|
|
137
|
+
*/
|
|
116
138
|
async installOrUpgradeApplication(bundlePathOnPhone, isUpgrade = false) {
|
|
117
139
|
const notificationService = await services.startNotificationProxyService(this.udid);
|
|
118
140
|
const installationService = await services.startInstallationProxyService(this.udid);
|
|
@@ -124,10 +146,10 @@ class RealDevice {
|
|
|
124
146
|
const clientOptions = {PackageType: 'Developer'};
|
|
125
147
|
try {
|
|
126
148
|
if (isUpgrade) {
|
|
127
|
-
log.debug(`An upgrade of the existing application is going to be performed`);
|
|
149
|
+
this.log.debug(`An upgrade of the existing application is going to be performed`);
|
|
128
150
|
await installationService.upgradeApplication(bundlePathOnPhone, clientOptions);
|
|
129
151
|
} else {
|
|
130
|
-
log.debug(`A new application installation is going to be performed`);
|
|
152
|
+
this.log.debug(`A new application installation is going to be performed`);
|
|
131
153
|
await installationService.installApplication(bundlePathOnPhone, clientOptions);
|
|
132
154
|
}
|
|
133
155
|
try {
|
|
@@ -137,7 +159,7 @@ class RealDevice {
|
|
|
137
159
|
`${APPLICATION_NOTIFICATION_TIMEOUT_MS}ms but we will continue`,
|
|
138
160
|
);
|
|
139
161
|
} catch (e) {
|
|
140
|
-
log.warn(`Failed to receive the notification. Error: ${e.message}`);
|
|
162
|
+
this.log.warn(`Failed to receive the notification. Error: ${e.message}`);
|
|
141
163
|
}
|
|
142
164
|
} finally {
|
|
143
165
|
installationService.close();
|
|
@@ -194,6 +216,11 @@ class RealDevice {
|
|
|
194
216
|
}
|
|
195
217
|
}
|
|
196
218
|
|
|
219
|
+
/**
|
|
220
|
+
* @param {string} bundleId
|
|
221
|
+
* @param {string} platformVersion
|
|
222
|
+
* @returns {Promise<boolean>}
|
|
223
|
+
*/
|
|
197
224
|
async terminateApp(bundleId, platformVersion) {
|
|
198
225
|
let instrumentService;
|
|
199
226
|
let installProxyService;
|
|
@@ -203,22 +230,22 @@ class RealDevice {
|
|
|
203
230
|
returnAttributes: ['CFBundleIdentifier', 'CFBundleExecutable']
|
|
204
231
|
});
|
|
205
232
|
if (!apps[bundleId]) {
|
|
206
|
-
log.info(`The bundle id '${bundleId}' did not exist`);
|
|
233
|
+
this.log.info(`The bundle id '${bundleId}' did not exist`);
|
|
207
234
|
return false;
|
|
208
235
|
}
|
|
209
236
|
const executableName = apps[bundleId].CFBundleExecutable;
|
|
210
|
-
log.debug(`The executable name for the bundle id '${bundleId}' was '${executableName}'`);
|
|
237
|
+
this.log.debug(`The executable name for the bundle id '${bundleId}' was '${executableName}'`);
|
|
211
238
|
|
|
212
239
|
// 'devicectl' has overhead (generally?) than the instrument service via appium-ios-device,
|
|
213
240
|
// so hre uses the 'devicectl' only for iOS 17+.
|
|
214
241
|
if (util.compareVersions(platformVersion, '>=', '17.0')) {
|
|
215
|
-
log.debug(`Calling devicectl to kill the process`);
|
|
242
|
+
this.log.debug(`Calling devicectl to kill the process`);
|
|
216
243
|
|
|
217
244
|
const pids = (await this.devicectl.listProcesses())
|
|
218
245
|
.filter(({executable}) => executable.endsWith(`/${executableName}`))
|
|
219
246
|
.map(({processIdentifier}) => processIdentifier);
|
|
220
247
|
if (_.isEmpty(pids)) {
|
|
221
|
-
log.info(`The process of the bundle id '${bundleId}' was not running`);
|
|
248
|
+
this.log.info(`The process of the bundle id '${bundleId}' was not running`);
|
|
222
249
|
return false;
|
|
223
250
|
}
|
|
224
251
|
await this.devicectl.sendSignalToProcess(pids[0], 2);
|
|
@@ -230,7 +257,7 @@ class RealDevice {
|
|
|
230
257
|
);
|
|
231
258
|
const process = processes.selector.find((process) => process.name === executableName);
|
|
232
259
|
if (!process) {
|
|
233
|
-
log.info(`The process of the bundle id '${bundleId}' was not running`);
|
|
260
|
+
this.log.info(`The process of the bundle id '${bundleId}' was not running`);
|
|
234
261
|
return false;
|
|
235
262
|
}
|
|
236
263
|
await instrumentService.callChannel(
|
|
@@ -240,7 +267,7 @@ class RealDevice {
|
|
|
240
267
|
);
|
|
241
268
|
}
|
|
242
269
|
} catch (err) {
|
|
243
|
-
log.warn(`Failed to kill '${bundleId}'. Original error: ${err.stderr || err.message}`);
|
|
270
|
+
this.log.warn(`Failed to kill '${bundleId}'. Original error: ${err.stderr || err.message}`);
|
|
244
271
|
return false;
|
|
245
272
|
} finally {
|
|
246
273
|
if (installProxyService) {
|
|
@@ -280,6 +307,9 @@ class RealDevice {
|
|
|
280
307
|
}
|
|
281
308
|
}
|
|
282
309
|
|
|
310
|
+
/**
|
|
311
|
+
* @returns {Promise<string>}
|
|
312
|
+
*/
|
|
283
313
|
async getPlatformVersion() {
|
|
284
314
|
return await utilities.getOSVersion(this.udid);
|
|
285
315
|
}
|
|
@@ -2,7 +2,6 @@ import {getSimulator} from 'appium-ios-simulator';
|
|
|
2
2
|
import Simctl from 'node-simctl';
|
|
3
3
|
import {resetTestProcesses} from 'appium-webdriveragent';
|
|
4
4
|
import _ from 'lodash';
|
|
5
|
-
import log from './logger';
|
|
6
5
|
import {util, timing} from 'appium/support';
|
|
7
6
|
import {UDID_AUTO, normalizePlatformName} from './utils';
|
|
8
7
|
|
|
@@ -16,22 +15,15 @@ const SAFARI_OPTS_ALIASES_MAP = /** @type {const} */ ({
|
|
|
16
15
|
safariOpenLinksInBackground: [['OpenLinksInBackground'], (x) => Number(Boolean(x))],
|
|
17
16
|
});
|
|
18
17
|
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {Object} SimulatorCreationOptions
|
|
21
|
-
* @property {string} deviceName - A name for the device
|
|
22
|
-
* @property {string} platformVersion - The version of iOS to use
|
|
23
|
-
* @property {string} [simulatorDevicesSetPath]
|
|
24
|
-
* @property {string} [platformName]
|
|
25
|
-
*/
|
|
26
18
|
/**
|
|
27
19
|
* Create a new simulator with `appiumTest-` prefix and return the object.
|
|
28
20
|
*
|
|
29
|
-
* @
|
|
21
|
+
* @this {import('./driver').XCUITestDriver}
|
|
30
22
|
* @returns {Promise<object>} Simulator object associated with the udid passed in.
|
|
31
23
|
*/
|
|
32
|
-
async function createSim(
|
|
33
|
-
const {simulatorDevicesSetPath: devicesSetPath, deviceName, platformVersion} =
|
|
34
|
-
const platform = normalizePlatformName(
|
|
24
|
+
export async function createSim() {
|
|
25
|
+
const {simulatorDevicesSetPath: devicesSetPath, deviceName, platformVersion} = this.opts;
|
|
26
|
+
const platform = normalizePlatformName(this.opts.platformName);
|
|
35
27
|
const simctl = new Simctl({devicesSetPath});
|
|
36
28
|
if (!deviceName) {
|
|
37
29
|
let deviceNames = 'none';
|
|
@@ -51,12 +43,13 @@ async function createSim(caps) {
|
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
const simName = `${APPIUM_SIM_PREFIX}-${util.uuidV4().toUpperCase()}-${deviceName}`;
|
|
54
|
-
log.debug(`Creating a temporary Simulator device '${simName}'`);
|
|
46
|
+
this.log.debug(`Creating a temporary Simulator device '${simName}'`);
|
|
55
47
|
const udid = await simctl.createDevice(simName, deviceName, platformVersion, {platform});
|
|
56
48
|
return await getSimulator(udid, {
|
|
57
49
|
platform,
|
|
58
50
|
checkExistence: false,
|
|
59
51
|
devicesSetPath,
|
|
52
|
+
logger: this.log,
|
|
60
53
|
});
|
|
61
54
|
}
|
|
62
55
|
|
|
@@ -72,24 +65,31 @@ async function createSim(caps) {
|
|
|
72
65
|
/**
|
|
73
66
|
* Get an existing simulator matching the provided capabilities.
|
|
74
67
|
*
|
|
75
|
-
* @
|
|
76
|
-
* @returns {Promise<
|
|
68
|
+
* @this {import('./driver').XCUITestDriver}
|
|
69
|
+
* @returns {Promise<import('./driver').Simulator|null>} The matched Simulator instance or `null` if no matching device is found.
|
|
77
70
|
*/
|
|
78
|
-
async function getExistingSim(
|
|
79
|
-
const {
|
|
71
|
+
export async function getExistingSim() {
|
|
72
|
+
const {
|
|
73
|
+
platformVersion,
|
|
74
|
+
deviceName,
|
|
75
|
+
udid,
|
|
76
|
+
simulatorDevicesSetPath: devicesSetPath,
|
|
77
|
+
platformName,
|
|
78
|
+
} = this.opts;
|
|
80
79
|
|
|
81
|
-
const platform = normalizePlatformName(
|
|
80
|
+
const platform = normalizePlatformName(platformName);
|
|
82
81
|
const selectSim = async (/** @type {{ udid: string; platform: string; }} */ dev) =>
|
|
83
82
|
await getSimulator(dev.udid, {
|
|
84
83
|
platform,
|
|
85
84
|
checkExistence: false,
|
|
86
85
|
devicesSetPath,
|
|
86
|
+
logger: this.log,
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
const simctl = new Simctl({devicesSetPath});
|
|
90
90
|
let devicesMap;
|
|
91
91
|
if (udid && _.toLower(udid) !== UDID_AUTO) {
|
|
92
|
-
log.debug(`Looking for an existing Simulator with UDID '${udid}'`);
|
|
92
|
+
this.log.debug(`Looking for an existing Simulator with UDID '${udid}'`);
|
|
93
93
|
devicesMap = await simctl.getDevices(null, platform);
|
|
94
94
|
for (const device of _.flatMap(_.values(devicesMap))) {
|
|
95
95
|
if (device.udid === udid) {
|
|
@@ -100,7 +100,7 @@ async function getExistingSim(opts = /** @type {SimulatorLookupOptions} */ ({}))
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
if (!platformVersion) {
|
|
103
|
-
log.debug(
|
|
103
|
+
this.log.debug(
|
|
104
104
|
`Provide 'platformVersion' capability if you prefer an existing Simulator to be selected`,
|
|
105
105
|
);
|
|
106
106
|
return null;
|
|
@@ -108,14 +108,14 @@ async function getExistingSim(opts = /** @type {SimulatorLookupOptions} */ ({}))
|
|
|
108
108
|
|
|
109
109
|
const devices =
|
|
110
110
|
devicesMap?.[platformVersion] ?? (await simctl.getDevices(platformVersion, platform));
|
|
111
|
-
log.debug(
|
|
111
|
+
this.log.debug(
|
|
112
112
|
`Looking for an existing Simulator with platformName: ${platform}, ` +
|
|
113
113
|
`platformVersion: ${platformVersion}, deviceName: ${deviceName}`,
|
|
114
114
|
);
|
|
115
115
|
for (const device of devices) {
|
|
116
116
|
if ((deviceName && device.name === deviceName) || !deviceName) {
|
|
117
117
|
if (!deviceName) {
|
|
118
|
-
log.debug(
|
|
118
|
+
this.log.debug(
|
|
119
119
|
`The 'deviceName' capability value is empty. ` +
|
|
120
120
|
`Selecting the first matching device '${device.name}' having the ` +
|
|
121
121
|
`'platformVersion' set to ${platformVersion}`,
|
|
@@ -127,13 +127,22 @@ async function getExistingSim(opts = /** @type {SimulatorLookupOptions} */ ({}))
|
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
/**
|
|
131
|
+
* @this {import('./driver').XCUITestDriver}
|
|
132
|
+
*/
|
|
133
|
+
export async function shutdownSimulator() {
|
|
134
|
+
const device = /** @type {import('./driver').Simulator} */ (this.device);
|
|
131
135
|
// stop XCTest processes if running to avoid unexpected side effects
|
|
132
136
|
await resetTestProcesses(device.udid, true);
|
|
133
137
|
await device.shutdown();
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
/**
|
|
141
|
+
* @this {import('./driver').XCUITestDriver}
|
|
142
|
+
* @property {boolean} [enforceSimulatorShutdown=false]
|
|
143
|
+
* @returns {Promise<void>}
|
|
144
|
+
*/
|
|
145
|
+
export async function runSimulatorReset(enforceSimulatorShutdown = false) {
|
|
137
146
|
const {
|
|
138
147
|
noReset,
|
|
139
148
|
fullReset,
|
|
@@ -142,29 +151,29 @@ async function runSimulatorReset(device, opts) {
|
|
|
142
151
|
bundleId,
|
|
143
152
|
app,
|
|
144
153
|
browserName,
|
|
145
|
-
|
|
146
|
-
} = opts;
|
|
154
|
+
} = this.opts;
|
|
147
155
|
if (noReset && !fullReset) {
|
|
148
156
|
// noReset === true && fullReset === false
|
|
149
|
-
log.debug('Reset: noReset is on. Leaving simulator as is');
|
|
157
|
+
this.log.debug('Reset: noReset is on. Leaving simulator as is');
|
|
150
158
|
return;
|
|
151
159
|
}
|
|
152
|
-
|
|
153
|
-
|
|
160
|
+
const device = /** @type {import('./driver').Simulator} */ (this.device);
|
|
161
|
+
|
|
162
|
+
if (!this.device) {
|
|
163
|
+
this.log.debug('Reset: no device available. Skipping');
|
|
154
164
|
return;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
if (fullReset) {
|
|
158
|
-
log.debug('Reset: fullReset is on. Cleaning simulator');
|
|
159
|
-
await shutdownSimulator(
|
|
160
|
-
const isKeychainsBackupSuccessful =
|
|
161
|
-
(keychainsExcludePatterns || keepKeyChains) && (await device.backupKeychains());
|
|
168
|
+
this.log.debug('Reset: fullReset is on. Cleaning simulator');
|
|
169
|
+
await shutdownSimulator.bind(this)();
|
|
170
|
+
const isKeychainsBackupSuccessful = (keychainsExcludePatterns || keepKeyChains) && (await device.backupKeychains());
|
|
162
171
|
await device.clean();
|
|
163
172
|
if (isKeychainsBackupSuccessful) {
|
|
164
173
|
await device.restoreKeychains(keychainsExcludePatterns || []);
|
|
165
|
-
log.info(`Successfully restored keychains after full reset`);
|
|
174
|
+
this.log.info(`Successfully restored keychains after full reset`);
|
|
166
175
|
} else if (keychainsExcludePatterns || keepKeyChains) {
|
|
167
|
-
log.warn(
|
|
176
|
+
this.log.warn(
|
|
168
177
|
'Cannot restore keychains after full reset, because ' +
|
|
169
178
|
'the backup operation did not succeed',
|
|
170
179
|
);
|
|
@@ -176,32 +185,32 @@ async function runSimulatorReset(device, opts) {
|
|
|
176
185
|
try {
|
|
177
186
|
await device.terminateApp(bundleId);
|
|
178
187
|
} catch (err) {
|
|
179
|
-
log.warn(`Reset: failed to terminate Simulator application with id "${bundleId}"`);
|
|
188
|
+
this.log.warn(`Reset: failed to terminate Simulator application with id "${bundleId}"`);
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
if (app) {
|
|
183
|
-
log.info('Not scrubbing third party app in anticipation of uninstall');
|
|
192
|
+
this.log.info('Not scrubbing third party app in anticipation of uninstall');
|
|
184
193
|
} else {
|
|
185
194
|
const isSafari = _.toLower(browserName) === 'safari';
|
|
186
195
|
try {
|
|
187
196
|
if (isSafari) {
|
|
188
|
-
await device.scrubSafari();
|
|
197
|
+
await device.scrubSafari(true);
|
|
189
198
|
} else {
|
|
190
199
|
await device.scrubApp(bundleId);
|
|
191
200
|
}
|
|
192
201
|
} catch (err) {
|
|
193
|
-
log.debug(err.stack);
|
|
194
|
-
log.warn(err.message);
|
|
195
|
-
log.warn(
|
|
202
|
+
this.log.debug(err.stack);
|
|
203
|
+
this.log.warn(err.message);
|
|
204
|
+
this.log.warn(
|
|
196
205
|
`Reset: could not scrub ${
|
|
197
|
-
isSafari ? 'Safari browser' : 'application with id "' + opts.bundleId + '"'
|
|
206
|
+
isSafari ? 'Safari browser' : 'application with id "' + this.opts.bundleId + '"'
|
|
198
207
|
}. ` + `Leaving as is.`,
|
|
199
208
|
);
|
|
200
209
|
}
|
|
201
210
|
}
|
|
202
211
|
|
|
203
212
|
if (enforceSimulatorShutdown && (await device.isRunning())) {
|
|
204
|
-
await shutdownSimulator(device);
|
|
213
|
+
await shutdownSimulator.bind(this)(device);
|
|
205
214
|
}
|
|
206
215
|
}
|
|
207
216
|
}
|
|
@@ -214,48 +223,52 @@ async function runSimulatorReset(device, opts) {
|
|
|
214
223
|
*/
|
|
215
224
|
|
|
216
225
|
/**
|
|
217
|
-
* @
|
|
226
|
+
* @this {import('./driver').XCUITestDriver}
|
|
218
227
|
* @param {string} app The app to the path
|
|
219
228
|
* @param {string} [bundleId] The bundle id to ensure it is already installed and uninstall it
|
|
220
|
-
* @param {InstallOptions} opts
|
|
229
|
+
* @param {InstallOptions} [opts={}]
|
|
221
230
|
*/
|
|
222
|
-
async function installToSimulator(
|
|
223
|
-
device,
|
|
231
|
+
export async function installToSimulator(
|
|
224
232
|
app,
|
|
225
233
|
bundleId,
|
|
226
|
-
opts =
|
|
234
|
+
opts = {},
|
|
227
235
|
) {
|
|
228
236
|
if (!app) {
|
|
229
|
-
log.debug('No app path is given. Nothing to install.');
|
|
237
|
+
this.log.debug('No app path is given. Nothing to install.');
|
|
230
238
|
return;
|
|
231
239
|
}
|
|
232
240
|
|
|
233
241
|
const {skipUninstall, newSimulator = false} = opts;
|
|
242
|
+
const device = /** @type {import('./driver').Simulator} */ (this.device);
|
|
234
243
|
|
|
235
244
|
if (!skipUninstall && !newSimulator && bundleId && (await device.isAppInstalled(bundleId))) {
|
|
236
|
-
log.debug(`Reset requested. Removing app with id '${bundleId}' from the device`);
|
|
245
|
+
this.log.debug(`Reset requested. Removing app with id '${bundleId}' from the device`);
|
|
237
246
|
await device.removeApp(bundleId);
|
|
238
247
|
}
|
|
239
248
|
|
|
240
|
-
log.debug(`Installing '${app}' on Simulator with UUID '${device.udid}'...`);
|
|
249
|
+
this.log.debug(`Installing '${app}' on Simulator with UUID '${device.udid}'...`);
|
|
241
250
|
const timer = new timing.Timer().start();
|
|
242
251
|
await device.installApp(app);
|
|
243
|
-
log.info(`The app has been successfully installed in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
252
|
+
this.log.info(`The app has been successfully installed in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
244
253
|
}
|
|
245
254
|
|
|
246
|
-
|
|
255
|
+
/**
|
|
256
|
+
* @this {import('./driver').XCUITestDriver}
|
|
257
|
+
*/
|
|
258
|
+
export async function shutdownOtherSimulators() {
|
|
259
|
+
const device = /** @type {import('./driver').Simulator} */ (this.device);
|
|
247
260
|
const simctl = new Simctl({
|
|
248
|
-
devicesSetPath:
|
|
261
|
+
devicesSetPath: device.devicesSetPath,
|
|
249
262
|
});
|
|
250
263
|
const allDevices = _.flatMap(_.values(await simctl.getDevices()));
|
|
251
264
|
const otherBootedDevices = allDevices.filter(
|
|
252
|
-
(device) => device.udid !==
|
|
265
|
+
(device) => device.udid !== device.udid && device.state === 'Booted',
|
|
253
266
|
);
|
|
254
267
|
if (_.isEmpty(otherBootedDevices)) {
|
|
255
|
-
log.info('No other running simulators have been detected');
|
|
268
|
+
this.log.info('No other running simulators have been detected');
|
|
256
269
|
return;
|
|
257
270
|
}
|
|
258
|
-
log.info(
|
|
271
|
+
this.log.info(
|
|
259
272
|
`Detected ${otherBootedDevices.length} other running ${util.pluralize(
|
|
260
273
|
'Simulator',
|
|
261
274
|
otherBootedDevices.length,
|
|
@@ -273,40 +286,39 @@ async function shutdownOtherSimulators(currentDevice) {
|
|
|
273
286
|
/**
|
|
274
287
|
* Configures Safari options based on the given session capabilities
|
|
275
288
|
*
|
|
276
|
-
* @
|
|
277
|
-
* @param {object} opts Session capabilities
|
|
289
|
+
* @this {import('./driver').XCUITestDriver}
|
|
278
290
|
* @return {Promise<boolean>} true if any preferences have been updated
|
|
279
291
|
*/
|
|
280
|
-
async function setSafariPrefs(
|
|
281
|
-
const safariSettings = _.cloneDeep(opts.safariGlobalPreferences ?? {});
|
|
292
|
+
export async function setSafariPrefs() {
|
|
293
|
+
const safariSettings = _.cloneDeep(this.opts.safariGlobalPreferences ?? {});
|
|
282
294
|
|
|
283
295
|
for (const [name, [aliases, valueConverter]] of _.toPairs(SAFARI_OPTS_ALIASES_MAP)) {
|
|
284
|
-
if (!_.has(opts, name)) {
|
|
296
|
+
if (!_.has(this.opts, name)) {
|
|
285
297
|
continue;
|
|
286
298
|
}
|
|
287
299
|
|
|
288
300
|
for (const alias of aliases) {
|
|
289
|
-
safariSettings[alias] = valueConverter(opts[name]);
|
|
301
|
+
safariSettings[alias] = valueConverter(this.opts[name]);
|
|
290
302
|
}
|
|
291
303
|
}
|
|
292
304
|
if (_.isEmpty(safariSettings)) {
|
|
293
305
|
return false;
|
|
294
306
|
}
|
|
295
307
|
|
|
296
|
-
log.debug(`About to update Safari preferences: ${JSON.stringify(safariSettings)}`);
|
|
297
|
-
await
|
|
308
|
+
this.log.debug(`About to update Safari preferences: ${JSON.stringify(safariSettings)}`);
|
|
309
|
+
await /** @type {import('./driver').Simulator} */ (this.device).updateSafariSettings(safariSettings);
|
|
298
310
|
return true;
|
|
299
311
|
}
|
|
300
312
|
|
|
301
313
|
/**
|
|
302
314
|
* Changes Simulator localization preferences
|
|
303
315
|
*
|
|
304
|
-
* @
|
|
305
|
-
* @param {object} opts Session capabilities
|
|
316
|
+
* @this {import('./driver').XCUITestDriver}
|
|
306
317
|
* @returns {Promise<boolean>} True if preferences were changed
|
|
307
318
|
*/
|
|
308
|
-
async function setLocalizationPrefs(
|
|
309
|
-
const {language, locale, calendarFormat, skipSyncUiDialogTranslation} = opts;
|
|
319
|
+
export async function setLocalizationPrefs() {
|
|
320
|
+
const {language, locale, calendarFormat, skipSyncUiDialogTranslation} = this.opts;
|
|
321
|
+
/** @type {import('appium-ios-simulator').LocalizationOptions} */
|
|
310
322
|
const l10nConfig = {};
|
|
311
323
|
if (language) {
|
|
312
324
|
l10nConfig.language = {name: language, skipSyncUiDialogTranslation };
|
|
@@ -321,18 +333,7 @@ async function setLocalizationPrefs(sim, opts = {}) {
|
|
|
321
333
|
return false;
|
|
322
334
|
}
|
|
323
335
|
|
|
324
|
-
log.debug(`About to update localization preferences: ${JSON.stringify(l10nConfig)}`);
|
|
325
|
-
await
|
|
336
|
+
this.log.debug(`About to update localization preferences: ${JSON.stringify(l10nConfig)}`);
|
|
337
|
+
await /** @type {import('./driver').Simulator} */ (this.device).configureLocalization(l10nConfig);
|
|
326
338
|
return true;
|
|
327
339
|
}
|
|
328
|
-
|
|
329
|
-
export {
|
|
330
|
-
createSim,
|
|
331
|
-
getExistingSim,
|
|
332
|
-
runSimulatorReset,
|
|
333
|
-
installToSimulator,
|
|
334
|
-
shutdownSimulator,
|
|
335
|
-
shutdownOtherSimulators,
|
|
336
|
-
setSafariPrefs,
|
|
337
|
-
setLocalizationPrefs,
|
|
338
|
-
};
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-xcuitest-driver",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.7.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-xcuitest-driver",
|
|
9
|
-
"version": "7.
|
|
9
|
+
"version": "7.7.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@colors/colors": "^1.6.0",
|
|
13
13
|
"appium-idb": "^1.6.13",
|
|
14
14
|
"appium-ios-device": "^2.5.4",
|
|
15
|
-
"appium-ios-simulator": "^
|
|
15
|
+
"appium-ios-simulator": "^6.1.2",
|
|
16
16
|
"appium-remote-debugger": "^11.0.0",
|
|
17
17
|
"appium-webdriveragent": "^8.1.0",
|
|
18
18
|
"appium-xcode": "^5.1.4",
|
|
@@ -955,9 +955,9 @@
|
|
|
955
955
|
}
|
|
956
956
|
},
|
|
957
957
|
"node_modules/appium-ios-simulator": {
|
|
958
|
-
"version": "
|
|
959
|
-
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-
|
|
960
|
-
"integrity": "sha512-
|
|
958
|
+
"version": "6.1.2",
|
|
959
|
+
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-6.1.2.tgz",
|
|
960
|
+
"integrity": "sha512-uE/qHQvf5WfogsjpPFo+iJE6NVTFCJReV3RxP0TwN/qYvbRWxJFMwpHzx6VGy7Lp86B2O+0ZWgkTDPZ1iJxAKw==",
|
|
961
961
|
"dependencies": {
|
|
962
962
|
"@appium/support": "^4.0.0",
|
|
963
963
|
"@xmldom/xmldom": "^0.x",
|
|
@@ -966,7 +966,7 @@
|
|
|
966
966
|
"asyncbox": "^3.0.0",
|
|
967
967
|
"bluebird": "^3.5.1",
|
|
968
968
|
"lodash": "^4.2.1",
|
|
969
|
-
"node-simctl": "^7.1
|
|
969
|
+
"node-simctl": "^7.4.1",
|
|
970
970
|
"semver": "^7.0.0",
|
|
971
971
|
"source-map-support": "^0.x",
|
|
972
972
|
"teen_process": "^2.0.0"
|
|
@@ -1021,28 +1021,6 @@
|
|
|
1021
1021
|
"npm": ">=8"
|
|
1022
1022
|
}
|
|
1023
1023
|
},
|
|
1024
|
-
"node_modules/appium-webdriveragent/node_modules/appium-ios-simulator": {
|
|
1025
|
-
"version": "6.1.2",
|
|
1026
|
-
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-6.1.2.tgz",
|
|
1027
|
-
"integrity": "sha512-uE/qHQvf5WfogsjpPFo+iJE6NVTFCJReV3RxP0TwN/qYvbRWxJFMwpHzx6VGy7Lp86B2O+0ZWgkTDPZ1iJxAKw==",
|
|
1028
|
-
"dependencies": {
|
|
1029
|
-
"@appium/support": "^4.0.0",
|
|
1030
|
-
"@xmldom/xmldom": "^0.x",
|
|
1031
|
-
"appium-xcode": "^5.0.0",
|
|
1032
|
-
"async-lock": "^1.0.0",
|
|
1033
|
-
"asyncbox": "^3.0.0",
|
|
1034
|
-
"bluebird": "^3.5.1",
|
|
1035
|
-
"lodash": "^4.2.1",
|
|
1036
|
-
"node-simctl": "^7.4.1",
|
|
1037
|
-
"semver": "^7.0.0",
|
|
1038
|
-
"source-map-support": "^0.x",
|
|
1039
|
-
"teen_process": "^2.0.0"
|
|
1040
|
-
},
|
|
1041
|
-
"engines": {
|
|
1042
|
-
"node": ">=14",
|
|
1043
|
-
"npm": ">=8"
|
|
1044
|
-
}
|
|
1045
|
-
},
|
|
1046
1024
|
"node_modules/appium-xcode": {
|
|
1047
1025
|
"version": "5.2.11",
|
|
1048
1026
|
"resolved": "https://registry.npmjs.org/appium-xcode/-/appium-xcode-5.2.11.tgz",
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"xcuitest",
|
|
9
9
|
"xctest"
|
|
10
10
|
],
|
|
11
|
-
"version": "7.
|
|
11
|
+
"version": "7.7.0",
|
|
12
12
|
"author": "Appium Contributors",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"repository": {
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@colors/colors": "^1.6.0",
|
|
80
80
|
"appium-idb": "^1.6.13",
|
|
81
81
|
"appium-ios-device": "^2.5.4",
|
|
82
|
-
"appium-ios-simulator": "^
|
|
82
|
+
"appium-ios-simulator": "^6.1.2",
|
|
83
83
|
"appium-remote-debugger": "^11.0.0",
|
|
84
84
|
"appium-webdriveragent": "^8.1.0",
|
|
85
85
|
"appium-xcode": "^5.1.4",
|