gst-atom-xcuitest-driver
Version:
ATOM driver for iOS using XCUITest for backend
1,309 lines (1,016 loc) • 171 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.XCUITestDriver = exports.default = void 0;
require("source-map-support/register");
var _gstAtomBaseDriver = require("gst-atom-base-driver");
var _appiumSupport = require("appium-support");
var _lodash = _interopRequireDefault(require("lodash"));
var _url = _interopRequireDefault(require("url"));
var _appiumWebdriveragent = require("appium-webdriveragent");
var _logger = _interopRequireDefault(require("./logger"));
var _simulatorManagement = require("./simulator-management");
var _appiumIosSimulator = require("appium-ios-simulator");
var _asyncbox = require("asyncbox");
var _gstAtomIosDriver = require("gst-atom-ios-driver");
var _desiredCaps = require("./desired-caps");
var _index = _interopRequireDefault(require("./commands/index"));
var _utils = require("./utils");
var _realDeviceManagement = require("./real-device-management");
var _bluebird = _interopRequireDefault(require("bluebird"));
var _asyncLock = _interopRequireDefault(require("async-lock"));
var _path = _interopRequireDefault(require("path"));
var _appiumIdb = _interopRequireDefault(require("appium-idb"));
var _deviceConnectionsFactory = _interopRequireDefault(require("./device-connections-factory"));
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
const SHUTDOWN_OTHER_FEAT_NAME = 'shutdown_other_sims';
const SAFARI_BUNDLE_ID = 'com.apple.mobilesafari';
const WDA_SIM_STARTUP_RETRIES = 2;
const WDA_REAL_DEV_STARTUP_RETRIES = 1;
const WDA_REAL_DEV_TUTORIAL_URL = 'https://github.com/appium/appium-xcuitest-driver/blob/master/docs/real-device-config.md';
const WDA_STARTUP_RETRY_INTERVAL = 10000;
const DEFAULT_SETTINGS = {
nativeWebTap: false,
nativeWebTapStrict: false,
useJSONSource: false,
shouldUseCompactResponses: true,
elementResponseAttributes: 'type,label',
mjpegServerScreenshotQuality: 25,
mjpegServerFramerate: 10,
screenshotQuality: 1,
mjpegScalingFactor: 100,
reduceMotion: null
};
const SHARED_RESOURCES_GUARD = new _asyncLock.default();
const NO_PROXY_NATIVE_LIST = [['DELETE', /window/], ['GET', /^\/session\/[^\/]+$/], ['GET', /alert_text/], ['GET', /alert\/[^\/]+/], ['GET', /appium/], ['GET', /attribute/], ['GET', /context/], ['GET', /location/], ['GET', /log/], ['GET', /screenshot/], ['GET', /size/], ['GET', /source/], ['GET', /timeouts$/], ['GET', /url/], ['GET', /window/], ['POST', /accept_alert/], ['POST', /actions$/], ['POST', /alert_text/], ['POST', /alert\/[^\/]+/], ['POST', /appium/], ['POST', /appium\/device\/is_locked/], ['POST', /appium\/device\/lock/], ['POST', /appium\/device\/unlock/], ['POST', /back/], ['POST', /clear/], ['POST', /context/], ['POST', /dismiss_alert/], ['POST', /element\/active/], ['POST', /element$/], ['POST', /elements$/], ['POST', /execute/], ['POST', /keys/], ['POST', /log/], ['POST', /moveto/], ['POST', /receive_async_response/], ['POST', /session\/[^\/]+\/location/], ['POST', /shake/], ['POST', /timeouts/], ['POST', /touch/], ['POST', /url/], ['POST', /value/], ['POST', /window/], ['DELETE', /cookie/], ['GET', /cookie/], ['POST', /cookie/]];
const NO_PROXY_WEB_LIST = [['GET', /attribute/], ['GET', /element/], ['GET', /text/], ['GET', /title/], ['POST', /clear/], ['POST', /click/], ['POST', /element/], ['POST', /forward/], ['POST', /frame/], ['POST', /keys/], ['POST', /refresh/]].concat(NO_PROXY_NATIVE_LIST);
const MEMOIZED_FUNCTIONS = ['getStatusBarHeight', 'getDevicePixelRatio', 'getScreenInfo'];
class XCUITestDriver extends _gstAtomBaseDriver.BaseDriver {
constructor(opts = {}, shouldValidateCaps = true) {
super(opts, shouldValidateCaps);
this.desiredCapConstraints = _desiredCaps.desiredCapConstraints;
this.locatorStrategies = ['xpath', 'id', 'name', 'class name', '-ios predicate string', '-ios class chain', 'accessibility id'];
this.webLocatorStrategies = ['link text', 'css selector', 'tag name', 'link text', 'partial link text'];
this.resetIos();
this.settings = new _gstAtomBaseDriver.DeviceSettings(DEFAULT_SETTINGS, this.onSettingsUpdate.bind(this));
this.logs = {};
for (const fn of MEMOIZED_FUNCTIONS) {
this[fn] = _lodash.default.memoize(this[fn]);
}
}
async onSettingsUpdate(key, value) {
if (key !== 'nativeWebTap' && key !== 'nativeWebTapStrict') {
return await this.proxyCommand('/appium/settings', 'POST', {
settings: {
[key]: value
}
});
}
this.opts[key] = !!value;
}
resetIos() {
this.opts = this.opts || {};
this.wda = null;
this.opts.device = null;
this.jwpProxyActive = false;
this.proxyReqRes = null;
this.jwpProxyAvoid = [];
this.safari = false;
this.cachedWdaStatus = null;
this.curWebFrames = [];
this.webElementIds = [];
this._currentUrl = null;
this.curContext = null;
this.xcodeVersion = {};
this.contexts = [];
this.implicitWaitMs = 0;
this.asynclibWaitMs = 0;
this.pageLoadMs = 6000;
this.landscapeWebCoordsOffset = 0;
this.remote = null;
}
get driverData() {
return {};
}
async getStatus() {
if (typeof this.driverInfo === 'undefined') {
this.driverInfo = await (0, _utils.getDriverInfo)();
}
let status = {
build: {
version: this.driverInfo.version
}
};
if (this.cachedWdaStatus) {
status.wda = this.cachedWdaStatus;
}
return status;
}
async createSession(...args) {
this.lifecycleData = {};
try {
let [sessionId, caps] = await super.createSession(...args);
this.opts.sessionId = sessionId;
await this.start();
caps = Object.assign({}, _gstAtomIosDriver.defaultServerCaps, caps);
caps.udid = this.opts.udid;
if (_lodash.default.has(this.opts, 'nativeWebTap')) {
await this.updateSettings({
nativeWebTap: this.opts.nativeWebTap
});
}
if (_lodash.default.has(this.opts, 'nativeWebTapStrict')) {
await this.updateSettings({
nativeWebTapStrict: this.opts.nativeWebTapStrict
});
}
if (_lodash.default.has(this.opts, 'useJSONSource')) {
await this.updateSettings({
useJSONSource: this.opts.useJSONSource
});
}
let wdaSettings = {
elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes,
shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses
};
if (_lodash.default.has(this.opts, 'elementResponseAttributes')) {
wdaSettings.elementResponseAttributes = this.opts.elementResponseAttributes;
}
if (_lodash.default.has(this.opts, 'shouldUseCompactResponses')) {
wdaSettings.shouldUseCompactResponses = this.opts.shouldUseCompactResponses;
}
if (_lodash.default.has(this.opts, 'mjpegServerScreenshotQuality')) {
wdaSettings.mjpegServerScreenshotQuality = this.opts.mjpegServerScreenshotQuality;
}
if (_lodash.default.has(this.opts, 'mjpegServerFramerate')) {
wdaSettings.mjpegServerFramerate = this.opts.mjpegServerFramerate;
}
if (_lodash.default.has(this.opts, 'screenshotQuality')) {
_logger.default.info(`Setting the quality of phone screenshot: '${this.opts.screenshotQuality}'`);
wdaSettings.screenshotQuality = this.opts.screenshotQuality;
}
await this.updateSettings(wdaSettings);
if (this.opts.mjpegScreenshotUrl) {
_logger.default.info(`Starting MJPEG stream reading URL: '${this.opts.mjpegScreenshotUrl}'`);
this.mjpegStream = new _appiumSupport.mjpeg.MJpegStream(this.opts.mjpegScreenshotUrl);
await this.mjpegStream.start();
}
return [sessionId, caps];
} catch (e) {
_logger.default.error(JSON.stringify(e));
await this.deleteSession();
throw e;
}
}
async start() {
this.opts.noReset = !!this.opts.noReset;
this.opts.fullReset = !!this.opts.fullReset;
await (0, _utils.printUser)();
this.opts.iosSdkVersion = null;
const {
device,
udid,
realDevice
} = await this.determineDevice();
_logger.default.info(`Determining device to run tests on: udid: '${udid}', real device: ${realDevice}`);
this.opts.device = device;
this.opts.udid = udid;
this.opts.realDevice = realDevice;
if (!this.opts.platformVersion && this.opts.device) {
this.opts.platformVersion = await this.opts.device.getPlatformVersion();
_logger.default.info(`No platformVersion specified. Using device version: '${this.opts.platformVersion}'`);
}
const normalizedVersion = (0, _utils.normalizePlatformVersion)(this.opts.platformVersion);
if (this.opts.platformVersion !== normalizedVersion) {
_logger.default.info(`Normalized platformVersion capability value '${this.opts.platformVersion}' to '${normalizedVersion}'`);
this.opts.platformVersion = normalizedVersion;
}
if (_appiumSupport.util.compareVersions(this.opts.platformVersion, '<', '9.3')) {
throw new Error(`Platform version must be 9.3 or above. '${this.opts.platformVersion}' is not supported.`);
}
if (_lodash.default.isEmpty(this.xcodeVersion) && (!this.opts.webDriverAgentUrl || !this.opts.realDevice)) {
this.xcodeVersion = await (0, _utils.getAndCheckXcodeVersion)();
}
this.logEvent('xcodeDetailsRetrieved');
const body = {
serial: this.opts.udid,
email: this.opts.userEmail
};
if (this.opts.dfTakeDeviceApi) {
await (0, _nodeFetch.default)(this.opts.dfTakeDeviceApi, {
method: 'post',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.opts.dfToken
},
timeout: 10000
}).catch(err => {
_logger.default.error(`[${this.opts.udid}] Cannot take the device ${err.message}`);
_logger.default.errorAndThrow(err);
});
_logger.default.info(`The device [${this.opts.udid}] now owned by [${this.opts.userEmail}]`);
}
if (_lodash.default.toLower(this.opts.browserName) === 'safari') {
_logger.default.info('Safari test requested');
this.safari = true;
this.opts.app = undefined;
this.opts.processArguments = this.opts.processArguments || {};
this.opts.bundleId = SAFARI_BUNDLE_ID;
this._currentUrl = this.opts.safariInitialUrl || (this.isRealDevice() ? 'http://appium.io' : `http://${this.opts.address}:${this.opts.port}/welcome`);
if (_appiumSupport.util.compareVersions(this.opts.platformVersion, '<', '12.2')) {
this.opts.processArguments.args = ['-u', this._currentUrl];
}
} else if (this.opts.app || this.opts.bundleId) {
await this.configureApp();
}
this.logEvent('appConfigured');
if (this.opts.app) {
await (0, _utils.checkAppPresent)(this.opts.app);
if (!this.opts.bundleId) {
this.opts.bundleId = await _gstAtomIosDriver.appUtils.extractBundleId(this.opts.app);
}
}
await this.runReset();
const memoizedLogInfo = _lodash.default.memoize(function logInfo() {
_logger.default.info("'skipLogCapture' is set. Skipping starting logs such as crash, system, safari console and safari network.");
});
const startLogCapture = async () => {
if (this.opts.skipLogCapture) {
memoizedLogInfo();
return false;
}
const result = await this.startLogCapture();
if (result) {
this.logEvent('logCaptureStarted');
}
return result;
};
const isLogCaptureStarted = await startLogCapture();
_logger.default.info(`Setting up ${this.isRealDevice() ? 'real device' : 'simulator'}`);
if (this.isSimulator()) {
if (this.opts.shutdownOtherSimulators) {
this.ensureFeatureEnabled(SHUTDOWN_OTHER_FEAT_NAME);
await (0, _simulatorManagement.shutdownOtherSimulators)(this.opts.device);
}
if (this.isSafari() && this.opts.safariGlobalPreferences) {
if (await this.opts.device.updateSafariGlobalSettings(this.opts.safariGlobalPreferences)) {
_logger.default.debug(`Safari global preferences updated`);
}
}
this.localConfig = await _gstAtomIosDriver.settings.setLocaleAndPreferences(this.opts.device, this.opts, this.isSafari(), async sim => {
await (0, _simulatorManagement.shutdownSimulator)(sim);
await _gstAtomIosDriver.settings.setLocaleAndPreferences(sim, this.opts, this.isSafari());
});
if (this.opts.customSSLCert) {
const certHead = _lodash.default.truncate(this.opts.customSSLCert, {
length: 20
});
_logger.default.info(`Installing the custom SSL certificate '${certHead}'`);
try {
await this.opts.device.simctl.addRootCertificate(this.opts.customSSLCert, {
raw: true
});
} catch (ign) {
if (await (0, _appiumIosSimulator.hasSSLCert)(this.opts.customSSLCert, this.opts.udid)) {
_logger.default.info(`SSL certificate '${certHead}' already installed`);
} else {
_logger.default.info(`Making sure Simulator is shut down, ' +
'so that SSL certificate installation takes effect`);
await (0, _simulatorManagement.shutdownSimulator)(this.opts.device);
await (0, _appiumIosSimulator.installSSLCert)(this.opts.customSSLCert, this.opts.udid);
}
}
this.logEvent('customCertInstalled');
}
await this.startSim();
if (this.opts.launchWithIDB && this.isSimulator()) {
try {
const idb = new _appiumIdb.default({
udid
});
await idb.connect();
this.opts.device.idb = idb;
} catch (e) {
_logger.default.info(`idb will not be used for Simulator interaction. Original error: ${e.message}`);
}
}
this.logEvent('simStarted');
if (!isLogCaptureStarted) {
await startLogCapture();
}
}
if (this.opts.app) {
await this.installAUT();
this.logEvent('appInstalled');
}
if (!this.opts.app && this.opts.bundleId && !this.safari) {}
if (this.opts.permissions) {
if (this.isSimulator()) {
_logger.default.debug('Setting the requested permissions before WDA is started');
for (const [bundleId, permissionsMapping] of _lodash.default.toPairs(JSON.parse(this.opts.permissions))) {
await this.opts.device.setPermissions(bundleId, permissionsMapping);
}
} else {
_logger.default.warn('Setting permissions is only supported on Simulator. ' + 'The "permissions" capability will be ignored.');
}
}
await this.startWda(this.opts.sessionId, realDevice);
await this.setReduceMotion(this.opts.reduceMotion);
await this.setInitialOrientation(this.opts.orientation);
this.logEvent('orientationSet');
if (this.isSafari() && !this.isRealDevice() && _appiumSupport.util.compareVersions(this.opts.platformVersion, '>=', '12.2')) {
await this.opts.device.openUrl(this._currentUrl);
}
if (this.isSafari() || this.opts.autoWebview) {
_logger.default.debug('Waiting for initial webview');
await this.navToInitialWebview();
this.logEvent('initialWebviewNavigated');
}
if (this.isSafari() && this.isRealDevice() && _appiumSupport.util.compareVersions(this.opts.platformVersion, '>=', '12.2')) {
await this.setUrl(this._currentUrl);
}
if (!this.isRealDevice()) {
if (this.opts.calendarAccessAuthorized) {
await this.opts.device.enableCalendarAccess(this.opts.bundleId);
} else if (this.opts.calendarAccessAuthorized === false) {
await this.opts.device.disableCalendarAccess(this.opts.bundleId);
}
}
}
async startWda(sessionId, realDevice) {
this.wda = new _appiumWebdriveragent.WebDriverAgent(this.xcodeVersion, this.opts);
if (!_appiumSupport.util.hasValue(this.wda.webDriverAgentUrl)) {
await this.wda.cleanupObsoleteProcesses();
}
const usePortForwarding = this.isRealDevice() && !this.wda.webDriverAgentUrl && (0, _utils.isLocalHost)(this.wda.wdaBaseUrl);
var options = {
udid: this.opts.udid,
port: this.wda.url.port,
devicePort: this.wda.wdaRemotePort,
usePortForwarding,
usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost,
usbmuxdRemotePort: this.opts.usbmuxdRemotePort
};
await _deviceConnectionsFactory.default.requestConnection(options);
let synchronizationKey = XCUITestDriver.name;
if (this.opts.useXctestrunFile || !(await this.wda.isSourceFresh())) {
const derivedDataPath = await this.wda.retrieveDerivedDataPath();
if (derivedDataPath) {
synchronizationKey = _path.default.normalize(derivedDataPath);
}
}
_logger.default.debug(`Starting WebDriverAgent initialization with the synchronization key '${synchronizationKey}'`);
if (SHARED_RESOURCES_GUARD.isBusy() && !this.opts.derivedDataPath && !this.opts.bootstrapPath) {
_logger.default.debug(`Consider setting a unique 'derivedDataPath' capability value for each parallel driver instance ` + `to avoid conflicts and speed up the building process`);
}
return await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
if (this.opts.useNewWDA) {
_logger.default.debug(`Capability 'useNewWDA' set to true, so uninstalling WDA before proceeding`);
await this.wda.quitAndUninstall();
this.logEvent('wdaUninstalled');
} else if (!_appiumSupport.util.hasValue(this.wda.webDriverAgentUrl)) {
await this.wda.setupCaching();
}
const quitAndUninstall = async msg => {
_logger.default.debug(msg);
if (this.opts.webDriverAgentUrl) {
_logger.default.debug('Not quitting/uninstalling WebDriverAgent since webDriverAgentUrl capability is provided');
throw new Error(msg);
}
_logger.default.warn('Quitting and uninstalling WebDriverAgent');
await this.wda.quitAndUninstall();
throw new Error(msg);
};
const startupRetries = this.opts.wdaStartupRetries || (this.isRealDevice() ? WDA_REAL_DEV_STARTUP_RETRIES : WDA_SIM_STARTUP_RETRIES);
const startupRetryInterval = this.opts.wdaStartupRetryInterval || WDA_STARTUP_RETRY_INTERVAL;
_logger.default.debug(`Trying to start WebDriverAgent ${startupRetries} times with ${startupRetryInterval}ms interval`);
if (!_appiumSupport.util.hasValue(this.opts.wdaStartupRetries) && !_appiumSupport.util.hasValue(this.opts.wdaStartupRetryInterval)) {
_logger.default.debug(`These values can be customized by changing wdaStartupRetries/wdaStartupRetryInterval capabilities`);
}
let retryCount = 0;
await (0, _asyncbox.retryInterval)(startupRetries, startupRetryInterval, async () => {
this.logEvent('wdaStartAttempted');
if (retryCount > 0) {
_logger.default.info(`Retrying WDA startup (${retryCount + 1} of ${startupRetries})`);
}
try {
const retries = this.xcodeVersion.major >= 10 ? 2 : 1;
this.cachedWdaStatus = await (0, _asyncbox.retry)(retries, this.wda.launch.bind(this.wda), sessionId, realDevice);
} catch (err) {
this.logEvent('wdaStartFailed');
retryCount++;
let errorMsg = `Unable to launch WebDriverAgent because of xcodebuild failure: ${err.message}`;
if (this.isRealDevice()) {
errorMsg += `. Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}. ` + `Try to remove the WebDriverAgentRunner application from the device if it is installed ` + `and reboot the device.`;
}
await quitAndUninstall(errorMsg);
}
this.proxyReqRes = this.wda.proxyReqRes.bind(this.wda);
this.jwpProxyActive = true;
let originalStacktrace = null;
try {
await (0, _asyncbox.retryInterval)(15, 1000, async () => {
this.logEvent('wdaSessionAttempted');
_logger.default.debug('Sending createSession command to WDA');
try {
this.cachedWdaStatus = this.cachedWdaStatus || (await this.proxyCommand('/status', 'GET'));
await this.startWdaSession(this.opts.bundleId, this.opts.processArguments);
} catch (err) {
originalStacktrace = err.stack;
_logger.default.debug(`Failed to create WDA session (${err.message}). Retrying...`);
throw err;
}
});
this.logEvent('wdaSessionStarted');
} catch (err) {
if (originalStacktrace) {
_logger.default.debug(originalStacktrace);
}
let errorMsg = `Unable to start WebDriverAgent session because of xcodebuild failure: ${err.message}`;
if (this.isRealDevice()) {
errorMsg += ` Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}. ` + `Try to remove the WebDriverAgentRunner application from the device if it is installed ` + `and reboot the device.`;
}
await quitAndUninstall(errorMsg);
}
if (this.opts.clearSystemFiles && !this.opts.webDriverAgentUrl) {
await (0, _utils.markSystemFilesForCleanup)(this.wda);
}
this.wda.fullyStarted = true;
this.logEvent('wdaStarted');
});
});
}
async runReset(opts = null) {
this.logEvent('resetStarted');
if (this.isRealDevice()) {
await (0, _realDeviceManagement.runRealDeviceReset)(this.opts.device, opts || this.opts);
} else {
await (0, _simulatorManagement.runSimulatorReset)(this.opts.device, opts || this.opts);
}
this.logEvent('resetComplete');
}
async deleteSession() {
await (0, _utils.removeAllSessionWebSocketHandlers)(this.server, this.sessionId);
if (this._recentScreenRecorder) {
await this._recentScreenRecorder.interrupt(true);
await this._recentScreenRecorder.cleanup();
this._recentScreenRecorder = null;
}
if (!_lodash.default.isEmpty(this._perfRecorders)) {
await _bluebird.default.all(this._perfRecorders.map(x => x.stop(true)));
this._perfRecorders = [];
}
await this.stop();
if (this.wda && !this.opts.webDriverAgentUrl) {
if (this.opts.clearSystemFiles) {
let synchronizationKey = XCUITestDriver.name;
const derivedDataPath = await this.wda.retrieveDerivedDataPath();
if (derivedDataPath) {
synchronizationKey = _path.default.normalize(derivedDataPath);
}
await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
await (0, _utils.clearSystemFiles)(this.wda);
});
} else {
_logger.default.debug('Not clearing log files. Use `clearSystemFiles` capability to turn on.');
}
}
if (this.remote) {
_logger.default.debug('Found a remote debugger session. Removing...');
await this.stopRemote();
}
if (this.opts.resetOnSessionStartOnly === false) {
await this.runReset(Object.assign({}, this.opts, {
enforceSimulatorShutdown: true
}));
}
if (this.isSimulator() && !this.opts.noReset && !!this.opts.device) {
if (this.lifecycleData.createSim) {
_logger.default.debug(`Deleting simulator created for this run (udid: '${this.opts.udid}')`);
await (0, _simulatorManagement.shutdownSimulator)(this.opts.device);
await this.opts.device.delete();
}
}
if (!_lodash.default.isEmpty(this.logs)) {
await this.logs.syslog.stopCapture();
this.logs = {};
}
if (this.mjpegStream) {
_logger.default.info('Closing MJPEG stream');
this.mjpegStream.stop();
}
this.resetIos();
await super.deleteSession();
}
async stop() {
this.jwpProxyActive = false;
this.proxyReqRes = null;
const body = {
serial: this.opts.udid
};
if (this.opts.dfReleaseDeviceApi) {
await (0, _nodeFetch.default)(this.opts.dfReleaseDeviceApi, {
method: 'post',
body: JSON.stringify(body),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.opts.dfToken
},
timeout: 10000
}).catch(err => {
_logger.default.error(`[${this.opts.udid}] Cannot release the device ${err.message}`);
_logger.default.errorAndThrow(err);
});
_logger.default.info(`Released device [${this.opts.udid}]`);
}
if (this.wda && this.wda.fullyStarted) {
if (this.wda.jwproxy) {
try {
await this.proxyCommand(`/session/${this.sessionId}`, 'DELETE');
} catch (err) {
_logger.default.debug(`Unable to DELETE session on WDA: '${err.message}'. Continuing shutdown.`);
}
}
if (!this.wda.webDriverAgentUrl && this.opts.useNewWDA) {
await this.wda.quit();
}
}
_deviceConnectionsFactory.default.releaseConnection(this.opts.udid);
}
async executeCommand(cmd, ...args) {
_logger.default.debug(`Executing command '${cmd}'`);
if (cmd === 'receiveAsyncResponse') {
return await this.receiveAsyncResponse(...args);
}
if (cmd === 'getStatus') {
return await this.getStatus();
}
return await super.executeCommand(cmd, ...args);
}
async configureApp() {
function appIsPackageOrBundle(app) {
return /^([a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+)+$/.test(app);
}
if (!this.opts.bundleId && appIsPackageOrBundle(this.opts.app)) {
this.opts.bundleId = this.opts.app;
this.opts.app = '';
}
if (this.opts.bundleId && appIsPackageOrBundle(this.opts.bundleId) && (this.opts.app === '' || appIsPackageOrBundle(this.opts.app))) {
_logger.default.debug('App is an iOS bundle, will attempt to run as pre-existing');
return;
}
switch (_lodash.default.toLower(this.opts.app)) {
case 'settings':
this.opts.bundleId = 'com.apple.Preferences';
this.opts.app = null;
return;
case 'calendar':
this.opts.bundleId = 'com.apple.mobilecal';
this.opts.app = null;
return;
}
try {
this.opts.appUrl = this.opts.app;
var setting = {
atompServiceKey: this.opts.atompServiceKey,
atompDomain: this.opts.atompDomain
};
this.opts.app = await this.helpers.configureApp(this.opts.app, '.app', setting);
} catch (err) {
_logger.default.error(err);
throw new Error(`Bad app: ${this.opts.app}. ` + `App paths need to be absolute or an URL to a compressed app file: ${err.message}`);
}
}
async determineDevice() {
this.lifecycleData.createSim = false;
this.opts.deviceName = (0, _utils.translateDeviceName)(this.opts.platformVersion, this.opts.deviceName);
const setupVersionCaps = async () => {
this.opts.iosSdkVersion = await (0, _utils.getAndCheckIosSdkVersion)();
_logger.default.info(`iOS SDK Version set to '${this.opts.iosSdkVersion}'`);
if (!this.opts.platformVersion && this.opts.iosSdkVersion) {
_logger.default.info(`No platformVersion specified. Using the latest version Xcode supports: '${this.opts.iosSdkVersion}'. ` + `This may cause problems if a simulator does not exist for this platform version.`);
this.opts.platformVersion = (0, _utils.normalizePlatformVersion)(this.opts.iosSdkVersion);
}
};
if (this.opts.udid) {
var option = {
udid: this.opts.udid,
usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost,
usbmuxdRemotePort: this.opts.usbmuxdRemotePort
};
if (this.opts.udid.toLowerCase() === 'auto') {
try {
this.opts.udid = await (0, _utils.detectUdid)(this.opts.usbmuxdRemoteHost, this.opts.usbmuxdRemotePort);
} catch (err) {
_logger.default.warn(`Cannot detect any connected real devices. Falling back to Simulator. Original error: ${err.message}`);
const device = await (0, _simulatorManagement.getExistingSim)(this.opts);
if (!device) {
_logger.default.errorAndThrow(`Cannot detect udid for ${this.opts.deviceName} Simulator running iOS ${this.opts.platformVersion}`);
}
this.opts.udid = device.udid;
const devicePlatform = (0, _utils.normalizePlatformVersion)(await device.getPlatformVersion());
if (this.opts.platformVersion !== devicePlatform) {
this.opts.platformVersion = devicePlatform;
_logger.default.info(`Set platformVersion to '${devicePlatform}' to match the device with given UDID`);
}
await setupVersionCaps();
return {
device,
realDevice: false,
udid: device.udid
};
}
} else if (!this.opts.webDriverAgentUrl) {
const devices = await (0, _realDeviceManagement.getConnectedDevices)(option);
_logger.default.debug(`Available devices: ${devices.join(', ')}`);
if (!devices.includes(this.opts.udid)) {
_logger.default.debug(`No real device with udid '${this.opts.udid}'. Looking for simulator`);
try {
const device = await (0, _appiumIosSimulator.getSimulator)(this.opts.udid);
return {
device,
realDevice: false,
udid: this.opts.udid
};
} catch (ign) {
throw new Error(`Unknown device or simulator UDID: '${this.opts.udid}'`);
}
}
}
var res = await (0, _realDeviceManagement.getRealDeviceObj)(this.opts);
return {
device: res,
realDevice: true,
udid: this.opts.udid
};
}
await setupVersionCaps();
if (this.opts.enforceFreshSimulatorCreation) {
_logger.default.debug(`New simulator is requested. If this is not wanted, set 'enforceFreshSimulatorCreation' capability to false`);
} else {
const device = await (0, _simulatorManagement.getExistingSim)(this.opts);
if (device) {
return {
device,
realDevice: false,
udid: device.udid
};
}
_logger.default.info('Simulator udid not provided');
}
_logger.default.info('Using desired caps to create a new simulator');
const device = await this.createSim();
return {
device,
realDevice: false,
udid: device.udid
};
}
async startSim() {
const runOpts = {
scaleFactor: this.opts.scaleFactor,
connectHardwareKeyboard: !!this.opts.connectHardwareKeyboard,
pasteboardAutomaticSync: this.opts.simulatorPasteboardAutomaticSync || 'off',
isHeadless: !!this.opts.isHeadless,
tracePointer: !!this.opts.simulatorTracePointer,
devicePreferences: {}
};
if (this.opts.SimulatorWindowCenter) {
runOpts.devicePreferences.SimulatorWindowCenter = this.opts.SimulatorWindowCenter;
}
if (_lodash.default.isInteger(this.opts.simulatorStartupTimeout)) {
runOpts.startupTimeout = this.opts.simulatorStartupTimeout;
}
const orientation = _lodash.default.isString(this.opts.orientation) && this.opts.orientation.toUpperCase();
switch (orientation) {
case 'LANDSCAPE':
runOpts.devicePreferences.SimulatorWindowOrientation = 'LandscapeLeft';
runOpts.devicePreferences.SimulatorWindowRotationAngle = 90;
break;
case 'PORTRAIT':
runOpts.devicePreferences.SimulatorWindowOrientation = 'Portrait';
runOpts.devicePreferences.SimulatorWindowRotationAngle = 0;
break;
}
await this.opts.device.run(runOpts);
}
async createSim() {
this.lifecycleData.createSim = true;
const platformName = this.isTvOS() ? _desiredCaps.PLATFORM_NAME_TVOS : _desiredCaps.PLATFORM_NAME_IOS;
let sim = await (0, _simulatorManagement.createSim)(this.opts, platformName);
_logger.default.info(`Created simulator with udid '${sim.udid}'.`);
return sim;
}
async launchApp() {
const APP_LAUNCH_TIMEOUT = 20 * 1000;
this.logEvent('appLaunchAttempted');
await this.opts.device.simctl.launchApp(this.opts.bundleId);
let checkStatus = async () => {
let response = await this.proxyCommand('/status', 'GET');
let currentApp = response.currentApp.bundleID;
if (currentApp !== this.opts.bundleId) {
throw new Error(`${this.opts.bundleId} not in foreground. ${currentApp} is in foreground`);
}
};
_logger.default.info(`Waiting for '${this.opts.bundleId}' to be in foreground`);
let retries = parseInt(APP_LAUNCH_TIMEOUT / 200, 10);
await (0, _asyncbox.retryInterval)(retries, 200, checkStatus);
_logger.default.info(`${this.opts.bundleId} is in foreground`);
this.logEvent('appLaunched');
}
async startWdaSession(bundleId, processArguments) {
let args = processArguments ? processArguments.args || [] : [];
if (!_lodash.default.isArray(args)) {
throw new Error(`processArguments.args capability is expected to be an array. ` + `${JSON.stringify(args)} is given instead`);
}
let env = processArguments ? processArguments.env || {} : {};
if (!_lodash.default.isPlainObject(env)) {
throw new Error(`processArguments.env capability is expected to be a dictionary. ` + `${JSON.stringify(env)} is given instead`);
}
let shouldWaitForQuiescence = _appiumSupport.util.hasValue(this.opts.waitForQuiescence) ? this.opts.waitForQuiescence : true;
let maxTypingFrequency = _appiumSupport.util.hasValue(this.opts.maxTypingFrequency) ? this.opts.maxTypingFrequency : 60;
let shouldUseSingletonTestManager = _appiumSupport.util.hasValue(this.opts.shouldUseSingletonTestManager) ? this.opts.shouldUseSingletonTestManager : true;
let shouldUseTestManagerForVisibilityDetection = false;
let eventloopIdleDelaySec = this.opts.wdaEventloopIdleDelay || 0;
if (_appiumSupport.util.hasValue(this.opts.simpleIsVisibleCheck)) {
shouldUseTestManagerForVisibilityDetection = this.opts.simpleIsVisibleCheck;
}
if (_appiumSupport.util.compareVersions(this.opts.platformVersion, '==', '9.3')) {
_logger.default.info(`Forcing shouldUseSingletonTestManager capability value to true, because of known XCTest issues under 9.3 platform version`);
shouldUseTestManagerForVisibilityDetection = true;
}
if (_appiumSupport.util.hasValue(this.opts.language)) {
args.push('-AppleLanguages', `(${this.opts.language})`);
args.push('-NSLanguages', `(${this.opts.language})`);
}
if (_appiumSupport.util.hasValue(this.opts.locale)) {
args.push('-AppleLocale', this.opts.locale);
}
const wdaCaps = {
bundleId: this.opts.autoLaunch === false ? undefined : bundleId,
arguments: args,
environment: env,
eventloopIdleDelaySec,
shouldWaitForQuiescence,
shouldUseTestManagerForVisibilityDetection,
maxTypingFrequency,
shouldUseSingletonTestManager
};
if (_appiumSupport.util.hasValue(this.opts.shouldUseCompactResponses)) {
wdaCaps.shouldUseCompactResponses = this.opts.shouldUseCompactResponses;
}
if (_appiumSupport.util.hasValue(this.opts.elementResponseFields)) {
wdaCaps.elementResponseFields = this.opts.elementResponseFields;
}
if (this.opts.autoAcceptAlerts) {
wdaCaps.defaultAlertAction = 'accept';
} else if (this.opts.autoDismissAlerts) {
wdaCaps.defaultAlertAction = 'dismiss';
}
await this.proxyCommand('/session', 'POST', {
capabilities: {
firstMatch: [wdaCaps],
alwaysMatch: {}
}
});
}
proxyActive() {
return this.jwpProxyActive;
}
getProxyAvoidList() {
if (this.isWebview()) {
return NO_PROXY_WEB_LIST;
}
return NO_PROXY_NATIVE_LIST;
}
canProxy() {
return true;
}
isSafari() {
return !!this.safari;
}
isRealDevice() {
return this.opts.realDevice;
}
isSimulator() {
return !this.opts.realDevice;
}
isTvOS() {
return _lodash.default.toLower(this.opts.platformName) === _lodash.default.toLower(_desiredCaps.PLATFORM_NAME_TVOS);
}
isWebview() {
return this.isSafari() || this.isWebContext();
}
validateLocatorStrategy(strategy) {
super.validateLocatorStrategy(strategy, this.isWebContext());
}
validateDesiredCaps(caps) {
if (!super.validateDesiredCaps(caps)) {
return false;
}
if (_lodash.default.toLower(caps.browserName) !== 'safari' && !caps.app && !caps.bundleId) {
_logger.default.info('The desired capabilities include neither an app nor a bundleId. ' + 'WebDriverAgent will be started without the default app');
}
if (!_appiumSupport.util.coerceVersion(caps.platformVersion, false)) {
_logger.default.warn(`'platformVersion' capability ('${caps.platformVersion}') is not a valid version number. ` + `Consider fixing it or be ready to experience an inconsistent driver behavior.`);
}
let verifyProcessArgument = processArguments => {
const {
args,
env
} = processArguments;
if (!_lodash.default.isNil(args) && !_lodash.default.isArray(args)) {
_logger.default.errorAndThrow('processArguments.args must be an array of strings');
}
if (!_lodash.default.isNil(env) && !_lodash.default.isPlainObject(env)) {
_logger.default.errorAndThrow('processArguments.env must be an object <key,value> pair {a:b, c:d}');
}
};
if (caps.processArguments) {
if (_lodash.default.isString(caps.processArguments)) {
try {
caps.processArguments = JSON.parse(caps.processArguments);
verifyProcessArgument(caps.processArguments);
} catch (err) {
_logger.default.errorAndThrow(`processArguments must be a JSON format or an object with format {args : [], env : {a:b, c:d}}. ` + `Both environment and argument can be null. Error: ${err}`);
}
} else if (_lodash.default.isPlainObject(caps.processArguments)) {
verifyProcessArgument(caps.processArguments);
} else {
_logger.default.errorAndThrow(`'processArguments must be an object, or a string JSON object with format {args : [], env : {a:b, c:d}}. ` + `Both environment and argument can be null.`);
}
}
if (caps.keychainPath && !caps.keychainPassword || !caps.keychainPath && caps.keychainPassword) {
_logger.default.errorAndThrow(`If 'keychainPath' is set, 'keychainPassword' must also be set (and vice versa).`);
}
this.opts.resetOnSessionStartOnly = !_appiumSupport.util.hasValue(this.opts.resetOnSessionStartOnly) || this.opts.resetOnSessionStartOnly;
this.opts.useNewWDA = _appiumSupport.util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
if (caps.commandTimeouts) {
caps.commandTimeouts = (0, _utils.normalizeCommandTimeouts)(caps.commandTimeouts);
}
if (_lodash.default.isString(caps.webDriverAgentUrl)) {
const {
protocol,
host
} = _url.default.parse(caps.webDriverAgentUrl);
if (_lodash.default.isEmpty(protocol) || _lodash.default.isEmpty(host)) {
_logger.default.errorAndThrow(`'webDriverAgentUrl' capability is expected to contain a valid WebDriverAgent server URL. ` + `'${caps.webDriverAgentUrl}' is given instead`);
}
}
if (caps.browserName) {
if (caps.bundleId) {
_logger.default.errorAndThrow(`'browserName' cannot be set together with 'bundleId' capability`);
}
if (caps.app) {
_logger.default.warn(`The capabilities should generally not include both an 'app' and a 'browserName'`);
}
}
if (caps.permissions) {
try {
for (const [bundleId, perms] of _lodash.default.toPairs(JSON.parse(caps.permissions))) {
if (!_lodash.default.isString(bundleId)) {
throw new Error(`'${JSON.stringify(bundleId)}' must be a string`);
}
if (!_lodash.default.isPlainObject(perms)) {
throw new Error(`'${JSON.stringify(perms)}' must be a JSON object`);
}
}
} catch (e) {
_logger.default.errorAndThrow(`'${caps.permissions}' is expected to be a valid object with format ` + `{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}. Original error: ${e.message}`);
}
}
if (caps.platformVersion && !_appiumSupport.util.coerceVersion(caps.platformVersion, false)) {
_logger.default.errorAndThrow(`'platformVersion' must be a valid version number. ` + `'${caps.platformVersion}' is given instead.`);
}
if (caps.additionalWebviewBundleIds) {
caps.additionalWebviewBundleIds = this.helpers.parseCapsArray(caps.additionalWebviewBundleIds);
}
return true;
}
async installAUT() {
if (this.isSafari()) {
return;
}
await (0, _utils.verifyApplicationPlatform)(this.opts.app, {
isSimulator: this.isSimulator(),
isTvOS: this.isTvOS()
});
if (this.isRealDevice()) {
await (0, _realDeviceManagement.installToRealDevice)(this.opts.device, this.opts.app, this.opts.bundleId, {
noReset: this.opts.noReset,
timeout: this.opts.appPushTimeout
});
} else {
await (0, _simulatorManagement.installToSimulator)(this.opts.device, this.opts.app, this.opts.bundleId, {
noReset: this.opts.noReset,
newSimulator: this.lifecycleData.createSim
});
}
if (this.opts.otherApps) {
await this.installOtherApps(this.opts.otherApps);
}
if (_appiumSupport.util.hasValue(this.opts.iosInstallPause)) {
let pause = parseInt(this.opts.iosInstallPause, 10);
_logger.default.debug(`iosInstallPause set. Pausing ${pause} ms before continuing`);
await _bluebird.default.delay(pause);
}
}
async installOtherApps(otherApps) {
if (this.isRealDevice()) {
_logger.default.warn('Capability otherApps is only supported for Simulators');
return;
}
try {
otherApps = this.helpers.parseCapsArray(otherApps);
} catch (e) {
_logger.default.errorAndThrow(`Could not parse "otherApps" capability: ${e.message}`);
}
for (const otherApp of otherApps) {
await (0, _simulatorManagement.installToSimulator)(this.opts.device, otherApp, undefined, {
noReset: this.opts.noReset,
newSimulator: this.lifecycleData.createSim
});
}
}
async setReduceMotion(isEnabled) {
if (this.isRealDevice() || !_lodash.default.isBoolean(isEnabled)) {
return;
}
_logger.default.info(`Setting reduceMotion to ${isEnabled}`);
await this.updateSettings({
reduceMotion: isEnabled
});
}
async setInitialOrientation(orientation) {
if (!_lodash.default.isString(orientation)) {
_logger.default.info('Skipping setting of the initial display orientation. ' + 'Set the "orientation" capability to either "LANDSCAPE" or "PORTRAIT", if this is an undesired behavior.');
return;
}
orientation = orientation.toUpperCase();
if (!_lodash.default.includes(['LANDSCAPE', 'PORTRAIT'], orientation)) {
_logger.default.debug(`Unable to set initial orientation to '${orientation}'`);
return;
}
_logger.default.debug(`Setting initial orientation to '${orientation}'`);
try {
await this.proxyCommand('/orientation', 'POST', {
orientation
});
this.opts.curOrientation = orientation;
} catch (err) {
_logger.default.warn(`Setting initial orientation failed with: ${err.message}`);
}
}
_getCommandTimeout(cmdName) {
if (this.opts.commandTimeouts) {
if (cmdName && _lodash.default.has(this.opts.commandTimeouts, cmdName)) {
return this.opts.commandTimeouts[cmdName];
}
return this.opts.commandTimeouts[_utils.DEFAULT_TIMEOUT_KEY];
}
}
async getSession() {
const driverSession = await super.getSession();
if (!this.wdaCaps) {
this.wdaCaps = await this.proxyCommand('/', 'GET');
}
if (!this.deviceCaps) {
const {
statusBarSize,
scale
} = await this.getScreenInfo();
this.deviceCaps = {
pixelRatio: scale,
statBarHeight: statusBarSize.height,
viewportRect: await this.getViewportRect()
};
}
_logger.default.info('Merging WDA caps over Appium caps for session detail response');
return Object.assign({
udid: this.opts.udid
}, driverSession, this.wdaCaps.capabilities, this.deviceCaps);
}
async reset() {
if (this.opts.noReset) {
let opts = _lodash.default.cloneDeep(this.opts);
opts.noReset = false;
opts.fullReset = false;
const shutdownHandler = this.resetOnUnexpectedShutdown;
this.resetOnUnexpectedShutdown = () => {};
try {
await this.runReset(opts);
} finally {
this.resetOnUnexpectedShutdown = shutdownHandler;
}
}
await super.reset();
}
}
exports.XCUITestDriver = XCUITestDriver;
Object.assign(XCUITestDriver.prototype, _index.default);
var _default = XCUITestDriver;
exports.default = _default;require('source-map-support').install();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9kcml2ZXIuanMiXSwibmFtZXMiOlsiU0hVVERPV05fT1RIRVJfRkVBVF9OQU1FIiwiU0FGQVJJX0JVTkRMRV9JRCIsIldEQV9TSU1fU1RBUlRVUF9SRVRSSUVTIiwiV0RBX1JFQUxfREVWX1NUQVJUVVBfUkVUUklFUyIsIldEQV9SRUFMX0RFVl9UVVRPUklBTF9VUkwiLCJXREFfU1RBUlRVUF9SRVRSWV9JTlRFUlZBTCIsIkRFRkFVTFRfU0VUVElOR1MiLCJuYXRpdmVXZWJUYXAiLCJuYXRpdmVXZWJUYXBTdHJpY3QiLCJ1c2VKU09OU291cmNlIiwic2hvdWxkVXNlQ29tcGFjdFJlc3BvbnNlcyIsImVsZW1lbnRSZXNwb25zZUF0dHJpYnV0ZXMiLCJtanBlZ1NlcnZlclNjcmVlbnNob3RRdWFsaXR5IiwibWpwZWdTZXJ2ZXJGcmFtZXJhdGUiLCJzY3JlZW5zaG90UXVhbGl0eSIsIm1qcGVnU2NhbGluZ0ZhY3RvciIsInJlZHVjZU1vdGlvbiIsIlNIQVJFRF9SRVNPVVJDRVNfR1VBUkQiLCJBc3luY0xvY2siLCJOT19QUk9YWV9OQVRJVkVfTElTVCIsIk5PX1BST1hZX1dFQl9MSVNUIiwiY29uY2F0IiwiTUVNT0laRURfRlVOQ1RJT05TIiwiWENVSVRlc3REcml2ZXIiLCJCYXNlRHJpdmVyIiwiY29uc3RydWN0b3IiLCJvcHRzIiwic2hvdWxkVmFsaWRhdGVDYXBzIiwiZGVzaXJlZENhcENvbnN0cmFpbnRzIiwibG9jYXRvclN0cmF0ZWdpZXMiLCJ3ZWJMb2NhdG9yU3RyYXRlZ2llcyIsInJlc2V0SW9zIiwic2V0dGluZ3MiLCJEZXZpY2VTZXR0aW5ncyIsIm9uU2V0dGluZ3NVcGRhdGUiLCJiaW5kIiwibG9ncyIsImZuIiwiXyIsIm1lbW9pemUiLCJrZXkiLCJ2YWx1ZSIsInByb3h5Q29tbWFuZCIsIndkYSIsImRldmljZSIsImp3cFByb3h5QWN0aXZlIiwicHJveHlSZXFSZXMiLCJqd3BQcm94eUF2b2lkIiwic2FmYXJpIiwiY2FjaGVkV2RhU3RhdHVzIiwiY3VyV2ViRnJhbWVzIiwid2ViRWxlbWVudElkcyIsIl9jdXJyZW50VXJsIiwiY3VyQ29udGV4dCIsInhjb2RlVmVyc2lvbiIsImNvbnRleHRzIiwiaW1wbGljaXRXYWl0TXMiLCJhc3luY2xpYldhaXRNcyIsInBhZ2VMb2FkTXMiLCJsYW5kc2NhcGVXZWJDb29yZHNPZmZzZXQiLCJyZW1vdGUiLCJkcml2ZXJEYXRhIiwiZ2V0U3RhdHVzIiwiZHJpdmVySW5mbyIsInN0YXR1cyIsImJ1aWxkIiwidmVyc2lvbiIsImNyZWF0ZVNlc3Npb24iLCJhcmdzIiwibGlmZWN5Y2xlRGF0YSIsInNlc3Npb25JZCIsImNhcHMiLCJzdGFydCIsIk9iamVjdCIsImFzc2lnbiIsImRlZmF1bHRTZXJ2ZXJDYXBzIiwidWRpZCIsImhhcyIsInVwZGF0ZVNldHRpbmdzIiwid2RhU2V0dGluZ3MiLCJsb2ciLCJpbmZvIiwibWpwZWdTY3JlZW5zaG90VXJsIiwibWpwZWdTdHJlYW0iLCJtanBlZyIsIk1KcGVnU3RyZWFtIiwiZSIsImVycm9yIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlbGV0ZVNlc3Npb24iLCJub1Jlc2V0IiwiZnVsbFJlc2V0IiwiaW9zU2RrVmVyc2lvbiIsInJlYWxEZXZpY2UiLCJkZXRlcm1pbmVEZXZpY2UiLCJwbGF0Zm9ybVZlcnNpb24iLCJnZXRQbGF0Zm9ybVZlcnNpb24iLCJub3JtYWxpemVkVmVyc2lvbiIsInV0aWwiLCJjb21wYXJlVmVyc2lvbnMiLCJFcnJvciIsImlzRW1wdHkiLCJ3ZWJEcml2ZXJBZ2VudFVybCIsImxvZ0V2ZW50IiwiYm9keSIsInNlcmlhbCIsImVtYWlsIiwidXNlckVtYWlsIiwiZGZUYWtlRGV2aWNlQXBpIiwibWV0aG9kIiwiaGVhZGVycyIsImRmVG9rZW4iLCJ0aW1lb3V0IiwiY2F0Y2giLCJlcnIiLCJtZXNzYWdlIiwiZXJyb3JBbmRUaHJvdyIsInRvTG93ZXIiLCJicm93c2VyTmFtZSIsImFwcCIsInVuZGVmaW5lZCIsInByb2Nlc3NBcmd1bWVudHMiLCJidW5kbGVJZCIsInNhZmFyaUluaXRpYWxVcmwiLCJpc1JlYWxEZXZpY2UiLCJhZGRyZXNzIiwicG9ydCIsImNvbmZpZ3VyZUFwcCIsImFwcFV0aWxzIiwiZXh0cmFjdEJ1bmRsZUlkIiwicnVuUmVzZXQiLCJtZW1vaXplZExvZ0luZm8iLCJsb2dJbmZvIiwic3RhcnRMb2dDYXB0dXJlIiwic2tpcExvZ0NhcHR1cmUiLCJyZXN1bHQiLCJpc0xvZ0NhcHR1cmVTdGFydGVkIiwiaXNTaW11bGF0b3IiLCJzaHV0ZG93bk90aGVyU2ltdWxhdG9ycyIsImVuc3VyZUZlYXR1cmVFbmFibGVkIiwiaXNTYWZhcmkiLCJzYWZhcmlHbG9iYWxQcmVmZXJlbmNlcyIsInVwZGF0ZVNhZmFyaUdsb2JhbFNldHRpbmdzIiwiZGVidWciLCJsb2NhbENvbmZpZyIsImlvc1NldHRpbmdzIiwic2V0TG9jYWxlQW5kUHJlZmVyZW5jZXMiLCJzaW0iLCJjdXN0b21TU0xDZXJ0IiwiY2VydEhlYWQiLCJ0cnVuY2F0ZSIsImxlbmd0aCIsInNpbWN0bCIsImFkZFJvb3RDZXJ0aWZpY2F0ZSIsInJhdyIsImlnbiIsInN0YXJ0U2ltIiwibGF1bmNoV2l0aElEQiIsImlkYiIsIklEQiIsImNvbm5lY3QiLCJpbnN0YWxsQVVUIiwicGVybWlzc2lvbnMiLCJwZXJtaXNzaW9uc01hcHBpbmciLCJ0b1BhaXJzIiwicGFyc2UiLCJzZXRQZXJtaXNzaW9ucyIsIndhcm4iLCJzdGFydFdkYSIsInNldFJlZHVjZU1vdGlvbiIsInNldEluaXRpYWxPcmllbnRhdGlvbiIsIm9yaWVudGF0aW9uIiwib3BlblVybCIsImF1dG9XZWJ2aWV3IiwibmF2VG9Jbml0aWFsV2VidmlldyIsInNldFVybCIsImNhbGVuZGFyQWNjZXNzQXV0aG9yaXplZCIsImVuYWJsZUNhbGVuZGFyQWNjZXNzIiwiZGlzYWJsZUNhbGVuZGFyQWNjZXNzIiwiV2ViRHJpdmVyQWdlbnQiLCJoYXNWYWx1ZSIsImNsZWFudXBPYnNvbGV0ZVByb2Nlc3NlcyIsInVzZVBvcnRGb3J3YXJkaW5nIiwid2RhQmFzZVVybCIsIm9wdGlvbnMiLCJ1cmwiLCJkZXZpY2VQb3J0Iiwid2RhUmVtb3RlUG9ydCIsInVzYm11eGRSZW1vdGVIb3N0IiwidXNibXV4ZFJlbW90ZVBvcnQiLCJERVZJQ0VfQ09OTkVDVElPTlNfRkFDVE9SWSIsInJlcXVlc3RDb25uZWN0aW9uIiwic3luY2hyb25pemF0aW9uS2V5IiwibmFtZSIsInVzZVhjdGVzdHJ1bkZpbGUiLCJpc1NvdXJjZUZyZXNoIiwiZGVyaXZlZERhdGFQYXRoIiwicmV0cmlldmVEZXJpdmVkRGF0YVBhdGgiLCJwYXRoIiwibm9ybWFsaXplIiwiaXNCdXN5IiwiYm9vdHN0cmFwUGF0aCIsImFjcXVpcmUiLCJ1c2VOZXdXREEiLCJxdWl0QW5kVW5pbnN0YWxsIiwic2V0dXBDYWNoaW5nIiwibXNnIiwic3RhcnR1cFJldHJpZXMiLCJ3ZGFTdGFydHVwUmV0cmllcyIsInN0YXJ0dXBSZXRyeUludGVydmFsIiwid2RhU3RhcnR1cFJldHJ5SW50ZXJ2YWwiLCJyZXRyeUNvdW50IiwicmV0cmllcyIsIm1ham9yIiwibGF1bmNoIiwiZXJyb3JNc2ciLCJvcmlnaW5hbFN0YWNrdHJhY2UiLCJzdGFydFdkYVNlc3Npb24iLCJzdGFjayIsImNsZWFyU3lzdGVtRmlsZXMiLCJmdWxseVN0YXJ0ZWQiLCJzZXJ2ZXIiLCJfcmVjZW50U2NyZWVuUmVjb3JkZXIiLCJpbnRlcnJ1cHQiLCJjbGVhbnVwIiwiX3BlcmZSZWNvcmRlcnMiLCJCIiwiYWxs