UNPKG

gst-atom-xcuitest-driver

Version:

ATOM driver for iOS using XCUITest for backend

1,309 lines (1,016 loc) 171 kB
"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