appium-ios-simulator
Version:
iOS Simulator interface for Appium.
145 lines • 6.24 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.openUrl = openUrl;
exports.scrubSafari = scrubSafari;
exports.updateSafariSettings = updateSafariSettings;
exports.getWebInspectorSocket = getWebInspectorSocket;
const node_path_1 = __importDefault(require("node:path"));
const support_1 = require("@appium/support");
const utils_1 = require("../utils");
const asyncbox_1 = require("asyncbox");
const teen_process_1 = require("teen_process");
// The root of all these files is located under Safari data container root
// in 'Library' subfolder
const DATA_FILES = [
['Caches', '*'],
['Image Cache', '*'],
['WebKit', utils_1.MOBILE_SAFARI_BUNDLE_ID, '*'],
['WebKit', 'GeolocationSites.plist'],
['WebKit', 'LocalStorage', '*.*'],
['Safari', '*'],
['Cookies', '*.binarycookies'],
['..', 'tmp', utils_1.MOBILE_SAFARI_BUNDLE_ID, '*'],
];
/**
* Open the given URL in mobile Safari browser.
* The browser will be started automatically if it is not running.
*
* @param url URL to open
*/
async function openUrl(url) {
if (!(await this.isRunning())) {
throw new Error(`Tried to open '${url}', but Simulator is not in Booted state`);
}
const timer = new support_1.timing.Timer().start();
await this.simctl.openUrl(url);
let psError;
try {
await (0, asyncbox_1.waitForCondition)(async () => {
let procList = [];
try {
procList = await this.ps();
psError = null;
}
catch (e) {
this.log.debug(e.message);
psError = e;
}
return procList.some(({ name }) => name === utils_1.MOBILE_SAFARI_BUNDLE_ID);
}, {
waitMs: utils_1.SAFARI_STARTUP_TIMEOUT_MS,
intervalMs: 500,
});
}
catch {
const secondsElapsed = timer.getDuration().asSeconds;
if (psError) {
this.log.warn(`Mobile Safari process existence cannot be verified after ${secondsElapsed.toFixed(3)}s. ` +
`Original error: ${psError.message}`);
this.log.warn('Continuing anyway');
}
else {
throw new Error(`Mobile Safari cannot open '${url}' after ${secondsElapsed.toFixed(3)}s. ` +
`Its process ${utils_1.MOBILE_SAFARI_BUNDLE_ID} does not exist in the list of Simulator processes`);
}
}
this.log.debug(`Safari successfully opened '${url}' in ${timer.getDuration().asSeconds.toFixed(3)}s`);
}
/**
* Clean up the directories for mobile Safari.
* Safari will be terminated if it is running.
*
* @param keepPrefs Whether to keep Safari preferences from being deleted.
*/
async function scrubSafari(keepPrefs = true) {
try {
await this.terminateApp(utils_1.MOBILE_SAFARI_BUNDLE_ID);
}
catch { }
this.log.debug('Scrubbing Safari data files');
const safariData = await this.simctl.getAppContainer(utils_1.MOBILE_SAFARI_BUNDLE_ID, 'data');
const libraryDir = node_path_1.default.resolve(safariData, 'Library');
const deletePromises = DATA_FILES.map((p) => support_1.fs.rimraf(node_path_1.default.join(libraryDir, ...p)));
if (!keepPrefs) {
deletePromises.push(support_1.fs.rimraf(node_path_1.default.join(libraryDir, 'Preferences', '*.plist')));
}
await Promise.all(deletePromises);
}
/**
* Updates various Safari settings. Simulator must be booted in order for it
* to success.
*
* @param updates An object containing Safari settings to be updated.
* The list of available setting names and their values could be retrieved by
* changing the corresponding Safari settings in the UI and then inspecting
* 'Library/Preferences/com.apple.mobilesafari.plist' file inside of
* com.apple.mobilesafari app container.
* The full path to the Mobile Safari's container could be retrieved from
* `xcrun simctl get_app_container <sim_udid> com.apple.mobilesafari data`
* command output.
* Use the `xcrun simctl spawn <sim_udid> defaults read <path_to_plist>` command
* to print the plist content to the Terminal.
* @returns Promise that resolves to true if settings were updated
*/
async function updateSafariSettings(updates) {
if (Object.keys(updates).length === 0) {
return false;
}
const containerRoot = await this.simctl.getAppContainer(utils_1.MOBILE_SAFARI_BUNDLE_ID, 'data');
const plistPath = node_path_1.default.join(containerRoot, 'Library', 'Preferences', 'com.apple.mobilesafari.plist');
return await this.updateSettings(plistPath, updates);
}
/**
* @returns Promise that resolves to the Web Inspector socket path or null
*/
async function getWebInspectorSocket() {
if (this._webInspectorSocket) {
return this._webInspectorSocket;
}
// lsof -aUc launchd_sim gives a set of records like
// https://github.com/appium/appium-ios-simulator/commit/c00901a9ddea178c5581a7a57d96d8cee3f17c59#diff-2be09dd2ea01cfd6bbbd73e10bc468da782a297365eec706999fc3709c01478dR102
// these _appear_ to always be grouped together by PID for each simulator.
// Therefore, by obtaining simulator PID with an expected simulator UDID,
// we can get the correct `com.apple.webinspectord_sim.socket`
// without depending on the order of `lsof -aUc launchd_sim` result.
const { stdout } = await (0, teen_process_1.exec)('lsof', ['-aUc', 'launchd_sim']);
const udidPattern = `([0-9]{1,5}).+${this.udid}`;
const udidMatch = stdout.match(new RegExp(udidPattern));
if (!udidMatch) {
this.log.debug(`Failed to get Web Inspector socket. lsof result: ${stdout}`);
return null;
}
const pidPattern = `${udidMatch[1]}.+\\s+(\\S+com\\.apple\\.webinspectord_sim\\.socket)`;
const pidMatch = stdout.match(new RegExp(pidPattern));
if (!pidMatch || !pidMatch[1]) {
this.log.debug(`Failed to get Web Inspector socket. lsof result: ${stdout}`);
return null;
}
const socketPath = pidMatch[1];
this._webInspectorSocket = socketPath;
return socketPath;
}
//# sourceMappingURL=safari.js.map