appium-xcuitest-driver
Version:
Appium driver for iOS using XCUITest for backend
128 lines • 6.09 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.installToRealDevice = installToRealDevice;
exports.runRealDeviceReset = runRealDeviceReset;
exports.applySafariStartupArgs = applySafariStartupArgs;
exports.detectUdid = detectUdid;
const lodash_1 = __importDefault(require("lodash"));
const app_utils_1 = require("./app-utils");
const appium_ios_device_1 = require("appium-ios-device");
const DEFAULT_APP_INSTALLATION_TIMEOUT_MS = 8 * 60 * 1000;
/**
* @typedef {Object} InstallOptions
*
* @property {boolean} [skipUninstall] Whether to skip app uninstall before installing it
* @property {number} [timeout=480000] App install timeout
* @property {boolean} [shouldEnforceUninstall] Whether to enforce the app uninstallation. e.g. fullReset, or enforceAppInstall is true
*/
/**
* @this {import('./driver').XCUITestDriver}
* @param {string} [app] The app to the path
* @param {string} [bundleId] The bundle id to ensure it is already installed and uninstall it
* @param {InstallOptions} [opts={}]
*/
async function installToRealDevice(app, bundleId, opts = {}) {
const device = /** @type {RealDevice} */ (this.device);
if (!device.udid || !app || !bundleId) {
this.log.debug('No device id, app or bundle id, not installing to real device.');
return;
}
const { skipUninstall, timeout = DEFAULT_APP_INSTALLATION_TIMEOUT_MS, } = opts;
if (!skipUninstall) {
this.log.info(`Reset requested. Removing app with id '${bundleId}' from the device`);
await device.remove(bundleId);
}
this.log.debug(`Installing '${app}' on the device with UUID '${device.udid}'`);
try {
await device.install(app, bundleId, {
timeoutMs: timeout,
});
this.log.debug('The app has been installed successfully.');
}
catch (e) {
// Want to clarify the device's application installation state in this situation.
if (!skipUninstall || !e.message.includes('MismatchedApplicationIdentifierEntitlement')) {
// Other error cases that could not be recoverable by here.
// Exact error will be in the log.
// We cannot recover 'ApplicationVerificationFailed' situation since this reason is clearly the app's provisioning profile was invalid.
// [XCUITest] Error installing app '/path/to.app': Unexpected data: {"Error":"ApplicationVerificationFailed","ErrorDetail":-402620395,"ErrorDescription":"Failed to verify code signature of /path/to.app : 0xe8008015 (A valid provisioning profile for this executable was not found.)"}
throw e;
}
// If the error was by below error case, we could recover the situation
// by uninstalling the device's app bundle id explicitly regard less the app exists on the device or not (e.g. offload app).
// [XCUITest] Error installing app '/path/to.app': Unexpected data: {"Error":"MismatchedApplicationIdentifierEntitlement","ErrorDescription":"Upgrade's application-identifier entitlement string (TEAM_ID.com.kazucocoa.example) does not match installed application's application-identifier string (ANOTHER_TEAM_ID.com.kazucocoa.example); rejecting upgrade."}
this.log.info(`The application identified by '${bundleId}' cannot be installed because it might ` +
`be already cached on the device, probably with a different signature. ` +
`Will try to remove it and install a new copy. Original error: ${e.message}`);
await device.remove(bundleId);
await device.install(app, bundleId, {
timeoutMs: timeout,
});
this.log.debug('The app has been installed after one retrial.');
}
}
/**
* @this {import('./driver').XCUITestDriver}
* @returns {Promise<void>}
*/
async function runRealDeviceReset() {
if (!this.opts.noReset || this.opts.fullReset) {
this.log.debug('Reset: running ios real device reset flow');
if (!this.opts.noReset) {
await /** @type {RealDevice} */ (this.device).reset(this.opts);
}
}
else {
this.log.debug('Reset: fullReset not set. Leaving as is');
}
}
/**
* Configures Safari startup options based on the given session capabilities.
*
* !!! This method mutates driver options.
*
* @this {import('./driver').XCUITestDriver}
* @return {boolean} true if process arguments have been modified
*/
function applySafariStartupArgs() {
const prefs = (0, app_utils_1.buildSafariPreferences)(this.opts);
if (lodash_1.default.isEmpty(prefs)) {
return false;
}
const args = lodash_1.default.toPairs(prefs)
.flatMap(([key, value]) => [lodash_1.default.startsWith(key, '-') ? key : `-${key}`, String(value)]);
this.log.debug(`Generated Safari command line arguments: ${args.join(' ')}`);
if (lodash_1.default.isPlainObject(this.opts.processArguments)) {
this.opts.processArguments.args = [...(this.opts.processArguments.args ?? []), ...args];
}
else {
this.opts.processArguments = { args };
}
return true;
}
/**
* @this {XCUITestDriver}
* @returns {Promise<string>}
*/
async function detectUdid() {
this.log.debug('Auto-detecting real device udid...');
const udids = await appium_ios_device_1.utilities.getConnectedDevices();
if (lodash_1.default.isEmpty(udids)) {
throw new Error('No real devices are connected to the host');
}
const udid = lodash_1.default.last(udids);
if (udids.length > 1) {
this.log.info(`Multiple devices found: ${udids.join(', ')}`);
this.log.info(`Choosing '${udid}'. Consider settings the 'udid' capability if another device must be selected`);
}
this.log.debug(`Detected real device udid: '${udid}'`);
return udid;
}
/**
* @typedef {import('./real-device').RealDevice} RealDevice}
* @typedef {import('./driver').XCUITestDriver} XCUITestDriver
*/
//# sourceMappingURL=real-device-management.js.map