diff --git a/.github/workflows/appiumV2_Android.yml b/.github/workflows/appium_Android.yml similarity index 97% rename from .github/workflows/appiumV2_Android.yml rename to .github/workflows/appium_Android.yml index 207b1049e..c5e884b81 100644 --- a/.github/workflows/appiumV2_Android.yml +++ b/.github/workflows/appium_Android.yml @@ -1,4 +1,4 @@ -name: Appium V2 Tests - Android +name: Appium Tests - Android on: push: diff --git a/.github/workflows/appiumV2_iOS.yml b/.github/workflows/appium_iOS.yml similarity index 97% rename from .github/workflows/appiumV2_iOS.yml rename to .github/workflows/appium_iOS.yml index 621dfa5f7..5335f6c19 100644 --- a/.github/workflows/appiumV2_iOS.yml +++ b/.github/workflows/appium_iOS.yml @@ -1,4 +1,4 @@ -name: Appium V2 Tests - iOS +name: Appium Tests - iOS on: push: diff --git a/README.md b/README.md index 5f65618c8..992f36f4c 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ ## Build Status -| Type | Engine | Status | -| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🌐 Web | Playwright | [![Playwright Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml) | -| 🌐 Web | Puppeteer | [![Puppeteer Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml) | -| 🌐 Web | WebDriver | [![WebDriver Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml) | -| 🌐 Web | TestCafe | [![TestCafe Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml) | -| 📱 Mobile | Appium | [![Appium V2 Tests - Android](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appiumV2_Android.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appiumV2_Android.yml) | +| Type | Engine | Status | +| --------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 🌐 Web | Playwright | [![Playwright Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/playwright.yml) | +| 🌐 Web | Puppeteer | [![Puppeteer Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/puppeteer.yml) | +| 🌐 Web | WebDriver | [![WebDriver Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/webdriver.yml) | +| 🌐 Web | TestCafe | [![TestCafe Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml) | +| 📱 Mobile | Appium | [![Appium Tests - Android](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium_Android.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium_Android.yml) | # CodeceptJS [![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua) diff --git a/docs/helpers/Appium.md b/docs/helpers/Appium.md index 66d58635b..1e18d08f2 100644 --- a/docs/helpers/Appium.md +++ b/docs/helpers/Appium.md @@ -32,20 +32,20 @@ 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 tests with AppiumV2. See more how to setup [here][3] -* `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 -* `platform`: (Android or IOS), which mobile OS to use; alias to desiredCapabilities.platformName -* `restart`: restart browser or app between tests (default: true), if set to false cookies will be cleaned but browser window will be kept and for apps nothing will be changed. -* `desiredCapabilities`: \[], Appium capabilities, see below - * `platformName` - Which mobile OS platform to use - * `appPackage` - Java package of the Android app you want to run - * `appActivity` - Activity name for the Android activity you want to launch from your package. - * `deviceName`: The kind of mobile device or emulator to use - * `platformVersion`: Mobile OS version - * `app` - The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. - * `browserName`: Name of mobile web browser to automate. Should be an empty string if automating an app instead. +- `appiumV2`: by default is true, set this to false if you want to run tests with AppiumV1. See more how to setup [here][3] +- `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 +- `platform`: (Android or IOS), which mobile OS to use; alias to desiredCapabilities.platformName +- `restart`: restart browser or app between tests (default: true), if set to false cookies will be cleaned but browser window will be kept and for apps nothing will be changed. +- `desiredCapabilities`: \[], Appium capabilities, see below + - `platformName` - Which mobile OS platform to use + - `appPackage` - Java package of the Android app you want to run + - `appActivity` - Activity name for the Android activity you want to launch from your package. + - `deviceName`: The kind of mobile device or emulator to use + - `platformVersion`: Mobile OS version + - `app` - The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. + - `browserName`: Name of mobile web browser to automate. Should be an empty string if automating an app instead. Example Android App: @@ -112,7 +112,7 @@ Example Android App using AppiumV2 on BrowserStack: { helpers: { Appium: { - appiumV2: true, + appiumV2: true, // By default is true, set to false if you want to run against Appium v1 host: "hub-cloud.browserstack.com", port: 4444, user: process.env.BROWSERSTACK_USER, @@ -157,7 +157,7 @@ let browser = this.helpers['Appium'].browser ### Parameters -* `config` +- `config` ### runOnIOS @@ -165,35 +165,38 @@ Execute code only on iOS ```js I.runOnIOS(() => { - I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'); - I.see('Hi, IOS', '~welcome'); -}); + I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]') + I.see('Hi, IOS', '~welcome') +}) ``` Additional filter can be applied by checking for capabilities. For instance, this code will be executed only on iPhone 5s: ```js -I.runOnIOS({deviceName: 'iPhone 5s'},() => { - // ... -}); +I.runOnIOS({ deviceName: 'iPhone 5s' }, () => { + // ... +}) ``` Also capabilities can be checked by a function. ```js -I.runOnAndroid((caps) => { - // caps is current config of desiredCapabiliites - return caps.platformVersion >= 6 -},() => { - // ... -}); +I.runOnAndroid( + caps => { + // caps is current config of desiredCapabiliites + return caps.platformVersion >= 6 + }, + () => { + // ... + }, +) ``` #### Parameters -* `caps` **any** -* `fn` **any** +- `caps` **any** +- `fn` **any** ### runOnAndroid @@ -201,35 +204,38 @@ Execute code only on Android ```js I.runOnAndroid(() => { - I.click('io.selendroid.testapp:id/buttonTest'); -}); + I.click('io.selendroid.testapp:id/buttonTest') +}) ``` Additional filter can be applied by checking for capabilities. For instance, this code will be executed only on Android 6.0: ```js -I.runOnAndroid({platformVersion: '6.0'},() => { - // ... -}); +I.runOnAndroid({ platformVersion: '6.0' }, () => { + // ... +}) ``` Also capabilities can be checked by a function. In this case, code will be executed only on Android >= 6. ```js -I.runOnAndroid((caps) => { - // caps is current config of desiredCapabiliites - return caps.platformVersion >= 6 -},() => { - // ... -}); +I.runOnAndroid( + caps => { + // caps is current config of desiredCapabiliites + return caps.platformVersion >= 6 + }, + () => { + // ... + }, +) ``` #### Parameters -* `caps` **any** -* `fn` **any** +- `caps` **any** +- `fn` **any** ### runInWeb @@ -237,9 +243,9 @@ Execute code only in Web mode. ```js I.runInWeb(() => { - I.waitForElement('#data'); - I.seeInCurrentUrl('/data'); -}); + I.waitForElement('#data') + I.seeInCurrentUrl('/data') +}) ``` ### checkIfAppIsInstalled @@ -247,12 +253,12 @@ I.runInWeb(() => { Returns app installation status. ```js -I.checkIfAppIsInstalled("com.example.android.apis"); +I.checkIfAppIsInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]<[boolean][7]>** Appium: support only Android @@ -261,12 +267,12 @@ Returns **[Promise][6]<[boolean][7]>** Appium: support only Android Check if an app is installed. ```js -I.seeAppIsInstalled("com.example.android.apis"); +I.seeAppIsInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]\** Appium: support only Android @@ -275,12 +281,12 @@ Returns **[Promise][6]\** Appium: support only Android Check if an app is not installed. ```js -I.seeAppIsNotInstalled("com.example.android.apis"); +I.seeAppIsNotInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]\** Appium: support only Android @@ -289,12 +295,12 @@ Returns **[Promise][6]\** Appium: support only Android Install an app on device. ```js -I.installApp('/path/to/file.apk'); +I.installApp('/path/to/file.apk') ``` #### Parameters -* `path` **[string][5]** path to apk file +- `path` **[string][5]** path to apk file Returns **[Promise][6]\** Appium: support only Android @@ -303,22 +309,22 @@ Returns **[Promise][6]\** Appium: support only Android Remove an app from the device. ```js -I.removeApp('appName', 'com.example.android.apis'); +I.removeApp('appName', 'com.example.android.apis') ``` Appium: support only Android #### Parameters -* `appId` **[string][5]** -* `bundleId` **[string][5]?** ID of bundle +- `appId` **[string][5]** +- `bundleId` **[string][5]?** ID of bundle ### resetApp Reset the currently running app for current session. ```js -I.resetApp(); +I.resetApp() ``` ### seeCurrentActivityIs @@ -326,12 +332,12 @@ I.resetApp(); Check current activity on an Android device. ```js -I.seeCurrentActivityIs(".HomeScreenActivity") +I.seeCurrentActivityIs('.HomeScreenActivity') ``` #### Parameters -* `currentActivity` **[string][5]** +- `currentActivity` **[string][5]** Returns **[Promise][6]\** Appium: support only Android @@ -340,7 +346,7 @@ Returns **[Promise][6]\** Appium: support only Android Check whether the device is locked. ```js -I.seeDeviceIsLocked(); +I.seeDeviceIsLocked() ``` Returns **[Promise][6]\** Appium: support only Android @@ -350,7 +356,7 @@ Returns **[Promise][6]\** Appium: support only Android Check whether the device is not locked. ```js -I.seeDeviceIsUnlocked(); +I.seeDeviceIsUnlocked() ``` Returns **[Promise][6]\** Appium: support only Android @@ -360,13 +366,13 @@ Returns **[Promise][6]\** Appium: support only Android Check the device orientation ```js -I.seeOrientationIs('PORTRAIT'); +I.seeOrientationIs('PORTRAIT') I.seeOrientationIs('LANDSCAPE') ``` #### Parameters -* `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS +- `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS Returns **[Promise][6]\** @@ -375,13 +381,13 @@ Returns **[Promise][6]\** Set a device orientation. Will fail, if app will not set orientation ```js -I.setOrientation('PORTRAIT'); +I.setOrientation('PORTRAIT') I.setOrientation('LANDSCAPE') ``` #### Parameters -* `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS +- `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS ### grabAllContexts @@ -396,7 +402,7 @@ Returns **[Promise][6]<[Array][8]<[string][5]>>** Appium: support Android and iO Retrieve current context ```js -let context = await I.grabContext(); +let context = await I.grabContext() ``` Returns **[Promise][6]<([string][5] | null)>** Appium: support Android and iOS @@ -406,7 +412,7 @@ Returns **[Promise][6]<([string][5] | null)>** Appium: support Android and iOS Get current device activity. ```js -let activity = await I.grabCurrentActivity(); +let activity = await I.grabCurrentActivity() ``` Returns **[Promise][6]<[string][5]>** Appium: support only Android @@ -418,7 +424,7 @@ The actual server value will be a number. However WebdriverIO additional properties to the response object to allow easier assertions. ```js -let con = await I.grabNetworkConnection(); +let con = await I.grabNetworkConnection() ``` Returns **[Promise][6]<{}>** Appium: support only Android @@ -428,7 +434,7 @@ Returns **[Promise][6]<{}>** Appium: support only Android Get current orientation. ```js -let orientation = await I.grabOrientation(); +let orientation = await I.grabOrientation() ``` Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -438,7 +444,7 @@ Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS Get all the currently specified settings. ```js -let settings = await I.grabSettings(); +let settings = await I.grabSettings() ``` Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -449,7 +455,7 @@ Switch to the specified context. #### Parameters -* `context` **any** the context to switch to +- `context` **any** the context to switch to ### switchToWeb @@ -458,33 +464,33 @@ If no context is provided switches to the first detected web context ```js // switch to first web context -I.switchToWeb(); +I.switchToWeb() // or set the context explicitly -I.switchToWeb('WEBVIEW_io.selendroid.testapp'); +I.switchToWeb('WEBVIEW_io.selendroid.testapp') ``` #### Parameters -* `context` **[string][5]?** +- `context` **[string][5]?** Returns **[Promise][6]\** ### switchToNative Switches to native context. -By default switches to NATIVE\_APP context unless other specified. +By default switches to NATIVE_APP context unless other specified. ```js -I.switchToNative(); +I.switchToNative() // or set context explicitly -I.switchToNative('SOME_OTHER_CONTEXT'); +I.switchToNative('SOME_OTHER_CONTEXT') ``` #### Parameters -* `context` **any?** (optional, default `null`) +- `context` **any?** (optional, default `null`) Returns **[Promise][6]\** @@ -493,15 +499,15 @@ Returns **[Promise][6]\** Start an arbitrary Android activity during a session. ```js -I.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); +I.startActivity('io.selendroid.testapp', '.RegisterUserActivity') ``` Appium: support only Android #### Parameters -* `appPackage` **[string][5]** -* `appActivity` **[string][5]** +- `appPackage` **[string][5]** +- `appActivity` **[string][5]** Returns **[Promise][6]\** @@ -509,9 +515,9 @@ Returns **[Promise][6]\** Set network connection mode. -* airplane mode -* wifi mode -* data data +- airplane mode +- wifi mode +- data data ```js I.setNetworkConnection(0) // airplane mode off, wifi off, data off @@ -527,7 +533,7 @@ Appium: support only Android #### Parameters -* `value` **[number][10]** The network connection mode bitmask +- `value` **[number][10]** The network connection mode bitmask Returns **[Promise][6]<[number][10]>** @@ -536,12 +542,12 @@ Returns **[Promise][6]<[number][10]>** Update the current setting on the device ```js -I.setSettings({cyberdelia: 'open'}); +I.setSettings({ cyberdelia: 'open' }) ``` #### Parameters -* `settings` **[object][11]** objectAppium: support Android and iOS +- `settings` **[object][11]** objectAppium: support Android and iOS ### hideDeviceKeyboard @@ -549,7 +555,7 @@ Hide the keyboard. ```js // taps outside to hide keyboard per default -I.hideDeviceKeyboard(); +I.hideDeviceKeyboard() ``` Appium: support Android and iOS @@ -560,12 +566,12 @@ Send a key event to the device. List of keys: [https://developer.android.com/reference/android/view/KeyEvent.html][12] ```js -I.sendDeviceKeyEvent(3); +I.sendDeviceKeyEvent(3) ``` #### Parameters -* `keyValue` **[number][10]** Device specific key value +- `keyValue` **[number][10]** Device specific key value Returns **[Promise][6]\** Appium: support only Android @@ -574,7 +580,7 @@ Returns **[Promise][6]\** Appium: support only Android Open the notifications panel on the device. ```js -I.openNotifications(); +I.openNotifications() ``` Returns **[Promise][6]\** Appium: support only Android @@ -588,13 +594,13 @@ application on the device. [See complete documentation][13] ```js -I.makeTouchAction("~buttonStartWebviewCD", 'tap'); +I.makeTouchAction('~buttonStartWebviewCD', 'tap') ``` #### Parameters -* `locator` -* `action` +- `locator` +- `action` Returns **[Promise][6]\** Appium: support Android and iOS @@ -603,14 +609,14 @@ Returns **[Promise][6]\** Appium: support Android and iOS Taps on element. ```js -I.tap("~buttonStartWebviewCD"); +I.tap('~buttonStartWebviewCD') ``` Shortcut for `makeTouchAction` #### Parameters -* `locator` **any** +- `locator` **any** Returns **[Promise][6]\** @@ -619,18 +625,18 @@ Returns **[Promise][6]\** Perform a swipe on the screen or an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipe(locator, 800, 1200, 1000); +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipe(locator, 800, 1200, 1000) ``` [See complete reference][14] #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]** -* `yoffset` **[number][10]** -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]** +- `yoffset` **[number][10]** +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -639,30 +645,30 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe on the screen. ```js -I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }); +I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }) ``` #### Parameters -* `from` **[object][11]** -* `to` **[object][11]** Appium: support Android and iOS +- `from` **[object][11]** +- `to` **[object][11]** Appium: support Android and iOS ### swipeDown Perform a swipe down on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeDown(locator); // simple swipe -I.swipeDown(locator, 500); // set speed -I.swipeDown(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeDown(locator) // simple swipe +I.swipeDown(locator, 500) // set speed +I.swipeDown(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `yoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `yoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -671,17 +677,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe left on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeLeft(locator); // simple swipe -I.swipeLeft(locator, 500); // set speed -I.swipeLeft(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeLeft(locator) // simple swipe +I.swipeLeft(locator, 500) // set speed +I.swipeLeft(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -690,17 +696,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe right on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeRight(locator); // simple swipe -I.swipeRight(locator, 500); // set speed -I.swipeRight(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeRight(locator) // simple swipe +I.swipeRight(locator, 500) // set speed +I.swipeRight(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -709,17 +715,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe up on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeUp(locator); // simple swipe -I.swipeUp(locator, 500); // set speed -I.swipeUp(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeUp(locator) // simple swipe +I.swipeUp(locator, 500) // set speed +I.swipeUp(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `yoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `yoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -729,22 +735,23 @@ Perform a swipe in selected direction on an element to searchable element. ```js I.swipeTo( - "android.widget.CheckBox", // searchable element - "//android.widget.ScrollView/android.widget.LinearLayout", // scroll element - "up", // direction - 30, - 100, - 500); + 'android.widget.CheckBox', // searchable element + '//android.widget.ScrollView/android.widget.LinearLayout', // scroll element + 'up', // direction + 30, + 100, + 500, +) ``` #### Parameters -* `searchableLocator` **[string][5]** -* `scrollLocator` **[string][5]** -* `direction` **[string][5]** -* `timeout` **[number][10]** -* `offset` **[number][10]** -* `speed` **[number][10]** +- `searchableLocator` **[string][5]** +- `scrollLocator` **[string][5]** +- `direction` **[string][5]** +- `timeout` **[number][10]** +- `offset` **[number][10]** +- `speed` **[number][10]** Returns **[Promise][6]\** Appium: support Android and iOS @@ -754,45 +761,50 @@ Performs a specific touch action. The action object need to contain the action name, x/y coordinates ```js -I.touchPerform([{ +I.touchPerform([ + { action: 'press', options: { x: 100, - y: 200 - } -}, {action: 'release'}]) - -I.touchPerform([{ - action: 'tap', - options: { - element: '1', // json web element was queried before - x: 10, // x offset - y: 20, // y offset - count: 1 // number of touches - } -}]); + y: 200, + }, + }, + { action: 'release' }, +]) + +I.touchPerform([ + { + action: 'tap', + options: { + element: '1', // json web element was queried before + x: 10, // x offset + y: 20, // y offset + count: 1, // number of touches + }, + }, +]) ``` Appium: support Android and iOS #### Parameters -* `actions` **[Array][8]** Array of touch actions +- `actions` **[Array][8]** Array of touch actions ### pullFile Pulls a file from the device. ```js -I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path'); +I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path') // save file to output dir -I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir); +I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir) ``` #### Parameters -* `path` **[string][5]** -* `dest` **[string][5]** +- `path` **[string][5]** +- `dest` **[string][5]** Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -801,7 +813,7 @@ Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS Perform a shake action on the device. ```js -I.shakeDevice(); +I.shakeDevice() ``` Returns **[Promise][6]\** Appium: support only iOS @@ -818,12 +830,12 @@ See corresponding [webdriverio reference][15]. #### Parameters -* `x` -* `y` -* `duration` -* `radius` -* `rotation` -* `touchCount` +- `x` +- `y` +- `duration` +- `radius` +- `rotation` +- `touchCount` Returns **[Promise][6]\** Appium: support only iOS @@ -835,8 +847,8 @@ See corresponding [webdriverio reference][16]. #### Parameters -* `id` -* `value` +- `id` +- `value` Returns **[Promise][6]\** Appium: support only iOS @@ -845,14 +857,14 @@ Returns **[Promise][6]\** Appium: support only iOS Simulate Touch ID with either valid (match == true) or invalid (match == false) fingerprint. ```js -I.touchId(); // simulates valid fingerprint -I.touchId(true); // simulates valid fingerprint -I.touchId(false); // simulates invalid fingerprint +I.touchId() // simulates valid fingerprint +I.touchId(true) // simulates valid fingerprint +I.touchId(false) // simulates invalid fingerprint ``` #### Parameters -* `match` +- `match` Returns **[Promise][6]\** Appium: support only iOS TODO: not tested @@ -862,7 +874,7 @@ TODO: not tested Close the given application. ```js -I.closeApp(); +I.closeApp() ``` Returns **[Promise][6]\** Appium: support both Android and iOS @@ -873,15 +885,15 @@ Appends text to a input field or textarea. Field is located by name, label, CSS or XPath ```js -I.appendField('#myTextField', 'appended'); +I.appendField('#myTextField', 'appended') // typing secret -I.appendField('password', secret('123456')); +I.appendField('password', secret('123456')) ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator -* `value` **[string][5]** text value to append. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator +- `value` **[string][5]** text value to append. Returns **void** automatically synchronized promise through #recorder @@ -893,15 +905,15 @@ Element is located by label or name or CSS or XPath. The second parameter is a context (CSS or XPath locator) to narrow the search. ```js -I.checkOption('#agree'); -I.checkOption('I Agree to Terms and Conditions'); -I.checkOption('agree', '//form'); +I.checkOption('#agree') +I.checkOption('I Agree to Terms and Conditions') +I.checkOption('agree', '//form') ``` #### Parameters -* `field` **([string][5] | [object][11])** checkbox located by label | name | CSS | XPath | strict locator. -* `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS | XPath | strict locator. (optional, default `null`) +- `field` **([string][5] | [object][11])** checkbox located by label | name | CSS | XPath | strict locator. +- `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS | XPath | strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -916,23 +928,23 @@ The second parameter is a context (CSS or XPath locator) to narrow the search. ```js // simple link -I.click('Logout'); +I.click('Logout') // button of form -I.click('Submit'); +I.click('Submit') // CSS button -I.click('#form input[type=submit]'); +I.click('#form input[type=submit]') // XPath -I.click('//form/*[@type=submit]'); +I.click('//form/*[@type=submit]') // link in context -I.click('Logout', '#nav'); +I.click('Logout', '#nav') // using strict locator -I.click({css: 'nav a.login'}); +I.click({ css: 'nav a.login' }) ``` #### Parameters -* `locator` **([string][5] | [object][11])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. -* `context` **([string][5]? | [object][11] | null)** (optional, `null` by default) element to search in CSS|XPath|Strict locator. (optional, default `null`) +- `locator` **([string][5] | [object][11])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][5]? | [object][11] | null)** (optional, `null` by default) element to search in CSS|XPath|Strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -941,14 +953,14 @@ Returns **void** automatically synchronized promise through #recorder Verifies that the specified checkbox is not checked. ```js -I.dontSeeCheckboxIsChecked('#agree'); // located by ID -I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label -I.dontSeeCheckboxIsChecked('agree'); // located by name +I.dontSeeCheckboxIsChecked('#agree') // located by ID +I.dontSeeCheckboxIsChecked('I agree to terms') // located by label +I.dontSeeCheckboxIsChecked('agree') // located by name ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -957,12 +969,12 @@ Returns **void** automatically synchronized promise through #recorder Opposite to `seeElement`. Checks that element is not visible (or in DOM) ```js -I.dontSeeElement('.modal'); // modal is not shown +I.dontSeeElement('.modal') // modal is not shown ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|Strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|Strict locator. Returns **void** automatically synchronized promise through #recorder @@ -972,14 +984,14 @@ Checks that value of input field or textarea doesn't equal to given value Opposite to `seeInField`. ```js -I.dontSeeInField('email', 'user@user.com'); // field by name -I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS +I.dontSeeInField('email', 'user@user.com') // field by name +I.dontSeeInField({ css: 'form input.email' }, 'user@user.com') // field by CSS ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** value to check. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** value to check. Returns **void** automatically synchronized promise through #recorder @@ -989,14 +1001,14 @@ Opposite to `see`. Checks that a text is not present on a page. Use context parameter to narrow down the search. ```js -I.dontSee('Login'); // assume we are already logged in. -I.dontSee('Login', '.nav'); // no login inside .nav element +I.dontSee('Login') // assume we are already logged in. +I.dontSee('Login', '.nav') // no login inside .nav element ``` #### Parameters -* `text` **[string][5]** which is not present. -* `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search. (optional, default `null`) +- `text` **[string][5]** which is not present. +- `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1007,19 +1019,19 @@ Field is located by name, label, CSS, or XPath. ```js // by label -I.fillField('Email', 'hello@world.com'); +I.fillField('Email', 'hello@world.com') // by name -I.fillField('password', secret('123456')); +I.fillField('password', secret('123456')) // by CSS -I.fillField('form#login input[name=username]', 'John'); +I.fillField('form#login input[name=username]', 'John') // or by strict locator -I.fillField({css: 'form#login input[name=username]'}, 'John'); +I.fillField({ css: 'form#login input[name=username]' }, 'John') ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** text value to fill. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** text value to fill. Returns **void** automatically synchronized promise through #recorder @@ -1029,12 +1041,12 @@ Retrieves all texts from an element located by CSS or XPath and returns it to te Resumes test execution, so **should be used inside async with `await`** operator. ```js -let pins = await I.grabTextFromAll('#pin li'); +let pins = await I.grabTextFromAll('#pin li') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1044,14 +1056,14 @@ Retrieves a text from an element located by CSS or XPath and returns it to test. Resumes test execution, so **should be used inside async with `await`** operator. ```js -let pin = await I.grabTextFrom('#pin'); +let pin = await I.grabTextFrom('#pin') ``` If multiple elements found returns first element. #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. Returns **[Promise][6]<[string][5]>** attribute value @@ -1061,12 +1073,12 @@ Grab number of visible elements by locator. Resumes test execution, so **should be used inside async function with `await`** operator. ```js -let numOfElements = await I.grabNumberOfVisibleElements('p'); +let numOfElements = await I.grabNumberOfVisibleElements('p') ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. Returns **[Promise][6]<[number][10]>** number of visible elements @@ -1079,13 +1091,13 @@ Resumes test execution, so **should be used inside async with `await`** operator If more than one element is found - attribute of first element is returned. ```js -let hint = await I.grabAttributeFrom('#tooltip', 'title'); +let hint = await I.grabAttributeFrom('#tooltip', 'title') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `attr` **[string][5]** attribute name. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `attr` **[string][5]** attribute name. Returns **[Promise][6]<[string][5]>** attribute value @@ -1096,13 +1108,13 @@ Retrieves an array of attributes from elements located by CSS or XPath and retur Resumes test execution, so **should be used inside async with `await`** operator. ```js -let hints = await I.grabAttributeFromAll('.tooltip', 'title'); +let hints = await I.grabAttributeFromAll('.tooltip', 'title') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `attr` **[string][5]** attribute name. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `attr` **[string][5]** attribute name. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1112,12 +1124,12 @@ Retrieves an array of value from a form located by CSS or XPath and returns it t Resumes test execution, so **should be used inside async function with `await`** operator. ```js -let inputs = await I.grabValueFromAll('//form/input'); +let inputs = await I.grabValueFromAll('//form/input') ``` #### Parameters -* `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1128,12 +1140,12 @@ Resumes test execution, so **should be used inside async function with `await`** If more than one element is found - value of first element is returned. ```js -let email = await I.grabValueFrom('input[name=email]'); +let email = await I.grabValueFrom('input[name=email]') ``` #### Parameters -* `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. Returns **[Promise][6]<[string][5]>** attribute value @@ -1143,12 +1155,12 @@ Saves a screenshot to ouput folder (set in codecept.conf.ts or codecept.conf.js) Filename is relative to output folder. ```js -I.saveScreenshot('debug.png'); +I.saveScreenshot('debug.png') ``` #### Parameters -* `fileName` **[string][5]** file name to save. +- `fileName` **[string][5]** file name to save. Returns **[Promise][6]\** @@ -1157,15 +1169,15 @@ Returns **[Promise][6]\** Scroll element into viewport. ```js -I.scrollIntoView('#submit'); -I.scrollIntoView('#submit', true); -I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" }); +I.scrollIntoView('#submit') +I.scrollIntoView('#submit', true) +I.scrollIntoView('#submit', { behavior: 'smooth', block: 'center', inline: 'center' }) ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. -* `scrollIntoViewOptions` **(ScrollIntoViewOptions | [boolean][7])** either alignToTop=true|false or scrollIntoViewOptions. See [https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView][17]. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `scrollIntoViewOptions` **(ScrollIntoViewOptions | [boolean][7])** either alignToTop=true|false or scrollIntoViewOptions. See [https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView][17]. Returns **void** automatically synchronized promise through #recorderSupported only for web testing @@ -1174,14 +1186,14 @@ Returns **void** automatically synchronized promise through #recorderSupported o Verifies that the specified checkbox is checked. ```js -I.seeCheckboxIsChecked('Agree'); -I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms -I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'}); +I.seeCheckboxIsChecked('Agree') +I.seeCheckboxIsChecked('#agree') // I suppose user agreed to terms +I.seeCheckboxIsChecked({ css: '#signup_form input[type=checkbox]' }) ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -1191,12 +1203,12 @@ Checks that a given Element is visible Element is located by CSS or XPath. ```js -I.seeElement('#modal'); +I.seeElement('#modal') ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -1206,16 +1218,16 @@ Checks that the given input field or textarea equals to given value. For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. ```js -I.seeInField('Username', 'davert'); -I.seeInField({css: 'form textarea'},'Type your comment here'); -I.seeInField('form input[type=hidden]','hidden_value'); -I.seeInField('#searchform input','Search'); +I.seeInField('Username', 'davert') +I.seeInField({ css: 'form textarea' }, 'Type your comment here') +I.seeInField('form input[type=hidden]', 'hidden_value') +I.seeInField('#searchform input', 'Search') ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** value to check. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** value to check. Returns **void** automatically synchronized promise through #recorder @@ -1225,15 +1237,15 @@ Checks that a page contains a visible text. Use context parameter to narrow down the search. ```js -I.see('Welcome'); // text welcome on a page -I.see('Welcome', '.content'); // text inside .content div -I.see('Register', {css: 'form.register'}); // use strict locator +I.see('Welcome') // text welcome on a page +I.see('Welcome', '.content') // text inside .content div +I.see('Register', { css: 'form.register' }) // use strict locator ``` #### Parameters -* `text` **[string][5]** expected on page. -* `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. (optional, default `null`) +- `text` **[string][5]** expected on page. +- `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1244,24 +1256,24 @@ Field is searched by label | name | CSS | XPath. Option is selected by visible text or by value. ```js -I.selectOption('Choose Plan', 'Monthly'); // select by label -I.selectOption('subscription', 'Monthly'); // match option by text -I.selectOption('subscription', '0'); // or by value -I.selectOption('//form/select[@name=account]','Premium'); -I.selectOption('form select[name=account]', 'Premium'); -I.selectOption({css: 'form select[name=account]'}, 'Premium'); +I.selectOption('Choose Plan', 'Monthly') // select by label +I.selectOption('subscription', 'Monthly') // match option by text +I.selectOption('subscription', '0') // or by value +I.selectOption('//form/select[@name=account]', 'Premium') +I.selectOption('form select[name=account]', 'Premium') +I.selectOption({ css: 'form select[name=account]' }, 'Premium') ``` Provide an array for the second argument to select multiple options. ```js -I.selectOption('Which OS do you use?', ['Android', 'iOS']); +I.selectOption('Which OS do you use?', ['Android', 'iOS']) ``` #### Parameters -* `select` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. -* `option` **([string][5] | [Array][8]\)** visible text or value of option. +- `select` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `option` **([string][5] | [Array][8]\)** visible text or value of option. Returns **void** automatically synchronized promise through #recorderSupported only for web testing @@ -1271,14 +1283,14 @@ Waits for element to be present on page (by default waits for 1sec). Element can be located by CSS or XPath. ```js -I.waitForElement('.btn.continue'); -I.waitForElement('.btn.continue', 5); // wait for 5 secs +I.waitForElement('.btn.continue') +I.waitForElement('.btn.continue', 5) // wait for 5 secs ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]?** (optional, `1` by default) time in seconds to wait (optional, default `null`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]?** (optional, `1` by default) time in seconds to wait (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1288,13 +1300,13 @@ Waits for an element to become visible on a page (by default waits for 1sec). Element can be located by CSS or XPath. ```js -I.waitForVisible('#popup'); +I.waitForVisible('#popup') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) Returns **void** automatically synchronized promise through #recorder @@ -1304,13 +1316,13 @@ Waits for an element to be removed or become invisible on a page (by default wai Element can be located by CSS or XPath. ```js -I.waitForInvisible('#popup'); +I.waitForInvisible('#popup') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) Returns **void** automatically synchronized promise through #recorder @@ -1321,48 +1333,32 @@ Element can be located by CSS or XPath. Narrow down search results by providing context. ```js -I.waitForText('Thank you, form has been submitted'); -I.waitForText('Thank you, form has been submitted', 5, '#modal'); +I.waitForText('Thank you, form has been submitted') +I.waitForText('Thank you, form has been submitted', 5, '#modal') ``` #### Parameters -* `text` **[string][5]** to wait for. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) -* `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator. (optional, default `null`) +- `text` **[string][5]** to wait for. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder [1]: http://codecept.io/helpers/WebDriver/ - [2]: https://appium.io/docs/en/2.1/ - [3]: https://codecept.io/mobile/#setting-up - [4]: https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/caps.md - [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise - [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean - [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array - [9]: https://webdriver.io/docs/api/chromium/#setnetworkconnection - [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number - [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [12]: https://developer.android.com/reference/android/view/KeyEvent.html - [13]: http://webdriver.io/api/mobile/touchAction.html - [14]: http://webdriver.io/api/mobile/swipe.html - [15]: http://webdriver.io/api/mobile/rotate.html - [16]: http://webdriver.io/api/mobile/setImmediateValue.html - [17]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView diff --git a/docs/plugins.md b/docs/plugins.md index 155550f7d..d18f534c4 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -757,79 +757,6 @@ Scenario('scenario tite', () => { - `config` -## retryTo - -Adds global `retryTo` which retries steps a few times before failing. - -Enable this plugin in `codecept.conf.js` (enabled by default for new setups): - -```js -plugins: { - retryTo: { - enabled: true - } -} -``` - -Use it in your tests: - -```js -// retry these steps 5 times before failing -await retryTo(tryNum => { - I.switchTo('#editor frame') - I.click('Open') - I.see('Opened') -}, 5) -``` - -Set polling interval as 3rd argument (200ms by default): - -```js -// retry these steps 5 times before failing -await retryTo( - tryNum => { - I.switchTo('#editor frame') - I.click('Open') - I.see('Opened') - }, - 5, - 100, -) -``` - -Default polling interval can be changed in a config: - -```js -plugins: { - retryTo: { - enabled: true, - pollInterval: 500, - } -} -``` - -Disables retryFailedStep plugin for steps inside a block; - -Use this plugin if: - -- you need repeat a set of actions in flaky tests -- iframe was not rendered and you need to retry switching to it - -#### Configuration - -- `pollInterval` - default interval between retries in ms. 200 by default. -- `registerGlobal` - to register `retryTo` function globally, true by default - -If `registerGlobal` is false you can use retryTo from the plugin: - -```js -const retryTo = codeceptjs.container.plugins('retryTo') -``` - -### Parameters - -- `config` - ## screenshotOnFail Creates screenshot on failure. Screenshot is saved into `output` directory. @@ -1083,76 +1010,6 @@ plugins: { } ``` -## tryTo - -Adds global `tryTo` function in which all failed steps won't fail a test but will return true/false. - -Enable this plugin in `codecept.conf.js` (enabled by default for new setups): - -```js -plugins: { - tryTo: { - enabled: true - } -} -``` - -Use it in your tests: - -```js -const result = await tryTo(() => I.see('Welcome')) - -// if text "Welcome" is on page, result => true -// if text "Welcome" is not on page, result => false -``` - -Disables retryFailedStep plugin for steps inside a block; - -Use this plugin if: - -- you need to perform multiple assertions inside a test -- there is A/B testing on a website you test -- there is "Accept Cookie" banner which may surprisingly appear on a page. - -#### Usage - -#### Multiple Conditional Assertions - -````js - -Add assert requires first: -```js -const assert = require('assert'); -```` - -Then use the assertion: -const result1 = await tryTo(() => I.see('Hello, user')); -const result2 = await tryTo(() => I.seeElement('.welcome')); -assert.ok(result1 && result2, 'Assertions were not succesful'); - -```` - -##### Optional click - -```js -I.amOnPage('/'); -tryTo(() => I.click('Agree', '.cookies')); -```` - -#### Configuration - -- `registerGlobal` - to register `tryTo` function globally, true by default - -If `registerGlobal` is false you can use tryTo from the plugin: - -```js -const tryTo = codeceptjs.container.plugins('tryTo') -``` - -### Parameters - -- `config` - ## wdio Webdriverio services runner. diff --git a/lib/helper/Appium.js b/lib/helper/Appium.js index f13b87216..2519d68eb 100644 --- a/lib/helper/Appium.js +++ b/lib/helper/Appium.js @@ -44,7 +44,7 @@ const vendorPrefix = { * * This helper should be configured in codecept.conf.ts or codecept.conf.js * - * * `appiumV2`: set this to true if you want to run tests with AppiumV2. See more how to setup [here](https://codecept.io/mobile/#setting-up) + * * `appiumV2`: by default is true, set this to false if you want to run tests with AppiumV1. See more how to setup [here](https://codecept.io/mobile/#setting-up) * * `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 @@ -124,7 +124,7 @@ const vendorPrefix = { * { * helpers: { * Appium: { - * appiumV2: true, + * appiumV2: true, // By default is true, set to false if you want to run against Appium v1 * host: "hub-cloud.browserstack.com", * port: 4444, * user: process.env.BROWSERSTACK_USER, @@ -178,14 +178,12 @@ class Appium extends Webdriver { super(config) this.isRunning = false - if (config.appiumV2 === true) { - this.appiumV2 = true - } + this.appiumV2 = config.appiumV2 || true this.axios = axios.create() webdriverio = require('webdriverio') if (!config.appiumV2) { - console.log('The Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. Please migrating to Appium 2.x by adding appiumV2: true to your config.') + console.log('The Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. Appium 2.x is used by default.') console.log('More info: https://bit.ly/appium-v2-migration') console.log('This Appium 1.x support will be removed in next major release.') } diff --git a/package.json b/package.json index 45f0a6c18..523704f2d 100644 --- a/package.json +++ b/package.json @@ -50,10 +50,10 @@ "test:unit": "mocha test/unit --recursive --timeout 10000", "test:runner": "mocha test/runner --recursive --timeout 10000", "test": "npm run test:unit && npm run test:runner", - "test:appium-quick": "mocha test/helper/AppiumV2_test.js --grep 'quick'", - "test:appium-other": "mocha test/helper/AppiumV2_test.js --grep 'second'", - "test:ios:appium-quick": "mocha test/helper/AppiumV2_ios_test.js --grep 'quick'", - "test:ios:appium-other": "mocha test/helper/AppiumV2_ios_test.js --grep 'second'", + "test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'", + "test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'", + "test:ios:appium-quick": "mocha test/helper/Appium_ios_test.js --grep 'quick'", + "test:ios:appium-other": "mocha test/helper/Appium_ios_test.js --grep 'second'", "test-app:start": "php -S 127.0.0.1:8000 -t test/data/app", "test-app:stop": "kill -9 $(lsof -t -i:8000)", "test:unit:webbapi:playwright": "mocha test/helper/Playwright_test.js", diff --git a/test/helper/AppiumV2Web_test.js b/test/helper/AppiumV2Web_test.js deleted file mode 100644 index 66ad70f4b..000000000 --- a/test/helper/AppiumV2Web_test.js +++ /dev/null @@ -1,165 +0,0 @@ -const Appium = require('../../lib/helper/Appium') -global.codeceptjs = require('../../lib') - -let I -const site_url = 'http://davertmik.github.io' - -describe('Appium Web', function () { - this.retries(4) - this.timeout(70000) - - before(() => { - I = new Appium({ - url: site_url, - appiumV2: true, - browser: 'chrome', - restart: false, - desiredCapabilities: { - 'sauce:options': { - appiumVersion: '2.0.0', - }, - recordVideo: 'false', - recordScreenshots: 'false', - platformName: 'Android', - platformVersion: '6.0', - deviceName: 'Android Emulator', - }, - host: 'ondemand.saucelabs.com', - port: 80, - // port: 4723, - // host: 'localhost', - user: process.env.SAUCE_USERNAME, - key: process.env.SAUCE_ACCESS_KEY, - }) - // I.isWeb = true; - I._init() - I._beforeSuite() - }) - - after(() => I._finishTest()) - - beforeEach(() => { - I.isWeb = true - return I._before() - }) - - afterEach(() => I._after()) - - describe('current url : #seeInCurrentUrl, #seeCurrentUrlEquals, ...', () => { - it('should check for url fragment', async () => { - await I.amOnPage('/angular-demo-app/#/info') - await I.seeInCurrentUrl('/info') - await I.dontSeeInCurrentUrl('/result') - }) - - it('should check for equality', async () => { - await I.amOnPage('/angular-demo-app/#/info') - await I.seeCurrentUrlEquals('/angular-demo-app/#/info') - await I.dontSeeCurrentUrlEquals('/angular-demo-app/#/result') - }) - }) - - describe('see text : #see', () => { - it('should check text on site', async () => { - await I.amOnPage('/angular-demo-app/') - await I.see('Description') - await I.dontSee('Create Event Today') - }) - - it('should check text inside element', async () => { - await I.amOnPage('/angular-demo-app/#/info') - await I.see('About', 'h1') - await I.see('Welcome to event app', { css: 'p.jumbotron' }) - await I.see('Back to form', '//div/a') - }) - }) - - describe('see element : #seeElement, #dontSeeElement', () => { - it('should check visible elements on page', async () => { - await I.amOnPage('/angular-demo-app/') - await I.seeElement('.btn.btn-primary') - await I.seeElement({ css: '.btn.btn-primary' }) - await I.dontSeeElement({ css: '.btn.btn-secondary' }) - }) - }) - - describe('#click', () => { - it('should click by text', async () => { - await I.amOnPage('/angular-demo-app/') - await I.dontSeeInCurrentUrl('/info') - await I.click('Get more info!') - await I.seeInCurrentUrl('/info') - }) - - it('should click by css', async () => { - await I.amOnPage('/angular-demo-app/') - await I.click('.btn-primary') - await I.wait(2) - await I.seeInCurrentUrl('/result') - }) - - it('should click by non-optimal css', async () => { - await I.amOnPage('/angular-demo-app/') - await I.click('form a.btn') - await I.wait(2) - await I.seeInCurrentUrl('/result') - }) - - it('should click by xpath', async () => { - await I.amOnPage('/angular-demo-app/') - await I.click('//a[contains(., "more info")]') - await I.seeInCurrentUrl('/info') - }) - - it('should click on context', async () => { - await I.amOnPage('/angular-demo-app/') - await I.click('.btn-primary', 'form') - await I.wait(2) - await I.seeInCurrentUrl('/result') - }) - - it('should click link with inner span', async () => { - await I.amOnPage('/angular-demo-app/#/result') - await I.click('Go to info') - await I.seeInCurrentUrl('/info') - }) - - it('should click buttons as links', async () => { - await I.amOnPage('/angular-demo-app/') - await I.click('Options') - await I.seeInCurrentUrl('/options') - }) - }) - - describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom', () => { - it('should grab text from page', async () => { - await I.amOnPage('/angular-demo-app/#/info') - const val = await I.grabTextFrom('p.jumbotron') - val.should.be.equal('Welcome to event app') - }) - - it('should grab value from field', async () => { - await I.amOnPage('/angular-demo-app/#/options') - const val = await I.grabValueFrom('#ssh') - val.should.be.equal('PUBLIC-SSH-KEY') - }) - - it('should grab attribute from element', async () => { - await I.amOnPage('/angular-demo-app/#/info') - const val = await I.grabAttributeFrom('a.btn', 'ng-href') - val.should.be.equal('#/') - }) - }) - - describe('#within', () => { - afterEach(() => I._withinEnd()) - - it('should work using within operator', async () => { - await I.amOnPage('/angular-demo-app/#/options') - await I.see('Choose if you ok with terms') - await I._withinBegin({ css: 'div.results' }) - await I.see('SSH Public Key: PUBLIC-SSH-KEY') - await I.dontSee('Options') - }) - }) -}) diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js deleted file mode 100644 index 8064d4ea9..000000000 --- a/test/helper/AppiumV2_test.js +++ /dev/null @@ -1,620 +0,0 @@ -const chai = require('chai') - -const expect = chai.expect -const assert = chai.assert -const path = require('path') - -const Appium = require('../../lib/helper/Appium') -const AssertionFailedError = require('../../lib/assert/error') -const fileExists = require('../../lib/utils').fileExists -global.codeceptjs = require('../../lib') - -let app -const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk' -const smallWait = 3 - -describe('Appium', function () { - // this.retries(1); - this.timeout(0) - - before(async () => { - global.codecept_dir = path.join(__dirname, '/../data') - app = new Appium({ - app: apk_path, - appiumV2: true, - desiredCapabilities: { - 'sauce:options': { - appiumVersion: '2.0.0', - }, - browserName: '', - recordVideo: 'false', - recordScreenshots: 'false', - platformName: 'Android', - platformVersion: '7.0', - deviceName: 'Android GoogleAPI Emulator', - androidInstallTimeout: 90000, - appWaitDuration: 300000, - }, - restart: true, - protocol: 'http', - host: 'ondemand.saucelabs.com', - port: 80, - // port: 4723, - // host: 'localhost', - user: process.env.SAUCE_USERNAME, - key: process.env.SAUCE_ACCESS_KEY, - }) - await app._beforeSuite() - app.isWeb = false - await app._before() - }) - - after(async () => { - await app._after() - }) - - describe('app installation : #seeAppIsInstalled, #installApp, #removeApp, #seeAppIsNotInstalled', () => { - describe('#grabAllContexts, #grabContext, #grabCurrentActivity, #grabNetworkConnection, #grabOrientation, #grabSettings', () => { - it('should grab all available contexts for screen', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - const val = await app.grabAllContexts() - assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']) - }) - - it('should grab current context', async () => { - const val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - }) - - it('should grab current activity of app', async () => { - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) - - it('should grab network connection settings', async () => { - await app.setNetworkConnection(4) - const val = await app.grabNetworkConnection() - assert.equal(val.value, 4) - assert.equal(val.inAirplaneMode, false) - assert.equal(val.hasWifi, false) - assert.equal(val.hasData, true) - }) - - it('should grab orientation', async () => { - const val = await app.grabOrientation() - assert.equal(val, 'PORTRAIT') - }) - - it('should grab custom settings', async () => { - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false }) - }) - }) - - it('should remove App and install it again', async () => { - await app.seeAppIsInstalled('io.selendroid.testapp') - await app.removeApp('io.selendroid.testapp') - await app.seeAppIsNotInstalled('io.selendroid.testapp') - await app.installApp(apk_path) - await app.seeAppIsInstalled('io.selendroid.testapp') - }) - - it('should return true if app is installed @quick', async () => { - const status = await app.checkIfAppIsInstalled('io.selendroid.testapp') - expect(status).to.be.true - }) - - it('should assert when app is/is not installed', async () => { - try { - await app.seeAppIsInstalled('io.super.app') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.super.app to be installed') - } - - try { - await app.seeAppIsNotInstalled('io.selendroid.testapp') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.selendroid.testapp not to be installed') - } - }) - }) - - describe('see seeCurrentActivity: #seeCurrentActivityIs', () => { - it('should return .HomeScreenActivity for default screen', async () => { - await app.seeCurrentActivityIs('.HomeScreenActivity') - }) - - it('should assert for wrong screen', async () => { - try { - await app.seeCurrentActivityIs('.SuperScreen') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected current activity to be .SuperScreen') - } - }) - }) - - describe('device lock : #seeDeviceIsLocked, #seeDeviceIsUnlocked', () => { - it('should return correct status about lock @second', async () => { - await app.seeDeviceIsUnlocked() - try { - await app.seeDeviceIsLocked() - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected device to be locked') - } - }) - }) - - describe('device orientation : #seeOrientationIs #setOrientation', () => { - it('should return correct status about lock', async () => { - await app.seeOrientationIs('PORTRAIT') - try { - await app.seeOrientationIs('LANDSCAPE') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected orientation to be LANDSCAPE') - } - }) - - it('should set device orientation', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - await app.setOrientation('LANDSCAPE') - await app.seeOrientationIs('LANDSCAPE') - }) - }) - - describe('app context and activity: #switchToContext, #switchToWeb, #switchToNative', () => { - it('should switch context', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - await app.switchToContext('WEBVIEW_io.selendroid.testapp') - const val = await app.grabContext() - return assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - }) - - it('should switch to native and web contexts @quick', async () => { - await app.resetApp() - await app.tap('~buttonStartWebviewCD') - await app.see('WebView location') - await app.switchToWeb() - let val = await app.grabContext() - assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - await app.see('Prefered Car') - assert.ok(app.isWeb) - await app.switchToNative() - val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - return assert.ok(!app.isWeb) - }) - - it('should switch activity', async () => { - await app.startActivity('io.selendroid.testapp', '.RegisterUserActivity') - const val = await app.grabCurrentActivity() - assert.equal(val, '.RegisterUserActivity') - }) - }) - - describe('#setNetworkConnection, #setSettings', () => { - it('should set Network Connection (airplane mode on)', async () => { - await app.setNetworkConnection(1) - const val = await app.grabNetworkConnection() - return assert.equal(val.value, 1) - }) - - it('should set custom settings', async () => { - await app.setSettings({ cyberdelia: 'open' }) - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false, cyberdelia: 'open' }) - }) - }) - - describe('#hideDeviceKeyboard', () => { - it('should hide device Keyboard @quick', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - try { - await app.tap('//android.widget.CheckBox') - } catch (e) { - e.message.should.include('Request failed with status code 404') - } - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.tap('//android.widget.CheckBox') - }) - - it('should assert if no keyboard', async () => { - try { - await app.hideDeviceKeyboard('pressKey', 'Done') - } catch (e) { - e.message.should.include('An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard') - } - }) - }) - - describe('#sendDeviceKeyEvent', () => { - it('should react on pressing keycode', async () => { - await app.sendDeviceKeyEvent(3) - await app.waitForVisible('~Apps') - }) - }) - - describe('#openNotifications', () => { - it('should react on notification opening', async () => { - try { - await app.seeElement('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen') - } - await app.openNotifications() - await app.waitForVisible('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', 10) - }) - }) - - describe('#makeTouchAction', () => { - it('should react on touch actions', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - const val = await app.grabCurrentActivity() - assert.equal(val, '.WebViewActivity') - }) - - it('should react on swipe action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipe("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vx = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) - - it('should react on swipeDown action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) - - it('run simplified swipeDown @quick', async () => { - await app.resetApp() - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - assert.equal(type, 'FLICK') - }) - - it('should react on swipeUp action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeUp("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps') - }) - - it('should react on swipeRight action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeRight("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']") - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) - - it('should react on swipeLeft action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeLeft("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000) - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']") - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps') - }) - - it('should react on touchPerform action', async () => { - await app.touchPerform([ - { - action: 'press', - options: { - x: 100, - y: 200, - }, - }, - { action: 'release' }, - ]) - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) - - it('should assert when you dont scroll the document anymore', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - try { - await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 500) - } catch (e) { - e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found') - } - }) - - it('should react on swipeTo action', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - }) - - describe('#performTouchAction', () => { - it('should react on swipeUp action @second', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006) - }) - - it('should react on swipeDown action @second', async () => { - await app.resetApp() - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300) - }) - - it('should react on swipeLeft action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeLeft("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.below(730) - }) - - it('should react on swipeRight action', async () => { - await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") - await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - await app.swipeRight("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") - const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']") - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.above(278) - }) - }) - }) - - describe('#pullFile', () => { - it('should pull file to local machine', async () => { - const savepath = path.join(__dirname, `/../data/output/testpullfile${new Date().getTime()}.png`) - await app.pullFile('/storage/emulated/0/DCIM/sauce_logo.png', savepath) - assert.ok(fileExists(savepath), null, 'file does not exists') - }) - }) - - describe('see text : #see', () => { - it('should work inside elements @second', async () => { - await app.resetApp() - await app.see('EN Button', '~buttonTestCD') - await app.see('Hello') - await app.dontSee('Welcome', '~buttonTestCD') - }) - - it('should work inside web view as normally @quick', async () => { - await app.resetApp() - await app.tap('~buttonStartWebviewCD') - await app.switchToWeb() - await app.see('Prefered Car:') - }) - }) - - describe('#appendField', () => { - it('should be able to send special keys to element @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.tap('~email of the customer') - await app.appendField('~email of the customer', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.tap('//android.widget.Button') - await app.see('1', '#io.selendroid.testapp:id/label_email_data') - }) - }) - - describe('#seeInSource', () => { - it('should check for text to be in HTML source', async () => { - await app.seeInSource('class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"') - await app.dontSeeInSource(' { - it('should return error if not present', async () => { - try { - await app.waitForText('Nothing here', 1, '~buttonTestCD') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected element ~buttonTestCD to include "Nothing here"') - } - }) - }) - - describe('#seeNumberOfElements @second', () => { - it('should return 1 as count', async () => { - await app.resetApp() - await app.seeNumberOfElements('~buttonTestCD', 1) - }) - }) - - describe('see element : #seeElement, #dontSeeElement', () => { - it('should check visible elements on page @quick', async () => { - await app.resetApp() - await app.seeElement('//android.widget.Button[@content-desc = "buttonTestCD"]') - await app.dontSeeElement('#something-beyond') - await app.dontSeeElement('//input[@id="something-beyond"]') - }) - }) - - describe('#click @quick', () => { - it('should click by accessibility id', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) - - it('should click by xpath', async () => { - await app.resetApp() - await app.tap('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) - }) - - describe('#fillField, #appendField @second', () => { - it('should fill field by accessibility id', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.tap('//android.widget.Button') - await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') - }) - - it('should fill field by xpath', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.tap('//android.widget.Button') - await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') - }) - - it('should append field value @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.appendField('~email of the customer', 'blabla') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.tap('//android.widget.Button') - await app.see('Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') - }) - }) - - describe('#clearField', () => { - it('should clear a given element', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.see('Nothing special', '~email of the customer') - await app.clearField('~email of the customer') - await app.dontSee('Nothing special', '~email of the customer') - }) - }) - - describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { - it('should grab text from page', async () => { - await app.resetApp() - const val = await app.grabTextFrom('//android.widget.Button[@content-desc="buttonTestCD"]') - assert.equal(val, 'EN Button') - }) - - it('should grab attribute from element', async () => { - await app.resetApp() - const val = await app.grabAttributeFrom('//android.widget.Button[@content-desc="buttonTestCD"]', 'resourceId') - assert.equal(val, 'io.selendroid.testapp:id/buttonTest') - }) - - it('should be able to grab elements', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.tap('~email of the customer') - await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.tap('//android.widget.Button') - await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') - const id = await app.grabNumberOfVisibleElements('//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription') - assert.strictEqual(1, id) - }) - }) - - describe('#saveScreenshot @quick', () => { - beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) - - it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await app.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) - - describe('#runOnIOS, #runOnAndroid, #runInWeb', () => { - it('should use Android locators', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.tap({ android: '~startUserRegistrationCD', ios: 'fake-element' }) - await app.see('Welcome to register a new User') - }) - - it('should execute only on Android @quick', () => { - let platform = null - app.runOnIOS(() => { - platform = 'ios' - }) - app.runOnAndroid(() => { - platform = 'android' - }) - app.runOnAndroid({ platformVersion: '7.0' }, () => { - platform = 'android' - }) - - assert.equal('android', platform) - }) - - it('should execute only on Android >= 5.0 @quick', () => { - app.runOnAndroid( - caps => caps.platformVersion >= 5, - () => {}, - ) - }) - - it('should execute only in Web', () => { - app.isWeb = true - let executed = false - app.runOnIOS(() => { - executed = true - }) - assert.ok(!executed) - }) - }) -}) diff --git a/test/helper/AppiumWeb_test.js b/test/helper/AppiumWeb_test.js index 27fc51a9b..bdda9685a 100644 --- a/test/helper/AppiumWeb_test.js +++ b/test/helper/AppiumWeb_test.js @@ -14,7 +14,9 @@ describe('Appium Web', function () { browser: 'chrome', restart: false, desiredCapabilities: { - appiumVersion: '1.6.5', + 'sauce:options': { + appiumVersion: '2.0.0', + }, recordVideo: 'false', recordScreenshots: 'false', platformName: 'Android', diff --git a/test/helper/AppiumV2_ios_test.js b/test/helper/Appium_ios_test.js similarity index 99% rename from test/helper/AppiumV2_ios_test.js rename to test/helper/Appium_ios_test.js index 6bc8fb51d..68b64073f 100644 --- a/test/helper/AppiumV2_ios_test.js +++ b/test/helper/Appium_ios_test.js @@ -21,7 +21,6 @@ describe('Appium iOS Tests', function () { global.codecept_dir = path.join(__dirname, '/../data') app = new Appium({ app: apk_path, - appiumV2: true, desiredCapabilities: { 'sauce:options': { appiumVersion: '2.0.0', diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index 9aacb8074..5d7f47f6d 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -2,7 +2,6 @@ const chai = require('chai') const expect = chai.expect const assert = chai.assert - const path = require('path') const Appium = require('../../lib/helper/Appium') @@ -23,13 +22,15 @@ describe('Appium', function () { app = new Appium({ app: apk_path, desiredCapabilities: { - appiumVersion: '1.20.1', + 'sauce:options': { + appiumVersion: '2.0.0', + }, browserName: '', recordVideo: 'false', recordScreenshots: 'false', platformName: 'Android', - platformVersion: '6.0', - deviceName: 'Android Emulator', + platformVersion: '7.0', + deviceName: 'Android GoogleAPI Emulator', androidInstallTimeout: 90000, appWaitDuration: 300000, }, @@ -56,7 +57,7 @@ describe('Appium', function () { it('should grab all available contexts for screen', async () => { await app.resetApp() await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') + await app.tap('~buttonStartWebviewCD') const val = await app.grabAllContexts() assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']) }) @@ -162,7 +163,7 @@ describe('Appium', function () { it('should set device orientation', async () => { await app.resetApp() await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') + await app.tap('~buttonStartWebviewCD') await app.setOrientation('LANDSCAPE') await app.seeOrientationIs('LANDSCAPE') }) @@ -172,7 +173,7 @@ describe('Appium', function () { it('should switch context', async () => { await app.resetApp() await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') + await app.tap('~buttonStartWebviewCD') await app.switchToContext('WEBVIEW_io.selendroid.testapp') const val = await app.grabContext() return assert.equal(val, 'WEBVIEW_io.selendroid.testapp') @@ -180,7 +181,7 @@ describe('Appium', function () { it('should switch to native and web contexts @quick', async () => { await app.resetApp() - await app.click('~buttonStartWebviewCD') + await app.tap('~buttonStartWebviewCD') await app.see('WebView location') await app.switchToWeb() let val = await app.grabContext() @@ -217,14 +218,14 @@ describe('Appium', function () { describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { await app.resetApp() - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') try { - await app.click('//android.widget.CheckBox') + await app.tap('//android.widget.CheckBox') } catch (e) { - e.message.should.include('element') + e.message.should.include('Request failed with status code 404') } await app.hideDeviceKeyboard('pressKey', 'Done') - await app.click('//android.widget.CheckBox') + await app.tap('//android.widget.CheckBox') }) it('should assert if no keyboard', async () => { @@ -266,7 +267,7 @@ describe('Appium', function () { }) it('should react on swipe action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipe("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -278,7 +279,7 @@ describe('Appium', function () { }) it('should react on swipeDown action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -289,7 +290,7 @@ describe('Appium', function () { it('run simplified swipeDown @quick', async () => { await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -297,7 +298,7 @@ describe('Appium', function () { }) it('should react on swipeUp action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeUp("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -307,7 +308,7 @@ describe('Appium', function () { }) it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeRight("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -317,7 +318,7 @@ describe('Appium', function () { }) it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeLeft("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000) const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -344,7 +345,7 @@ describe('Appium', function () { it('should assert when you dont scroll the document anymore', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') try { await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 500) } catch (e) { @@ -355,13 +356,13 @@ describe('Appium', function () { it('should react on swipeTo action', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) }) describe('#performTouchAction', () => { it('should react on swipeUp action @second', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -372,7 +373,7 @@ describe('Appium', function () { it('should react on swipeDown action @second', async () => { await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -382,7 +383,7 @@ describe('Appium', function () { }) it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeLeft("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -392,7 +393,7 @@ describe('Appium', function () { }) it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.tap("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") await app.swipeRight("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") @@ -421,7 +422,7 @@ describe('Appium', function () { it('should work inside web view as normally @quick', async () => { await app.resetApp() - await app.click('~buttonStartWebviewCD') + await app.tap('~buttonStartWebviewCD') await app.switchToWeb() await app.see('Prefered Car:') }) @@ -431,12 +432,12 @@ describe('Appium', function () { it('should be able to send special keys to element @second', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.click('~email of the customer') + await app.tap('~startUserRegistrationCD') + await app.tap('~email of the customer') await app.appendField('~email of the customer', '1') await app.hideDeviceKeyboard('pressKey', 'Done') await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.click('//android.widget.Button') + await app.tap('//android.widget.Button') await app.see('1', '#io.selendroid.testapp:id/label_email_data') }) }) @@ -484,7 +485,7 @@ describe('Appium', function () { it('should click by xpath', async () => { await app.resetApp() - await app.click('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]') + await app.tap('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]') await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') }) }) @@ -493,34 +494,34 @@ describe('Appium', function () { it('should fill field by accessibility id', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') await app.fillField('~email of the customer', 'Nothing special') await app.hideDeviceKeyboard('pressKey', 'Done') await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.click('//android.widget.Button') + await app.tap('//android.widget.Button') await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') }) it('should fill field by xpath', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special') await app.hideDeviceKeyboard('pressKey', 'Done') await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.click('//android.widget.Button') + await app.tap('//android.widget.Button') await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') }) it('should append field value @second', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') await app.fillField('~email of the customer', 'Nothing special') await app.appendField('~email of the customer', 'blabla') await app.hideDeviceKeyboard('pressKey', 'Done') await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.click('//android.widget.Button') + await app.tap('//android.widget.Button') await app.see('Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') }) }) @@ -529,7 +530,7 @@ describe('Appium', function () { it('should clear a given element', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.tap('~startUserRegistrationCD') await app.fillField('~email of the customer', 'Nothing special') await app.see('Nothing special', '~email of the customer') await app.clearField('~email of the customer') @@ -557,7 +558,7 @@ describe('Appium', function () { await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1') await app.hideDeviceKeyboard('pressKey', 'Done') await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700) - await app.click('//android.widget.Button') + await app.tap('//android.widget.Button') await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') const id = await app.grabNumberOfVisibleElements('//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription') assert.strictEqual(1, id) @@ -580,7 +581,7 @@ describe('Appium', function () { it('should use Android locators', async () => { await app.resetApp() await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click({ android: '~startUserRegistrationCD', ios: 'fake-element' }) + await app.tap({ android: '~startUserRegistrationCD', ios: 'fake-element' }) await app.see('Welcome to register a new User') }) @@ -593,7 +594,7 @@ describe('Appium', function () { platform = 'android' }) app.runOnAndroid({ platformVersion: '7.0' }, () => { - platform = 'android7' + platform = 'android' }) assert.equal('android', platform)