UNPKG

appium-xcuitest-driver

Version:

Appium driver for iOS using XCUITest for backend

124 lines (113 loc) 4.18 kB
import {retryInterval} from 'asyncbox'; import _ from 'lodash'; import {errors} from 'appium/driver'; import {util, imageUtil} from 'appium/support'; export default { /** * @this {XCUITestDriver} * @returns {Promise<string>} */ async getScreenshot() { if (this.isWebContext()) { const webScreenshotMode = (await this.settings.getSettings()).webScreenshotMode; switch (_.toLower(webScreenshotMode)) { case 'page': case 'viewport': return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot({ coordinateSystem: /** @type {'Viewport'|'Page'} */ (_.capitalize(webScreenshotMode)), }); case 'native': case undefined: case null: break; default: this.log.warn( `The webScreenshotMode setting value '${webScreenshotMode}' is not known. ` + `Supported values are: page, viewport and native. Falling back to the native mode.` ); break; } } const getScreenshotFromWDA = async () => { this.log.debug(`Taking screenshot with WDA`); const data = await this.proxyCommand('/screenshot', 'GET'); if (!_.isString(data)) { throw new Error(`Unable to take screenshot. WDA returned '${JSON.stringify(data)}'`); } return data; }; // if we've specified an mjpeg server, use that if (this.mjpegStream) { this.log.info(`mjpeg video stream provided, returning latest frame as screenshot`); const data = await this.mjpegStream.lastChunkPNGBase64(); if (data) { return data; } this.log.warn( 'Tried to get screenshot from active MJPEG stream, but there ' + 'was no data yet. Falling back to regular screenshot methods.', ); } try { return await getScreenshotFromWDA(); } catch (err) { this.log.warn(`Error getting screenshot: ${err.message}`); } // simulator attempt if (this.isSimulator()) { this.log.info(`Falling back to 'simctl io screenshot' API`); const payload = await /** @type {import('../driver').Simulator} */ (this.device).simctl.getScreenshot(); if (!payload) { throw new errors.UnableToCaptureScreen(); } return payload; } // Retry for real devices only. Fail fast on Simulator if simctl does not work as expected return /** @type {string} */ (await retryInterval(2, 1000, getScreenshotFromWDA)); }, /** * @this {XCUITestDriver} */ async getElementScreenshot(el) { el = util.unwrapElement(el); if (this.isWebContext()) { const atomsElement = this.getAtomsElement(el); const {width, height} = await this.executeAtom('get_size', [atomsElement]); if (!width || !height) { throw new errors.UnableToCaptureScreen('Cannot take a screenshot of a zero-size element'); } const {x, y} = await this.executeAtom('get_top_left_coordinates', [atomsElement]); return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)) .captureScreenshot({rect: {x, y, width, height}}); } const data = await this.proxyCommand(`/element/${el}/screenshot`, 'GET'); if (!_.isString(data)) { throw new errors.UnableToCaptureScreen( `Unable to take an element screenshot. WDA returned: ${JSON.stringify(data)}`, ); } return data; }, /** * @this {XCUITestDriver} * @returns {Promise<string>} */ async getViewportScreenshot() { if (this.isWebContext()) { return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot(); } const screenshot = await this.getScreenshot(); // if we don't have a status bar, there's nothing to crop, so we can avoid // extra calls and return straightaway if ((await this.getStatusBarHeight()) === 0) { return screenshot; } return await imageUtil.cropBase64Image( screenshot, await this.getViewportRect() ); }, }; /** * @typedef {import('../driver').XCUITestDriver} XCUITestDriver */