Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: install prebuilt WDA as prebuiltWDAPath capability #1672

Merged
merged 12 commits into from
May 11, 2023
3 changes: 2 additions & 1 deletion docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ Capability | Description
|`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`|e.g., `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`|e.g., `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`.|e.g., `true`|
|`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. The preinstalled WebDriverAgent package must have been built by Xcode 12+. The default target bundle identifier is `com.facebook.WebDriverAgentRunner.xctrunner`. If `appium:updatedWDABundleId` is provided, `<appium:updatedWDABundleId>.xctrunner` will be launched. Please read [Run Preinstalled WebDriverAgentRunner](./run-preinstalled-wda.md) for more details. Defaults to `false`. |`true` or `false`|
|`appium:prebuiltWDAPath`| The path to a WebDriverAgentRunner application package to be installed with `appium:usePreinstalledWDA` capability for real devices. The package's bundle id will be used over `appium:updatedWDABundleId`. |e.g., `/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. If `appium:prebuiltWDAPath` is provided, XCUITest driver will install it before launching the application. The preinstalled WebDriverAgent package must have been built by Xcode 12+. The default target bundle identifier is `com.facebook.WebDriverAgentRunner.xctrunner`. If `appium:updatedWDABundleId` is provided, `<appium:updatedWDABundleId>.xctrunner` will be launched. Please read [Run Preinstalled WebDriverAgentRunner](./run-preinstalled-wda.md) for more details. Defaults to `false`. |`true` or `false`|
|`appium:shouldUseSingletonTestManager`|Use default proxy for test management within `WebDriverAgent`. Setting this to `false` sometimes helps with socket hangup problems. Defaults to `true`.|e.g., `false`|
|`appium:waitForIdleTimeout`|The amount of time in float seconds to wait until the application under test is idling. XCTest requires the app's main thread to be idling in order to execute any action on it, so WDA might not even start/freeze if the app under test is constantly hogging the main thread. The default value is `10` (seconds). Setting it to zero disables idling checks completely (not recommended) and has the same effect as setting `waitForQuiescence` to `false`. Available since Appium 1.20.0. |
|`appium:useXctestrunFile`|Use Xctestrun file to launch WDA. It will search for such file in `bootstrapPath`. Expected name of file is `WebDriverAgentRunner_iphoneos<sdkVersion>-arm64.xctestrun` for real device and `WebDriverAgentRunner_iphonesimulator<sdkVersion>-x86_64.xctestrun` for simulator. One can do `build-for-testing` for `WebDriverAgent` project for simulator and real device and then you will see [Product Folder like this](useXctestrunFile.png) and you need to copy content of this folder at `bootstrapPath` location. Since this capability expects that you have already built `WDA` project, it neither checks whether you have necessary dependencies to build `WDA` nor will it try to build project. Defaults to `false`. _Tips: `Xcodebuild` builds for the target platform version. We'd recommend you to build with minimal OS version which you'd like to run as the original WDA module. e.g. If you build WDA for 12.2, the module cannot run on iOS 11.4 because of loading some module error on simulator. A module built with 11.4 can work on iOS 12.2. (This is xcodebuild's expected behaviour.)_ |e.g., `true`|
Expand Down
30 changes: 30 additions & 0 deletions docs/run-preinstalled-wda.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ It lets you to start a XCUITest driver session without the `xcodebuild` command
- [`appium:usePreinstalledWDA`](capabilities.md#webdriveragent)
- Optional
- [`appium:updatedWDABundleId`](capabilities.md#webdriveragent)
- [`appium:prebuiltWDAPath`](capabilities.md#webdriveragent)

### Example steps with Xcode

Expand Down Expand Up @@ -80,3 +81,32 @@ Some 3rd party tools such as [ios-deploy](https://github.com/ios-control/ios-dep

`WebDriverAgentRunner-Runner.app` package may exist in a `derivedDataPath` directory as explained in [Real Device Configuration tutorial](./real-device-config.md).
The `WebDriverAgentRunner-Runner.app` can be installed without xcodebuild with the 3rd party tools.


### Set `appium:prebuiltWDAPath`

If `appium:prebuiltWDAPath` is provided with properly signed `WebDriverAgentRunner-Runner.app` test bundle (please check [Real Device Configuration tutorial](real-device-config.md)), XCUITest driver will install the application and launch it every test session.
Test bundles cannot be versioned using `CFBundleVersion` as vanilla applications do. That is why it is necessary to (re)install them for every test session.

Usually you can find the actual WebDriverAgentRunner application bundle at the below location if you use Xcode to build it.

```
~/Library/Developer/Xcode/DerivedData/WebDriverAgent-<random string>/Build/Products/Debug-iphoneos/WebDriverAgentRunner-Runner.app
```

Then, the capabilities will be:

```ruby
# Ruby
capabilities: {
"platformName": "ios",
"appium:automationName": "xcuitest",
"appium:udid": "<udid>",
"appium:usePreinstalledWDA": true,
"appium:prebuiltWDAPath": "/path/to/Library/Developer/Xcode/DerivedData/WebDriverAgent-<random string>/Build/Products/Debug-iphoneos/WebDriverAgentRunner-Runner.app"
}
@core = Appium::Core.for capabilities: capabilities
driver = @core.start_driver
# do something
driver.quit
```
3 changes: 3 additions & 0 deletions lib/desired-caps.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ const desiredCapConstraints = /** @type {const} */({
usePrebuiltWDA: {
isBoolean: true
},
prebuiltWDAPath: {
isString: true,
},
usePreinstalledWDA: {
isBoolean: true,
},
Expand Down
37 changes: 30 additions & 7 deletions lib/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -748,12 +748,19 @@ class XCUITestDriver extends BaseDriver {
);
}

if (this.opts.usePreinstalledWDA && !this.isRealDevice()) {
throw new Error(
`'usePreinstalledWDA' capability is only supported for real devices. ` +
`'useXctestrunFile' or 'usePrebuiltWDA' may help to get similar errort on Simulators.`
);
if (this.opts.usePreinstalledWDA) {
if (!this.isRealDevice()) {
throw new Error(
`'usePreinstalledWDA' capability is only supported for real devices. ` +
`'useXctestrunFile' or 'usePrebuiltWDA' may help to get similar errort on Simulators.`
);
}
// below will be only for real devices if the caps has "this.opts.usePreinstalledWDA"

if (this.opts.prebuiltWDAPath && !(await fs.exists(this.opts.prebuiltWDAPath))) {
throw new Error(`'${this.opts.prebuiltWDAPath}' provided as 'prebuiltWDAPath' capability did not exist. ` +
`Please make sure if the path exits.`);
}
}

return await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
Expand Down Expand Up @@ -817,8 +824,24 @@ class XCUITestDriver extends BaseDriver {
// Stop the existing process before starting a new one to start a fresh WDA process every session.
await this.mobileKillApp(this.wda.bundleIdForXctest);

// TODO: Define `prebuiltWDAPath` or something as a new capability.
// Then, we can start installing the WDA package to start a session without xcodebuild.
if (this.opts.prebuiltWDAPath) {
const candidateBundleId = await extractBundleId.bind(this)(this.opts.prebuiltWDAPath);
this.wda.updatedWDABundleId = candidateBundleId.replace('.xctrunner', '');
this.log.info(`Installing prebuilt WDA ${this.opts.prebuiltWDAPath}`);
// Note: The CFBundleVersion in the test bundle was always 1.
// It may not be able to compare with the installed versio.
await installToRealDevice(
// @ts-expect-error - do not assign arbitrary properties to `this.opts`
this.opts.device,
this.opts.prebuiltWDAPath,
candidateBundleId,
{
skipUninstall: true,
mykola-mokhnach marked this conversation as resolved.
Show resolved Hide resolved
timeout: this.opts.appPushTimeout,
strategy: this.opts.appInstallStrategy,
}
);
}
}

// Over Xcode 10 will often try to access the app from its staging
Expand Down