From 9e77d9f509f691d6ab2951abf3ef8d2776161a3c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 1 Nov 2023 21:59:56 -0700 Subject: [PATCH 01/27] chore: add workaround --- lib/driver.js | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index a3824e9c1..c147eeeca 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -386,6 +386,10 @@ class XCUITestDriver extends BaseDriver { return !(this.opts.webDriverAgentUrl || this.opts.usePreinstalledWDA); } + skipDeviceCheck() { + return isTvOs(this.opts.platformName); + } + async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) { try { let [sessionId, caps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData); @@ -1249,19 +1253,23 @@ class XCUITestDriver extends BaseDriver { return {device, realDevice: false, udid: device.udid}; } } else { - // make sure it is a connected device. If not, the udid passed in is invalid - 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, - }); - return {device, realDevice: false, udid: this.opts.udid}; - } catch (ign) { - throw new Error(`Unknown device or simulator UDID: '${this.opts.udid}'`); + if (!this.skipDeviceCheck()) { + this.log.info(`Skipping connected device check. Using the given udid ${this.opts.udid}.`); + } else { + // make sure it is a connected device. If not, the udid passed in is invalid + 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, + }); + return {device, realDevice: false, udid: this.opts.udid}; + } catch (ign) { + throw new Error(`Unknown device or simulator UDID: '${this.opts.udid}'`); + } } } } @@ -1675,6 +1683,11 @@ class XCUITestDriver extends BaseDriver { isTvOS: isTvOs(this.opts.platformName), }); + if (this.opts.bundleId && this.skipDeviceCheck()) { + // TODO: remove if tvOS iOS 17 has no issue with this installation device check state. + this.log.info('Skip the bundle id installation check'); + } + const {install, skipUninstall} = await this.checkAutInstallationState(); if (install) { if (this.isRealDevice()) { From efb3ff9fc1d9ed9448f3ccb1298bb35530cad174 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 1 Nov 2023 22:25:24 -0700 Subject: [PATCH 02/27] chore: always return true --- lib/driver.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index c147eeeca..7d4e262f1 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -387,7 +387,8 @@ class XCUITestDriver extends BaseDriver { } skipDeviceCheck() { - return isTvOs(this.opts.platformName); + return true; + // return isTvOs(this.opts.platformName); } async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) { @@ -1253,7 +1254,7 @@ class XCUITestDriver extends BaseDriver { return {device, realDevice: false, udid: device.udid}; } } else { - if (!this.skipDeviceCheck()) { + if (this.skipDeviceCheck()) { this.log.info(`Skipping connected device check. Using the given udid ${this.opts.udid}.`); } else { // make sure it is a connected device. If not, the udid passed in is invalid From 206235da4adc1561d5e3527a6643aa82e16d7645 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 6 Nov 2023 22:56:14 -0800 Subject: [PATCH 03/27] chore: add caps --- docs/capabilities.md | 2 ++ docs/ios-tvos.md | 6 ++++-- lib/desired-caps.js | 3 +++ lib/driver.js | 21 ++++++++++++++------- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/capabilities.md b/docs/capabilities.md index edb6b3bc0..b026579b6 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -80,6 +80,8 @@ Capability | Description |`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:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Only commands that can work over WebDriverAgent may work. + ### Simulator diff --git a/docs/ios-tvos.md b/docs/ios-tvos.md index bdbe84795..7a47aeb6b 100644 --- a/docs/ios-tvos.md +++ b/docs/ios-tvos.md @@ -7,8 +7,10 @@ tvOS is supported since XCUITest driver bundled with Appium 1.13.0+ > **Warning** -> Apple TV 4K is not supported because [appium-ios-device](https://github.com/appium/appium-ios-device) library, -> that we use to support low-level communication with devices, only supports devices connected via USB. +> Apple TV 4K device with tvOS 17 may not work because [appium-ios-device](https://github.com/appium/appium-ios-device) library, +> that we use to support low-level communication with devices, does not work for tvOS 17. +> As a workaround, please use `appium:skipDeviceCheck` capability with `appium:webDriverAgentUrl` to avoid device communication. +> [This page](./attach-to-running-wda.md) may help to check how to use `appium:webDriverAgentUrl`. ## Setup diff --git a/lib/desired-caps.js b/lib/desired-caps.js index f04bd29b3..0b6e27448 100644 --- a/lib/desired-caps.js +++ b/lib/desired-caps.js @@ -352,6 +352,9 @@ const desiredCapConstraints = /** @type {const} */ ({ skipTriggerInputEventAfterSendkeys: { isBoolean: true, }, + skipDeviceCheck: { + isBoolean: true, + } }); export {desiredCapConstraints, PLATFORM_NAME_IOS, PLATFORM_NAME_TVOS}; diff --git a/lib/driver.js b/lib/driver.js index 7d4e262f1..9d89dd892 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -386,9 +386,16 @@ class XCUITestDriver extends BaseDriver { return !(this.opts.webDriverAgentUrl || this.opts.usePreinstalledWDA); } + /** + * Whether to skip the device check in a new session request. + * This is a workaround for network connected devices such as an Apple TV 4k real device. + * A situation that requires this capability may hve an issue to communicate with the device + * over appium-ios-device for example. + * Some methods that require the appium-ios-device may get issues. + * @returns {boolean} + */ skipDeviceCheck() { - return true; - // return isTvOs(this.opts.platformName); + return !!this.opts.skipDeviceCheck; } async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) { @@ -1679,16 +1686,16 @@ class XCUITestDriver extends BaseDriver { return; } + if (this.opts.bundleId && this.skipDeviceCheck()) { + this.log.info('Skipping the bundle id installation check'); + return; + } + await verifyApplicationPlatform.bind(this)(this.opts.app, { isSimulator: this.isSimulator(), isTvOS: isTvOs(this.opts.platformName), }); - if (this.opts.bundleId && this.skipDeviceCheck()) { - // TODO: remove if tvOS iOS 17 has no issue with this installation device check state. - this.log.info('Skip the bundle id installation check'); - } - const {install, skipUninstall} = await this.checkAutInstallationState(); if (install) { if (this.isRealDevice()) { From e128d07a5c043901fcf7b5718b5c410064e96a85 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 6 Nov 2023 23:02:00 -0800 Subject: [PATCH 04/27] docs: tweak --- docs/attach-to-running-wda.md | 4 ++-- docs/capabilities.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/attach-to-running-wda.md b/docs/attach-to-running-wda.md index 1410e3535..27939691e 100644 --- a/docs/attach-to-running-wda.md +++ b/docs/attach-to-running-wda.md @@ -27,11 +27,11 @@ If the environment had port-forward to the connected device, it can be `http://l } ``` -This method allows you to manage the WebDriverAgent application process by yourself. +This method allows you to manage the WebDriverAgent application process by yourself, for example manage the process with 3rd party libraries, Xcode etc. XCUITest driver simply attaches to the WebDriverAgent application process. It may improve the application performance. -Some xcuitest driver APIs (for example the [mobile: calibrateWebToRealCoordinatesTranslation](./execute-methods.md#mobile-calibratewebtorealcoordinatestranslation) one) might still require to know +Some XCUITest driver APIs (for example the [mobile: calibrateWebToRealCoordinatesTranslation](./execute-methods.md#mobile-calibratewebtorealcoordinatestranslation) one) might still require to know the port number of the remote device if it is a real device. Providing `webDriverAgentUrl` capability might not be sufficient to recognize the remote port number in case it is different from the local one. Consider settings the `appium:wdaRemotePort` capability value in such case to supply the driver with the appropriate data. diff --git a/docs/capabilities.md b/docs/capabilities.md index b026579b6..78179a275 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -80,7 +80,7 @@ Capability | Description |`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:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Only commands that can work over WebDriverAgent may work. +|`appium:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. Default is `false`. | `true` or `false` | ### Simulator From b88182206ef14f5198f1d514b680cc66ca9ee808 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 6 Nov 2023 23:05:07 -0800 Subject: [PATCH 05/27] docs: add note --- docs/capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/capabilities.md b/docs/capabilities.md index 78179a275..4e027d64b 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -80,7 +80,7 @@ Capability | Description |`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:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. Default is `false`. | `true` or `false` | +|`appium:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | ### Simulator From 143cfb5053f177e3a0ac0515ae5d885de1141f42 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 12 Jan 2024 15:21:38 -0800 Subject: [PATCH 06/27] chore: do not check the installed app --- lib/driver.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 8d5b0a69b..b4d7b4850 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -610,14 +610,16 @@ class XCUITestDriver extends BaseDriver { await this.installAUT(); // if we only have bundle identifier and no app, fail if it is not already installed - if ( - !this.opts.app && - this.opts.bundleId && - !this.isSafari() && - // @ts-expect-error - do not assign arbitrary properties to `this.opts` - !(await this.opts.device.isAppInstalled(this.opts.bundleId)) - ) { - this.log.errorAndThrow(`App with bundle identifier '${this.opts.bundleId}' unknown`); + if (!this.skipDeviceCheck()) { + if ( + !this.opts.app && + this.opts.bundleId && + !this.isSafari() && + // @ts-expect-error - do not assign arbitrary properties to `this.opts` + !(await this.opts.device.isAppInstalled(this.opts.bundleId)) + ) { + this.log.errorAndThrow(`App with bundle identifier '${this.opts.bundleId}' unknown`); + } } if (this.isSimulator()) { From 9e469e4f57ca08ea6b5b815fc9577c29ff67292f Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 14 Feb 2024 02:00:55 -0800 Subject: [PATCH 07/27] Update driver.js --- lib/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/driver.js b/lib/driver.js index 19cbf445c..bd30e0193 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1717,7 +1717,7 @@ class XCUITestDriver extends BaseDriver { return; } - await verifyApplicationPlatform.bind(this)(this.opts.app, { + await verifyApplicationPlatform(this.opts.app, { isSimulator: this.isSimulator(), isTvOS: isTvOs(this.opts.platformName), }); From e79b5f03c0074f9c6f700ebf2f414e1c47c6f7cb Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 23 Feb 2024 15:18:45 -0800 Subject: [PATCH 08/27] remove no-deps deps --- lib/ios-fs-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ios-fs-helpers.js b/lib/ios-fs-helpers.js index 248df25d2..d7b3c1127 100644 --- a/lib/ios-fs-helpers.js +++ b/lib/ios-fs-helpers.js @@ -198,7 +198,7 @@ async function pushFolder(afcService, srcRootPath, dstRootPath, opts = {}) { const {timeoutMs = IO_TIMEOUT_MS, enableParallelPush = false} = opts; const timer = new timing.Timer().start(); - const allItems = /** @type {import('path-scurry').Path[]} */ (/** @type {unknown} */ ( + const allItems = /** @type {Object} */ (/** @type {unknown} */ ( await fs.glob('**', { cwd: srcRootPath, withFileTypes: true, From 168c01a4a709df8adfbd5f52fa4f246a22dfe0d0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 1 Mar 2024 01:38:43 -0800 Subject: [PATCH 09/27] Revert "remove no-deps deps" This reverts commit e79b5f03c0074f9c6f700ebf2f414e1c47c6f7cb. --- lib/ios-fs-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ios-fs-helpers.js b/lib/ios-fs-helpers.js index d7b3c1127..248df25d2 100644 --- a/lib/ios-fs-helpers.js +++ b/lib/ios-fs-helpers.js @@ -198,7 +198,7 @@ async function pushFolder(afcService, srcRootPath, dstRootPath, opts = {}) { const {timeoutMs = IO_TIMEOUT_MS, enableParallelPush = false} = opts; const timer = new timing.Timer().start(); - const allItems = /** @type {Object} */ (/** @type {unknown} */ ( + const allItems = /** @type {import('path-scurry').Path[]} */ (/** @type {unknown} */ ( await fs.glob('**', { cwd: srcRootPath, withFileTypes: true, From 229773cfd97343229660dc4858f591233d320ede Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sat, 23 Mar 2024 17:31:03 -0700 Subject: [PATCH 10/27] feat: add appium:usePreinstalledWDA for real iOS 17 devices (#2350) * feat: add appium:usePreinstalledWDA for real iOS 17 devices * add Xcode 15 * add version --- docs/guides/run-preinstalled-wda.md | 19 +++++++++++++++---- package.json | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/guides/run-preinstalled-wda.md b/docs/guides/run-preinstalled-wda.md index 2de286726..cecaedd25 100644 --- a/docs/guides/run-preinstalled-wda.md +++ b/docs/guides/run-preinstalled-wda.md @@ -8,8 +8,8 @@ command execution, improving the session startup performance. !!! warning - This method currently does not work natively for iOS 17/tvOS 17 due to platform changes. - Please use the default `xcodebuild` approach or 3rd party tools such as `pymobiledevice3`. + This method currently works over `devicectl` for iOS 17+ with Xcode 15+ since XCUITest driver v7.5.0. + This may not work for tvOS 17+. ## Capabilities @@ -27,7 +27,7 @@ Running a test for the WDA package in Xcode is the easiest way to prepare the de 1. Open WebDriverAgent project in Xcode - You can run `appium driver run xcuitest open-wda` if using XCUITest driver 4.13 or newer -2. Select the _WebDriverAgentRunner_ scheme +2. Select the _WebDriverAgentRunner_ scheme 3. Select the scheme as _Product -> Scheme -> WebDriverAgentRunner_ (or _WebDriverAgentRunner\_tvOS_ for tvOS) 4. Select your device in _Product -> Destination_ 5. Select _Product -> Test_ to build and install the WDA app @@ -45,6 +45,17 @@ The WDA app package (`WebDriverAgentRunner-Runner.app`) can be generated in the directory, as explained in [Manual Configuration for a Generic Device](../preparation/prov-profile-generic-manual.md). The app can then be installed without `xcodebuild` using the 3rd party tools. + +### Additional requirement for iOS 17+/tvOS17+ + +To launch the WebDriverAgentRunner package with `xcrun devicectl device process launch` it should not have `Frameworks/XC**` files. + +For example, after building the WebDriverAgent with Xcode with proper sign, it generates `/Users//Library/Developer/Xcode/DerivedData/WebDriverAgent-ezumztihszjoxgacuhatrhxoklbh/Build/Products/Debug-appletvos/WebDriverAgentRunner-Runner.app`. +Then you can remove `Frameworks/XC**` in `WebDriverAgentRunner-Runner.app` like `rm Frameworks/WebDriverAgentRunner-Runner.app/XC**`. + +Configuring `appium:prebuiltWDAPath` to the `/Users//Library/Developer/Xcode/DerivedData/WebDriverAgent-ezumztihszjoxgacuhatrhxoklbh/Build/Products/Debug-appletvos/WebDriverAgentRunner-Runner.app` would install the `WebDriverAgentRunner-Runner.app`, which has no `Frameworks/XC**` to the target device and launch it with `devicectl` command as part of `appium:usePreinstalledWDA` functionality. + + ## Launch the Session After installing the `WebDriverAgentRunner-Runner` application, you can start the Appium server @@ -113,7 +124,7 @@ driver.quit `com.apple.dt.testmanagerd.runner`. It causes an unexpected WDA process crash with embedded XCTest frameworks while running a single WebDriverAgent package on various OS environments without `xcodebuild`. - + Since WDA v5.10.0, the module can refer to the device's local XCTest frameworks. It lets the Appium/WebDriverAgent package use proper dependencies for the device with a single prebuilt WebDriverAgent package. To set this up, you should remove the package internal frameworks from diff --git a/package.json b/package.json index 2410f5e7a..88a3eb254 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "appium-ios-device": "^2.5.4", "appium-ios-simulator": "^5.5.1", "appium-remote-debugger": "^11.0.0", - "appium-webdriveragent": "^7.2.0", + "appium-webdriveragent": "^7.3.0", "appium-xcode": "^5.1.4", "async-lock": "^1.4.0", "asyncbox": "^3.0.0", From 8cb25547cc79b10f5c5e5839d95f44872149cd83 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 24 Mar 2024 00:32:30 +0000 Subject: [PATCH 11/27] chore(release): 7.5.0 [skip ci] ## [7.5.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.4.2...v7.5.0) (2024-03-24) ### Features * add appium:usePreinstalledWDA for real iOS 17 devices ([#2350](https://github.com/appium/appium-xcuitest-driver/issues/2350)) ([ec5a1f7](https://github.com/appium/appium-xcuitest-driver/commit/ec5a1f73f06763da47c06386aac729e8ee75d990)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3b616e71..219e6c750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.5.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.4.2...v7.5.0) (2024-03-24) + + +### Features + +* add appium:usePreinstalledWDA for real iOS 17 devices ([#2350](https://github.com/appium/appium-xcuitest-driver/issues/2350)) ([ec5a1f7](https://github.com/appium/appium-xcuitest-driver/commit/ec5a1f73f06763da47c06386aac729e8ee75d990)) + ## [7.4.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.4.1...v7.4.2) (2024-03-23) diff --git a/package.json b/package.json index 88a3eb254..48e37bc61 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.4.2", + "version": "7.5.0", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 218a0fc3ad95709532d533627c43e57036be519a Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 01:31:20 -0700 Subject: [PATCH 12/27] chore: skip connected device check if the caps had webDriverAgentUrl (#2351) * chore: skip connected device check if the caps had webDriverAgentUrl * fix lint * Update driver.js * Update driver.js --- lib/driver.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 010771f38..3573ad2a7 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1221,8 +1221,10 @@ class XCUITestDriver extends BaseDriver { return {device, realDevice: false, udid: device.udid}; } } else { - if (this.skipDeviceCheck()) { - this.log.info(`Skipping connected device check. Using the given udid ${this.opts.udid}.`); + // 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.logs.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 const devices = await getConnectedDevices(); From 7836dc598b7bd425a1903b77eb739f5a394bf758 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 24 Mar 2024 08:32:49 +0000 Subject: [PATCH 13/27] chore(release): 7.5.1 [skip ci] ## [7.5.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.5.0...v7.5.1) (2024-03-24) ### Miscellaneous Chores * skip connected device check if the caps had webDriverAgentUrl ([#2351](https://github.com/appium/appium-xcuitest-driver/issues/2351)) ([407ad58](https://github.com/appium/appium-xcuitest-driver/commit/407ad58e8df03b700152f9c9bf41546e65afac4f)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 219e6c750..e5962d2a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.5.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.5.0...v7.5.1) (2024-03-24) + + +### Miscellaneous Chores + +* skip connected device check if the caps had webDriverAgentUrl ([#2351](https://github.com/appium/appium-xcuitest-driver/issues/2351)) ([407ad58](https://github.com/appium/appium-xcuitest-driver/commit/407ad58e8df03b700152f9c9bf41546e65afac4f)) + ## [7.5.0](https://github.com/appium/appium-xcuitest-driver/compare/v7.4.2...v7.5.0) (2024-03-24) diff --git a/package.json b/package.json index 48e37bc61..dbb2bb2af 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.5.0", + "version": "7.5.1", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 6d516f05619a9ae3dd2810f84fe0dd793f395c0d Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 09:22:42 -0700 Subject: [PATCH 14/27] chore: rename IosDeploy obhect to RealDevice to make the object meaning actual usage (#2353) * chore: rename IosDeploy obhect to RealDevice to make the object meaning actual usage * rename in test code --- lib/real-device-management.js | 12 +-- lib/{ios-deploy.js => real-device.js} | 4 +- test/unit/real-device-management-specs.js | 90 +++++++++++------------ 3 files changed, 53 insertions(+), 53 deletions(-) rename lib/{ios-deploy.js => real-device.js} (99%) diff --git a/lib/real-device-management.js b/lib/real-device-management.js index 84ddcab78..cc080c43a 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -1,5 +1,5 @@ import {utilities} from 'appium-ios-device'; -import IOSDeploy from './ios-deploy'; +import RealDevice from './real-device'; import log from './logger'; import {SAFARI_BUNDLE_ID} from './app-utils'; @@ -16,7 +16,7 @@ async function getOSVersion(udid) { } /** - * @param {IOSDeploy} device + * @param {RealDevice} device * @param {import('./driver').XCUITestDriverOpts} opts * @returns {Promise} */ @@ -51,7 +51,7 @@ async function resetRealDevice(device, opts) { } /** - * @param {IOSDeploy} device + * @param {RealDevice} device * @param {import('./driver').XCUITestDriverOpts} opts * @returns {Promise} */ @@ -76,7 +76,7 @@ async function runRealDeviceReset(device, opts) { */ /** - * @param {IOSDeploy} device The device instance + * @param {RealDevice} device The device instance * @param {string} [app] The app to the path * @param {string} [bundleId] The bundle id to ensure it is already installed and uninstall it * @param {InstallOptions} [opts] @@ -124,11 +124,11 @@ async function installToRealDevice(device, app, bundleId, opts) { /** * @param {string} udid - * @returns {IOSDeploy} + * @returns {RealDevice} */ function getRealDeviceObj(udid) { log.debug(`Creating iDevice object with udid '${udid}'`); - return new IOSDeploy(udid); + return new RealDevice(udid); } export { diff --git a/lib/ios-deploy.js b/lib/real-device.js similarity index 99% rename from lib/ios-deploy.js rename to lib/real-device.js index a71eb8a4b..cce654dca 100644 --- a/lib/ios-deploy.js +++ b/lib/real-device.js @@ -20,7 +20,7 @@ const APP_INSTALL_STRATEGY = Object.freeze({ IOS_DEPLOY, }); -class IOSDeploy { +class RealDevice { constructor(udid) { this.udid = udid; } @@ -281,4 +281,4 @@ class IOSDeploy { } } -export default IOSDeploy; +export default RealDevice; diff --git a/test/unit/real-device-management-specs.js b/test/unit/real-device-management-specs.js index 2264899e5..87e15cd3e 100644 --- a/test/unit/real-device-management-specs.js +++ b/test/unit/real-device-management-specs.js @@ -3,7 +3,7 @@ import chaiAsPromised from 'chai-as-promised'; import {createSandbox} from 'sinon'; import sinonChai from 'sinon-chai'; import { installToRealDevice } from '../../lib/real-device-management'; -import IOSDeploy from '../../lib/ios-deploy'; +import RealDevice from '../../lib/real-device'; chai.should(); chai.use(sinonChai).use(chaiAsPromised); @@ -26,51 +26,51 @@ describe('installToRealDevice', function () { }); it('nothing happen without app', async function () { - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').resolves(); + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').resolves(); - await installToRealDevice(iosDeploy, undefined, bundleId, {}); - expect(iosDeploy.remove).to.not.have.been.called; - expect(iosDeploy.install).to.not.have.been.called; + await installToRealDevice(realDevice, undefined, bundleId, {}); + expect(realDevice.remove).to.not.have.been.called; + expect(realDevice.install).to.not.have.been.called; }); it('nothing happen without bundle id', async function () { - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').resolves(); + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').resolves(); - await installToRealDevice(iosDeploy, app, undefined, {}); - expect(iosDeploy.remove).to.not.have.been.called; - expect(iosDeploy.install).to.not.have.been.called; + await installToRealDevice(realDevice, app, undefined, {}); + expect(realDevice.remove).to.not.have.been.called; + expect(realDevice.install).to.not.have.been.called; }); it('should install without remove', async function () { const opts = { skipUninstall: true }; - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').resolves(); + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').resolves(); - await installToRealDevice(iosDeploy, app, bundleId, opts); + await installToRealDevice(realDevice, app, bundleId, opts); - expect(iosDeploy.remove).to.not.have.been.called; - expect(iosDeploy.install).to.have.been.calledOnce; + expect(realDevice.remove).to.not.have.been.called; + expect(realDevice.install).to.have.been.calledOnce; }); it('should install after remove', async function () { const opts = { skipUninstall: false }; - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').resolves(); + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').resolves(); - await installToRealDevice(iosDeploy, app, bundleId, opts); + await installToRealDevice(realDevice, app, bundleId, opts); - expect(iosDeploy.remove).to.have.been.calledOnce; - expect(iosDeploy.install).to.have.been.calledOnce; + expect(realDevice.remove).to.have.been.calledOnce; + expect(realDevice.install).to.have.been.calledOnce; }); it('should raise an error for invalid verification error after uninstall', async function () { @@ -78,13 +78,13 @@ describe('installToRealDevice', function () { skipUninstall: false }; const err_msg = `{"Error":"ApplicationVerificationFailed","ErrorDetail":-402620395,"ErrorDescription":"Failed to verify code signature of /path/to.app : 0xe8008015 (A valid provisioning profile for this executable was not found.)"}`; - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').throws(err_msg); + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').throws(err_msg); - await installToRealDevice(iosDeploy, app, bundleId, opts).should.be.rejectedWith('ApplicationVerificationFailed'); - expect(iosDeploy.remove).to.have.been.calledOnce; - expect(iosDeploy.install).to.have.been.calledOnce; + await installToRealDevice(realDevice, app, bundleId, opts).should.be.rejectedWith('ApplicationVerificationFailed'); + expect(realDevice.remove).to.have.been.calledOnce; + expect(realDevice.install).to.have.been.calledOnce; }); it('should install after removal once because of MismatchedApplicationIdentifierEntitlement error', async function () { @@ -93,16 +93,16 @@ describe('installToRealDevice', function () { const opts = { skipUninstall: true }; - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install') + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install') .onCall(0).throws(`{"Error":"MismatchedApplicationIdentifierEntitlement","ErrorDescription":"Upgrade's application-identifier entitlement string (TEAM_ID.com.kazucocoa.example) does not match installed application's application-identifier string (ANOTHER_TEAM_ID.com.kazucocoa.example); rejecting upgrade."}`) .onCall(1).resolves(); - await installToRealDevice(iosDeploy, app, bundleId, opts); + await installToRealDevice(realDevice, app, bundleId, opts); - expect(iosDeploy.remove).to.have.been.calledOnce; - expect(iosDeploy.install).to.have.been.calledTwice; + expect(realDevice.remove).to.have.been.calledOnce; + expect(realDevice.install).to.have.been.calledTwice; }); it('should raise an error in the install ApplicationVerificationFailed error because it is not recoverable', async function () { @@ -110,13 +110,13 @@ describe('installToRealDevice', function () { skipUninstall: true }; const err_msg = `{"Error":"ApplicationVerificationFailed","ErrorDetail":-402620395,"ErrorDescription":"Failed to verify code signature of /path/to.app : 0xe8008015 (A valid provisioning profile for this executable was not found.)"}`; - const iosDeploy = new IOSDeploy(udid); - sandbox.stub(iosDeploy, 'remove').resolves(); - sandbox.stub(iosDeploy, 'install').throws(err_msg); - sandbox.stub(iosDeploy, 'isAppInstalled').resolves(true); - - await installToRealDevice(iosDeploy, app, bundleId, opts).should.be.rejectedWith('ApplicationVerificationFailed'); - expect(iosDeploy.remove).to.not.have.been.called; - expect(iosDeploy.install).to.have.been.calledOnce; + const realDevice = new RealDevice(udid); + sandbox.stub(realDevice, 'remove').resolves(); + sandbox.stub(realDevice, 'install').throws(err_msg); + sandbox.stub(realDevice, 'isAppInstalled').resolves(true); + + await installToRealDevice(realDevice, app, bundleId, opts).should.be.rejectedWith('ApplicationVerificationFailed'); + expect(realDevice.remove).to.not.have.been.called; + expect(realDevice.install).to.have.been.calledOnce; }); }); From 3a3b6c5d803bc5ed58da2bec0e177857cb72ebd5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 24 Mar 2024 16:24:09 +0000 Subject: [PATCH 15/27] chore(release): 7.5.2 [skip ci] ## [7.5.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.5.1...v7.5.2) (2024-03-24) ### Miscellaneous Chores * rename IosDeploy obhect to RealDevice to make the object meaning actual usage ([#2353](https://github.com/appium/appium-xcuitest-driver/issues/2353)) ([b3b7349](https://github.com/appium/appium-xcuitest-driver/commit/b3b734913bc5ef824b6cde58bfe0b389bb87abac)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5962d2a1..a656f8ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [7.5.2](https://github.com/appium/appium-xcuitest-driver/compare/v7.5.1...v7.5.2) (2024-03-24) + + +### Miscellaneous Chores + +* rename IosDeploy obhect to RealDevice to make the object meaning actual usage ([#2353](https://github.com/appium/appium-xcuitest-driver/issues/2353)) ([b3b7349](https://github.com/appium/appium-xcuitest-driver/commit/b3b734913bc5ef824b6cde58bfe0b389bb87abac)) + ## [7.5.1](https://github.com/appium/appium-xcuitest-driver/compare/v7.5.0...v7.5.1) (2024-03-24) diff --git a/package.json b/package.json index dbb2bb2af..81d27aaa5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "xcuitest", "xctest" ], - "version": "7.5.1", + "version": "7.5.2", "author": "Appium Contributors", "license": "Apache-2.0", "repository": { From 22cef06c555ed8a2efa5156fc882e6761624ed71 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 17:07:20 -0700 Subject: [PATCH 16/27] chore: include devicectl in IOSDeploy object (#2352) * chore: include devicectl in IOSDeploy object * add ignore * define once to reduce ignore * define once to reduce ignore * mofidy log --- lib/commands/memory.js | 11 ++++++----- lib/commands/xctest-record-screen.js | 9 +++++---- lib/driver.js | 2 +- lib/real-device-management.js | 5 +++-- lib/real-device.js | 8 ++++---- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/commands/memory.js b/lib/commands/memory.js index bbe01b7ab..d99174721 100644 --- a/lib/commands/memory.js +++ b/lib/commands/memory.js @@ -1,5 +1,4 @@ import _ from 'lodash'; -import { Devicectl } from '../devicectl'; import { errors } from 'appium/driver'; export default { @@ -16,9 +15,11 @@ export default { throw new Error('Memory warning simulation is only supported on real devices'); } - const devicectl = new Devicectl(this.opts.udid, this.log); + // @ts-expect-error - do not assign arbitrary properties to `this.opts` + const device = this.opts.device; + /** @type {import('../devicectl').AppInfo[]} */ - const appInfos = await devicectl.listApps(bundleId); + const appInfos = await device.devicectl.listApps(bundleId); if (_.isEmpty(appInfos)) { throw new errors.InvalidArgumentError( `The application identified by ${bundleId} cannot be found on the device. Is it installed?` @@ -36,7 +37,7 @@ export default { // allow to connect a bundle id to a process id. const pattern = new RegExp(`^${_.escapeRegExp(appInfos[0].url)}[^/]+$`); /** @type {number[]} */ - const pids = (await devicectl.listProcesses()) + const pids = (await device.devicectl.listProcesses()) .filter(({executable}) => pattern.test(executable)) .map(({processIdentifier}) => processIdentifier); if (_.isEmpty(pids)) { @@ -45,7 +46,7 @@ export default { ); } this.log.info(`Emulating Low Memory warning for the process id ${pids[0]}, bundle id ${bundleId}`); - await devicectl.sendMemoryWarning(pids[0]); + await device.devicectl.sendMemoryWarning(pids[0]); } }; diff --git a/lib/commands/xctest-record-screen.js b/lib/commands/xctest-record-screen.js index 50f302542..f910397de 100644 --- a/lib/commands/xctest-record-screen.js +++ b/lib/commands/xctest-record-screen.js @@ -2,7 +2,6 @@ import _ from 'lodash'; import {fs, util} from 'appium/support'; import {encodeBase64OrUpload} from '../utils'; import path from 'node:path'; -import {Devicectl} from '../devicectl'; const MOV_EXT = '.mov'; const FEATURE_NAME = 'xctest_screen_record'; @@ -60,8 +59,10 @@ async function retrieveRecodingFromSimulator(uuid) { * @returns {Promise} The full path to the screen recording movie */ async function retrieveRecodingFromRealDevice(uuid) { - const devicectl = new Devicectl(this.opts.udid, this.log); - const fileNames = await devicectl.listFiles(DOMAIN_TYPE, DOMAIN_IDENTIFIER, { + // @ts-expect-error - do not assign arbitrary properties to `this.opts` + const device = this.opts.device; + + const fileNames = await device.devicectl.listFiles(DOMAIN_TYPE, DOMAIN_IDENTIFIER, { username: USERNAME, subdirectory: SUBDIRECTORY, }); @@ -71,7 +72,7 @@ async function retrieveRecodingFromRealDevice(uuid) { ); } const videoPath = path.join(/** @type {string} */ (this.opts.tmpDir), `${uuid}${MOV_EXT}`); - await devicectl.pullFile(`${SUBDIRECTORY}/${uuid}`, videoPath, { + await device.devicectl.pullFile(`${SUBDIRECTORY}/${uuid}`, videoPath, { username: USERNAME, domainIdentifier: DOMAIN_IDENTIFIER, domainType: DOMAIN_TYPE, diff --git a/lib/driver.js b/lib/driver.js index 3573ad2a7..b0abcac5d 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1244,7 +1244,7 @@ class XCUITestDriver extends BaseDriver { } } - const device = getRealDeviceObj(this.opts.udid); + const device = getRealDeviceObj(this.opts.udid, this.log); return {device, realDevice: true, udid: this.opts.udid}; } diff --git a/lib/real-device-management.js b/lib/real-device-management.js index cc080c43a..a78bea43d 100644 --- a/lib/real-device-management.js +++ b/lib/real-device-management.js @@ -124,11 +124,12 @@ async function installToRealDevice(device, app, bundleId, opts) { /** * @param {string} udid + * @param {import('@appium/types').AppiumLogger} logger * @returns {RealDevice} */ -function getRealDeviceObj(udid) { +function getRealDeviceObj(udid, logger) { log.debug(`Creating iDevice object with udid '${udid}'`); - return new RealDevice(udid); + return new RealDevice(udid, logger); } export { diff --git a/lib/real-device.js b/lib/real-device.js index cce654dca..218de5c48 100644 --- a/lib/real-device.js +++ b/lib/real-device.js @@ -21,8 +21,9 @@ const APP_INSTALL_STRATEGY = Object.freeze({ }); class RealDevice { - constructor(udid) { + constructor(udid, logger) { this.udid = udid; + this.devicectl = new Devicectl(this.udid, logger); } async remove(bundleId) { @@ -211,15 +212,14 @@ class RealDevice { if (util.compareVersions(platformVersion, '>=', '17.0')) { log.debug(`Calling devicectl to kill the process`); - const devicectl = new Devicectl(this.udid, log); - const pids = (await devicectl.listProcesses()) + const pids = (await this.devicectl.listProcesses()) .filter(({executable}) => executable.endsWith(`/${executableName}`)) .map(({processIdentifier}) => processIdentifier); if (_.isEmpty(pids)) { log.info(`The process of the bundle id '${bundleId}' was not running`); return false; } - await devicectl.sendSignalToProcess(pids[0], 2); + await this.devicectl.sendSignalToProcess(pids[0], 2); } else { instrumentService = await services.startInstrumentService(this.udid); const processes = await instrumentService.callChannel( From 41f71096d986ba4d9efa4ce6ed3827296a0bf366 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 22:05:05 -0700 Subject: [PATCH 17/27] docs: add description the warning is not for ios 16 and lower --- docs/guides/run-preinstalled-wda.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/guides/run-preinstalled-wda.md b/docs/guides/run-preinstalled-wda.md index cecaedd25..826338e12 100644 --- a/docs/guides/run-preinstalled-wda.md +++ b/docs/guides/run-preinstalled-wda.md @@ -8,8 +8,11 @@ command execution, improving the session startup performance. !!! warning - This method currently works over `devicectl` for iOS 17+ with Xcode 15+ since XCUITest driver v7.5.0. + iOS/tvOS 17+ speicic: + + This method currently works over `devicectl` for iOS 17+ with Xcode 15+ environment since XCUITest driver v7.5.0. This may not work for tvOS 17+. + iOS/tvOS 16 and lower ones work over [appium-ios-device](https://github.com/appium/appium-ios-device) directly. ## Capabilities From c423f37736ec09f48a39e82d76961f5f20387daf Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 22:47:52 -0700 Subject: [PATCH 18/27] add experimental description --- docs/reference/capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index dd3641253..fad13f81f 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -84,7 +84,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:skipDeviceCheck`| Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | +|`appium:skipDeviceCheck`| _Experimental. This capability may be removed without major version update if we no longer need this._ Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | ### Simulator From 977ba5b3e051df6ea43a6b1320aa57589d1085fd Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 22:58:15 -0700 Subject: [PATCH 19/27] fix typo --- lib/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/driver.js b/lib/driver.js index b0abcac5d..513702a0b 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -1224,7 +1224,7 @@ class XCUITestDriver extends BaseDriver { // 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.logs.debug('Skipping checking of the device availability since the session specifies appium: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 const devices = await getConnectedDevices(); From 250493e1b1beb16d32cdadd245c93fb99d101b16 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 23:08:35 -0700 Subject: [PATCH 20/27] tweak --- lib/driver.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 513702a0b..03101636d 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -256,6 +256,9 @@ class XCUITestDriver extends BaseDriver { /** @type {import('./commands/pcap').TrafficCapture|null} */ _trafficCapture; + /** @type {boolean} */ + skipDeviceCheck; + /** * * @param {XCUITestDriverOpts} opts @@ -303,6 +306,13 @@ class XCUITestDriver extends BaseDriver { } this.lifecycleData = {}; this._audioRecorder = null; + + // Whether to skip the device check in a new session request. + // This is a workaround for network connected devices such as an Apple TV 4k tvOS 17+ real device. + // A situation that requires this capability may hve an issue to communicate with the device + // over appium-ios-device for example. + // Please remove this capability when we no longer need this workaround. + this.skipDeviceCheck = this.opts.skipDeviceCheck || false; } async onSettingsUpdate(key, value) { @@ -388,18 +398,6 @@ class XCUITestDriver extends BaseDriver { return !(CAP_NAMES_NO_XCODEBUILD_REQUIRED.some((x) => Boolean(this.opts[x]))); } - /** - * Whether to skip the device check in a new session request. - * This is a workaround for network connected devices such as an Apple TV 4k real device. - * A situation that requires this capability may hve an issue to communicate with the device - * over appium-ios-device for example. - * Some methods that require the appium-ios-device may get issues. - * @returns {boolean} - */ - skipDeviceCheck() { - return !!this.opts.skipDeviceCheck; - } - async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) { try { let [sessionId, caps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData); @@ -611,8 +609,10 @@ class XCUITestDriver extends BaseDriver { await this.installAUT(); - // if we only have bundle identifier and no app, fail if it is not already installed - if (!this.skipDeviceCheck()) { + // if we only have bundle identifier and no app, fail if it is not already installed. + if (this.skipDeviceCheck) { + this.logs.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`) + } else { if ( !this.opts.app && this.opts.bundleId && @@ -1676,8 +1676,8 @@ class XCUITestDriver extends BaseDriver { return; } - if (this.opts.bundleId && this.skipDeviceCheck()) { - this.log.info('Skipping the bundle id installation check'); + if (this.opts.bundleId && this.skipDeviceCheck) { + this.log.debug('Skipping the bundle id installation check'); return; } From 7c9f73c706c9e92f97000172b05638b65cab3815 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 24 Mar 2024 23:09:02 -0700 Subject: [PATCH 21/27] fix lint --- lib/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/driver.js b/lib/driver.js index 03101636d..aaccd3c1e 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -611,7 +611,7 @@ class XCUITestDriver extends BaseDriver { // if we only have bundle identifier and no app, fail if it is not already installed. if (this.skipDeviceCheck) { - this.logs.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`) + this.logs.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`); } else { if ( !this.opts.app && From 80d50c65ea6cdac1280cd0d4b2aeb01eb85665b0 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Mar 2024 21:52:14 -0700 Subject: [PATCH 22/27] combine if --- lib/driver.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index bc5d33f1c..910555bcf 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -613,15 +613,13 @@ export class XCUITestDriver extends BaseDriver { // if we only have bundle identifier and no app, fail if it is not already installed. if (this.skipDeviceCheck) { this.logs.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`); - } else { - if ( - !this.opts.app && - this.opts.bundleId && - !this.isSafari() && - !(await this.device.isAppInstalled(this.opts.bundleId)) - ) { - this.log.errorAndThrow(`App with bundle identifier '${this.opts.bundleId}' unknown`); - } + } else if ( + !this.opts.app && + this.opts.bundleId && + !this.isSafari() && + !(await this.device.isAppInstalled(this.opts.bundleId)) + ) { + throw this.log.errorWithException(`App with bundle identifier '${this.opts.bundleId}' unknown`); } if (this.isSimulator()) { From 8358e16b2aa46adf712b06715263dd6ea02a4a9c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Mar 2024 21:58:42 -0700 Subject: [PATCH 23/27] update doc --- docs/reference/capabilities.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index 0c7428552..7f4417b6e 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -85,8 +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:skipDeviceCheck`| _Experimental. This capability may be removed without major version update if we no longer need this._ Whether to skip the device check in a new session request. This could help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session will have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | - +|`appium:skipDeviceCheck`| _Experimental. This capability may be removed without major version update if we no longer need this._ Whether to skip the device check in a new session request. This capability, `"appium:webDriverAgentUrl": ":"` and `"appium:skipLogCapture": true` might help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session would have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | ### Simulator From 38b0e5b02bdc535bfbade886dddc795c2ae5f793 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 28 Mar 2024 22:05:25 -0700 Subject: [PATCH 24/27] move to the bottom --- docs/reference/capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/capabilities.md b/docs/reference/capabilities.md index aecb5eb16..8412a4be2 100644 --- a/docs/reference/capabilities.md +++ b/docs/reference/capabilities.md @@ -85,8 +85,8 @@ 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:skipDeviceCheck`| _Experimental. This capability may be removed without major version update if we no longer need this._ Whether to skip the device check in a new session request. This capability, `"appium:webDriverAgentUrl": ":"` and `"appium:skipLogCapture": true` might help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session would have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `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` | +|`appium:skipDeviceCheck`| _Experimental. This capability may be removed without major version update if we no longer need this._ Whether to skip the device check in a new session request. This capability, `"appium:webDriverAgentUrl": ":"` and `"appium:skipLogCapture": true` might help to avoid [Apple TV 4k tvOS 17](https://github.com/appium/appium/issues/19343) connection issue, but if you need this capability, the session would have communication issue with the device. Commands that can work over WebDriverAgent may work, but commands such as application installation may not work. (We do not recommend using this capability. Please use this only when you need this.) Default is `false`. | `true` or `false` | ### Simulator From db1beba690d29f8897c184f2afaf517ab98a3b9c Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 26 Apr 2024 11:27:19 -0700 Subject: [PATCH 25/27] Update driver.js --- lib/driver.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 715d96324..95f754b1b 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -311,12 +311,11 @@ export class XCUITestDriver extends BaseDriver { } this.lifecycleData = {}; this._audioRecorder = null; - this.appInfosCache = new AppInfosCache(this.log); // Whether to skip the device check in a new session request. - // This is a workaround for network connected devices such as an Apple TV 4k tvOS 17+ real device. - // A situation that requires this capability may hve an issue to communicate with the device + // This is a workaround for network-connected devices such as an Apple TV 4k tvOS 17+ real device. + // A situation that requires this capability may have an issue with communicating with the device // over appium-ios-device for example. // Please remove this capability when we no longer need this workaround. this.skipDeviceCheck = this.opts.skipDeviceCheck || false; From c765bdc4735e59307ffaf63666de5ac8366b972b Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 22 Oct 2024 19:23:07 -0700 Subject: [PATCH 26/27] fix log --- lib/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/driver.js b/lib/driver.js index 0b36601bb..d1f3a3c41 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -632,7 +632,7 @@ export class XCUITestDriver extends BaseDriver { // if we only have bundle identifier and no app, fail if it is not already installed. if (this.skipDeviceCheck) { - this.logs.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`); + this.log.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`); } else if ( !this.opts.app && this.opts.bundleId && From ca7003b92067d3526bfced9a2bc280490e6fb450 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 24 Jan 2025 11:46:19 -0800 Subject: [PATCH 27/27] update the option handling --- lib/driver.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/driver.js b/lib/driver.js index 1d39c253b..21b1facbb 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -255,9 +255,6 @@ export class XCUITestDriver extends BaseDriver { /** @type {import('./commands/pcap').TrafficCapture|null} */ _trafficCapture; - /** @type {boolean} */ - skipDeviceCheck; - /** @type {Simulator|RealDevice} */ _device; @@ -326,13 +323,6 @@ export class XCUITestDriver extends BaseDriver { this.appInfosCache = new AppInfosCache(this.log); this.remote = null; this.doesSupportBidi = true; - - // Whether to skip the device check in a new session request. - // This is a workaround for network-connected devices such as an Apple TV 4k tvOS 17+ real device. - // A situation that requires this capability may have an issue with communicating with the device - // over appium-ios-device for example. - // Please remove this capability when we no longer need this workaround. - this.skipDeviceCheck = this.opts.skipDeviceCheck || false; } async onSettingsUpdate(key, value) { @@ -632,7 +622,12 @@ export class XCUITestDriver extends BaseDriver { await this.installAUT(); // if we only have bundle identifier and no app, fail if it is not already installed. - if (this.skipDeviceCheck) { + if (!!this.opts.skipDeviceCheck) { + // Whether to skip the device check in a new session request. + // This is a workaround for network-connected devices such as an Apple TV 4k tvOS 17+ real device. + // A situation that requires this capability may have an issue with communicating with the device + // over appium-ios-device for example. + // Please remove this capability when we no longer need this workaround. this.log.debug(`Skipping ${this.opts.bundleId} installation check since skipDeviceCheck was given.`); } else if ( !this.opts.app && @@ -1596,7 +1591,7 @@ export class XCUITestDriver extends BaseDriver { return; } - if (this.opts.bundleId && this.skipDeviceCheck) { + if (this.opts.bundleId && !!this.opts.skipDeviceCheck) { this.log.debug('Skipping the bundle id installation check'); return; }