Skip to content

Commit

Permalink
feat: appium v2 support (#3622)
Browse files Browse the repository at this point in the history
* feat: appium v2 support

* Fix: Bump node version

* fix: ubuntu bump

* fix: try out another selenium version

* try another php version

* log webdriverio version

* bump other wdio libs

* fix: typo

* fix: undefined error

fix [1] Error | TypeError: Cannot read properties of undefined (reading 'restart')

* fix: missing appiumV2 config

* fix(docs): appium docs

* fix: _convertedCaps logic
  • Loading branch information
kobenguyent committed May 28, 2023
1 parent de8e0d4 commit 4aa8450
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 14 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/webdriver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ jobs:
node-version: [16.x]

steps:
- run: docker run -d --net=host --shm-size=2g selenium/standalone-chrome:3.141.59-oxygen
- uses: actions/checkout@v3
- run: docker run -d --net=host --shm-size=2g selenium/standalone-chrome:3.141.0
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: shivammathur/setup-php@v2
with:
php-version: 7.4
php-version: 8.0
- name: npm install
run: |
npm install --legacy-peer-deps
Expand Down
1 change: 1 addition & 0 deletions docs/helpers/Appium.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Launch the daemon: `appium`

This helper should be configured in codecept.conf.ts or codecept.conf.js

- `appiumV2`: set this to true if you want to run with Appiumv2
- `app`: Application path. Local path or remote URL to an .ipa or .apk file, or a .zip containing one of these. Alias to desiredCapabilities.appPackage
- `host`: (default: 'localhost') Appium host
- `port`: (default: '4723') Appium port
Expand Down
51 changes: 49 additions & 2 deletions docs/mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,69 @@ To install Appium use npm:
npm i -g appium
```

To use Appium 2.x:
```sh
npm i -g appium@next
```
Appium 2x (still beta) reenvisions Appium as a platform where “drivers” and “plugins” can be easily created and shared independently.
Install an Appium driver and its dependencies
To install the Appium driver and its dependencies, we'll be using the uiautomator2 (Android), XCUITest (iOS) drivers.

```
appium driver install xcuitest
appium driver install uiautomator2
```
To make sure that all the drivers are installed successfully, run the following command:

```
appium driver list
tth~$appium driver list
✔ Listing available drivers
- [email protected] [installed (NPM)]
- [email protected] [installed (NPM)]
- [email protected] [installed (NPM)]
- mac2 [not installed]
- safari [not installed]
- gecko [not installed]
- chromium [not installed]
```

Then you need to prepare application for execution.
It should be packed into apk (for Android) or .ipa (for iOS) or zip.

Next, is to launch the emulator or connect physical device.
Next, is to launch the emulator or connect a physical device.
Once they are prepared, launch Appium:

```sh
appium
```

To use Appium 2.x:
```sh
tth~$npx appium --base-path=/wd/hub
[Appium] Welcome to Appium v2.0.0-beta.57 (REV 3e675c32ae71dc0b00749d5d29213e2ea5b53c5b)
[Appium] Non-default server args:
[Appium] {
[Appium] basePath: '/wd/hub'
[Appium] }
[Appium] Attempting to load driver espresso...
[debug] [Appium] Requiring driver at /Users/trung-thanh/Desktop/thanh-nguyen/task2/node_modules/appium-espresso-driver
[Appium] Attempting to load driver uiautomator2...
[debug] [Appium] Requiring driver at /Users/trung-thanh/Desktop/thanh-nguyen/task2/node_modules/appium-uiautomator2-driver
[Appium] Appium REST http interface listener started on 0.0.0.0:4723
[Appium] Available drivers:
[Appium] - [email protected] (automationName 'Espresso')
[Appium] - [email protected] (automationName 'UiAutomator2')
[Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.
```
To run mobile test you need either an device emulator (available with Android SDK or iOS), real device connected for mobile testing. Alternatively, you may execute Appium with device emulator inside Docker container.
CodeceptJS should be installed with webdriverio support:
```bash
npm install codeceptjs webdriverio --save
npm install codeceptjs webdriverio@8.6.3 --save
```
## Configuring
Expand Down
49 changes: 43 additions & 6 deletions lib/helper/Appium.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const supportedPlatform = {
iOS: 'iOS',
};

const vendorPrefix = {
appium: 'appium',
};

/**
* Appium helper extends [Webriver](http://codecept.io/helpers/WebDriver/) helper.
* It supports all browser methods and also includes special methods for mobile apps testing.
Expand Down Expand Up @@ -135,6 +139,9 @@ class Appium extends Webdriver {
super(config);

this.isRunning = false;
if (config.appiumV2 === true) {
this.appiumV2 = true;
}
this.axios = axios.create();

webdriverio = require('webdriverio');
Expand Down Expand Up @@ -181,14 +188,22 @@ class Appium extends Webdriver {

config.baseUrl = config.url || config.baseUrl;
if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
config.capabilities = config.desiredCapabilities;
config.capabilities = this.appiumV2 === true ? this._convertAppiumV2Caps(config.desiredCapabilities) : config.desiredCapabilities;
}

if (this.appiumV2) {
config.capabilities[`${vendorPrefix.appium}:deviceName`] = config[`${vendorPrefix.appium}:device`] || config.capabilities[`${vendorPrefix.appium}:deviceName`];
config.capabilities[`${vendorPrefix.appium}:browserName`] = config[`${vendorPrefix.appium}:browser`] || config.capabilities[`${vendorPrefix.appium}:browserName`];
config.capabilities[`${vendorPrefix.appium}:app`] = config[`${vendorPrefix.appium}:app`] || config.capabilities[`${vendorPrefix.appium}:app`];
config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`] = config[`${vendorPrefix.appium}:tunnelIdentifier`] || config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`]; // Adding the code to connect to sauce labs via sauce tunnel
} else {
config.capabilities.deviceName = config.device || config.capabilities.deviceName;
config.capabilities.browserName = config.browser || config.capabilities.browserName;
config.capabilities.app = config.app || config.capabilities.app;
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier; // Adding the code to connect to sauce labs via sauce tunnel
}

config.capabilities.deviceName = config.device || config.capabilities.deviceName;
config.capabilities.browserName = config.browser || config.capabilities.browserName;
config.capabilities.app = config.app || config.capabilities.app;
config.capabilities.platformName = config.platform || config.capabilities.platformName;
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier; // Adding the code to connect to sauce labs via sauce tunnel
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000; // convert to seconds

// [CodeceptJS compatible] transform host to hostname
Expand All @@ -203,13 +218,29 @@ class Appium extends Webdriver {
}

this.platform = null;
if (config.capabilities[`${vendorPrefix.appium}:platformName`]) {
this.platform = config.capabilities[`${vendorPrefix.appium}:platformName`].toLowerCase();
}

if (config.capabilities.platformName) {
this.platform = config.capabilities.platformName.toLowerCase();
}

return config;
}

_convertAppiumV2Caps(capabilities) {
const _convertedCaps = {};
for (const [key, value] of Object.entries(capabilities)) {
if (!key.startsWith(vendorPrefix.appium)) {
_convertedCaps[`${vendorPrefix.appium}:${key}`] = value;
} else {
_convertedCaps[`${key}`] = value;
}
}
return _convertedCaps;
}

static _config() {
return [{
name: 'app',
Expand All @@ -229,6 +260,11 @@ class Appium extends Webdriver {
}

async _startBrowser() {
if (this.appiumV2 === true) {
this.options.capabilities = this._convertAppiumV2Caps(this.options.capabilities);
this.options.desiredCapabilities = this._convertAppiumV2Caps(this.options.desiredCapabilities);
}

try {
if (this.options.multiremote) {
this.browser = await webdriverio.multiremote(this.options.multiremote);
Expand Down Expand Up @@ -445,6 +481,7 @@ class Appium extends Webdriver {
*/
async checkIfAppIsInstalled(bundleId) {
onlyForApps.call(this, supportedPlatform.android);

return this.browser.isAppInstalled(bundleId);
}

Expand Down Expand Up @@ -481,7 +518,7 @@ class Appium extends Webdriver {
async seeAppIsNotInstalled(bundleId) {
onlyForApps.call(this, supportedPlatform.android);
const res = await this.browser.isAppInstalled(bundleId);
return truth(`app ${bundleId}`, 'to be installed').negate(res);
return truth(`app ${bundleId}`, 'not to be installed').negate(res);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@
"@pollyjs/core": "^5.1.0",
"@types/inquirer": "^0.0.35",
"@types/node": "^8.10.66",
"@wdio/sauce-service": "^5.22.5",
"@wdio/selenium-standalone-service": "^5.16.10",
"@wdio/utils": "^5.23.0",
"@wdio/sauce-service": "^8.3.8",
"@wdio/selenium-standalone-service": "^8.3.2",
"@wdio/utils": "^8.3.0",
"apollo-server-express": "^2.25.3",
"chai-as-promised": "^7.1.1",
"chai-subset": "^1.6.0",
Expand Down

0 comments on commit 4aa8450

Please sign in to comment.