From 8f530f6e6e97fd8e068efe0a0657776b87e53d77 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 9 Jan 2025 13:22:55 +0100 Subject: [PATCH 1/5] upload mobile builds to SL --- .github/workflows/appiumV2_Android.yml | 35 ++++++++++++------- .github/workflows/appiumV2_iOS.yml | 15 +++++--- test/data/mobile/TestApp-iphonesimulator.zip | Bin 0 -> 42453 bytes 3 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 test/data/mobile/TestApp-iphonesimulator.zip diff --git a/.github/workflows/appiumV2_Android.yml b/.github/workflows/appiumV2_Android.yml index 2b4a0f3eb..e472e3729 100644 --- a/.github/workflows/appiumV2_Android.yml +++ b/.github/workflows/appiumV2_Android.yml @@ -4,11 +4,14 @@ on: push: branches: - 3.x + - improve-appium-workflow env: CI: true # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} jobs: appium: @@ -20,17 +23,23 @@ jobs: test-suite: ['other', 'quick'] steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - run: npm i --force - env: - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - - run: "npm run test:appium-${{ matrix.test-suite }}" - env: # Or as an environment variable - SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} - SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - run: npm i --force + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true + + - name: Upload APK to Sauce Labs + run: | + curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \ + --location --request POST 'https://api.us-west-1.saucelabs.com/v1/storage/upload' \ + --form 'payload=@test/data/mobile/selendroid-test-app-0.17.0.apk' \ + --form 'name="selendroid-test-app-0.17.0.apk"' + + - run: 'npm run test:appium-${{ matrix.test-suite }}' diff --git a/.github/workflows/appiumV2_iOS.yml b/.github/workflows/appiumV2_iOS.yml index 64ae5e12a..03af5de54 100644 --- a/.github/workflows/appiumV2_iOS.yml +++ b/.github/workflows/appiumV2_iOS.yml @@ -4,11 +4,14 @@ on: push: branches: - 3.x + - improve-appium-workflow env: CI: true # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} jobs: appium: @@ -29,8 +32,12 @@ jobs: env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - - run: "npm run test:ios:appium-${{ matrix.test-suite }}" - env: # Or as an environment variable - SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} - SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + - name: Upload APK to Sauce Labs + run: | + curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \ + --location --request POST 'https://api.us-west-1.saucelabs.com/v1/storage/upload' \ + --form 'payload=@test/data/mobile/TestApp-iphonesimulator.zip' \ + --form 'name="TestApp-iphonesimulator.zip"' + + - run: 'npm run test:ios:appium-${{ matrix.test-suite }}' diff --git a/test/data/mobile/TestApp-iphonesimulator.zip b/test/data/mobile/TestApp-iphonesimulator.zip new file mode 100644 index 0000000000000000000000000000000000000000..a339486caffc817c570e9786bdfe78dc9e6a1c3f GIT binary patch literal 42453 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 literal 0 HcmV?d00001 From 185c759ea401243aec71a5e923feac1660e9d73a Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 9 Jan 2025 14:37:14 +0100 Subject: [PATCH 2/5] fix: appium UTs --- lib/helper/Appium.js | 43 ++++++++++++++--------- test/helper/AppiumV2_test.js | 68 ++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/lib/helper/Appium.js b/lib/helper/Appium.js index 627823a97..f13b87216 100644 --- a/lib/helper/Appium.js +++ b/lib/helper/Appium.js @@ -386,7 +386,7 @@ class Appium extends Webdriver { _buildAppiumEndpoint() { const { protocol, port, hostname, path } = this.browser.options // Build path to Appium REST API endpoint - return `${protocol}://${hostname}:${port}${path}` + return `${protocol}://${hostname}:${port}${path}/session/${this.browser.sessionId}` } /** @@ -602,7 +602,7 @@ class Appium extends Webdriver { return this.axios({ method: 'post', - url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/appium/device/remove_app`, + url: `${this._buildAppiumEndpoint()}/appium/device/remove_app`, data: { appId, bundleId }, }) } @@ -619,7 +619,7 @@ class Appium extends Webdriver { onlyForApps.call(this) return this.axios({ method: 'post', - url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/appium/app/reset`, + url: `${this._buildAppiumEndpoint()}/appium/app/reset`, }) } @@ -693,7 +693,7 @@ class Appium extends Webdriver { const res = await this.axios({ method: 'get', - url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/orientation`, + url: `${this._buildAppiumEndpoint()}/orientation`, }) const currentOrientation = res.data.value @@ -717,7 +717,7 @@ class Appium extends Webdriver { return this.axios({ method: 'post', - url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/orientation`, + url: `${this._buildAppiumEndpoint()}/orientation`, data: { orientation }, }) } @@ -956,21 +956,19 @@ class Appium extends Webdriver { * ```js * // taps outside to hide keyboard per default * I.hideDeviceKeyboard(); - * I.hideDeviceKeyboard('tapOutside'); - * - * // or by pressing key - * I.hideDeviceKeyboard('pressKey', 'Done'); * ``` * * Appium: support Android and iOS * - * @param {'tapOutside' | 'pressKey'} [strategy] Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’) - * @param {string} [key] Optional key */ - async hideDeviceKeyboard(strategy, key) { + async hideDeviceKeyboard() { onlyForApps.call(this) - strategy = strategy || 'tapOutside' - return this.browser.hideKeyboard(strategy, key) + + return this.axios({ + method: 'post', + url: `${this._buildAppiumEndpoint()}/appium/device/hide_keyboard`, + data: {}, + }) } /** @@ -1046,7 +1044,13 @@ class Appium extends Webdriver { * @param {*} locator */ async tap(locator) { - return this.makeTouchAction(locator, 'tap') + const { elementId } = await this.browser.$(parseLocator.call(this, locator)) + + return this.axios({ + method: 'post', + url: `${this._buildAppiumEndpoint()}/element/${elementId}/click`, + data: {}, + }) } /** @@ -1493,7 +1497,14 @@ class Appium extends Webdriver { */ async click(locator, context) { if (this.isWeb) return super.click(locator, context) - return super.click(parseLocator.call(this, locator), parseLocator.call(this, context)) + + const { elementId } = await this.browser.$(parseLocator.call(this, locator), parseLocator.call(this, context)) + + return this.axios({ + method: 'post', + url: `${this._buildAppiumEndpoint()}/element/${elementId}/click`, + data: {}, + }) } /** diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index 5bcc0157f..e19f94062 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -58,7 +58,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']) }) @@ -164,7 +164,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') }) @@ -174,7 +174,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') @@ -182,7 +182,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() @@ -219,14 +219,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 () => { @@ -268,7 +268,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']") @@ -280,7 +280,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']") @@ -291,7 +291,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']") @@ -299,7 +299,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']") @@ -309,7 +309,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']") @@ -319,7 +319,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']") @@ -346,7 +346,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) { @@ -357,13 +357,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']") @@ -374,7 +374,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']") @@ -384,7 +384,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']") @@ -394,7 +394,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']") @@ -423,7 +423,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:') }) @@ -433,12 +433,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') }) }) @@ -486,7 +486,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"]') }) }) @@ -495,34 +495,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"]') }) }) @@ -531,7 +531,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') @@ -559,7 +559,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) @@ -582,7 +582,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') }) From de5d1f42a0f846ec6daa1250883c838c10cfd102 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 9 Jan 2025 14:44:44 +0100 Subject: [PATCH 3/5] fix: appium types --- docs/helpers/Appium.md | 595 ++++++++++++------------ typings/tests/helpers/Appium.types.ts | 178 ++++--- typings/tests/helpers/AppiumTs.types.ts | 178 ++++--- 3 files changed, 465 insertions(+), 486 deletions(-) diff --git a/docs/helpers/Appium.md b/docs/helpers/Appium.md index 7b9fdab62..3cce1dae4 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`: 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. Example Android App: @@ -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,32 +555,23 @@ Hide the keyboard. ```js // taps outside to hide keyboard per default -I.hideDeviceKeyboard(); -I.hideDeviceKeyboard('tapOutside'); - -// or by pressing key -I.hideDeviceKeyboard('pressKey', 'Done'); +I.hideDeviceKeyboard() ``` Appium: support Android and iOS -#### Parameters - -* `strategy` **(`"tapOutside"` | `"pressKey"`)?** Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’) -* `key` **[string][5]?** Optional key - ### sendDeviceKeyEvent 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 @@ -583,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 @@ -597,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 @@ -612,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]\** @@ -628,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 @@ -648,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 @@ -680,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 @@ -699,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 @@ -718,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 @@ -738,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 @@ -763,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 @@ -810,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 @@ -827,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 @@ -844,8 +847,8 @@ See corresponding [webdriverio reference][16]. #### Parameters -* `id` -* `value` +- `id` +- `value` Returns **[Promise][6]\** Appium: support only iOS @@ -854,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 @@ -871,7 +874,7 @@ TODO: not tested Close the given application. ```js -I.closeApp(); +I.closeApp() ``` Returns **[Promise][6]\** Appium: support both Android and iOS @@ -882,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 @@ -902,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 @@ -925,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 @@ -950,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 @@ -966,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 @@ -981,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 @@ -998,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 @@ -1016,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 @@ -1038,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 @@ -1053,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 @@ -1070,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 @@ -1088,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 @@ -1105,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 @@ -1121,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 @@ -1137,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 @@ -1152,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]\** @@ -1166,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 @@ -1183,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 @@ -1200,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 @@ -1215,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 @@ -1234,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 @@ -1253,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 @@ -1280,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 @@ -1297,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 @@ -1313,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 @@ -1330,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/typings/tests/helpers/Appium.types.ts b/typings/tests/helpers/Appium.types.ts index 458519b16..de7581914 100644 --- a/typings/tests/helpers/Appium.types.ts +++ b/typings/tests/helpers/Appium.types.ts @@ -1,98 +1,94 @@ -import { expectError, expectType } from 'tsd'; +import { expectError, expectType } from 'tsd' // @ts-ignore -const appium = new CodeceptJS.Appium(); +const appium = new CodeceptJS.Appium() -const str = 'text'; -const num = 1; -const appPackage = 'com.example.android.apis'; +const str = 'text' +const num = 1 +const appPackage = 'com.example.android.apis' -expectError(appium.touchPerform()); -expectError(appium.touchPerform('press')); -expectType(appium.touchPerform([{ action: 'press' }])); -expectType(appium.touchPerform([{ action: 'press' }, { action: 'release' }])); -expectError(appium.touchPerform([{ action: 'press' }], [{ action: 'release' }])); +expectError(appium.touchPerform()) +expectError(appium.touchPerform('press')) +expectType(appium.touchPerform([{ action: 'press' }])) +expectType(appium.touchPerform([{ action: 'press' }, { action: 'release' }])) +expectError(appium.touchPerform([{ action: 'press' }], [{ action: 'release' }])) -expectType(appium.hideDeviceKeyboard()); -expectType(appium.hideDeviceKeyboard('tapOutside')); -expectType(appium.hideDeviceKeyboard('pressKey', 'Done')); -expectError(appium.hideDeviceKeyboard('pressKey', 'Done', 'Done')); +expectType(appium.hideDeviceKeyboard()) -expectError(appium.removeApp()); -expectType(appium.removeApp('appName')); -expectType(appium.removeApp('appName', appPackage)); -expectError(appium.removeApp('appName', appPackage, 'remove')); - -expectType(appium.runOnIOS(str, () => {})); -expectType(appium.runOnAndroid(str, () => {})); -expectType>(appium.seeAppIsInstalled(str)); -expectType>(appium.seeAppIsNotInstalled(str)); -expectType>(appium.installApp(str)); -expectType(appium.removeApp(str)); -expectType>(appium.seeCurrentActivityIs(str)); -expectType>(appium.seeDeviceIsLocked()); -expectType>(appium.seeDeviceIsUnlocked()); -expectType>(appium.seeOrientationIs('LANDSCAPE')); -expectType(appium.setOrientation('LANDSCAPE')); -expectType>(appium.grabAllContexts()); -expectType>(appium.grabContext()); -expectType>(appium.grabCurrentActivity()); -expectType>(appium.grabNetworkConnection()); -expectType>(appium.grabOrientation()); -expectType>(appium.grabSettings()); -expectType(appium.switchToContext(str)); -expectType>(appium.switchToWeb()); -expectType>(appium.switchToNative()); -expectType>(appium.switchToNative(str)); -expectError(appium.startActivity()); -expectError(appium.startActivity(appPackage)); -expectType>(appium.startActivity(appPackage, '.RegisterUserActivity')); -expectType>(appium.setNetworkConnection(num)); -expectError(appium.setNetworkConnection()); -expectType(appium.setSettings(str)); -expectType(appium.hideDeviceKeyboard()); -expectType>(appium.sendDeviceKeyEvent(num)); -expectType>(appium.openNotifications()); -expectType>(appium.makeTouchAction()); -expectType>(appium.tap(str)); -expectType(appium.performSwipe(str, str)); -expectType>(appium.swipeDown(str)); -expectType>(appium.swipeLeft(str)); -expectType>(appium.swipeRight(str)); -expectType>(appium.swipeUp(str)); -expectType>(appium.swipeTo(str, str, str, num, num, num)); -expectType(appium.touchPerform([])); -expectType>(appium.pullFile(str, str)); -expectType>(appium.shakeDevice()); -expectType>(appium.rotate()); -expectType>(appium.setImmediateValue()); -expectType>(appium.simulateTouchId()); -expectType>(appium.closeApp()); -expectType(appium.appendField(str, str)); -expectType(appium.checkOption(str)); -expectType(appium.click(str)); -expectType(appium.dontSeeCheckboxIsChecked(str)); -expectType(appium.dontSeeElement(str)); -expectType(appium.dontSeeInField(str, str)); -expectType(appium.dontSee(str)); -expectType(appium.fillField(str, str)); -expectType>(appium.grabTextFromAll(str)); -expectType>(appium.grabTextFrom(str)); -expectType>(appium.grabNumberOfVisibleElements(str)); -expectType>(appium.grabAttributeFrom(str, str)); -expectType>(appium.grabAttributeFromAll(str, str)); -expectType>(appium.grabValueFromAll(str)); -expectType>(appium.grabValueFrom(str)); -expectType>(appium.saveScreenshot(str)); -expectType(appium.scrollIntoView(str, {})); -expectType(appium.scrollIntoView(str, true)); -expectType(appium.seeCheckboxIsChecked(str)); -expectType(appium.seeElement(str)); -expectType(appium.seeInField(str, str)); -expectType(appium.see(str)); -expectType(appium.selectOption(str, str)); -expectType(appium.waitForElement(str)); -expectType(appium.waitForVisible(str)); -expectType(appium.waitForInvisible(str)); -expectType(appium.waitForText(str)); +expectError(appium.removeApp()) +expectType(appium.removeApp('appName')) +expectType(appium.removeApp('appName', appPackage)) +expectError(appium.removeApp('appName', appPackage, 'remove')) +expectType(appium.runOnIOS(str, () => {})) +expectType(appium.runOnAndroid(str, () => {})) +expectType>(appium.seeAppIsInstalled(str)) +expectType>(appium.seeAppIsNotInstalled(str)) +expectType>(appium.installApp(str)) +expectType(appium.removeApp(str)) +expectType>(appium.seeCurrentActivityIs(str)) +expectType>(appium.seeDeviceIsLocked()) +expectType>(appium.seeDeviceIsUnlocked()) +expectType>(appium.seeOrientationIs('LANDSCAPE')) +expectType(appium.setOrientation('LANDSCAPE')) +expectType>(appium.grabAllContexts()) +expectType>(appium.grabContext()) +expectType>(appium.grabCurrentActivity()) +expectType>(appium.grabNetworkConnection()) +expectType>(appium.grabOrientation()) +expectType>(appium.grabSettings()) +expectType(appium.switchToContext(str)) +expectType>(appium.switchToWeb()) +expectType>(appium.switchToNative()) +expectType>(appium.switchToNative(str)) +expectError(appium.startActivity()) +expectError(appium.startActivity(appPackage)) +expectType>(appium.startActivity(appPackage, '.RegisterUserActivity')) +expectType>(appium.setNetworkConnection(num)) +expectError(appium.setNetworkConnection()) +expectType(appium.setSettings(str)) +expectType(appium.hideDeviceKeyboard()) +expectType>(appium.sendDeviceKeyEvent(num)) +expectType>(appium.openNotifications()) +expectType>(appium.makeTouchAction()) +expectType>(appium.tap(str)) +expectType(appium.performSwipe(str, str)) +expectType>(appium.swipeDown(str)) +expectType>(appium.swipeLeft(str)) +expectType>(appium.swipeRight(str)) +expectType>(appium.swipeUp(str)) +expectType>(appium.swipeTo(str, str, str, num, num, num)) +expectType(appium.touchPerform([])) +expectType>(appium.pullFile(str, str)) +expectType>(appium.shakeDevice()) +expectType>(appium.rotate()) +expectType>(appium.setImmediateValue()) +expectType>(appium.simulateTouchId()) +expectType>(appium.closeApp()) +expectType(appium.appendField(str, str)) +expectType(appium.checkOption(str)) +expectType(appium.click(str)) +expectType(appium.dontSeeCheckboxIsChecked(str)) +expectType(appium.dontSeeElement(str)) +expectType(appium.dontSeeInField(str, str)) +expectType(appium.dontSee(str)) +expectType(appium.fillField(str, str)) +expectType>(appium.grabTextFromAll(str)) +expectType>(appium.grabTextFrom(str)) +expectType>(appium.grabNumberOfVisibleElements(str)) +expectType>(appium.grabAttributeFrom(str, str)) +expectType>(appium.grabAttributeFromAll(str, str)) +expectType>(appium.grabValueFromAll(str)) +expectType>(appium.grabValueFrom(str)) +expectType>(appium.saveScreenshot(str)) +expectType(appium.scrollIntoView(str, {})) +expectType(appium.scrollIntoView(str, true)) +expectType(appium.seeCheckboxIsChecked(str)) +expectType(appium.seeElement(str)) +expectType(appium.seeInField(str, str)) +expectType(appium.see(str)) +expectType(appium.selectOption(str, str)) +expectType(appium.waitForElement(str)) +expectType(appium.waitForVisible(str)) +expectType(appium.waitForInvisible(str)) +expectType(appium.waitForText(str)) diff --git a/typings/tests/helpers/AppiumTs.types.ts b/typings/tests/helpers/AppiumTs.types.ts index 458519b16..de7581914 100644 --- a/typings/tests/helpers/AppiumTs.types.ts +++ b/typings/tests/helpers/AppiumTs.types.ts @@ -1,98 +1,94 @@ -import { expectError, expectType } from 'tsd'; +import { expectError, expectType } from 'tsd' // @ts-ignore -const appium = new CodeceptJS.Appium(); +const appium = new CodeceptJS.Appium() -const str = 'text'; -const num = 1; -const appPackage = 'com.example.android.apis'; +const str = 'text' +const num = 1 +const appPackage = 'com.example.android.apis' -expectError(appium.touchPerform()); -expectError(appium.touchPerform('press')); -expectType(appium.touchPerform([{ action: 'press' }])); -expectType(appium.touchPerform([{ action: 'press' }, { action: 'release' }])); -expectError(appium.touchPerform([{ action: 'press' }], [{ action: 'release' }])); +expectError(appium.touchPerform()) +expectError(appium.touchPerform('press')) +expectType(appium.touchPerform([{ action: 'press' }])) +expectType(appium.touchPerform([{ action: 'press' }, { action: 'release' }])) +expectError(appium.touchPerform([{ action: 'press' }], [{ action: 'release' }])) -expectType(appium.hideDeviceKeyboard()); -expectType(appium.hideDeviceKeyboard('tapOutside')); -expectType(appium.hideDeviceKeyboard('pressKey', 'Done')); -expectError(appium.hideDeviceKeyboard('pressKey', 'Done', 'Done')); +expectType(appium.hideDeviceKeyboard()) -expectError(appium.removeApp()); -expectType(appium.removeApp('appName')); -expectType(appium.removeApp('appName', appPackage)); -expectError(appium.removeApp('appName', appPackage, 'remove')); - -expectType(appium.runOnIOS(str, () => {})); -expectType(appium.runOnAndroid(str, () => {})); -expectType>(appium.seeAppIsInstalled(str)); -expectType>(appium.seeAppIsNotInstalled(str)); -expectType>(appium.installApp(str)); -expectType(appium.removeApp(str)); -expectType>(appium.seeCurrentActivityIs(str)); -expectType>(appium.seeDeviceIsLocked()); -expectType>(appium.seeDeviceIsUnlocked()); -expectType>(appium.seeOrientationIs('LANDSCAPE')); -expectType(appium.setOrientation('LANDSCAPE')); -expectType>(appium.grabAllContexts()); -expectType>(appium.grabContext()); -expectType>(appium.grabCurrentActivity()); -expectType>(appium.grabNetworkConnection()); -expectType>(appium.grabOrientation()); -expectType>(appium.grabSettings()); -expectType(appium.switchToContext(str)); -expectType>(appium.switchToWeb()); -expectType>(appium.switchToNative()); -expectType>(appium.switchToNative(str)); -expectError(appium.startActivity()); -expectError(appium.startActivity(appPackage)); -expectType>(appium.startActivity(appPackage, '.RegisterUserActivity')); -expectType>(appium.setNetworkConnection(num)); -expectError(appium.setNetworkConnection()); -expectType(appium.setSettings(str)); -expectType(appium.hideDeviceKeyboard()); -expectType>(appium.sendDeviceKeyEvent(num)); -expectType>(appium.openNotifications()); -expectType>(appium.makeTouchAction()); -expectType>(appium.tap(str)); -expectType(appium.performSwipe(str, str)); -expectType>(appium.swipeDown(str)); -expectType>(appium.swipeLeft(str)); -expectType>(appium.swipeRight(str)); -expectType>(appium.swipeUp(str)); -expectType>(appium.swipeTo(str, str, str, num, num, num)); -expectType(appium.touchPerform([])); -expectType>(appium.pullFile(str, str)); -expectType>(appium.shakeDevice()); -expectType>(appium.rotate()); -expectType>(appium.setImmediateValue()); -expectType>(appium.simulateTouchId()); -expectType>(appium.closeApp()); -expectType(appium.appendField(str, str)); -expectType(appium.checkOption(str)); -expectType(appium.click(str)); -expectType(appium.dontSeeCheckboxIsChecked(str)); -expectType(appium.dontSeeElement(str)); -expectType(appium.dontSeeInField(str, str)); -expectType(appium.dontSee(str)); -expectType(appium.fillField(str, str)); -expectType>(appium.grabTextFromAll(str)); -expectType>(appium.grabTextFrom(str)); -expectType>(appium.grabNumberOfVisibleElements(str)); -expectType>(appium.grabAttributeFrom(str, str)); -expectType>(appium.grabAttributeFromAll(str, str)); -expectType>(appium.grabValueFromAll(str)); -expectType>(appium.grabValueFrom(str)); -expectType>(appium.saveScreenshot(str)); -expectType(appium.scrollIntoView(str, {})); -expectType(appium.scrollIntoView(str, true)); -expectType(appium.seeCheckboxIsChecked(str)); -expectType(appium.seeElement(str)); -expectType(appium.seeInField(str, str)); -expectType(appium.see(str)); -expectType(appium.selectOption(str, str)); -expectType(appium.waitForElement(str)); -expectType(appium.waitForVisible(str)); -expectType(appium.waitForInvisible(str)); -expectType(appium.waitForText(str)); +expectError(appium.removeApp()) +expectType(appium.removeApp('appName')) +expectType(appium.removeApp('appName', appPackage)) +expectError(appium.removeApp('appName', appPackage, 'remove')) +expectType(appium.runOnIOS(str, () => {})) +expectType(appium.runOnAndroid(str, () => {})) +expectType>(appium.seeAppIsInstalled(str)) +expectType>(appium.seeAppIsNotInstalled(str)) +expectType>(appium.installApp(str)) +expectType(appium.removeApp(str)) +expectType>(appium.seeCurrentActivityIs(str)) +expectType>(appium.seeDeviceIsLocked()) +expectType>(appium.seeDeviceIsUnlocked()) +expectType>(appium.seeOrientationIs('LANDSCAPE')) +expectType(appium.setOrientation('LANDSCAPE')) +expectType>(appium.grabAllContexts()) +expectType>(appium.grabContext()) +expectType>(appium.grabCurrentActivity()) +expectType>(appium.grabNetworkConnection()) +expectType>(appium.grabOrientation()) +expectType>(appium.grabSettings()) +expectType(appium.switchToContext(str)) +expectType>(appium.switchToWeb()) +expectType>(appium.switchToNative()) +expectType>(appium.switchToNative(str)) +expectError(appium.startActivity()) +expectError(appium.startActivity(appPackage)) +expectType>(appium.startActivity(appPackage, '.RegisterUserActivity')) +expectType>(appium.setNetworkConnection(num)) +expectError(appium.setNetworkConnection()) +expectType(appium.setSettings(str)) +expectType(appium.hideDeviceKeyboard()) +expectType>(appium.sendDeviceKeyEvent(num)) +expectType>(appium.openNotifications()) +expectType>(appium.makeTouchAction()) +expectType>(appium.tap(str)) +expectType(appium.performSwipe(str, str)) +expectType>(appium.swipeDown(str)) +expectType>(appium.swipeLeft(str)) +expectType>(appium.swipeRight(str)) +expectType>(appium.swipeUp(str)) +expectType>(appium.swipeTo(str, str, str, num, num, num)) +expectType(appium.touchPerform([])) +expectType>(appium.pullFile(str, str)) +expectType>(appium.shakeDevice()) +expectType>(appium.rotate()) +expectType>(appium.setImmediateValue()) +expectType>(appium.simulateTouchId()) +expectType>(appium.closeApp()) +expectType(appium.appendField(str, str)) +expectType(appium.checkOption(str)) +expectType(appium.click(str)) +expectType(appium.dontSeeCheckboxIsChecked(str)) +expectType(appium.dontSeeElement(str)) +expectType(appium.dontSeeInField(str, str)) +expectType(appium.dontSee(str)) +expectType(appium.fillField(str, str)) +expectType>(appium.grabTextFromAll(str)) +expectType>(appium.grabTextFrom(str)) +expectType>(appium.grabNumberOfVisibleElements(str)) +expectType>(appium.grabAttributeFrom(str, str)) +expectType>(appium.grabAttributeFromAll(str, str)) +expectType>(appium.grabValueFromAll(str)) +expectType>(appium.grabValueFrom(str)) +expectType>(appium.saveScreenshot(str)) +expectType(appium.scrollIntoView(str, {})) +expectType(appium.scrollIntoView(str, true)) +expectType(appium.seeCheckboxIsChecked(str)) +expectType(appium.seeElement(str)) +expectType(appium.seeInField(str, str)) +expectType(appium.see(str)) +expectType(appium.selectOption(str, str)) +expectType(appium.waitForElement(str)) +expectType(appium.waitForVisible(str)) +expectType(appium.waitForInvisible(str)) +expectType(appium.waitForText(str)) From bc4408757493ed2719a51980c03568208219bb56 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 9 Jan 2025 14:46:11 +0100 Subject: [PATCH 4/5] fix: appium types --- .github/workflows/appiumV2_Android.yml | 1 - .github/workflows/appiumV2_iOS.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/appiumV2_Android.yml b/.github/workflows/appiumV2_Android.yml index e472e3729..676416829 100644 --- a/.github/workflows/appiumV2_Android.yml +++ b/.github/workflows/appiumV2_Android.yml @@ -4,7 +4,6 @@ on: push: branches: - 3.x - - improve-appium-workflow env: CI: true diff --git a/.github/workflows/appiumV2_iOS.yml b/.github/workflows/appiumV2_iOS.yml index 03af5de54..621dfa5f7 100644 --- a/.github/workflows/appiumV2_iOS.yml +++ b/.github/workflows/appiumV2_iOS.yml @@ -4,7 +4,6 @@ on: push: branches: - 3.x - - improve-appium-workflow env: CI: true From 712e92c36f7f097226ec75c8f0c0149e60b894aa Mon Sep 17 00:00:00 2001 From: kobenguyent <7845001+kobenguyent@users.noreply.github.com> Date: Fri, 10 Jan 2025 06:29:55 +0100 Subject: [PATCH 5/5] Update appiumV2_Android.yml --- .github/workflows/appiumV2_Android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/appiumV2_Android.yml b/.github/workflows/appiumV2_Android.yml index 676416829..207b1049e 100644 --- a/.github/workflows/appiumV2_Android.yml +++ b/.github/workflows/appiumV2_Android.yml @@ -29,7 +29,7 @@ jobs: with: node-version: ${{ matrix.node-version }} - - run: npm i --force + - run: npm i env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true