appium-ios-simulator 8.1.3 → 8.2.1
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 +12 -0
- package/build/lib/extensions/settings.js +5 -5
- package/build/lib/extensions/settings.js.map +1 -1
- package/build/lib/simulator-xcode-14.d.ts +2 -0
- package/build/lib/simulator-xcode-14.d.ts.map +1 -1
- package/build/lib/simulator-xcode-14.js +18 -20
- package/build/lib/simulator-xcode-14.js.map +1 -1
- package/build/lib/simulator-xcode-15.d.ts.map +1 -1
- package/build/lib/simulator-xcode-15.js +2 -16
- package/build/lib/simulator-xcode-15.js.map +1 -1
- package/build/lib/simulator-xcode-27.d.ts +6 -0
- package/build/lib/simulator-xcode-27.d.ts.map +1 -0
- package/build/lib/simulator-xcode-27.js +13 -0
- package/build/lib/simulator-xcode-27.js.map +1 -0
- package/build/lib/simulator.d.ts.map +1 -1
- package/build/lib/simulator.js +9 -8
- package/build/lib/simulator.js.map +1 -1
- package/build/lib/utils/constants.d.ts +7 -0
- package/build/lib/utils/constants.d.ts.map +1 -0
- package/build/lib/utils/constants.js +10 -0
- package/build/lib/utils/constants.js.map +1 -0
- package/build/lib/{defaults-utils.d.ts → utils/defaults.d.ts} +1 -1
- package/build/lib/utils/defaults.d.ts.map +1 -0
- package/build/lib/{defaults-utils.js → utils/defaults.js} +2 -2
- package/build/lib/utils/defaults.js.map +1 -0
- package/build/lib/utils/devices.d.ts +13 -0
- package/build/lib/utils/devices.d.ts.map +1 -0
- package/build/lib/utils/devices.js +24 -0
- package/build/lib/utils/devices.js.map +1 -0
- package/build/lib/utils/get-devices.d.ts +7 -0
- package/build/lib/utils/get-devices.d.ts.map +1 -0
- package/build/lib/utils/get-devices.js +12 -0
- package/build/lib/utils/get-devices.js.map +1 -0
- package/build/lib/utils/index.d.ts +9 -0
- package/build/lib/utils/index.d.ts.map +1 -0
- package/build/lib/utils/index.js +28 -0
- package/build/lib/utils/index.js.map +1 -0
- package/build/lib/utils/lifecycle.d.ts +6 -0
- package/build/lib/utils/lifecycle.d.ts.map +1 -0
- package/build/lib/utils/lifecycle.js +66 -0
- package/build/lib/utils/lifecycle.js.map +1 -0
- package/build/lib/utils/process.d.ts +11 -0
- package/build/lib/utils/process.d.ts.map +1 -0
- package/build/lib/utils/process.js +36 -0
- package/build/lib/utils/process.js.map +1 -0
- package/build/lib/utils/types.d.ts +4 -0
- package/build/lib/utils/types.d.ts.map +1 -0
- package/build/lib/utils/types.js +3 -0
- package/build/lib/utils/types.js.map +1 -0
- package/build/lib/utils/xcode.d.ts +23 -0
- package/build/lib/utils/xcode.d.ts.map +1 -0
- package/build/lib/utils/xcode.js +73 -0
- package/build/lib/utils/xcode.js.map +1 -0
- package/lib/extensions/settings.ts +1 -1
- package/lib/simulator-xcode-14.ts +20 -20
- package/lib/simulator-xcode-15.ts +4 -15
- package/lib/simulator-xcode-27.ts +9 -0
- package/lib/simulator.ts +14 -10
- package/lib/utils/constants.ts +6 -0
- package/lib/{defaults-utils.ts → utils/defaults.ts} +1 -1
- package/lib/utils/devices.ts +25 -0
- package/lib/utils/get-devices.ts +10 -0
- package/lib/utils/index.ts +15 -0
- package/lib/utils/lifecycle.ts +78 -0
- package/lib/utils/process.ts +31 -0
- package/lib/utils/types.ts +3 -0
- package/lib/utils/xcode.ts +78 -0
- package/package.json +1 -1
- package/build/lib/defaults-utils.d.ts.map +0 -1
- package/build/lib/defaults-utils.js.map +0 -1
- package/build/lib/utils.d.ts +0 -44
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js +0 -211
- package/build/lib/utils.js.map +0 -1
- package/lib/utils.ts +0 -189
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.killAllSimulators = exports.readBundleIdFromPlist = exports.getUiClientAppPath = exports.assertXcodeVersion = exports.getMacAppPidByBundleId = exports.simExists = exports.getSimulatorInfo = exports.getDevices = exports.generateDefaultsCommandArgs = exports.toXmlArg = exports.NSUserDefaults = exports.MIN_DEVICE_HUB_XCODE_VERSION = exports.MIN_SUPPORTED_XCODE_VERSION = exports.DEVICE_HUB_UI_CLIENT_BUNDLE_ID = exports.SIMULATOR_UI_CLIENT_BUNDLE_ID = exports.MOBILE_SAFARI_BUNDLE_ID = exports.SAFARI_STARTUP_TIMEOUT_MS = void 0;
|
|
4
|
+
var constants_1 = require("./constants");
|
|
5
|
+
Object.defineProperty(exports, "SAFARI_STARTUP_TIMEOUT_MS", { enumerable: true, get: function () { return constants_1.SAFARI_STARTUP_TIMEOUT_MS; } });
|
|
6
|
+
Object.defineProperty(exports, "MOBILE_SAFARI_BUNDLE_ID", { enumerable: true, get: function () { return constants_1.MOBILE_SAFARI_BUNDLE_ID; } });
|
|
7
|
+
Object.defineProperty(exports, "SIMULATOR_UI_CLIENT_BUNDLE_ID", { enumerable: true, get: function () { return constants_1.SIMULATOR_UI_CLIENT_BUNDLE_ID; } });
|
|
8
|
+
Object.defineProperty(exports, "DEVICE_HUB_UI_CLIENT_BUNDLE_ID", { enumerable: true, get: function () { return constants_1.DEVICE_HUB_UI_CLIENT_BUNDLE_ID; } });
|
|
9
|
+
Object.defineProperty(exports, "MIN_SUPPORTED_XCODE_VERSION", { enumerable: true, get: function () { return constants_1.MIN_SUPPORTED_XCODE_VERSION; } });
|
|
10
|
+
Object.defineProperty(exports, "MIN_DEVICE_HUB_XCODE_VERSION", { enumerable: true, get: function () { return constants_1.MIN_DEVICE_HUB_XCODE_VERSION; } });
|
|
11
|
+
var defaults_1 = require("./defaults");
|
|
12
|
+
Object.defineProperty(exports, "NSUserDefaults", { enumerable: true, get: function () { return defaults_1.NSUserDefaults; } });
|
|
13
|
+
Object.defineProperty(exports, "toXmlArg", { enumerable: true, get: function () { return defaults_1.toXmlArg; } });
|
|
14
|
+
Object.defineProperty(exports, "generateDefaultsCommandArgs", { enumerable: true, get: function () { return defaults_1.generateDefaultsCommandArgs; } });
|
|
15
|
+
var get_devices_1 = require("./get-devices");
|
|
16
|
+
Object.defineProperty(exports, "getDevices", { enumerable: true, get: function () { return get_devices_1.getDevices; } });
|
|
17
|
+
var devices_1 = require("./devices");
|
|
18
|
+
Object.defineProperty(exports, "getSimulatorInfo", { enumerable: true, get: function () { return devices_1.getSimulatorInfo; } });
|
|
19
|
+
Object.defineProperty(exports, "simExists", { enumerable: true, get: function () { return devices_1.simExists; } });
|
|
20
|
+
var process_1 = require("./process");
|
|
21
|
+
Object.defineProperty(exports, "getMacAppPidByBundleId", { enumerable: true, get: function () { return process_1.getMacAppPidByBundleId; } });
|
|
22
|
+
var xcode_1 = require("./xcode");
|
|
23
|
+
Object.defineProperty(exports, "assertXcodeVersion", { enumerable: true, get: function () { return xcode_1.assertXcodeVersion; } });
|
|
24
|
+
Object.defineProperty(exports, "getUiClientAppPath", { enumerable: true, get: function () { return xcode_1.getUiClientAppPath; } });
|
|
25
|
+
Object.defineProperty(exports, "readBundleIdFromPlist", { enumerable: true, get: function () { return xcode_1.readBundleIdFromPlist; } });
|
|
26
|
+
var lifecycle_1 = require("./lifecycle");
|
|
27
|
+
Object.defineProperty(exports, "killAllSimulators", { enumerable: true, get: function () { return lifecycle_1.killAllSimulators; } });
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/utils/index.ts"],"names":[],"mappings":";;;AAAA,yCAOqB;AANnB,sHAAA,yBAAyB,OAAA;AACzB,oHAAA,uBAAuB,OAAA;AACvB,0HAAA,6BAA6B,OAAA;AAC7B,2HAAA,8BAA8B,OAAA;AAC9B,wHAAA,2BAA2B,OAAA;AAC3B,yHAAA,4BAA4B,OAAA;AAG9B,uCAAiF;AAAzE,0GAAA,cAAc,OAAA;AAAE,oGAAA,QAAQ,OAAA;AAAE,uHAAA,2BAA2B,OAAA;AAC7D,6CAAyC;AAAjC,yGAAA,UAAU,OAAA;AAClB,qCAAsD;AAA9C,2GAAA,gBAAgB,OAAA;AAAE,oGAAA,SAAS,OAAA;AACnC,qCAAiD;AAAzC,iHAAA,sBAAsB,OAAA;AAC9B,iCAAsF;AAA9E,2GAAA,kBAAkB,OAAA;AAAE,2GAAA,kBAAkB,OAAA;AAAE,8GAAA,qBAAqB,OAAA;AACrE,yCAA8C;AAAtC,8GAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param timeout - Timeout in milliseconds (default: DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS).
|
|
3
|
+
* @returns Promise that resolves when all simulators are killed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function killAllSimulators(timeout?: number): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../lib/utils/lifecycle.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,MAAwC,GAChD,OAAO,CAAC,IAAI,CAAC,CAuCf"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.killAllSimulators = killAllSimulators;
|
|
4
|
+
const logger_1 = require("../logger");
|
|
5
|
+
const teen_process_1 = require("teen_process");
|
|
6
|
+
const asyncbox_1 = require("asyncbox");
|
|
7
|
+
const appium_xcode_1 = require("appium-xcode");
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const get_devices_1 = require("./get-devices");
|
|
10
|
+
const process_1 = require("./process");
|
|
11
|
+
const DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS = 60000;
|
|
12
|
+
/**
|
|
13
|
+
* @param timeout - Timeout in milliseconds (default: DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS).
|
|
14
|
+
* @returns Promise that resolves when all simulators are killed.
|
|
15
|
+
*/
|
|
16
|
+
async function killAllSimulators(timeout = DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS) {
|
|
17
|
+
logger_1.log.debug('Killing all iOS Simulators');
|
|
18
|
+
const xcodeVersion = await (0, appium_xcode_1.getVersion)(true);
|
|
19
|
+
const uiClientBundleId = xcodeVersion.major >= constants_1.MIN_DEVICE_HUB_XCODE_VERSION
|
|
20
|
+
? constants_1.DEVICE_HUB_UI_CLIENT_BUNDLE_ID
|
|
21
|
+
: constants_1.SIMULATOR_UI_CLIENT_BUNDLE_ID;
|
|
22
|
+
const startedMs = performance.now();
|
|
23
|
+
try {
|
|
24
|
+
await (0, teen_process_1.exec)('xcrun', ['simctl', 'shutdown', 'all'], { timeout });
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
logger_1.log.debug(`Failed to shutdown all simulators: ${err.stderr || err.message}`);
|
|
28
|
+
}
|
|
29
|
+
const uiClientPid = await (0, process_1.getMacAppPidByBundleId)(uiClientBundleId);
|
|
30
|
+
if (uiClientPid) {
|
|
31
|
+
logger_1.log.debug(`Killing UI client '${uiClientBundleId}' (pid ${uiClientPid})`);
|
|
32
|
+
await (0, process_1.killMacAppByBundleId)(uiClientBundleId);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
logger_1.log.debug(`UI client '${uiClientBundleId}' is not running`);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await (0, asyncbox_1.waitForCondition)(allSimsAreDown, {
|
|
39
|
+
waitMs: Math.max(1000, startedMs + timeout - performance.now()),
|
|
40
|
+
intervalMs: 200,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
const remainingDevices = await getNonShutdownDeviceDescriptions();
|
|
45
|
+
const message = remainingDevices.length > 0
|
|
46
|
+
? `The following devices are still not in the correct state after ${timeout} ms:\n` +
|
|
47
|
+
remainingDevices.map((device) => ` ${device}`).join('\n')
|
|
48
|
+
: `Timed out after ${timeout} ms waiting for all simulators to shut down`;
|
|
49
|
+
throw new Error(message, { cause: err });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function allSimsAreDown() {
|
|
53
|
+
try {
|
|
54
|
+
return (await getNonShutdownDeviceDescriptions()).length === 0;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function getNonShutdownDeviceDescriptions() {
|
|
61
|
+
const devices = Object.values(await (0, get_devices_1.getDevices)()).flat();
|
|
62
|
+
return devices
|
|
63
|
+
.filter((sim) => !['shutdown', 'unavailable', 'disconnected'].includes(sim.state.toLowerCase()))
|
|
64
|
+
.map((sim) => `${sim.name} (${sim.sdk}, udid: ${sim.udid}) is still in state '${sim.state.toLowerCase()}'`);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../lib/utils/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param bundleId - The bundle identifier of a running macOS application.
|
|
3
|
+
* @returns The process ID or null if the application is not running.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getMacAppPidByBundleId(bundleId: string): Promise<string | null>;
|
|
6
|
+
/**
|
|
7
|
+
* @param bundleId - The bundle identifier of a running macOS application.
|
|
8
|
+
* @returns True if the kill command succeeded.
|
|
9
|
+
*/
|
|
10
|
+
export declare function killMacAppByBundleId(bundleId: string): Promise<boolean>;
|
|
11
|
+
//# sourceMappingURL=process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../../lib/utils/process.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASrF;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ7E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMacAppPidByBundleId = getMacAppPidByBundleId;
|
|
4
|
+
exports.killMacAppByBundleId = killMacAppByBundleId;
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const teen_process_1 = require("teen_process");
|
|
7
|
+
/**
|
|
8
|
+
* @param bundleId - The bundle identifier of a running macOS application.
|
|
9
|
+
* @returns The process ID or null if the application is not running.
|
|
10
|
+
*/
|
|
11
|
+
async function getMacAppPidByBundleId(bundleId) {
|
|
12
|
+
let stdout;
|
|
13
|
+
try {
|
|
14
|
+
({ stdout } = await (0, teen_process_1.exec)('lsappinfo', ['info', '-only', 'pid', bundleId]));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const match = stdout.trim().match(/"pid"=(\d+)/);
|
|
20
|
+
return match?.[1] ?? null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @param bundleId - The bundle identifier of a running macOS application.
|
|
24
|
+
* @returns True if the kill command succeeded.
|
|
25
|
+
*/
|
|
26
|
+
async function killMacAppByBundleId(bundleId) {
|
|
27
|
+
try {
|
|
28
|
+
await (0, teen_process_1.exec)('lsappinfo', ['kill', '-hard', bundleId]);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
logger_1.log.debug(`Could not kill '${bundleId}' via lsappinfo: ${e.stderr || e.message}`);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../../lib/utils/process.ts"],"names":[],"mappings":";;AAOA,wDASC;AAMD,oDAQC;AA9BD,sCAA8B;AAC9B,+CAAkC;AAElC;;;GAGG;AACI,KAAK,UAAU,sBAAsB,CAAC,QAAgB;IAC3D,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,CAAC,EAAC,MAAM,EAAC,GAAG,MAAM,IAAA,mBAAI,EAAC,WAAW,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACjD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IACzD,IAAI,CAAC;QACH,MAAM,IAAA,mBAAI,EAAC,WAAW,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,YAAG,CAAC,KAAK,CAAC,mBAAmB,QAAQ,oBAAoB,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAClF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../lib/utils/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../lib/utils/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type XcodeVersion } from 'appium-xcode';
|
|
2
|
+
/**
|
|
3
|
+
* @param bundleId - The bundle identifier of the Simulator UI client.
|
|
4
|
+
* @param xcodeVersion - The active Xcode version.
|
|
5
|
+
* @returns The full path to the UI client app in the active Xcode installation.
|
|
6
|
+
* @throws {Error} If no matching app is found in the active Xcode folder.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getUiClientAppPath(bundleId: string, xcodeVersion: XcodeVersion): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Asserts that the Xcode version meets the minimum supported version requirement.
|
|
11
|
+
*
|
|
12
|
+
* @template V - The Xcode version type.
|
|
13
|
+
* @param xcodeVersion - The Xcode version to check.
|
|
14
|
+
* @returns The same Xcode version if it meets the requirement.
|
|
15
|
+
* @throws {Error} If the Xcode version is below the minimum supported version.
|
|
16
|
+
*/
|
|
17
|
+
export declare function assertXcodeVersion<V extends XcodeVersion>(xcodeVersion: V): V;
|
|
18
|
+
/**
|
|
19
|
+
* @param infoPlistPath - The full path to an Info.plist file.
|
|
20
|
+
* @returns The bundle identifier or null if it cannot be read.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readBundleIdFromPlist(infoPlistPath: string): Promise<string | null>;
|
|
23
|
+
//# sourceMappingURL=xcode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode.d.ts","sourceRoot":"","sources":["../../../lib/utils/xcode.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,YAAY,EAAC,MAAM,cAAc,CAAC;AAGxD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CAQ7E;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWzF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getUiClientAppPath = getUiClientAppPath;
|
|
7
|
+
exports.assertXcodeVersion = assertXcodeVersion;
|
|
8
|
+
exports.readBundleIdFromPlist = readBundleIdFromPlist;
|
|
9
|
+
const support_1 = require("@appium/support");
|
|
10
|
+
const teen_process_1 = require("teen_process");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const appium_xcode_1 = require("appium-xcode");
|
|
13
|
+
const constants_1 = require("./constants");
|
|
14
|
+
/**
|
|
15
|
+
* @param bundleId - The bundle identifier of the Simulator UI client.
|
|
16
|
+
* @param xcodeVersion - The active Xcode version.
|
|
17
|
+
* @returns The full path to the UI client app in the active Xcode installation.
|
|
18
|
+
* @throws {Error} If no matching app is found in the active Xcode folder.
|
|
19
|
+
*/
|
|
20
|
+
async function getUiClientAppPath(bundleId, xcodeVersion) {
|
|
21
|
+
const devRoot = await (0, appium_xcode_1.getPath)();
|
|
22
|
+
const applicationsDir = xcodeVersion.major >= constants_1.MIN_DEVICE_HUB_XCODE_VERSION
|
|
23
|
+
? node_path_1.default.resolve(devRoot, '..', 'Applications')
|
|
24
|
+
: node_path_1.default.resolve(devRoot, 'Applications');
|
|
25
|
+
if (await support_1.fs.exists(applicationsDir)) {
|
|
26
|
+
const appPaths = (await support_1.fs.readdir(applicationsDir))
|
|
27
|
+
.filter((entry) => entry.endsWith('.app'))
|
|
28
|
+
.map((entry) => node_path_1.default.resolve(applicationsDir, entry));
|
|
29
|
+
const apps = await Promise.all(appPaths.map(async (appPath) => ({
|
|
30
|
+
appPath,
|
|
31
|
+
bundleId: await readBundleIdFromPlist(node_path_1.default.resolve(appPath, 'Contents', 'Info.plist')),
|
|
32
|
+
})));
|
|
33
|
+
const match = apps.find((app) => app.bundleId === bundleId);
|
|
34
|
+
if (match) {
|
|
35
|
+
return match.appPath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Could not find UI client app with bundle id '${bundleId}' under '${applicationsDir}' ` +
|
|
39
|
+
`(active Xcode developer root: ${devRoot})`);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Asserts that the Xcode version meets the minimum supported version requirement.
|
|
43
|
+
*
|
|
44
|
+
* @template V - The Xcode version type.
|
|
45
|
+
* @param xcodeVersion - The Xcode version to check.
|
|
46
|
+
* @returns The same Xcode version if it meets the requirement.
|
|
47
|
+
* @throws {Error} If the Xcode version is below the minimum supported version.
|
|
48
|
+
*/
|
|
49
|
+
function assertXcodeVersion(xcodeVersion) {
|
|
50
|
+
if (xcodeVersion.major < constants_1.MIN_SUPPORTED_XCODE_VERSION) {
|
|
51
|
+
throw new Error(`Tried to use an iOS simulator with xcode version ${xcodeVersion.versionString} but only Xcode version ` +
|
|
52
|
+
`${constants_1.MIN_SUPPORTED_XCODE_VERSION} and up are supported`);
|
|
53
|
+
}
|
|
54
|
+
return xcodeVersion;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @param infoPlistPath - The full path to an Info.plist file.
|
|
58
|
+
* @returns The bundle identifier or null if it cannot be read.
|
|
59
|
+
*/
|
|
60
|
+
async function readBundleIdFromPlist(infoPlistPath) {
|
|
61
|
+
try {
|
|
62
|
+
const { stdout } = await (0, teen_process_1.exec)('/usr/libexec/PlistBuddy', [
|
|
63
|
+
'-c',
|
|
64
|
+
'print CFBundleIdentifier',
|
|
65
|
+
infoPlistPath,
|
|
66
|
+
]);
|
|
67
|
+
return stdout.trim() || null;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=xcode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode.js","sourceRoot":"","sources":["../../../lib/utils/xcode.ts"],"names":[],"mappings":";;;;;AAYA,gDA8BC;AAUD,gDAQC;AAMD,sDAWC;AA7ED,6CAAmC;AACnC,+CAAkC;AAClC,0DAA6B;AAC7B,+CAAwD;AACxD,2CAAsF;AAEtF;;;;;GAKG;AACI,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,YAA0B;IAE1B,MAAM,OAAO,GAAG,MAAM,IAAA,sBAAO,GAAE,CAAC;IAChC,MAAM,eAAe,GACnB,YAAY,CAAC,KAAK,IAAI,wCAA4B;QAChD,CAAC,CAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC;QAC7C,CAAC,CAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAE5C,IAAI,MAAM,YAAE,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,MAAM,YAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;aACjD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;aACzC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAI,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAC/B,OAAO;YACP,QAAQ,EAAE,MAAM,qBAAqB,CAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;SACvF,CAAC,CAAC,CACJ,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC5D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,gDAAgD,QAAQ,YAAY,eAAe,IAAI;QACrF,iCAAiC,OAAO,GAAG,CAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAyB,YAAe;IACxE,IAAI,YAAY,CAAC,KAAK,GAAG,uCAA2B,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,oDAAoD,YAAY,CAAC,aAAa,0BAA0B;YACtG,GAAG,uCAA2B,uBAAuB,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,qBAAqB,CAAC,aAAqB;IAC/D,IAAI,CAAC;QACH,MAAM,EAAC,MAAM,EAAC,GAAG,MAAM,IAAA,mBAAI,EAAC,yBAAyB,EAAE;YACrD,IAAI;YACJ,0BAA0B;YAC1B,aAAa;SACd,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {fs, timing, util} from '@appium/support';
|
|
2
2
|
import {waitForCondition, retryInterval} from 'asyncbox';
|
|
3
|
-
import {
|
|
3
|
+
import {getMacAppPidByBundleId, getUiClientAppPath, SIMULATOR_UI_CLIENT_BUNDLE_ID} from './utils';
|
|
4
|
+
import {getPath} from 'appium-xcode';
|
|
4
5
|
import {exec} from 'teen_process';
|
|
5
6
|
import {log as defaultLog} from './logger';
|
|
6
7
|
import EventEmitter from 'node:events';
|
|
7
8
|
import AsyncLock from 'async-lock';
|
|
8
9
|
import path from 'node:path';
|
|
9
|
-
import {getPath as getXcodePath} from 'appium-xcode';
|
|
10
10
|
import {Simctl} from 'node-simctl';
|
|
11
11
|
import * as appExtensions from './extensions/applications';
|
|
12
12
|
import * as biometricExtensions from './extensions/biometric';
|
|
@@ -37,7 +37,6 @@ import type {AppiumLogger, StringRecord} from '@appium/types';
|
|
|
37
37
|
|
|
38
38
|
const SIMULATOR_SHUTDOWN_TIMEOUT = 15 * 1000;
|
|
39
39
|
const STARTUP_LOCK = new AsyncLock();
|
|
40
|
-
const UI_CLIENT_BUNDLE_ID = 'com.apple.iphonesimulator';
|
|
41
40
|
const STARTUP_TIMEOUT_MS = 120 * 1000;
|
|
42
41
|
|
|
43
42
|
export class SimulatorXcode14
|
|
@@ -110,6 +109,7 @@ export class SimulatorXcode14
|
|
|
110
109
|
private readonly _simctl: Simctl;
|
|
111
110
|
private readonly _xcodeVersion: XcodeVersion;
|
|
112
111
|
private readonly _log: AppiumLogger;
|
|
112
|
+
private _uiClientAppPath: Promise<string> | undefined;
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Constructs the object with the `udid` and version of Xcode.
|
|
@@ -174,7 +174,7 @@ export class SimulatorXcode14
|
|
|
174
174
|
* @returns The bundle identifier of the Simulator UI client.
|
|
175
175
|
*/
|
|
176
176
|
get uiClientBundleId(): string {
|
|
177
|
-
return
|
|
177
|
+
return SIMULATOR_UI_CLIENT_BUNDLE_ID;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
/**
|
|
@@ -305,18 +305,11 @@ export class SimulatorXcode14
|
|
|
305
305
|
* @returns The process ID or null if the UI client is not running.
|
|
306
306
|
*/
|
|
307
307
|
async getUIClientPid(): Promise<string | null> {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
(
|
|
311
|
-
} catch {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
if (isNaN(parseInt(stdout, 10))) {
|
|
315
|
-
return null;
|
|
308
|
+
const pid = await getMacAppPidByBundleId(this.uiClientBundleId);
|
|
309
|
+
if (pid) {
|
|
310
|
+
this.log.debug(`Got UI client PID: ${pid}`);
|
|
316
311
|
}
|
|
317
|
-
|
|
318
|
-
this.log.debug(`Got Simulator UI client PID: ${stdout}`);
|
|
319
|
-
return stdout;
|
|
312
|
+
return pid;
|
|
320
313
|
}
|
|
321
314
|
|
|
322
315
|
/**
|
|
@@ -456,14 +449,14 @@ export class SimulatorXcode14
|
|
|
456
449
|
...opts,
|
|
457
450
|
};
|
|
458
451
|
|
|
459
|
-
const
|
|
460
|
-
const args = ['-Fn',
|
|
461
|
-
this.log.info(`Starting
|
|
452
|
+
const uiClientApp = await this._getUiClientAppPath();
|
|
453
|
+
const args = ['-Fn', uiClientApp];
|
|
454
|
+
this.log.info(`Starting UI client: ${util.quote(['open', ...args])}`);
|
|
462
455
|
try {
|
|
463
456
|
await exec('open', args, {timeout: startUiOpts.startupTimeout});
|
|
464
457
|
} catch (err: any) {
|
|
465
458
|
throw new Error(
|
|
466
|
-
`Got an unexpected error while opening
|
|
459
|
+
`Got an unexpected error while opening UI client: ${err.stderr || err.stdout || err.message}`,
|
|
467
460
|
{cause: err},
|
|
468
461
|
);
|
|
469
462
|
}
|
|
@@ -647,7 +640,7 @@ export class SimulatorXcode14
|
|
|
647
640
|
* @returns The full path to the LaunchDaemons directory.
|
|
648
641
|
*/
|
|
649
642
|
async getLaunchDaemonsRoot(): Promise<string> {
|
|
650
|
-
const devRoot = await
|
|
643
|
+
const devRoot = await getPath();
|
|
651
644
|
return path.resolve(
|
|
652
645
|
devRoot,
|
|
653
646
|
'Platforms',
|
|
@@ -666,4 +659,11 @@ export class SimulatorXcode14
|
|
|
666
659
|
'LaunchDaemons',
|
|
667
660
|
);
|
|
668
661
|
}
|
|
662
|
+
|
|
663
|
+
private async _getUiClientAppPath(): Promise<string> {
|
|
664
|
+
if (!this._uiClientAppPath) {
|
|
665
|
+
this._uiClientAppPath = getUiClientAppPath(this.uiClientBundleId, this.xcodeVersion);
|
|
666
|
+
}
|
|
667
|
+
return this._uiClientAppPath;
|
|
668
|
+
}
|
|
669
669
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {fs} from '@appium/support';
|
|
2
|
-
import {exec} from 'teen_process';
|
|
3
2
|
import path from 'node:path';
|
|
3
|
+
import {readBundleIdFromPlist} from './utils';
|
|
4
4
|
import {SimulatorXcode14} from './simulator-xcode-14';
|
|
5
5
|
|
|
6
6
|
export class SimulatorXcode15 extends SimulatorXcode14 {
|
|
@@ -114,23 +114,12 @@ export class SimulatorXcode15 extends SimulatorXcode14 {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
const appsRoot = path.resolve(await this._getSystemRoot(), 'Applications');
|
|
117
|
-
const fetchBundleId = async (appRoot: string): Promise<string | null> => {
|
|
118
|
-
const infoPlistPath = path.resolve(appRoot, 'Info.plist');
|
|
119
|
-
try {
|
|
120
|
-
const {stdout} = await exec('/usr/libexec/PlistBuddy', [
|
|
121
|
-
'-c',
|
|
122
|
-
'print CFBundleIdentifier',
|
|
123
|
-
infoPlistPath,
|
|
124
|
-
]);
|
|
125
|
-
return stdout.trim();
|
|
126
|
-
} catch {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
117
|
const allApps = (await fs.readdir(appsRoot))
|
|
131
118
|
.filter((x) => x.endsWith('.app'))
|
|
132
119
|
.map((x) => path.join(appsRoot, x));
|
|
133
|
-
const bundleIds = await Promise.all(
|
|
120
|
+
const bundleIds = await Promise.all(
|
|
121
|
+
allApps.map((appRoot) => readBundleIdFromPlist(path.resolve(appRoot, 'Info.plist'))),
|
|
122
|
+
);
|
|
134
123
|
this._systemAppBundleIds = new Set(bundleIds.filter((x): x is string => x !== null));
|
|
135
124
|
return this._systemAppBundleIds;
|
|
136
125
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {DEVICE_HUB_UI_CLIENT_BUNDLE_ID} from './utils';
|
|
2
|
+
import {SimulatorXcode15} from './simulator-xcode-15';
|
|
3
|
+
|
|
4
|
+
export class SimulatorXcode27 extends SimulatorXcode15 {
|
|
5
|
+
/** @inheritdoc */
|
|
6
|
+
override get uiClientBundleId(): string {
|
|
7
|
+
return DEVICE_HUB_UI_CLIENT_BUNDLE_ID;
|
|
8
|
+
}
|
|
9
|
+
}
|
package/lib/simulator.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {SimulatorXcode14} from './simulator-xcode-14';
|
|
2
2
|
import {SimulatorXcode15} from './simulator-xcode-15';
|
|
3
|
-
import {
|
|
3
|
+
import {SimulatorXcode27} from './simulator-xcode-27';
|
|
4
|
+
import {
|
|
5
|
+
assertXcodeVersion,
|
|
6
|
+
getSimulatorInfo,
|
|
7
|
+
MIN_DEVICE_HUB_XCODE_VERSION,
|
|
8
|
+
MIN_SUPPORTED_XCODE_VERSION,
|
|
9
|
+
} from './utils';
|
|
4
10
|
import * as xcode from 'appium-xcode';
|
|
5
11
|
import {log} from './logger';
|
|
6
12
|
import type {Simulator, SimulatorLookupOptions} from './types';
|
|
@@ -38,15 +44,13 @@ export async function getSimulator(
|
|
|
38
44
|
(logger ?? log).info(
|
|
39
45
|
`Constructing ${platform} simulator for Xcode version ${xcodeVersion.versionString} with udid '${udid}'`,
|
|
40
46
|
);
|
|
41
|
-
let SimClass: typeof SimulatorXcode14 | typeof SimulatorXcode15;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
SimClass = SimulatorXcode15;
|
|
49
|
-
break;
|
|
47
|
+
let SimClass: typeof SimulatorXcode14 | typeof SimulatorXcode15 | typeof SimulatorXcode27;
|
|
48
|
+
if (xcodeVersion.major === MIN_SUPPORTED_XCODE_VERSION) {
|
|
49
|
+
SimClass = SimulatorXcode14;
|
|
50
|
+
} else if (xcodeVersion.major >= MIN_DEVICE_HUB_XCODE_VERSION) {
|
|
51
|
+
SimClass = SimulatorXcode27;
|
|
52
|
+
} else {
|
|
53
|
+
SimClass = SimulatorXcode15;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
const result = new SimClass(udid, xcodeVersion, logger);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const SAFARI_STARTUP_TIMEOUT_MS = 25 * 1000;
|
|
2
|
+
export const MOBILE_SAFARI_BUNDLE_ID = 'com.apple.mobilesafari';
|
|
3
|
+
export const SIMULATOR_UI_CLIENT_BUNDLE_ID = 'com.apple.iphonesimulator';
|
|
4
|
+
export const DEVICE_HUB_UI_CLIENT_BUNDLE_ID = 'com.apple.dt.Devices';
|
|
5
|
+
export const MIN_SUPPORTED_XCODE_VERSION = 14;
|
|
6
|
+
export const MIN_DEVICE_HUB_XCODE_VERSION = 27;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type {SimulatorInfoOptions} from './types';
|
|
2
|
+
import {getDevices} from './get-devices';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param udid - The simulator UDID.
|
|
6
|
+
* @param opts - Options including devicesSetPath.
|
|
7
|
+
* @returns Promise that resolves to simulator info or undefined if not found.
|
|
8
|
+
*/
|
|
9
|
+
export async function getSimulatorInfo(
|
|
10
|
+
udid: string,
|
|
11
|
+
opts: SimulatorInfoOptions = {},
|
|
12
|
+
): Promise<any> {
|
|
13
|
+
const {devicesSetPath} = opts;
|
|
14
|
+
// see the README for github.com/appium/node-simctl for example output of getDevices()
|
|
15
|
+
const devices = Object.values(await getDevices({devicesSetPath})).flat();
|
|
16
|
+
return devices.find((sim: any) => sim.udid === udid);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param udid - The simulator UDID.
|
|
21
|
+
* @returns Promise that resolves to true if simulator exists, false otherwise.
|
|
22
|
+
*/
|
|
23
|
+
export async function simExists(udid: string): Promise<boolean> {
|
|
24
|
+
return !!(await getSimulatorInfo(udid));
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {Simctl} from 'node-simctl';
|
|
2
|
+
import type {StringRecord} from '@appium/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param simctlOpts - Optional simctl options
|
|
6
|
+
* @returns Promise that resolves to a record of devices grouped by SDK version
|
|
7
|
+
*/
|
|
8
|
+
export async function getDevices(simctlOpts?: StringRecord): Promise<Record<string, any[]>> {
|
|
9
|
+
return await new Simctl(simctlOpts).getDevices();
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SAFARI_STARTUP_TIMEOUT_MS,
|
|
3
|
+
MOBILE_SAFARI_BUNDLE_ID,
|
|
4
|
+
SIMULATOR_UI_CLIENT_BUNDLE_ID,
|
|
5
|
+
DEVICE_HUB_UI_CLIENT_BUNDLE_ID,
|
|
6
|
+
MIN_SUPPORTED_XCODE_VERSION,
|
|
7
|
+
MIN_DEVICE_HUB_XCODE_VERSION,
|
|
8
|
+
} from './constants';
|
|
9
|
+
export type {SimulatorInfoOptions} from './types';
|
|
10
|
+
export {NSUserDefaults, toXmlArg, generateDefaultsCommandArgs} from './defaults';
|
|
11
|
+
export {getDevices} from './get-devices';
|
|
12
|
+
export {getSimulatorInfo, simExists} from './devices';
|
|
13
|
+
export {getMacAppPidByBundleId} from './process';
|
|
14
|
+
export {assertXcodeVersion, getUiClientAppPath, readBundleIdFromPlist} from './xcode';
|
|
15
|
+
export {killAllSimulators} from './lifecycle';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {log} from '../logger';
|
|
2
|
+
import {exec, type ExecError} from 'teen_process';
|
|
3
|
+
import {waitForCondition} from 'asyncbox';
|
|
4
|
+
import {getVersion} from 'appium-xcode';
|
|
5
|
+
import {
|
|
6
|
+
DEVICE_HUB_UI_CLIENT_BUNDLE_ID,
|
|
7
|
+
MIN_DEVICE_HUB_XCODE_VERSION,
|
|
8
|
+
SIMULATOR_UI_CLIENT_BUNDLE_ID,
|
|
9
|
+
} from './constants';
|
|
10
|
+
import {getDevices} from './get-devices';
|
|
11
|
+
import {getMacAppPidByBundleId, killMacAppByBundleId} from './process';
|
|
12
|
+
|
|
13
|
+
const DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS = 60000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param timeout - Timeout in milliseconds (default: DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS).
|
|
17
|
+
* @returns Promise that resolves when all simulators are killed.
|
|
18
|
+
*/
|
|
19
|
+
export async function killAllSimulators(
|
|
20
|
+
timeout: number = DEFAULT_SIM_SHUTDOWN_TIMEOUT_MS,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
log.debug('Killing all iOS Simulators');
|
|
23
|
+
const xcodeVersion = await getVersion(true);
|
|
24
|
+
const uiClientBundleId =
|
|
25
|
+
xcodeVersion.major >= MIN_DEVICE_HUB_XCODE_VERSION
|
|
26
|
+
? DEVICE_HUB_UI_CLIENT_BUNDLE_ID
|
|
27
|
+
: SIMULATOR_UI_CLIENT_BUNDLE_ID;
|
|
28
|
+
|
|
29
|
+
const startedMs = performance.now();
|
|
30
|
+
try {
|
|
31
|
+
await exec('xcrun', ['simctl', 'shutdown', 'all'], {timeout});
|
|
32
|
+
} catch (err: unknown) {
|
|
33
|
+
log.debug(
|
|
34
|
+
`Failed to shutdown all simulators: ${(err as ExecError).stderr || (err as Error).message}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const uiClientPid = await getMacAppPidByBundleId(uiClientBundleId);
|
|
39
|
+
if (uiClientPid) {
|
|
40
|
+
log.debug(`Killing UI client '${uiClientBundleId}' (pid ${uiClientPid})`);
|
|
41
|
+
await killMacAppByBundleId(uiClientBundleId);
|
|
42
|
+
} else {
|
|
43
|
+
log.debug(`UI client '${uiClientBundleId}' is not running`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await waitForCondition(allSimsAreDown, {
|
|
48
|
+
waitMs: Math.max(1000, startedMs + timeout - performance.now()),
|
|
49
|
+
intervalMs: 200,
|
|
50
|
+
});
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const remainingDevices = await getNonShutdownDeviceDescriptions();
|
|
53
|
+
const message =
|
|
54
|
+
remainingDevices.length > 0
|
|
55
|
+
? `The following devices are still not in the correct state after ${timeout} ms:\n` +
|
|
56
|
+
remainingDevices.map((device) => ` ${device}`).join('\n')
|
|
57
|
+
: `Timed out after ${timeout} ms waiting for all simulators to shut down`;
|
|
58
|
+
throw new Error(message, {cause: err});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function allSimsAreDown(): Promise<boolean> {
|
|
63
|
+
try {
|
|
64
|
+
return (await getNonShutdownDeviceDescriptions()).length === 0;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function getNonShutdownDeviceDescriptions(): Promise<string[]> {
|
|
71
|
+
const devices = Object.values(await getDevices()).flat();
|
|
72
|
+
return devices
|
|
73
|
+
.filter((sim) => !['shutdown', 'unavailable', 'disconnected'].includes(sim.state.toLowerCase()))
|
|
74
|
+
.map(
|
|
75
|
+
(sim) =>
|
|
76
|
+
`${sim.name} (${sim.sdk}, udid: ${sim.udid}) is still in state '${sim.state.toLowerCase()}'`,
|
|
77
|
+
);
|
|
78
|
+
}
|