90 lines
4.3 KiB
JavaScript
90 lines
4.3 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.runOnSimulator = exports.getSimulators = void 0;
|
|
const child_process_1 = require("child_process"); // TODO: need cross-spawn for windows?
|
|
const Debug = require("debug");
|
|
const errors_1 = require("../../errors");
|
|
const log_1 = require("../../utils/log");
|
|
const process_1 = require("../../utils/process");
|
|
const xcode_1 = require("./xcode");
|
|
const debug = Debug('native-run:ios:utils:simulator');
|
|
async function getSimulators() {
|
|
const simctl = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'list', '--json'], {
|
|
encoding: 'utf8',
|
|
});
|
|
if (simctl.status) {
|
|
throw new errors_1.Exception(`Unable to retrieve simulator list: ${simctl.stderr}`);
|
|
}
|
|
try {
|
|
const output = JSON.parse(simctl.stdout);
|
|
return output.runtimes
|
|
.filter((runtime) => runtime.name.indexOf('watch') === -1 && runtime.name.indexOf('tv') === -1)
|
|
.map((runtime) => (output.devices[runtime.identifier] || output.devices[runtime.name])
|
|
.filter((device) => device.isAvailable)
|
|
.map((device) => ({ ...device, runtime })))
|
|
.reduce((prev, next) => prev.concat(next)) // flatten
|
|
.sort((a, b) => (a.name < b.name ? -1 : 1));
|
|
}
|
|
catch (err) {
|
|
throw new errors_1.Exception(`Unable to retrieve simulator list: ${err.message}`);
|
|
}
|
|
}
|
|
exports.getSimulators = getSimulators;
|
|
async function runOnSimulator(udid, appPath, bundleId, waitForApp) {
|
|
debug(`Booting simulator ${udid}`);
|
|
const bootResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'boot', udid], {
|
|
encoding: 'utf8',
|
|
});
|
|
// TODO: is there a better way to check this?
|
|
if (bootResult.status && !bootResult.stderr.includes('Unable to boot device in current state: Booted')) {
|
|
throw new errors_1.Exception(`There was an error booting simulator: ${bootResult.stderr}`);
|
|
}
|
|
debug(`Installing ${appPath} on ${udid}`);
|
|
const installResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'install', udid, appPath], { encoding: 'utf8' });
|
|
if (installResult.status) {
|
|
throw new errors_1.Exception(`There was an error installing app on simulator: ${installResult.stderr}`);
|
|
}
|
|
const xCodePath = await (0, xcode_1.getXCodePath)();
|
|
debug(`Running simulator ${udid}`);
|
|
const openResult = (0, child_process_1.spawnSync)('open', [`${xCodePath}/Applications/Simulator.app`, '--args', '-CurrentDeviceUDID', udid], { encoding: 'utf8' });
|
|
if (openResult.status) {
|
|
throw new errors_1.Exception(`There was an error opening simulator: ${openResult.stderr}`);
|
|
}
|
|
debug(`Launching ${appPath} on ${udid}`);
|
|
const launchResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'launch', udid, bundleId], { encoding: 'utf8' });
|
|
if (launchResult.status) {
|
|
throw new errors_1.Exception(`There was an error launching app on simulator: ${launchResult.stderr}`);
|
|
}
|
|
if (waitForApp) {
|
|
(0, process_1.onBeforeExit)(async () => {
|
|
const terminateResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'terminate', udid, bundleId], { encoding: 'utf8' });
|
|
if (terminateResult.status) {
|
|
debug('Unable to terminate app on simulator');
|
|
}
|
|
});
|
|
(0, log_1.log)(`Waiting for app to close...\n`);
|
|
await waitForSimulatorClose(udid, bundleId);
|
|
}
|
|
}
|
|
exports.runOnSimulator = runOnSimulator;
|
|
async function waitForSimulatorClose(udid, bundleId) {
|
|
return new Promise((resolve) => {
|
|
// poll service list for bundle id
|
|
const interval = setInterval(async () => {
|
|
try {
|
|
const data = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'spawn', udid, 'launchctl', 'list'], { encoding: 'utf8' });
|
|
// if bundle id isn't in list, app isn't running
|
|
if (data.stdout.indexOf(bundleId) === -1) {
|
|
clearInterval(interval);
|
|
resolve();
|
|
}
|
|
}
|
|
catch (e) {
|
|
debug('Error received from launchctl: %O', e);
|
|
debug('App %s no longer found in process list for %s', bundleId, udid);
|
|
clearInterval(interval);
|
|
resolve();
|
|
}
|
|
}, 500);
|
|
});
|
|
}
|