UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

271 lines 10.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.active = active; exports.touchId = touchId; exports.toggleEnrollTouchId = toggleEnrollTouchId; exports.getWindowSize = getWindowSize; exports.getDeviceTime = getDeviceTime; exports.mobileGetDeviceTime = mobileGetDeviceTime; exports.getWindowRect = getWindowRect; exports.removeApp = removeApp; exports.launchApp = launchApp; exports.closeApp = closeApp; exports.setUrl = setUrl; exports.getViewportRect = getViewportRect; exports.getScreenInfo = getScreenInfo; exports.getStatusBarHeight = getStatusBarHeight; exports.getDevicePixelRatio = getDevicePixelRatio; exports.mobilePressButton = mobilePressButton; exports.mobileSiriCommand = mobileSiriCommand; const lodash_1 = __importDefault(require("lodash")); const driver_1 = require("appium/driver"); const moment_timezone_1 = __importDefault(require("moment-timezone")); const lockdown_client_1 = require("../device/lockdown-client"); const MOMENT_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ'; /** * Gets the currently active element. * * In web context, returns the active element from the DOM. * In native context, returns the active element from the current view. * * @returns The active element */ async function active() { if (this.isWebContext()) { return this.cacheWebElements(await this.executeAtom('active_element', [])); } return await this.proxyCommand(`/element/active`, 'GET'); } /** * Trigger a touch/fingerprint match or match failure. * * @param match - Whether the match should be a success or failure */ async function touchId(match = true) { await this.mobileSendBiometricMatch('touchId', match); } /** * Toggle whether the device is enrolled in the touch ID program. * * @param isEnabled - Whether to enable or disable the touch ID program */ async function toggleEnrollTouchId(isEnabled = true) { await this.mobileEnrollBiometric(isEnabled); } /** * Get the window size. * * @returns The window size (width and height) */ async function getWindowSize() { const { width, height } = await this.getWindowRect(); return { width, height }; } /** * Retrieves the actual device time. * * @param format - The format specifier string. Read the [MomentJS documentation](https://momentjs.com/docs/) to get the full list of supported datetime format specifiers. The default format is `YYYY-MM-DDTHH:mm:ssZ`, which complies to ISO-8601. * @returns Formatted datetime string or the raw command output (if formatting fails) */ async function getDeviceTime(format = MOMENT_FORMAT_ISO8601) { this.log.debug('Attempting to capture iOS device date and time'); if (!this.isRealDevice()) { this.log.debug('On simulator. Assuming device time is the same as host time'); const hostNow = (0, moment_timezone_1.default)(); const utc = moment_timezone_1.default.unix(hostNow.unix()).utc(); return utc.utcOffset(hostNow.utcOffset()).format(format); } const udid = this.opts.udid; if (!udid) { throw new driver_1.errors.UnknownError('Device UDID is required to read time on a real device'); } const lockdown = await lockdown_client_1.LockdownClient.createForDevice(udid, this.opts, this.log); let timestamp; let utcOffset; try { ({ timestamp, utcOffset } = await lockdown.getDeviceTimeFields()); } finally { await lockdown.close(); } this.log.debug(`timestamp: ${timestamp}, utcOffset: ${utcOffset}`); const utc = moment_timezone_1.default.unix(timestamp).utc(); return utc.utcOffset(utcOffset).format(format); } /** * Retrieves the current device time. * * This is a wrapper around {@linkcode getDeviceTime}. * * @param format - See {@linkcode getDeviceTime.format} * @returns Formatted datetime string or the raw command output if formatting fails */ async function mobileGetDeviceTime(format = MOMENT_FORMAT_ISO8601) { return await this.getDeviceTime(format); } /** * Gets the window rectangle (position and size). * * For W3C compatibility. In web context, returns the browser window dimensions. * In native context, returns the device window dimensions. * * @returns The window rectangle */ async function getWindowRect() { if (this.isWebContext()) { const script = 'return {' + 'x: window.screenX || 0,' + 'y: window.screenY || 0,' + 'width: window.innerWidth,' + 'height: window.innerHeight' + '}'; return await this.executeAtom('execute_script', [script]); } return (await this.proxyCommand('/window/rect', 'GET')); } /** * Removes/uninstalls the given application from the device under test. * * This is a wrapper around {@linkcode mobileRemoveApp mobile: removeApp}. * * @param bundleId - The bundle identifier of the application to be removed * @returns `true` if the application has been removed successfully; `false` otherwise */ async function removeApp(bundleId) { return await this.mobileRemoveApp(bundleId); } /** * Launches the app. * * @deprecated This API has been deprecated and is not supported anymore. * Consider using corresponding 'mobile:' extensions to manage the state of the app under test. * @throws {Error} Always throws an error indicating the API is deprecated */ async function launchApp() { throw new Error(`The launchApp API has been deprecated and is not supported anymore. ` + `Consider using corresponding 'mobile:' extensions to manage the state of the app under test.`); } /** * Closes the app. * * @deprecated This API has been deprecated and is not supported anymore. * Consider using corresponding 'mobile:' extensions to manage the state of the app under test. * @throws {Error} Always throws an error indicating the API is deprecated */ async function closeApp() { throw new Error(`The closeApp API has been deprecated and is not supported anymore. ` + `Consider using corresponding 'mobile:' extensions to manage the state of the app under test.`); } /** * Sets the URL for the current session. * * In web context, navigates to the URL using the remote debugger. * In native context on real devices, uses the proxy command. * In native context on simulators, uses simctl to open the URL. * * @param url - The URL to navigate to */ async function setUrl(url) { this.log.debug(`Attempting to set url '${url}'`); if (this.isWebContext()) { this.setCurrentUrl(url); // make sure to clear out any leftover web frames this.curWebFrames = []; await this.remote.navToUrl(url); return; } if (this.isRealDevice()) { await this.proxyCommand('/url', 'POST', { url }); } else { await this.device.simctl.openUrl(url); } } /** * Retrieves the viewport dimensions. * * The viewport is the device's screen size with status bar size subtracted if the latter is present/visible. * * @returns The viewport rectangle */ async function getViewportRect() { const scale = await this.getDevicePixelRatio(); // status bar height comes in unscaled, so scale it const statusBarHeight = Math.trunc((await this.getStatusBarHeight()) * scale); const windowSize = await this.getWindowRect(); // ios returns coordinates/dimensions in logical pixels, not device pixels, // so scale up to device pixels. status bar height is already scaled. return { left: 0, top: statusBarHeight, width: Math.trunc(windowSize.width * scale), height: Math.trunc(windowSize.height * scale) - statusBarHeight, }; } /** * Get information about the screen. * * @privateRemarks memoized in constructor * @returns Screen information including dimensions, scale, and status bar size */ async function getScreenInfo() { return (await this.proxyCommand('/wda/screen', 'GET')); } /** * Gets the status bar height. * * @returns The height of the status bar in logical pixels */ async function getStatusBarHeight() { const { statusBarSize } = await this.getScreenInfo(); return statusBarSize.height; } /** * Gets the device pixel ratio. * * @privateRemarks memoized in constructor * @returns The device pixel ratio (scale factor) */ async function getDevicePixelRatio() { const { scale } = await this.getScreenInfo(); return scale; } /** * Emulates press action on the given physical device button. * * This executes different methods based on the platform: * * - iOS: [`pressButton:`](https://developer.apple.com/documentation/xctest/xcuidevice/1619052-pressbutton) * - tvOS: [`pressButton:`](https://developer.apple.com/documentation/xctest/xcuiremote/1627475-pressbutton) or [`pressButton:forDuration:`](https://developer.apple.com/documentation/xctest/xcuiremote/1627476-pressbutton) * * Use {@linkcode mobilePerformIoHidEvent} to call a more universal API to perform a button press with duration on any supported device. * * @param name - The name of the button to be pressed * @param durationSeconds - The duration of the button press in seconds (float) */ async function mobilePressButton(name, durationSeconds) { if (!name) { throw new driver_1.errors.InvalidArgumentError('Button name is mandatory'); } if (!lodash_1.default.isNil(durationSeconds) && !lodash_1.default.isNumber(durationSeconds)) { throw new driver_1.errors.InvalidArgumentError('durationSeconds should be a number'); } return await this.proxyCommand('/wda/pressButton', 'POST', { name, duration: durationSeconds }); } /** * Process a string as speech and send it to Siri. * * Presents the Siri UI, if it is not currently active, and accepts a string which is then processed as if it were recognized speech. See [the documentation of `activateWithVoiceRecognitionText`](https://developer.apple.com/documentation/xctest/xcuisiriservice/2852140-activatewithvoicerecognitiontext?language=objc) for more details. * * @param text - Text to be sent to Siri */ async function mobileSiriCommand(text) { if (!text) { throw new driver_1.errors.InvalidArgumentError('"text" argument is mandatory'); } await this.proxyCommand('/wda/siri/activate', 'POST', { text }); } //# sourceMappingURL=general.js.map