From 6b2479455edddec3c9438994584dfd5f36f84c01 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Mar 2024 02:12:32 -0700 Subject: [PATCH 01/23] docs: add links to improve startup performance (#2370) * docs: add links to improve startup performance --- docs/preparation/real-device-config.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/preparation/real-device-config.md b/docs/preparation/real-device-config.md index 382caf844..10ecbf45f 100644 --- a/docs/preparation/real-device-config.md +++ b/docs/preparation/real-device-config.md @@ -86,3 +86,15 @@ Since iOS 16, Apple requires a device to have a live internet connection for val signing. It is possible to set up an offline enabled provisiong profile, which allows you to avoid the limitation. Please read [this issue](https://github.com/appium/appium/issues/18378#issuecomment-1482678074) regarding detailed configuration steps. + +## Tune WebDriverAgent to improve session startup performance + +Running `xcodebuild` every time takes much longer time to complete a session startup. +XCUITest driver offers a few methods to improve the performance with, or without using `xcodebuild`. + +Some might require deeper understanding of iOS development environment, +but they help to improve speedup your test execution speed. + +- [Run Preinstalled WebDriverAgentRunner](./../guides/run-preinstalled-wda.md) +- [Run Prebuilt WebDriverAgentRunner](./../guides/run-prebuilt-wda.md) +- [Attach to a Running WebDriverAgent](./../guides/attach-to-running-wda.md) From c0514e4050c7ab19d3e83a0026a81fa83e8218c4 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 28 Mar 2024 21:50:25 +0100 Subject: [PATCH 02/23] feat: Add 'appLaunchStateTimeoutSec' capability support (#2371) --- docs/reference/capabilities.md | 1 + lib/desired-caps.js | 3 +++ lib/driver.js | 1 + package.json | 2 +- test/unit/language-specs.js | 1 + test/unit/processargs-specs.js | 1 + 6 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index a1c5128f7..d26dd5877 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -85,6 +85,7 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e |`appium:shouldTerminateApp`| Specify if the app should be terminated on session end. This capability only has an effect if an application identifier has been passed to the test session (either explicitly, by setting bundleId, or implicitly, by providing app). Default is `true` unless `noReset` capability is set to `true`. |`true` or `false`| |`appium:forceAppLaunch`| Specify if the app should be forcefully restarted if it is already running on session startup. This capability only has an effect if an application identifier has been passed to the test session (either explicitly, by setting bundleId, or implicitly, by providing app). Default is `true` unless `noReset` capability is set to `true`. |`true` or `false`| |`appium:useNativeCachingStrategy`| Set this capability to `false` in order to use the custom elements caching strategy. This might help to avoid stale element exception on property change. By default the native XCTest cache resolution is used (`true`) for all native locators (e.g. all, but xpath). Check the corresponding [WebDriverAgent pull request](https://github.com/appium/WebDriverAgent/pull/516) for more details. |`true` or `false`| +|`appium:appLaunchStateTimeoutSec`|Allows to set the timeout in float seconds for the application state change on the session startup in range (0, 240) exclusively. The default value for it in XCTest is 60 seconds, which means WDA would throw an exception if the application under test is not ready for accessibility interactions in 60s after its process has started. **Important**: The fact the application's user interface is visible does not necessarily mean it could be immediately interacted with by XCTest. The latter must ensure the app's main thread is also idling. Setting this capability to a lower value might help to avoid prolonged test startup with problematic apps taking too much time to be ready and fail fast. It is not advised to increase the capability value above 60 seconds, rather consider fixing the affected application itself. Too low values though may cause unexpected app startup failures. The capability does not have an effect if the app under test is not (re)started at the beginning of the session. | `10.5` | ### Simulator diff --git a/lib/desired-caps.js b/lib/desired-caps.js index 3ca459156..35a89005d 100644 --- a/lib/desired-caps.js +++ b/lib/desired-caps.js @@ -366,6 +366,9 @@ const desiredCapConstraints = /** @type {const} */ ({ }, forceSimulatorSoftwareKeyboardPresence: { isBoolean: true, + }, + appLaunchStateTimeoutSec: { + isNumber: true, } }); diff --git a/lib/driver.js b/lib/driver.js index e0b9d9d00..1dbfb603a 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1347,6 +1347,7 @@ export class XCUITestDriver extends BaseDriver { disableAutomaticScreenshots: this.opts.disableAutomaticScreenshots, shouldTerminateApp: this.opts.shouldTerminateApp ?? true, forceAppLaunch: this.opts.forceAppLaunch ?? true, + appLaunchStateTimeoutSec: this.opts.appLaunchStateTimeoutSec, useNativeCachingStrategy: this.opts.useNativeCachingStrategy ?? true, forceSimulatorSoftwareKeyboardPresence: this.opts.forceSimulatorSoftwareKeyboardPresence ?? diff --git a/package.json b/package.json index b560d15df..0caec8d46 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "appium-ios-device": "^2.5.4", "appium-ios-simulator": "^6.1.2", "appium-remote-debugger": "^11.0.0", - "appium-webdriveragent": "^8.1.0", + "appium-webdriveragent": "^8.2.1", "appium-xcode": "^5.1.4", "async-lock": "^1.4.0", "asyncbox": "^3.0.0", diff --git a/test/unit/language-specs.js b/test/unit/language-specs.js index 273e783ee..d141e7b50 100644 --- a/test/unit/language-specs.js +++ b/test/unit/language-specs.js @@ -23,6 +23,7 @@ describe('language and locale', function () { useNativeCachingStrategy: true, shouldUseSingletonTestManager: true, eventloopIdleDelaySec: 0, + appLaunchStateTimeoutSec: undefined, environment: {}, }; diff --git a/test/unit/processargs-specs.js b/test/unit/processargs-specs.js index 88814507f..566d6fb15 100644 --- a/test/unit/processargs-specs.js +++ b/test/unit/processargs-specs.js @@ -22,6 +22,7 @@ describe('process args', function () { useNativeCachingStrategy: true, shouldTerminateApp: true, shouldUseSingletonTestManager: true, + appLaunchStateTimeoutSec: undefined, eventloopIdleDelaySec: 0, }; From 1a17e698fee501d7ffd08ddb471160b067289075 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 28 Mar 2024 20:51:58 +0000 Subject: [PATCH 03/23] chore(release): 7.8.0 [skip ci] ## [7.8.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.7.2...v7.8.0) (2024-03-28) ### Features * Add 'appLaunchStateTimeoutSec' capability support ([#2371](https://github.com/appium/appium-xcuitest-driver/issues/2371)) ([c0514e4](https://github.com/appium/appium-xcuitest-driver/commit/c0514e4050c7ab19d3e83a0026a81fa83e8218c4)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b5fb2a9e..b56fd60f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.8.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.7.2...v7.8.0) (2024-03-28) + + +### Features + +* Add 'appLaunchStateTimeoutSec' capability support ([#2371](https://github.com/appium/appium-xcuitest-driver/issues/2371)) ([c0514e4](https://github.com/appium/appium-xcuitest-driver/commit/c0514e4050c7ab19d3e83a0026a81fa83e8218c4)) + ## [7.7.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.7.1...v7.7.2) (2024-03-28) diff --git a/package.json b/package.json index 0caec8d46..cb441b198 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.7.2", + "version": "7.8.0", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 3f13c624ab2c89c8ff89dd07b2fdcaf33f5d5265 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Mar 2024 23:16:55 -0700 Subject: [PATCH 04/23] chore: left a comment for future work (#2372) --- lib/real-device.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/real-device.js b/lib/real-device.js index 2193462b9..fa7ad7588 100644 --- a/lib/real-device.js +++ b/lib/real-device.js @@ -251,6 +251,10 @@ export class RealDevice { await this.devicectl.sendSignalToProcess(pids[0], 2); } else { instrumentService = await services.startInstrumentService(this.udid); + + // The result of "runningProcesses" includes `bundle_id` key in iOS 16+ (possibly a specific 16.x+) + // then here may not be necessary to find a process with `CFBundleExecutable` + // after dropping older iOS version support. const processes = await instrumentService.callChannel( INSTRUMENT_CHANNEL.DEVICE_INFO, 'runningProcesses', From 9e18e0b903e809aafc13a967c79d18e645448aeb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 29 Mar 2024 06:18:52 +0000 Subject: [PATCH 05/23] chore(release): 7.8.1 [skip ci] ## [7.8.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.0...v7.8.1) (2024-03-29) ### Miscellaneous Chores * left a comment for future work ([#2372](https://github.com/appium/appium-xcuitest-driver/issues/2372)) ([3f13c62](https://github.com/appium/appium-xcuitest-driver/commit/3f13c624ab2c89c8ff89dd07b2fdcaf33f5d5265)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b56fd60f0..87547a80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.8.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.0...v7.8.1) (2024-03-29) + + +### Miscellaneous Chores + +* left a comment for future work ([#2372](https://github.com/appium/appium-xcuitest-driver/issues/2372)) ([3f13c62](https://github.com/appium/appium-xcuitest-driver/commit/3f13c624ab2c89c8ff89dd07b2fdcaf33f5d5265)) + ## [7.8.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.7.2...v7.8.0) (2024-03-28) diff --git a/package.json b/package.json index cb441b198..f1bed3449 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.8.0", + "version": "7.8.1", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 1c3d68b13a60513b4da9179351831ab05ca14bf3 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 29 Mar 2024 10:28:53 +0100 Subject: [PATCH 06/23] chore: bump WDA --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f1bed3449..57a7d8563 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "appium-ios-device": "^2.5.4", "appium-ios-simulator": "^6.1.2", "appium-remote-debugger": "^11.0.0", - "appium-webdriveragent": "^8.2.1", + "appium-webdriveragent": "^8.3.0", "appium-xcode": "^5.1.4", "async-lock": "^1.4.0", "asyncbox": "^3.0.0", From 61a23a319aed095168c88e2742086fee7eea581a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 29 Mar 2024 09:30:46 +0000 Subject: [PATCH 07/23] chore(release): 7.8.2 [skip ci] ## [7.8.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.1...v7.8.2) (2024-03-29) ### Miscellaneous Chores * bump WDA ([1c3d68b](https://github.com/appium/appium-xcuitest-driver/commit/1c3d68b13a60513b4da9179351831ab05ca14bf3)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87547a80c..866d26a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.8.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.1...v7.8.2) (2024-03-29) + + +### Miscellaneous Chores + +* bump WDA ([1c3d68b](https://github.com/appium/appium-xcuitest-driver/commit/1c3d68b13a60513b4da9179351831ab05ca14bf3)) + ## [7.8.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.0...v7.8.1) (2024-03-29) diff --git a/package.json b/package.json index 57a7d8563..77f2a40eb 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.8.1", + "version": "7.8.2", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 2bf1dc56d80ec712c6a7691ca24192df6fc6f4eb Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sun, 31 Mar 2024 09:10:31 +0200 Subject: [PATCH 08/23] feat: Enable Safari settings modification for real devices (#2373) --- docs/reference/capabilities.md | 8 +-- lib/app-utils.js | 30 +++++++++ lib/driver.js | 12 ++-- lib/real-device-management.js | 112 ++++++++++++--------------------- lib/real-device.js | 44 ++++++++++++- lib/simulator-management.js | 27 ++------ test/unit/driver-specs.js | 1 + 7 files changed, 132 insertions(+), 102 deletions(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index d26dd5877..ddc801c1e 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -113,7 +113,7 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e |`appium:simulatorPasteboardAutomaticSync`| Handle the `-PasteboardAutomaticSync` flag when simulator process launches. It could improve launching simulator performance not to sync pasteboard with the system when this value is `off`. `on` forces the flag enabled. `system` does not provide the flag to the launching command. `on`, `off`, or `system` is available. They are case insensitive. Defaults to `off` | `system` | |`appium:simulatorDevicesSetPath`| This capability allows to set an alternative path to the simulator devices set in case you have multiple sets deployed on your local system. Such feature could be useful if you, for example, would like to save disk space on the main system volume. | `/MyVolume/Devices` | |`appium:webkitResponseTimeout`| (Real device only) Set the time, in ms, to wait for a response from WebKit in a Safari session. Defaults to `5000` | `10000`| -|`appium:safariGlobalPreferences`| Allows changing of Mobile Safari's preferences at the session startup. Check the documentation on arguments of [mobile: updateSafariPreferences](./execute-methods.md#mobile-updatesafaripreferences) extension to get more details on the value type requirements. | `{ ShowTabBar: 0, WarnAboutFraudulentWebsites: 0 }` | +|`appium:safariGlobalPreferences`| Allows changing of Mobile Safari's preferences at the session startup. Check the documentation on arguments of [mobile: updateSafariPreferences](./execute-methods.md#mobile-updatesafaripreferences) extension to get more details on the value type requirements. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup for this capability to take effect on real devices. | `{ ShowTabBar: 0, WarnAboutFraudulentWebsites: 0 }` | ### Web Context @@ -133,9 +133,9 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e |`appium:nativeWebTap`| Enable native, non-javascript-based taps being in web context mode. Defaults to `false`. Warning: sometimes the preciseness of native taps could be broken, because there is no reliable way to map web element coordinates to native ones. | `true` | |`appium:nativeWebTapStrict`| Enabling this capability would skip the additional logic that tries to match web view elements to native ones by using their textual descriptions. Depending on the actual web view content this algorithm might sometimes be not very reliable and will slow down each click as we anyway fallback to the usual coordinates transformation flow if it fails. It is advised to enable strict tap if you use [mobile: calibrateWebToRealCoordinatesTranslation](./execute-methods.md#mobile-calibratewebtorealcoordinatestranslation) extension. Only applicable if `nativeWebTap` is enabled. `false` by default | `true` | |`appium:safariInitialUrl`| Initial safari url, default is a local welcome page. Setting it to an empty string will skip the initial navigation. | `https://www.github.com` | -|`appium:safariAllowPopups`| (Simulator only) Allow javascript to open new windows in Safari. Default keeps current sim setting. |`true` or `false`| -|`appium:safariIgnoreFraudWarning`| (Simulator only) Prevent Safari from showing a fraudulent website warning. Default keeps current sim setting. |`true` or `false`| -|`appium:safariOpenLinksInBackground`| (Simulator only) Whether Safari should allow links to open in new windows. Default keeps current sim setting. |`true` or `false`| +|`appium:safariAllowPopups`| Allow javascript to open new windows in Safari. Default keeps the current setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`| +|`appium:safariIgnoreFraudWarning`| Prevent Safari from showing a fraudulent website warning. Default keeps the current setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`| +|`appium:safariOpenLinksInBackground`| Whether Safari should allow links to open in new windows. Default keeps the current sim setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`| |`appium:webviewConnectRetries`| Number of times to send connection message to remote debugger, to get webview. Default: `8` |`12`| |`appium:webkitResponseTimeout`| (Real device only) Set the time, in ms, to wait for a response from WebKit in a Safari session. Defaults to `5000`|`10000`| |`appium:enableAsyncExecuteFromHttps`| Capability to allow simulators to execute asynchronous JavaScript on pages using HTTPS. Defaults to `false` | `true` or `false` | diff --git a/lib/app-utils.js b/lib/app-utils.js index b73614df5..dda29ce53 100644 --- a/lib/app-utils.js +++ b/lib/app-utils.js @@ -14,6 +14,15 @@ export const APP_EXT = '.app'; export const IPA_EXT = '.ipa'; /** @type {LRUCache} */ const PLIST_CACHE = new LRUCache({max: 20}); +const SAFARI_OPTS_ALIASES_MAP = /** @type {const} */ ({ + safariAllowPopups: [ + ['WebKitJavaScriptCanOpenWindowsAutomatically', 'JavaScriptCanOpenWindowsAutomatically'], + (x) => Number(Boolean(x)), + ], + safariIgnoreFraudWarning: [['WarnAboutFraudulentWebsites'], (x) => Number(!x)], + safariOpenLinksInBackground: [['OpenLinksInBackground'], (x) => Number(Boolean(x))], +}); + /** * Retrieves the value of the given entry name from the application's Info.plist. @@ -288,3 +297,24 @@ export async function isolateAppBundle(appRoot) { await fs.mv(appRoot, dstRoot, {mkdirp: true}); return dstRoot; } + +/** + * Builds Safari preferences object based on the given session capabilities + * + * @param {import('./driver').XCUITestDriverOpts} opts + * @return {Promise} + */ +export function buildSafariPreferences(opts) { + const safariSettings = _.cloneDeep(opts?.safariGlobalPreferences ?? {}); + + for (const [name, [aliases, valueConverter]] of _.toPairs(SAFARI_OPTS_ALIASES_MAP)) { + if (!_.has(opts, name)) { + continue; + } + + for (const alias of aliases) { + safariSettings[alias] = valueConverter(opts[name]); + } + } + return safariSettings; +} diff --git a/lib/driver.js b/lib/driver.js index 1dbfb603a..dbaf247d7 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -30,11 +30,14 @@ import {executeMethodMap} from './execute-method-map'; import {newMethodMap} from './method-map'; import Pyidevice from './py-ios-device-client'; import { - getConnectedDevices, - getRealDeviceObj, installToRealDevice, runRealDeviceReset, + applySafariStartupArgs, } from './real-device-management'; +import { + RealDevice, + getConnectedDevices, +} from './real-device'; import { createSim, getExistingSim, @@ -531,6 +534,7 @@ export class XCUITestDriver extends BaseDriver { this.safari = true; this.opts.app = undefined; this.opts.processArguments = this.opts.processArguments || {}; + applySafariStartupArgs.bind(this)(); this.opts.bundleId = SAFARI_BUNDLE_ID; this._currentUrl = this.opts.safariInitialUrl || this.getDefaultUrl(); } else if (this.opts.app || this.opts.bundleId) { @@ -1221,7 +1225,8 @@ export class XCUITestDriver extends BaseDriver { } } - const device = getRealDeviceObj.bind(this)(); + this.log.debug(`Creating iDevice object with udid '${this.opts.udid}'`); + const device = new RealDevice(this.opts.udid, this.log); return {device, realDevice: true, udid: this.opts.udid}; } @@ -2260,5 +2265,4 @@ export default XCUITestDriver; * @typedef {import('./types').WDACapabilities} WDACapabilities * @typedef {import('appium-xcode').XcodeVersion} XcodeVersion * @typedef {import('appium-ios-simulator').Simulator} Simulator - * @typedef {import('./real-device').RealDevice} RealDevice */ diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 5d89f4788..647278837 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,70 +1,5 @@ -import {utilities} from 'appium-ios-device'; -import RealDevice from './real-device'; -import {SAFARI_BUNDLE_ID} from './app-utils'; - -export async function getConnectedDevices() { - return await utilities.getConnectedDevices(); -} - -/** - * @param {string} udid - * @returns {Promise} - */ -export async function getOSVersion(udid) { - return await utilities.getOSVersion(udid); -} - -/** - * @this {import('./driver').XCUITestDriver} - * @returns {Promise} - */ -export async function resetRealDevice() { - const {bundleId, fullReset} = this.opts; - if (!bundleId) { - return; - } - - const device = /** @type {RealDevice} */ (this.device); - - if (bundleId === SAFARI_BUNDLE_ID) { - this.log.debug('Reset requested. About to terminate Safari'); - await device.terminateApp(bundleId, String(this.opts.platformVersion)); - return; - } - - if (!fullReset) { - return; - } - - this.log.debug(`Reset: fullReset requested. Will try to uninstall the app '${bundleId}'.`); - if (!(await device.isAppInstalled(bundleId))) { - this.log.debug('Reset: app not installed. No need to uninstall'); - return; - } - - try { - await device.remove(bundleId); - } catch (err) { - this.log.error(`Reset: could not remove '${bundleId}' from device: ${err.message}`); - throw err; - } - this.log.debug(`Reset: removed '${bundleId}'`); -} - -/** - * @this {import('./driver').XCUITestDriver} - * @returns {Promise} - */ -export async function runRealDeviceReset() { - if (!this.opts.noReset || this.opts.fullReset) { - this.log.debug('Reset: running ios real device reset flow'); - if (!this.opts.noReset) { - await resetRealDevice.bind(this)(); - } - } else { - this.log.debug('Reset: fullReset not set. Leaving as is'); - } -} +import _ from 'lodash'; +import {buildSafariPreferences} from './app-utils'; /** * @typedef {Object} InstallOptions @@ -126,9 +61,44 @@ export async function installToRealDevice(app, bundleId, opts = {}) { /** * @this {import('./driver').XCUITestDriver} - * @returns {RealDevice} + * @returns {Promise} */ -export function getRealDeviceObj() { - this.log.debug(`Creating iDevice object with udid '${this.opts.udid}'`); - return new RealDevice(this.opts.udid, this.log); +export async function runRealDeviceReset() { + if (!this.opts.noReset || this.opts.fullReset) { + this.log.debug('Reset: running ios real device reset flow'); + if (!this.opts.noReset) { + await /** @type {RealDevice} */ (this.device).reset(this.opts); + } + } else { + this.log.debug('Reset: fullReset not set. Leaving as is'); + } +} + +/** + * Configures Safari startup options based on the given session capabilities. + * + * !!! This method mutates driver options. + * + * @this {import('./driver').XCUITestDriver} + * @return {boolean} true if process arguments have been modified + */ +export function applySafariStartupArgs() { + const prefs = buildSafariPreferences(this.opts); + if (_.isEmpty(prefs)) { + return false; + } + + const args = _.toPairs(prefs) + .flatMap(([key, value]) => [_.startsWith(key, '-') ? key : `-${key}`, String(value)]); + this.log.debug(`Generated Safari command line arguments: ${args.join(' ')}`); + if (_.isPlainObject(this.opts.processArguments)) { + this.opts.processArguments.args = [...(this.opts.processArguments.args ?? []), ...args]; + } else { + this.opts.processArguments = {args}; + } + return true; } + +/** + * @typedef {import('./real-device').RealDevice} RealDevice} + */ diff --git a/lib/real-device.js b/lib/real-device.js index fa7ad7588..7e9fee689 100644 --- a/lib/real-device.js +++ b/lib/real-device.js @@ -5,7 +5,7 @@ import B from 'bluebird'; import defaultLogger from './logger'; import _ from 'lodash'; import {exec} from 'teen_process'; -import {extractBundleId} from './app-utils'; +import {extractBundleId, SAFARI_BUNDLE_ID} from './app-utils'; import {pushFolder} from './ios-fs-helpers'; import { Devicectl } from './devicectl'; @@ -20,6 +20,13 @@ const APP_INSTALL_STRATEGY = Object.freeze({ IOS_DEPLOY, }); +/** + * @returns {Promise} + */ +export async function getConnectedDevices() { + return await utilities.getConnectedDevices(); +} + export class RealDevice { /** * @param {string} udid @@ -317,6 +324,41 @@ export class RealDevice { async getPlatformVersion() { return await utilities.getOSVersion(this.udid); } + + /** + * @param {import('./driver').XCUITestDriverOpts} opts + * @returns {Promise} + */ + async reset({bundleId, fullReset, platformVersion}) { + if (!bundleId) { + return; + } + + if (bundleId === SAFARI_BUNDLE_ID) { + this.log.debug('Reset requested. About to terminate Safari'); + await this.terminateApp(bundleId, String(platformVersion)); + return; + } + + if (!fullReset) { + return; + } + + this.log.debug(`Reset: fullReset requested. Will try to uninstall the app '${bundleId}'.`); + if (!(await this.isAppInstalled(bundleId))) { + this.log.debug('Reset: app not installed. No need to uninstall'); + return; + } + + try { + await this.remove(bundleId); + } catch (err) { + this.log.error(`Reset: could not remove '${bundleId}' from device: ${err.message}`); + throw err; + } + this.log.debug(`Reset: removed '${bundleId}'`); + } + } export default RealDevice; diff --git a/lib/simulator-management.js b/lib/simulator-management.js index 401c31e31..1830d5602 100644 --- a/lib/simulator-management.js +++ b/lib/simulator-management.js @@ -4,16 +4,9 @@ import {resetTestProcesses} from 'appium-webdriveragent'; import _ from 'lodash'; import {util, timing} from 'appium/support'; import {UDID_AUTO, normalizePlatformName} from './utils'; +import {buildSafariPreferences} from './app-utils'; const APPIUM_SIM_PREFIX = 'appiumTest'; -const SAFARI_OPTS_ALIASES_MAP = /** @type {const} */ ({ - safariAllowPopups: [ - ['WebKitJavaScriptCanOpenWindowsAutomatically', 'JavaScriptCanOpenWindowsAutomatically'], - (x) => Number(Boolean(x)), - ], - safariIgnoreFraudWarning: [['WarnAboutFraudulentWebsites'], (x) => Number(!x)], - safariOpenLinksInBackground: [['OpenLinksInBackground'], (x) => Number(Boolean(x))], -}); /** * Create a new simulator with `appiumTest-` prefix and return the object. @@ -290,23 +283,13 @@ export async function shutdownOtherSimulators() { * @return {Promise} true if any preferences have been updated */ export async function setSafariPrefs() { - const safariSettings = _.cloneDeep(this.opts.safariGlobalPreferences ?? {}); - - for (const [name, [aliases, valueConverter]] of _.toPairs(SAFARI_OPTS_ALIASES_MAP)) { - if (!_.has(this.opts, name)) { - continue; - } - - for (const alias of aliases) { - safariSettings[alias] = valueConverter(this.opts[name]); - } - } - if (_.isEmpty(safariSettings)) { + const prefs = buildSafariPreferences(this.opts); + if (_.isEmpty(prefs)) { return false; } - this.log.debug(`About to update Safari preferences: ${JSON.stringify(safariSettings)}`); - await /** @type {import('./driver').Simulator} */ (this.device).updateSafariSettings(safariSettings); + this.log.debug(`About to update Safari preferences: ${JSON.stringify(prefs)}`); + await /** @type {import('./driver').Simulator} */ (this.device).updateSafariSettings(prefs); return true; } diff --git a/test/unit/driver-specs.js b/test/unit/driver-specs.js index 49adf8efc..bba5c78cf 100644 --- a/test/unit/driver-specs.js +++ b/test/unit/driver-specs.js @@ -114,6 +114,7 @@ describe('XCUITestDriver', function () { }, setReduceTransparency: _.noop, setAutoFillPasswords: _.noop, + reset: _.noop, }; realDevice = null; sandbox From 37fb8b4cd38b26fd1ffbbf0b561aca02158a978e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 31 Mar 2024 07:12:27 +0000 Subject: [PATCH 09/23] chore(release): 7.9.0 [skip ci] ## [7.9.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.2...v7.9.0) (2024-03-31) ### Features * Enable Safari settings modification for real devices ([#2373](https://github.com/appium/appium-xcuitest-driver/issues/2373)) ([2bf1dc5](https://github.com/appium/appium-xcuitest-driver/commit/2bf1dc56d80ec712c6a7691ca24192df6fc6f4eb)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 866d26a3d..e18a892c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.9.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.2...v7.9.0) (2024-03-31) + + +### Features + +* Enable Safari settings modification for real devices ([#2373](https://github.com/appium/appium-xcuitest-driver/issues/2373)) ([2bf1dc5](https://github.com/appium/appium-xcuitest-driver/commit/2bf1dc56d80ec712c6a7691ca24192df6fc6f4eb)) + ## [7.8.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.1...v7.8.2) (2024-03-29) diff --git a/package.json b/package.json index 77f2a40eb..73be61f5f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.8.2", + "version": "7.9.0", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From a777b93a5953dfd59e54f40817d198307f72289f Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 31 Mar 2024 10:02:07 -0700 Subject: [PATCH 10/23] chore: bump wda --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73be61f5f..9eb45a575 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "appium-ios-device": "^2.5.4", "appium-ios-simulator": "^6.1.2", "appium-remote-debugger": "^11.0.0", - "appium-webdriveragent": "^8.3.0", + "appium-webdriveragent": "^8.3.1", "appium-xcode": "^5.1.4", "async-lock": "^1.4.0", "asyncbox": "^3.0.0", From 11d411a42fa0fb9198bb983359eedfea3c3988ec Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 31 Mar 2024 17:04:06 +0000 Subject: [PATCH 11/23] chore(release): 7.9.1 [skip ci] ## [7.9.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.0...v7.9.1) (2024-03-31) ### Miscellaneous Chores * bump wda ([a777b93](https://github.com/appium/appium-xcuitest-driver/commit/a777b93a5953dfd59e54f40817d198307f72289f)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e18a892c7..901e8d712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.9.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.0...v7.9.1) (2024-03-31) + + +### Miscellaneous Chores + +* bump wda ([a777b93](https://github.com/appium/appium-xcuitest-driver/commit/a777b93a5953dfd59e54f40817d198307f72289f)) + ## [7.9.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.8.2...v7.9.0) (2024-03-31) diff --git a/package.json b/package.json index 9eb45a575..64339143c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.9.0", + "version": "7.9.1", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From c70df43f6df532a230d777535d513a56e70f511e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 2 Apr 2024 09:14:11 -0700 Subject: [PATCH 12/23] docs: add missing appium:prebuildWDA in caps (#2375) * docs: add missing prebuildWDA * Update run-prebuilt-wda.md --- docs/guides/run-prebuilt-wda.md | 9 +++++++-- docs/reference/capabilities.md | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/guides/run-prebuilt-wda.md b/docs/guides/run-prebuilt-wda.md index 24b4db6bd..adefc6ccf 100644 --- a/docs/guides/run-prebuilt-wda.md +++ b/docs/guides/run-prebuilt-wda.md @@ -55,7 +55,7 @@ xcodebuild test-without-building \ provided `.xctestrun` file. Once this is done, `http://localhost:8100` will be able to receive commands for the target device. -## Capabilities for Prebuilt WDA with `appium:useXctestrunFile` +## Capabilities for Prebuilt WDA with `appium:useXctestrunFile`, `appium:usePrebuiltWDA` or `appium:prebuildWDA` The XCUITest driver provides two capabilities that allow skipping the `build-for-testing` command, and executing only the `test-without-building` command: __`appium:useXctestrunFile`__ and @@ -85,10 +85,15 @@ The capabilities can be used as follows: Not all combinations have been tested, but the target device can probably be anything. -The same thing can be achieved with the `appium:derivedDataPath` and `appium:usePrebuiltWDA` +The same thing can be achieved with the __`appium:derivedDataPath`__ and __`appium:usePrebuiltWDA`__ capabilities, but this may fail if `xcodebuild` cannot find or handle the `.xctestrun` file properly. The stability depends on Xcode. +__`appium:prebuildWDA`__ lets the XCUITest driver build the WDA before running it, then the session +will be handled with `appium:usePrebuiltWDA`. +It might have additional building steps than with `appium:derivedDataPath` and `appium:usePrebuiltWDA` +combination, but it could help `appium:usePrebuiltWDA` to not manage the WDA project. + ## Capabilities for Prebuilt WDA with `appium:prebuiltWDAPath` [Run Preinstalled WebDriverAgentRunner](./run-prebuilt-wda.md) provides `appium:prebuiltWDAPath` capability. diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index ddc801c1e..1ee585524 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -60,7 +60,8 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e |`appium:wdaBaseUrl`| This value if specified, will be used as a prefix to build a custom `WebDriverAgent` url. It is different from `webDriverAgentUrl`, because if the latter is set then it expects `WebDriverAgent` to be already listening and skips the building phase. Defaults to `http://localhost` | `http://192.168.1.100`| |`appium:showXcodeLog`|Whether to display the output of the Xcode command used to run the tests. If this is `true`, there will be **lots** of extra logging at startup. Defaults to `false`|`true`| |`appium:iosInstallPause`|Time in milliseconds to pause between installing the application and starting `WebDriverAgent` on the device. Used particularly for larger applications. Defaults to `0`|`8000`| -|`appium:usePrebuiltWDA`|Skips the build phase of running the WDA app. Building is then the responsibility of the user. Only works for Xcode 8+. Defaults to `false`.|`true`| +|`appium:prebuildWDA`|Enables prebuilding if the WebDriverAgentRunner application before running the WDA app. With this capability, XCUITest driver builds the WDA project first, then it handles the session as `appium:usePrebuiltWDA` `true` behavior. Defaults to `false`.|`true`| +|`appium:usePrebuiltWDA`|Skips the build phase of running the WDA app. Building is then the responsibility of the user. `appium:derivedDataPath` let the session use the path as `-derivedDataPath` argument for `xcodebuild` command. Defaults to `false`.|`true`| |`appium:prebuiltWDAPath`| The full path to the prebuilt WebDriverAgent-Runner application package to be installed if `appium:usePreinstalledWDA` capability is enabled. The package's bundle identifier could be customized via `appium:updatedWDABundleId` capability. |`/path/to/WebDriverAgentRunner-Runner.app`| |`appium:usePreinstalledWDA`| Whether to launch a preinstalled WebDriverAgentRunner application using a custom XCTest API client (via `com.apple.instruments` service) instead of running `xcodebuild` for real devices or simulators via simctl tool (since driver version 7.4.0). If `appium:prebuiltWDAPath` is provided, XCUITest driver will install WebDriverAgent-Runner app from the given path before launching the application. The preinstalled WebDriverAgent package must be built by Xcode 12+. The default target bundle identifier is `com.facebook.WebDriverAgentRunner.xctrunner`, although it could be customized by providing the `appium:updatedWDABundleId` capability value (the `.xctrunner` suffix is added automatically). Please read [Run Preinstalled WebDriverAgentRunner](../guides/run-preinstalled-wda.md) for more details. Defaults to `false`. |`true` or `false`| |`appium:updatedWDABundleIdSuffix`| Add suffix for the bundle id provided by the `appium:updatedWDABundleId` capability value in `appium:usePreinstalledWDA` capability usage since XCUITest driver v7.6.0. This is for an advanced usage that sets an arbitrary `CFBundleIdentifier` for prebuilt WebDriverAgent package to sign with the bundle identifier's certificate. For example, if you would need to sign a WebDriverAgent package with `io.appium.wda` bundle identifier's certificate, the WebDriverAgent's package must have the same bundle identifier as `CFBundleIdentifier`. Then, the WebDriverAgent package can be launched by `io.appium.wda`, which does not have `.xctrunner`. Then `"appium:updatedWDABundleIdSuffix": ""` (an empty string) helps. Please read [Run Preinstalled WebDriverAgentRunner](../guides/run-preinstalled-wda.md) for more details. Defaults to `.xctrunner`. | `""`, `".customsuffix"` | From bc7141569f6148a8de77dc1989c2400a10a6c3f8 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sun, 7 Apr 2024 21:47:53 +0200 Subject: [PATCH 13/23] fix: Properly match simulator udid if webDriverAgentUrl is provided (#2377) --- lib/driver.js | 39 +++++++++++++++++++---------------- lib/real-device-management.js | 21 +++++++++++++++++++ lib/utils.js | 27 +++++++++--------------- test/unit/utils-specs.js | 4 ++-- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index dbaf247d7..3b74d5531 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -33,6 +33,7 @@ import { installToRealDevice, runRealDeviceReset, applySafariStartupArgs, + detectUdid, } from './real-device-management'; import { RealDevice, @@ -53,7 +54,6 @@ import { UDID_AUTO, checkAppPresent, clearSystemFiles, - detectUdid, getAndCheckIosSdkVersion, getAndCheckXcodeVersion, getDriverInfo, @@ -1165,7 +1165,7 @@ export class XCUITestDriver extends BaseDriver { this.lifecycleData.createSim = false; // if we get generic names, translate them - this.opts.deviceName = translateDeviceName(this.opts.platformVersion, this.opts.deviceName); + this.opts.deviceName = translateDeviceName(this.opts.platformVersion ?? '', this.opts.deviceName); const setupVersionCaps = async () => { this._iosSdkVersion = await getAndCheckIosSdkVersion(); @@ -1182,7 +1182,7 @@ export class XCUITestDriver extends BaseDriver { if (this.opts.udid) { if (this.opts.udid.toLowerCase() === UDID_AUTO) { try { - this.opts.udid = await detectUdid(); + this.opts.udid = await detectUdid.bind(this)(); } catch (err) { // Trying to find matching UDID for Simulator this.log.warn( @@ -1203,24 +1203,27 @@ export class XCUITestDriver extends BaseDriver { } else { // If the session specified this.opts.webDriverAgentUrl with a real device, // we can assume the user prepared the device properly already. - if (this.opts.webDriverAgentUrl) { - this.log.debug('Skipping checking of the device availability since the session specifies appium:webDriverAgentUrl'); - } else { - // make sure it is a connected device. If not, the udid passed in is invalid + let isRealDeviceUdid = false; + const shouldCheckAvailableRealDevices = !this.opts.webDriverAgentUrl; + if (!shouldCheckAvailableRealDevices) { const devices = await getConnectedDevices(); - this.log.debug(`Available devices: ${devices.join(', ')}`); - if (!devices.includes(this.opts.udid)) { - // check for a particular simulator - this.log.debug(`No real device with udid '${this.opts.udid}'. Looking for a simulator`); - try { - const device = await getSimulator(this.opts.udid, { - devicesSetPath: this.opts.simulatorDevicesSetPath, - logger: this.log, - }); - return {device, realDevice: false, udid: this.opts.udid}; - } catch (ign) { + this.log.debug(`Available real devices: ${devices.join(', ')}`); + isRealDeviceUdid = devices.includes(this.opts.udid); + } + if (!isRealDeviceUdid) { + try { + const device = await getSimulator(this.opts.udid, { + devicesSetPath: this.opts.simulatorDevicesSetPath, + logger: this.log, + }); + return {device, realDevice: false, udid: this.opts.udid}; + } catch { + if (shouldCheckAvailableRealDevices) { throw new Error(`Unknown device or simulator UDID: '${this.opts.udid}'`); } + this.log.debug( + 'Skipping checking of the real devices availability since the session specifies appium:webDriverAgentUrl' + ); } } } diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 647278837..d8463634c 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,5 +1,6 @@ import _ from 'lodash'; import {buildSafariPreferences} from './app-utils'; +import {utilities} from 'appium-ios-device'; /** * @typedef {Object} InstallOptions @@ -99,6 +100,26 @@ export function applySafariStartupArgs() { return true; } +/** + * @this {XCUITestDriver} + * @returns {Promise} + */ +export async function detectUdid() { + this.log.debug('Auto-detecting real device udid...'); + const udids = await utilities.getConnectedDevices(); + if (_.isEmpty(udids)) { + throw new Error('No real devices are connected to the host'); + } + const udid = _.last(udids); + if (udids.length > 1) { + this.log.info(`Multiple devices found: ${udids.join(', ')}`); + this.log.info(`Choosing '${udid}'. Consider settings the 'udid' capability if another device must be selected`); + } + this.log.debug(`Detected real device udid: '${udid}'`); + return udid; +} + /** * @typedef {import('./real-device').RealDevice} RealDevice} + * @typedef {import('./driver').XCUITestDriver} XCUITestDriver */ diff --git a/lib/utils.js b/lib/utils.js index df8cd7728..a238c465f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,4 +1,3 @@ -import {utilities} from 'appium-ios-device'; import xcode from 'appium-xcode'; import {errors} from 'appium/driver'; import {fs, net, util} from 'appium/support'; @@ -22,21 +21,6 @@ const XCTEST_LOG_FILES_PATTERNS = [ ]; const XCTEST_LOGS_CACHE_FOLDER_PREFIX = 'com.apple.dt.XCTest'; -async function detectUdid() { - log.debug('Auto-detecting real device udid...'); - const udids = await utilities.getConnectedDevices(); - if (_.isEmpty(udids)) { - throw new Error('No device is connected to the host'); - } - const udid = _.last(udids); - if (udids.length > 1) { - log.warn(`Multiple devices found: ${udids.join(', ')}`); - log.warn(`Choosing '${udid}'. If this is wrong, manually set with 'udid' desired capability`); - } - log.debug(`Detected real device udid: '${udid}'`); - return udid; -} - /** * @privateRemarks Is the minimum version really Xcode 7.3? * @returns {Promise} @@ -98,6 +82,12 @@ function getGenericSimulatorForIosVersion(platformVersion, deviceName) { return result; } +/** + * + * @param {string} platformVersion + * @param {string} deviceName + * @returns {string} + */ function translateDeviceName(platformVersion, deviceName) { if (!deviceName) { return deviceName; @@ -114,6 +104,10 @@ function translateDeviceName(platformVersion, deviceName) { return deviceNameTranslated; } +/** + * @param {string[]} locations + * @returns {Promise} + */ async function clearLogs(locations) { log.debug('Clearing log files'); const cleanupPromises = []; @@ -503,7 +497,6 @@ export function normalizePlatformName(platformName) { } export { - detectUdid, getAndCheckXcodeVersion, getAndCheckIosSdkVersion, checkAppPresent, diff --git a/test/unit/utils-specs.js b/test/unit/utils-specs.js index 0e319afa6..48082e9fd 100644 --- a/test/unit/utils-specs.js +++ b/test/unit/utils-specs.js @@ -89,11 +89,11 @@ describe('utils', function () { deviceName.should.equal('iPad Retina'); }); it('should set the correct iPad simulator generic device for iOS >= 10.3', function () { - let deviceName = translateDeviceName(10.103, ipadDeviceName); + let deviceName = translateDeviceName('10.103', ipadDeviceName); deviceName.should.equal('iPad Air'); deviceName = translateDeviceName('10.3', ipadDeviceName); deviceName.should.equal('iPad Air'); - deviceName = translateDeviceName(10.3, ipadDeviceName); + deviceName = translateDeviceName('10.3', ipadDeviceName); deviceName.should.equal('iPad Air'); }); it('should set the correct iPhone simulator generic device', function () { From 20eb0ede4fb2bb29e239dd67fecf91853cff9877 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 7 Apr 2024 19:49:46 +0000 Subject: [PATCH 14/23] chore(release): 7.9.2 [skip ci] ## [7.9.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.1...v7.9.2) (2024-04-07) ### Bug Fixes * Properly match simulator udid if webDriverAgentUrl is provided ([#2377](https://github.com/appium/appium-xcuitest-driver/issues/2377)) ([bc71415](https://github.com/appium/appium-xcuitest-driver/commit/bc7141569f6148a8de77dc1989c2400a10a6c3f8)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 901e8d712..92681e003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.9.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.1...v7.9.2) (2024-04-07) + + +### Bug Fixes + +* Properly match simulator udid if webDriverAgentUrl is provided ([#2377](https://github.com/appium/appium-xcuitest-driver/issues/2377)) ([bc71415](https://github.com/appium/appium-xcuitest-driver/commit/bc7141569f6148a8de77dc1989c2400a10a6c3f8)) + ## [7.9.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.0...v7.9.1) (2024-03-31) diff --git a/package.json b/package.json index 64339143c..0a54d8fca 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.9.1", + "version": "7.9.2", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From e75cd2c127b0b2d1206cbd4d7b22923ee553798c Mon Sep 17 00:00:00 2001 From: Finja Hauschild <11769157+FiniH@users.noreply.github.com> Date: Sun, 7 Apr 2024 22:01:51 +0200 Subject: [PATCH 15/23] fix: Added platformVersion to capabilities (#2378) --- lib/driver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/driver.js b/lib/driver.js index 3b74d5531..584fdd6d6 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -522,6 +522,7 @@ export class XCUITestDriver extends BaseDriver { ); this.opts.platformVersion = normalizedVersion; } + this.caps.platformVersion = this.opts.platformVersion; if (_.isEmpty(this.xcodeVersion) && (this.isXcodebuildNeeded() || this.isSimulator())) { // no `webDriverAgentUrl`, or on a simulator, so we need an Xcode version From 1e18b2f7c859f915aa353716add65d0a404c0fa7 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sun, 7 Apr 2024 22:48:26 +0200 Subject: [PATCH 16/23] fix: Update various type declarations (#2380) --- lib/commands/recordscreen.js | 2 +- lib/driver.js | 10 +++++-- lib/types.ts | 35 ----------------------- package.json | 2 +- test/unit/commands/activeAppInfo-specs.js | 3 +- test/unit/commands/deviceinfo-specs.js | 3 +- test/unit/commands/proxy-helper-specs.js | 6 +++- test/unit/driver-specs.js | 2 ++ 8 files changed, 20 insertions(+), 43 deletions(-) diff --git a/lib/commands/recordscreen.js b/lib/commands/recordscreen.js index 536080c44..f1d4e3749 100644 --- a/lib/commands/recordscreen.js +++ b/lib/commands/recordscreen.js @@ -252,7 +252,7 @@ export default { } let {mjpegServerScreenshotQuality, mjpegServerFramerate} = - /** @type {import('../types').WDASettings} */ ( + /** @type {import('appium-webdriveragent').WDASettings} */ ( await this.proxyCommand('/appium/settings', 'GET') ); if (videoQuality) { diff --git a/lib/driver.js b/lib/driver.js index 584fdd6d6..6dbeb936f 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -265,6 +265,9 @@ export class XCUITestDriver extends BaseDriver { /** @type {string|null} */ _iosSdkVersion; + /** @type {WebDriverAgent} */ + wda; + /** * * @param {XCUITestDriverOpts} opts @@ -331,6 +334,7 @@ export class XCUITestDriver extends BaseDriver { resetIos() { this.opts = this.opts || {}; + // @ts-ignore this is ok this.wda = null; this.jwpProxyActive = false; this.proxyReqRes = null; @@ -431,7 +435,7 @@ export class XCUITestDriver extends BaseDriver { await this.updateSettings({useJSONSource: this.opts.useJSONSource}); } - /** @type {import('./types').WDASettings} */ + /** @type {import('appium-webdriveragent').WDASettings} */ let wdaSettings = { elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes, shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses, @@ -563,6 +567,7 @@ export class XCUITestDriver extends BaseDriver { realDevice: this.isRealDevice(), iosSdkVersion: this._iosSdkVersion, }, + // @ts-ignore this is ok this.log, ); // Derived data path retrieval is an expensive operation @@ -1338,7 +1343,7 @@ export class XCUITestDriver extends BaseDriver { } } - /** @type {WDACapabilities} */ + /** @type {import('appium-webdriveragent').WDACapabilities} */ const wdaCaps = /** @type {any} */ ({ bundleId: this.opts.autoLaunch === false ? undefined : bundleId, arguments: args, @@ -2266,7 +2271,6 @@ export default XCUITestDriver; * @typedef {typeof desiredCapConstraints} XCUITestDriverConstraints * @typedef {import('@appium/types').DriverOpts} XCUITestDriverOpts * @typedef {import('./commands/types').FullContext} FullContext - * @typedef {import('./types').WDACapabilities} WDACapabilities * @typedef {import('appium-xcode').XcodeVersion} XcodeVersion * @typedef {import('appium-ios-simulator').Simulator} Simulator */ diff --git a/lib/types.ts b/lib/types.ts index b7464519a..dc234d68d 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,5 +1,3 @@ -import {StringRecord} from '@appium/types'; - export interface Page { id: number | string; isKey?: boolean; @@ -15,39 +13,6 @@ export interface LifecycleData { createSim?: boolean; } -export interface WDASettings { - elementResponseAttributes: string; - shouldUseCompactResponses: boolean; - mjpegServerScreenshotQuality?: number; - mjpegServerFramerate?: number; - screenshotQuality?: number; -} - -/** - * @todo This should likely be shipped by `appium-webdriveragent` instead. - */ -export interface WDACapabilities { - bundleId?: string; - initialUrl?: string; - arguments: string[]; - environment: Record; - eventloopIdleDelaySec: number; - shouldWaitForQuiescence: boolean; - shouldUseTestManagerForVisibilityDetection: boolean; - maxTypingFrequency: number; - shouldUseSingletonTestManager: boolean; - waitForIdleTimeout?: number; - shouldUseCompactResponses?: number; - elementResponseFields?: unknown; - disableAutomaticScreenshots?: boolean; - shouldTerminateApp: boolean; - forceAppLaunch: boolean; - useNativeCachingStrategy: boolean; - forceSimulatorSoftwareKeyboardPresence: boolean; - defaultAlertAction: 'accept' | 'dismiss'; - capabilities?: StringRecord; -} - export interface CalibrationData { /** * webview x offset in real coordinates diff --git a/package.json b/package.json index 0a54d8fca..219e50684 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "appium-ios-device": "^2.5.4", "appium-ios-simulator": "^6.1.2", "appium-remote-debugger": "^11.0.0", - "appium-webdriveragent": "^8.3.1", + "appium-webdriveragent": "^8.5.0", "appium-xcode": "^5.1.4", "async-lock": "^1.4.0", "asyncbox": "^3.0.0", diff --git a/test/unit/commands/activeAppInfo-specs.js b/test/unit/commands/activeAppInfo-specs.js index 0050437ba..ededab475 100644 --- a/test/unit/commands/activeAppInfo-specs.js +++ b/test/unit/commands/activeAppInfo-specs.js @@ -8,11 +8,12 @@ chai.use(chaiAsPromised); describe('get activeapp commands', function () { const driver = new XCUITestDriver(); - // give the driver a spy-able proxy object + // @ts-ignore give the driver a spy-able proxy object driver.wda = {jwproxy: {command: () => {}}}; let proxyStub; this.beforeEach(function () { + // @ts-ignore ok for tests proxyStub = sinon.stub(driver.wda.jwproxy, 'command'); }); diff --git a/test/unit/commands/deviceinfo-specs.js b/test/unit/commands/deviceinfo-specs.js index 3c95c2258..4d06ae6b5 100644 --- a/test/unit/commands/deviceinfo-specs.js +++ b/test/unit/commands/deviceinfo-specs.js @@ -8,11 +8,12 @@ chai.use(chaiAsPromised); describe('get deviceinfo commands', function () { const driver = new XCUITestDriver(); - // give the driver a spy-able proxy object + // @ts-ignore give the driver a spy-able proxy object driver.wda = {jwproxy: {command: () => {}}}; let proxyStub; this.beforeEach(function () { + // @ts-ignore ok for tests proxyStub = sinon.stub(driver.wda.jwproxy, 'command'); }); diff --git a/test/unit/commands/proxy-helper-specs.js b/test/unit/commands/proxy-helper-specs.js index 78beada4e..34aff6edc 100644 --- a/test/unit/commands/proxy-helper-specs.js +++ b/test/unit/commands/proxy-helper-specs.js @@ -9,8 +9,9 @@ chai.use(chaiAsPromised); describe('proxy commands', function () { let driver = new XCUITestDriver(); - // give the driver a spy-able proxy object + // @ts-ignore give the driver a spy-able proxy object driver.wda = {jwproxy: {command: () => {}}}; + // @ts-ignore ok for tests const proxyStub = sinon.stub(driver.wda.jwproxy, 'command'); afterEach(function () { @@ -25,8 +26,11 @@ describe('proxy commands', function () { await driver.proxyCommand('/some/endpoint', 'POST', {some: 'stuff'}); proxyStub.calledOnce.should.be.true; + // @ts-ignore proxyStub.firstCall.args[0].should.eql('/some/endpoint'); + // @ts-ignore proxyStub.firstCall.args[1].should.eql('POST'); + // @ts-ignore proxyStub.firstCall.args[2].some.should.eql('stuff'); }); it('should throw an error if no endpoint is given', async function () { diff --git a/test/unit/driver-specs.js b/test/unit/driver-specs.js index bba5c78cf..17ccc6658 100644 --- a/test/unit/driver-specs.js +++ b/test/unit/driver-specs.js @@ -75,6 +75,7 @@ describe('XCUITestDriver', function () { // fake the proxy to WDA const jwproxy = new JWProxy(); jwproxyCommandSpy = sandbox.stub(jwproxy, 'command').resolves({some: 'thing'}); + // @ts-ignore ok for tests driver.wda = { jwproxy, }; @@ -247,6 +248,7 @@ describe('XCUITestDriver', function () { driver = new XCUITestDriver(); const jwproxy = new JWProxy(); sandbox.stub(jwproxy, 'command').resolves(deviceInfoResponse); + // @ts-ignore ok for tests driver.wda = { jwproxy, }; From 08aa9ceb2794874d8795cb48231379932f76c504 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 7 Apr 2024 20:50:23 +0000 Subject: [PATCH 17/23] chore(release): 7.9.3 [skip ci] ## [7.9.3](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.2...v7.9.3) (2024-04-07) ### Bug Fixes * Added platformVersion to capabilities ([#2378](https://github.com/appium/appium-xcuitest-driver/issues/2378)) ([e75cd2c](https://github.com/appium/appium-xcuitest-driver/commit/e75cd2c127b0b2d1206cbd4d7b22923ee553798c)) * Update various type declarations ([#2380](https://github.com/appium/appium-xcuitest-driver/issues/2380)) ([1e18b2f](https://github.com/appium/appium-xcuitest-driver/commit/1e18b2f7c859f915aa353716add65d0a404c0fa7)) --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92681e003..7ec4a998f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [7.9.3](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.2...v7.9.3) (2024-04-07) + + +### Bug Fixes + +* Added platformVersion to capabilities ([#2378](https://github.com/appium/appium-xcuitest-driver/issues/2378)) ([e75cd2c](https://github.com/appium/appium-xcuitest-driver/commit/e75cd2c127b0b2d1206cbd4d7b22923ee553798c)) +* Update various type declarations ([#2380](https://github.com/appium/appium-xcuitest-driver/issues/2380)) ([1e18b2f](https://github.com/appium/appium-xcuitest-driver/commit/1e18b2f7c859f915aa353716add65d0a404c0fa7)) + ## [7.9.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.1...v7.9.2) (2024-04-07) diff --git a/package.json b/package.json index 219e50684..612d9b6af 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.9.2", + "version": "7.9.3", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From a06931fca03ef4f3de0ea65eb7814660dcb08117 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 8 Apr 2024 08:23:15 +0200 Subject: [PATCH 18/23] feat: Add `appTimeZone` capability (#2379) --- docs/reference/capabilities.md | 1 + lib/desired-caps.js | 5 ++++- lib/driver.js | 9 +++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index 1ee585524..d652aaad0 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -37,6 +37,7 @@ about capabilities, refer to the [Appium documentation](https://appium.io/docs/e | `appium:calendarFormat` | Calendar format to set for iOS Simulator, for example `gregorian` or `persian`. Can only be set in conjunction with `appium:locale`. | | `appium:appPushTimeout` | The timeout for application upload in milliseconds. Works for real devices only. The default value is `30000`ms | | `appium:appInstallStrategy` | Select application installation strategy for real devices. The following strategies are supported:
`serial` (default) - pushes app files to the device in a sequential order; this is the least performant strategy, although the most reliable
`parallel` - pushes app files simultaneously; this is usually the the most performant strategy, but sometimes could not be very stable
`ios-deploy` - tells the driver to use a third-party tool [ios-deploy](https://www.npmjs.com/package/ios-deploy) to install the app; obviously the tool must be installed separately first and must be present in PATH before it could be used. | +| `appium:appTimeZone` | Defines the custom time zone override for the application under test. You can use UTC, PST, EST, as well as place-based timezone names such as America/Los_Angeles. The application must be (re)launched for the capability to take effect. See the [List of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for more details. The same behavior could be achieved by providing a custom value to the [TZ](https://developer.apple.com/forums/thread/86951#263395) environment variable via the `appium:processArguments` capability | UTC | ### WebDriverAgent diff --git a/lib/desired-caps.js b/lib/desired-caps.js index 35a89005d..f7e291b92 100644 --- a/lib/desired-caps.js +++ b/lib/desired-caps.js @@ -369,7 +369,10 @@ const desiredCapConstraints = /** @type {const} */ ({ }, appLaunchStateTimeoutSec: { isNumber: true, - } + }, + appTimeZone: { + isString: true, + }, }); export {desiredCapConstraints, PLATFORM_NAME_IOS, PLATFORM_NAME_TVOS}; diff --git a/lib/driver.js b/lib/driver.js index 6dbeb936f..30f869b4e 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1343,8 +1343,13 @@ export class XCUITestDriver extends BaseDriver { } } + if (util.hasValue(this.opts.appTimeZone)) { + // https://developer.apple.com/forums/thread/86951?answerId=263395022#263395022 + env.TZ = this.opts.appTimeZone; + } + /** @type {import('appium-webdriveragent').WDACapabilities} */ - const wdaCaps = /** @type {any} */ ({ + const wdaCaps = { bundleId: this.opts.autoLaunch === false ? undefined : bundleId, arguments: args, environment: env, @@ -1366,7 +1371,7 @@ export class XCUITestDriver extends BaseDriver { forceSimulatorSoftwareKeyboardPresence: this.opts.forceSimulatorSoftwareKeyboardPresence ?? (this.opts.connectHardwareKeyboard === true ? false : true), - }); + }; if (this.opts.autoAcceptAlerts) { wdaCaps.defaultAlertAction = 'accept'; } else if (this.opts.autoDismissAlerts) { From 7f0e53bc274531545a48fb6a08c30b65a94461df Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 8 Apr 2024 06:25:05 +0000 Subject: [PATCH 19/23] chore(release): 7.10.0 [skip ci] ## [7.10.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.3...v7.10.0) (2024-04-08) ### Features * Add `appTimeZone` capability ([#2379](https://github.com/appium/appium-xcuitest-driver/issues/2379)) ([a06931f](https://github.com/appium/appium-xcuitest-driver/commit/a06931fca03ef4f3de0ea65eb7814660dcb08117)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ec4a998f..767b155d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.10.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.3...v7.10.0) (2024-04-08) + + +### Features + +* Add `appTimeZone` capability ([#2379](https://github.com/appium/appium-xcuitest-driver/issues/2379)) ([a06931f](https://github.com/appium/appium-xcuitest-driver/commit/a06931fca03ef4f3de0ea65eb7814660dcb08117)) + ## [7.9.3](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.2...v7.9.3) (2024-04-07) diff --git a/package.json b/package.json index 612d9b6af..fa9fa4d85 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.9.3", + "version": "7.10.0", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From e8fd02e00dc6be595d2bef253c00ab75783504e5 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 8 Apr 2024 03:06:12 -0400 Subject: [PATCH 20/23] feat: export doctor used in xcuitest driver (#2381) --- index.js | 3 +++ lib/doctor/checks.js | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 lib/doctor/checks.js diff --git a/index.js b/index.js index 08d83ec28..dce22c867 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,7 @@ import {XCUITestDriver} from './lib/driver'; export {XCUITestDriver}; + +export * as doctor from './lib/doctor/checks'; + export default XCUITestDriver; diff --git a/lib/doctor/checks.js b/lib/doctor/checks.js new file mode 100644 index 000000000..06304f705 --- /dev/null +++ b/lib/doctor/checks.js @@ -0,0 +1,2 @@ +export * as required from './required-checks'; +export * as optional from './optional-checks'; From 8147302ce4ea6d7ee63076fdf8754c070646ec97 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 8 Apr 2024 07:07:57 +0000 Subject: [PATCH 21/23] chore(release): 7.11.0 [skip ci] ## [7.11.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.10.0...v7.11.0) (2024-04-08) ### Features * export doctor used in xcuitest driver ([#2381](https://github.com/appium/appium-xcuitest-driver/issues/2381)) ([e8fd02e](https://github.com/appium/appium-xcuitest-driver/commit/e8fd02e00dc6be595d2bef253c00ab75783504e5)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 767b155d5..1c3e4512d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.11.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.10.0...v7.11.0) (2024-04-08) + + +### Features + +* export doctor used in xcuitest driver ([#2381](https://github.com/appium/appium-xcuitest-driver/issues/2381)) ([e8fd02e](https://github.com/appium/appium-xcuitest-driver/commit/e8fd02e00dc6be595d2bef253c00ab75783504e5)) + ## [7.10.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.9.3...v7.10.0) (2024-04-08) diff --git a/package.json b/package.json index fa9fa4d85..22811cdde 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.10.0", + "version": "7.11.0", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 9255e7c932d20967b0c7860df14015c5b4a63d15 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 8 Apr 2024 10:07:01 +0200 Subject: [PATCH 22/23] fix: update real device check condition --- lib/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/driver.js b/lib/driver.js index 30f869b4e..34c094206 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1211,7 +1211,7 @@ export class XCUITestDriver extends BaseDriver { // we can assume the user prepared the device properly already. let isRealDeviceUdid = false; const shouldCheckAvailableRealDevices = !this.opts.webDriverAgentUrl; - if (!shouldCheckAvailableRealDevices) { + if (shouldCheckAvailableRealDevices) { const devices = await getConnectedDevices(); this.log.debug(`Available real devices: ${devices.join(', ')}`); isRealDeviceUdid = devices.includes(this.opts.udid); From 6c4479b8c91031ef1989282756fa6306c04d2af4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 8 Apr 2024 08:08:54 +0000 Subject: [PATCH 23/23] chore(release): 7.11.1 [skip ci] ## [7.11.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.11.0...v7.11.1) (2024-04-08) ### Bug Fixes * update real device check condition ([9255e7c](https://github.com/appium/appium-xcuitest-driver/commit/9255e7c932d20967b0c7860df14015c5b4a63d15)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3e4512d..d624cb65f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.11.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.11.0...v7.11.1) (2024-04-08) + + +### Bug Fixes + +* update real device check condition ([9255e7c](https://github.com/appium/appium-xcuitest-driver/commit/9255e7c932d20967b0c7860df14015c5b4a63d15)) + ## [7.11.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.10.0...v7.11.0) (2024-04-08) diff --git a/package.json b/package.json index 22811cdde..3c8d01bae 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.11.0", + "version": "7.11.1", "author": "Appium Contributors", "license": "Apache-2.0", "repository": {