diff --git a/README.md b/README.md index 8e67ac1..ba30460 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,59 @@ # webdriverio-appium-app-browserstack -[WebdriverIO](http://webdriver.io/) Integration with BrowserStack. +This repository demonstrates how to run Appium tests using [WebdriverIO](http://webdriver.io/) on BrowserStack App Automate. -![BrowserStack Logo](https://d98b8t1nnulk5.cloudfront.net/production/images/layout/logo-header.png?1469004780) - - +
+
+ +
Code samples to get started with Appium tests for your Native App using WebdriverIO. -## Resources -* [Get Started guide](https://www.browserstack.com/app-automate/appium-webdriverio) +## Setup + +### Requirements + +* Node.js 8.11.2+ + - If you don't have Node installed, download it from [here](https://nodejs.org/en/) + +### Install the dependencies + +For Android tests, run the following command in project's base directory : + +```sh +cd android +npm i +``` + +Or, + +For dependencies for iOS tests, run following command in project's base directory : + +```sh +cd ios +npm i +``` + +## Getting Started + +Getting Started with Appium tests using WebdriverIO on BrowserStack couldn't be easier! + +### Run first test: + - Test script is available in `run-first-test` directory under [Android examples](./android) or [iOS examples](./ios) + - Follow the steps outlined in the documentation - [Get Started with your first test on App Automate](https://www.browserstack.com/docs/app-automate/appium/getting-started/nodejs/webdriverio) + +### Speed up test execution with parallel testing : + +- Test script is available in `run-parallel-test` directory under [Android examples](./android) or [iOS examples](./ios) +- Follow the steps outlined in the documentation - [Get Started with parallel testing on App Automate](https://www.browserstack.com/docs/app-automate/appium/getting-started/nodejs/webdriverio/parallelize-tests) + +### Use Local testing for apps that access resources hosted in development or testing environments : + +- Test script is available in `run-local-test` directory under [Android examples](./android) or [iOS examples](./ios) +- Follow the steps outlined in the documentation - [Get Started with Local testing on App Automate](https://www.browserstack.com/docs/app-automate/appium/getting-started/nodejs/webdriverio/local-testing) + +**Note**: For other test frameworks supported by App-Automate refer our [Developer documentation](https://www.browserstack.com/docs/) + +## Getting Help + +If you are running into any issues or have any queries, please check [Browserstack Support page](https://www.browserstack.com/support/app-automate) or [get in touch with us](https://www.browserstack.com/contact?ref=help). + diff --git a/android/README.md b/android/README.md deleted file mode 100644 index 18dae00..0000000 --- a/android/README.md +++ /dev/null @@ -1,32 +0,0 @@ -## Setup -* Clone the repo -* Install dependencies `npm install` -* Update `*.conf.js` files inside the `conf/` directory with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings) - -## Running your tests -- Upload your Native App (.apk file) to BrowserStack servers using upload API: - - ``` - curl -u "username:accesskey" -X POST "https://api.browserstack.com/app-automate/upload" -F "file=@/path/to/app/file/Application-debug.apk" - ``` - -- If you do not have an .apk file and looking to simply try App Automate, [you can download our sample app and upload](https://www.browserstack.com/app-automate/sample-apps/android/WikipediaSample.apk) -to the BrowserStack servers using the above API. -* For running local tests, you can use our [local sample app](https://www.browserstack.com/app-automate/sample-apps/android/LocalSample.apk). -- Update the desired capability "app" with the App URL returned from the above API call -- To run a single test, run `npm run single` -- To run parallel tests, run `npm run parallel` -- To run local tests, run `npm run local` - -## Notes -* You can view your test results on the [BrowserStack App Automate dashboard](https://www.browserstack.com/app-automate) -* Refer [Get Started](https://www.browserstack.com/app-automate/appium-webdriverio) document to configure the capabilities -* You can export the environment variables for the Username and Access Key of your BrowserStack account - - ``` - export BROWSERSTACK_USERNAME= && - export BROWSERSTACK_ACCESS_KEY= - ``` - -## Additional Resources -* [Getting Started with App Automate](https://www.browserstack.com/app-automate/appium-webdriverio) diff --git a/android/conf/single.conf.js b/android/examples/run-first-test/first.conf.js similarity index 62% rename from android/conf/single.conf.js rename to android/examples/run-first-test/first.conf.js index 38c8fcc..aa83cf6 100644 --- a/android/conf/single.conf.js +++ b/android/examples/run-first-test/first.conf.js @@ -1,23 +1,24 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/single_test.js' + './examples/run-first-test/specs/first_test.js' ], exclude: [], capabilities: [{ - name: 'single_appium_test', - build: 'webdriver-browserstack', - device: 'Samsung Galaxy S7', - browserName: 'android', + project: "First Webdriverio Android Project", + build: 'Webdriverio Android', + name: 'first_test', + device: 'Google Pixel 3', + os_version: "9.0", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/android/examples/run-first-test/specs/first_test.js b/android/examples/run-first-test/specs/first_test.js new file mode 100644 index 0000000..271e958 --- /dev/null +++ b/android/examples/run-first-test/specs/first_test.js @@ -0,0 +1,18 @@ +var assert = require('assert'); + +describe('Search Wikipedia Functionality', () => { + it('can find search results', async () => { + var searchSelector = await $(`~Search Wikipedia`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + await insertTextSelector.addValue("Browsertack"); + await browser.pause(5000); + + var allProductsName = await $$(`android.widget.TextView`); + assert(allProductsName.length > 0); + }); +}); diff --git a/android/conf/local.conf.js b/android/examples/run-local-test/local.conf.js similarity index 54% rename from android/conf/local.conf.js rename to android/examples/run-local-test/local.conf.js index c8b3209..966c7c9 100644 --- a/android/conf/local.conf.js +++ b/android/examples/run-local-test/local.conf.js @@ -2,25 +2,26 @@ var browserstack = require('browserstack-local'); exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/local_test.js' + './examples/run-local-test/specs/local_test.js' ], exclude: [], capabilities: [{ - name: 'local_appium_test', - build: 'webdriver-browserstack', - device: 'Google Pixel', - browserName: 'android', + project: "First Webdriverio Android Project", + build: 'Webdriverio Android Local', + name: 'local_test', + device: 'Google Pixel 3', + os_version: "9.0", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.local': true, 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', @@ -35,11 +36,11 @@ exports.config = { }, // Code to start browserstack local before start of test - onPrepare: function (config, capabilities) { + onPrepare: (config, capabilities) => { console.log("Connecting local"); - return new Promise(function(resolve, reject){ + return new Promise( (resolve, reject) => { exports.bs_local = new browserstack.Local(); - exports.bs_local.start({'key': exports.config.key }, function(error) { + exports.bs_local.start({'key': exports.config.key }, (error) => { if (error) return reject(error); console.log('Connected. Now testing...'); @@ -49,7 +50,15 @@ exports.config = { }, // Code to stop browserstack local after end of test - onComplete: function (capabilties, specs) { - exports.bs_local.stop(function() {}); + onComplete: (capabilties, specs) => { + console.log("Closing local tunnel"); + return new Promise( (resolve, reject) => { + exports.bs_local.stop( (error) => { + if (error) return reject(error); + console.log("Stopped BrowserStackLocal"); + + resolve(); + }); + }); } }; diff --git a/android/examples/run-local-test/specs/local_test.js b/android/examples/run-local-test/specs/local_test.js new file mode 100644 index 0000000..472a5e5 --- /dev/null +++ b/android/examples/run-local-test/specs/local_test.js @@ -0,0 +1,32 @@ +var path = require('path'); +var assert = require('assert'); + +describe('BrowserStack Local Testing', () => { + it('can check tunnel working', async () => { + var searchSelector = await $('android=new UiSelector().resourceId("com.example.android.basicnetworking:id/test_action")'); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $(`android.widget.TextView`); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + var testElement = null; + + try { + var textElement = await $('android=new UiSelector().textContains("active connection is")'); + await textElement.waitForDisplayed({ timeout: 30000 }); + testElement = textElement; + } + catch { + var screenshotPath = path.resolve(__dirname, 'screenshot.png'); + await browser.saveScreenshot(screenshotPath); + console.log('Screenshot stored at ' + screenshotPath); + throw new Error('Cannot find the needed TextView element from app'); + } + + var matchedString = await testElement.getText(); + console.log(matchedString); + assert(matchedString.indexOf('The active connection is wifi') !== -1); + assert(matchedString.indexOf('Up and running') !== -1); + }); +}); diff --git a/android/conf/multiple.conf.js b/android/examples/run-multiple-test/multiple.conf.js similarity index 60% rename from android/conf/multiple.conf.js rename to android/examples/run-multiple-test/multiple.conf.js index c332a4f..c377060 100644 --- a/android/conf/multiple.conf.js +++ b/android/examples/run-multiple-test/multiple.conf.js @@ -1,23 +1,24 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/multiple_test.js' + './examples/run-multiple-test/specs/multiple_test.js' ], exclude: [], capabilities: [{ - name: 'multiple_appium_test', - build: 'webdriver-browserstack', - device: 'Google Nexus 9', - browserName: 'android', + project: "First Webdriverio Android Project", + build: 'Webdriverio Android Multiple', + name: 'multiple_test', + device: 'Google Pixel 3', + os_version: "9.0", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/android/examples/run-multiple-test/specs/multiple/test_01.js b/android/examples/run-multiple-test/specs/multiple/test_01.js new file mode 100644 index 0000000..fc33c42 --- /dev/null +++ b/android/examples/run-multiple-test/specs/multiple/test_01.js @@ -0,0 +1,18 @@ +var assert = require('assert'); + +describe('Search Wikipedia Functionality', () => { + it('can find search results', async () => { + var searchSelector = await $(`~Search Wikipedia`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + await insertTextSelector.addValue("Browsertack01"); + await browser.pause(5000); + + var allProductsName = await $$(`android.widget.TextView`); + assert(allProductsName.length > 0); + }); +}); diff --git a/android/examples/run-multiple-test/specs/multiple/test_02.js b/android/examples/run-multiple-test/specs/multiple/test_02.js new file mode 100644 index 0000000..ac5f06a --- /dev/null +++ b/android/examples/run-multiple-test/specs/multiple/test_02.js @@ -0,0 +1,18 @@ +var assert = require('assert'); + +describe('Search Wikipedia Functionality', () => { + it('can find search results', async () => { + var searchSelector = await $(`~Search Wikipedia`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + await insertTextSelector.addValue("Browsertack02"); + await browser.pause(5000); + + var allProductsName = await $$(`android.widget.TextView`); + assert(allProductsName.length > 0); + }); +}); diff --git a/android/examples/run-multiple-test/specs/multiple/test_03.js b/android/examples/run-multiple-test/specs/multiple/test_03.js new file mode 100644 index 0000000..bbe3bdf --- /dev/null +++ b/android/examples/run-multiple-test/specs/multiple/test_03.js @@ -0,0 +1,18 @@ +var assert = require('assert'); + +describe('Search Wikipedia Functionality', () => { + it('can find search results', async () => { + var searchSelector = await $(`~Search Wikipedia`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + await insertTextSelector.addValue("Browsertack03"); + await browser.pause(5000); + + var allProductsName = await $$(`android.widget.TextView`); + assert(allProductsName.length > 0); + }); +}); diff --git a/android/tests/specs/multiple_test.js b/android/examples/run-multiple-test/specs/multiple_test.js similarity index 100% rename from android/tests/specs/multiple_test.js rename to android/examples/run-multiple-test/specs/multiple_test.js diff --git a/android/conf/parallel.conf.js b/android/examples/run-parallel-test/parallel.conf.js similarity index 66% rename from android/conf/parallel.conf.js rename to android/examples/run-parallel-test/parallel.conf.js index f637b47..930b16b 100644 --- a/android/conf/parallel.conf.js +++ b/android/examples/run-parallel-test/parallel.conf.js @@ -1,33 +1,31 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/single_test.js' + './examples/run-parallel-test/specs/single_test.js' ], exclude: [], maxInstances: 10, commonCapabilities: { - name: 'parallel_appium_test', - build: 'webdriver-browserstack', - browserName: 'android', + project: "First Webdriverio Android Project", + build: 'Webdriverio Android Parallel', + name: 'parallel_test', app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }, capabilities: [{ - device: 'Google Pixel' + device: 'Google Pixel 3', + os_version: "9.0" }, { - device: 'Samsung Galaxy S7' - }, { - device: 'Samsung Galaxy S6' - }, { - device: 'Google Nexus 9' + device: 'Samsung Galaxy S10e', + os_version: "9.0" }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/android/examples/run-parallel-test/specs/single_test.js b/android/examples/run-parallel-test/specs/single_test.js new file mode 100644 index 0000000..271e958 --- /dev/null +++ b/android/examples/run-parallel-test/specs/single_test.js @@ -0,0 +1,18 @@ +var assert = require('assert'); + +describe('Search Wikipedia Functionality', () => { + it('can find search results', async () => { + var searchSelector = await $(`~Search Wikipedia`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); + await insertTextSelector.waitForDisplayed({ timeout: 30000 }); + + await insertTextSelector.addValue("Browsertack"); + await browser.pause(5000); + + var allProductsName = await $$(`android.widget.TextView`); + assert(allProductsName.length > 0); + }); +}); diff --git a/android/package.json b/android/package.json index fa1193c..2cfca95 100644 --- a/android/package.json +++ b/android/package.json @@ -4,11 +4,11 @@ "readme": "WendriverIO Integration with [BrowserStack](https://www.browserstack.com)", "description": "Selenium examples for WebdriverIO and BrowserStack App Automate", "scripts": { - "test": "npm run single && npm run local && npm run parallel", - "single": "./node_modules/.bin/wdio conf/single.conf.js", - "parallel": "./node_modules/.bin/wdio conf/parallel.conf.js", - "local": "./node_modules/.bin/wdio conf/local.conf.js", - "multiple": "./node_modules/.bin/wdio conf/multiple.conf.js" + "test": "npm run first && npm run local && npm run parallel", + "first": "./node_modules/.bin/wdio examples/run-first-test/first.conf.js", + "parallel": "./node_modules/.bin/wdio examples/run-parallel-test/parallel.conf.js", + "local": "./node_modules/.bin/wdio examples/run-local-test/local.conf.js", + "multiple": "./node_modules/.bin/wdio examples/run-multiple-test/multiple.conf.js" }, "repository": { "type": "git", @@ -25,13 +25,9 @@ }, "homepage": "https://github.com/browserstack/webdriverio-appium-app-browserstack#readme", "dependencies": { - "browserstack-local": "^1.0.0", - "webdriverio": "^4.0.5" - }, - "devDependencies": { - "wdio-mocha-framework": "^0.2.11" - }, - "engines": { - "node": "^6" + "@wdio/cli": "^5.20.1", + "@wdio/local-runner": "^5.20.1", + "@wdio/mocha-framework": "^5.18.7", + "browserstack-local": "^1.4.5" } } diff --git a/android/tests/specs/local_test.js b/android/tests/specs/local_test.js deleted file mode 100644 index d43a9b2..0000000 --- a/android/tests/specs/local_test.js +++ /dev/null @@ -1,38 +0,0 @@ -var path = require('path'); -var assert = require('assert'); - -describe('BrowserStack Local Testing', function () { - it('can check tunnel working', function () { - var searchSelector = 'android=new UiSelector().resourceId("com.example.android.basicnetworking:id/test_action")'; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var insertTextSelector = `android.widget.TextView`; - browser.waitForVisible(insertTextSelector, 30000); - - var allTextElements = browser.elements(`android.widget.TextView`).value; - browser.pause(10000); - - var testElement = null; - allTextElements.forEach(function (textElement) { - var textContent = browser.elementIdText(textElement['ELEMENT']).value; - if (textContent.indexOf('The active connection is') !== -1) { - testElement = textElement; - } - }); - - if (testElement === null) { - var screenshotPath = path.resolve(__dirname, 'screenshot.png'); - browser.saveScreenshot(screenshotPath); - console.log('Screenshot stored at ' + screenshotPath); - throw new Error('Cannot find the needed TextView element from app'); - } - - var matchedString = browser.elementIdText(testElement['ELEMENT']).value; - console.log(matchedString); - assert(matchedString.indexOf('The active connection is wifi') !== -1); - assert(matchedString.indexOf('Up and running') !== -1); - }); -}); diff --git a/android/tests/specs/multiple/test_01.js b/android/tests/specs/multiple/test_01.js deleted file mode 100644 index 6fcdaad..0000000 --- a/android/tests/specs/multiple/test_01.js +++ /dev/null @@ -1,25 +0,0 @@ -var assert = require('assert'); - -describe('Search Wikipedia Functionality', function () { - it('can find search results', function () { - var searchSelector = `~Search Wikipedia`; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var insertTextSelector = 'android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'; - browser.waitForVisible(insertTextSelector); - browser - .element(insertTextSelector) - .keys('BrowserStack 01') - .pause(5000); - - var allProductsName = browser.elements(`android.widget.TextView`).value; - assert(allProductsName.length > 0); - browser - .hideDeviceKeyboard() - .back() - .pause(3000); - }); -}); diff --git a/android/tests/specs/multiple/test_02.js b/android/tests/specs/multiple/test_02.js deleted file mode 100644 index afa995f..0000000 --- a/android/tests/specs/multiple/test_02.js +++ /dev/null @@ -1,25 +0,0 @@ -var assert = require('assert'); - -describe('Search Wikipedia Functionality', function () { - it('can find search results', function () { - var searchSelector = `~Search Wikipedia`; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var insertTextSelector = 'android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'; - browser.waitForVisible(insertTextSelector); - browser - .element(insertTextSelector) - .keys('BrowserStack 02') - .pause(5000); - - var allProductsName = browser.elements(`android.widget.TextView`).value; - assert(allProductsName.length > 0); - browser - .hideDeviceKeyboard() - .back() - .pause(3000); - }); -}); diff --git a/android/tests/specs/multiple/test_03.js b/android/tests/specs/multiple/test_03.js deleted file mode 100644 index b9eb374..0000000 --- a/android/tests/specs/multiple/test_03.js +++ /dev/null @@ -1,25 +0,0 @@ -var assert = require('assert'); - -describe('Search Wikipedia Functionality', function () { - it('can find search results', function () { - var searchSelector = `~Search Wikipedia`; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var insertTextSelector = 'android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'; - browser.waitForVisible(insertTextSelector); - browser - .element(insertTextSelector) - .keys('BrowserStack 03') - .pause(5000); - - var allProductsName = browser.elements(`android.widget.TextView`).value; - assert(allProductsName.length > 0); - browser - .hideDeviceKeyboard() - .back() - .pause(3000); - }); -}); diff --git a/android/tests/specs/single_test.js b/android/tests/specs/single_test.js deleted file mode 100644 index 00aa5cd..0000000 --- a/android/tests/specs/single_test.js +++ /dev/null @@ -1,21 +0,0 @@ -var assert = require('assert'); - -describe('Search Wikipedia Functionality', function () { - it('can find search results', function () { - var searchSelector = `~Search Wikipedia`; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var insertTextSelector = 'android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'; - browser.waitForVisible(insertTextSelector); - browser - .element(insertTextSelector) - .keys('BrowserStack') - .pause(5000); - - var allProductsName = browser.elements(`android.widget.TextView`).value; - assert(allProductsName.length > 0); - }); -}); diff --git a/ios/README.md b/ios/README.md deleted file mode 100644 index 056273f..0000000 --- a/ios/README.md +++ /dev/null @@ -1,32 +0,0 @@ -## Setup -* Clone the repo -* Install dependencies `npm install` -* Update `*.conf.js` files inside the `conf/` directory with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings) - -## Running your tests -- Upload your Native App (.ipa file) to BrowserStack servers using upload API: - - ``` - curl -u "username:accesskey" -X POST "https://api.browserstack.com/app-automate/upload" -F "file=@/path/to/app/file/Application-debug.ipa" - ``` - -- If you do not have an .ipa file and looking to simply try App Automate, [you can download our sample app and upload](https://www.browserstack.com/app-automate/sample-apps/ios/BStackSampleApp.ipa) -to the BrowserStack servers using the above API. -- For running local tests, you can use our [local sample app](https://www.browserstack.com/app-automate/sample-apps/ios/LocalSample.ipa). -- Update the desired capability "app" with the App URL returned from the above API call -- To run a single test, run `npm run single` -- To run parallel tests, run `npm run parallel` -- To run local tests, run `npm run local` - -## Notes -* You can view your test results on the [BrowserStack App Automate dashboard](https://www.browserstack.com/app-automate) -* Refer [Get Started](https://www.browserstack.com/app-automate/appium-webdriverio) document to configure the capabilities -* You can export the environment variables for the Username and Access Key of your BrowserStack account - - ``` - export BROWSERSTACK_USERNAME= && - export BROWSERSTACK_ACCESS_KEY= - ``` - -## Additional Resources -* [Getting Started with App Automate](https://www.browserstack.com/app-automate/appium-webdriverio) diff --git a/ios/conf/single.conf.js b/ios/examples/run-first-test/first.conf.js similarity index 62% rename from ios/conf/single.conf.js rename to ios/examples/run-first-test/first.conf.js index 9487e3b..2462928 100644 --- a/ios/conf/single.conf.js +++ b/ios/examples/run-first-test/first.conf.js @@ -1,22 +1,24 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/single_test.js' + './examples/run-first-test/specs/first_test.js' ], exclude: [], capabilities: [{ - name: 'single_appium_test', - build: 'webdriver-browserstack', - device: 'iPhone 7', + project: "First Webdriverio iOS Project", + build: 'Webdriverio iOS', + name: 'single_test', + device: 'iPhone 11 Pro', + os_version: "13", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/ios/examples/run-first-test/specs/first_test.js b/ios/examples/run-first-test/specs/first_test.js new file mode 100644 index 0000000..ef4e4ac --- /dev/null +++ b/ios/examples/run-first-test/specs/first_test.js @@ -0,0 +1,23 @@ +var assert = require('assert'); + +describe('Text Verification', () => { + it('should match displayed text with input text', async () => { + var textButton = await $(`~Text Button`); + await textButton.waitForDisplayed({ timeout: 30000 }); + await textButton.click(); + + var textInput = await $(`~Text Input`); + await textInput.waitForDisplayed({ timeout: 30000 }); + await textInput.click() + await textInput.addValue("hello@browserstack.com"+"\n"); + + var textOutput = await $(`~Text Output`); + await textOutput.waitForDisplayed({ timeout: 30000 }); + var value = await textOutput.getText(); + + if (value === "hello@browserstack.com") + assert(true) + else + assert(false) + }); +}); diff --git a/ios/conf/local.conf.js b/ios/examples/run-local-test/local.conf.js similarity index 54% rename from ios/conf/local.conf.js rename to ios/examples/run-local-test/local.conf.js index eca40fd..8fd8bd3 100644 --- a/ios/conf/local.conf.js +++ b/ios/examples/run-local-test/local.conf.js @@ -2,24 +2,26 @@ var browserstack = require('browserstack-local'); exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/local_test.js' + './examples/run-local-test/specs/local_test.js' ], exclude: [], capabilities: [{ - name: 'local_appium_test', - build: 'webdriver-browserstack', - device: 'iPhone 7', + project: "First Webdriverio iOS Project", + build: 'Webdriverio iOS Local', + name: 'local_test', + device: 'iPhone 11 Pro', + os_version: "13", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.local': true, 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', @@ -34,11 +36,11 @@ exports.config = { }, // Code to start browserstack local before start of test - onPrepare: function (config, capabilities) { + onPrepare: (config, capabilities) => { console.log("Connecting local"); - return new Promise(function(resolve, reject){ + return new Promise( (resolve, reject) => { exports.bs_local = new browserstack.Local(); - exports.bs_local.start({'key': exports.config.key }, function(error) { + exports.bs_local.start({'key': exports.config.key }, (error) => { if (error) return reject(error); console.log('Connected. Now testing...'); @@ -48,7 +50,15 @@ exports.config = { }, // Code to stop browserstack local after end of test - onComplete: function (capabilties, specs) { - exports.bs_local.stop(function() {}); + onComplete: (capabilties, specs) => { + console.log("Closing local tunnel"); + return new Promise( (resolve, reject) => { + exports.bs_local.stop( (error) => { + if (error) return reject(error); + console.log("Stopped BrowserStackLocal"); + + resolve(); + }); + }); } }; diff --git a/ios/examples/run-local-test/specs/local_test.js b/ios/examples/run-local-test/specs/local_test.js new file mode 100644 index 0000000..94fdf1f --- /dev/null +++ b/ios/examples/run-local-test/specs/local_test.js @@ -0,0 +1,30 @@ +var path = require('path'); +var assert = require('assert'); + +describe('BrowserStack Local Testing', () => { + it('can check tunnel working', async () => { + var searchSelector = await $(`~Test BrowserStackLocal connection`); + await searchSelector.waitForDisplayed({ timeout: 30000 }); + await searchSelector.click(); + + var textElements = await $(`~ResultBrowserStackLocal`); + await textElements.waitForDisplayed({ timeout: 30000 }); + + var testElement = null; + + var textContent = await textElements.getText(); + if (textContent.indexOf('Up and running') !== -1) { + testElement = textElements; + } + + if (testElement === null) { + var screenshotPath = path.resolve(__dirname, 'screenshot.png'); + await browser.saveScreenshot(screenshotPath); + console.log('Screenshot stored at ' + screenshotPath); + throw new Error('Cannot find the Up and running response'); + } + + var matchedString = await testElement.getText(); + assert(matchedString == 'Response is: Up and running'); + }); +}); diff --git a/ios/conf/multiple.conf.js b/ios/examples/run-multiple-test/multiple.conf.js similarity index 61% rename from ios/conf/multiple.conf.js rename to ios/examples/run-multiple-test/multiple.conf.js index 7cba139..b67b1eb 100644 --- a/ios/conf/multiple.conf.js +++ b/ios/examples/run-multiple-test/multiple.conf.js @@ -1,22 +1,24 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/multiple_test.js' + './examples/run-multiple-test/specs/multiple_test.js' ], exclude: [], capabilities: [{ - name: 'multiple_appium_test', - build: 'webdriver-browserstack', - device: 'iPhone 7', + project: "First Webdriverio iOS Project", + build: 'Webdriverio iOS Multiple', + name: 'multiple_test', + device: 'iPhone 11 Pro', + os_version: "13", app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/ios/examples/run-multiple-test/specs/multiple/test_01.js b/ios/examples/run-multiple-test/specs/multiple/test_01.js new file mode 100644 index 0000000..fe0a1b9 --- /dev/null +++ b/ios/examples/run-multiple-test/specs/multiple/test_01.js @@ -0,0 +1,26 @@ +var assert = require('assert'); + +describe('Text Verification', () => { + it('should match displayed text with input text', async () => { + var textButton = await $(`~Text Button`); + await textButton.waitForDisplayed({ timeout: 30000 }); + await textButton.click(); + + var textInput = await $(`~Text Input`); + await textInput.waitForDisplayed({ timeout: 30000 }); + await textInput.click() + await textInput.addValue("hello01@browserstack.com"+"\n"); + + var textOutput = await $(`~Text Output`); + await textOutput.waitForDisplayed({ timeout: 30000 }); + var value = await textOutput.getText(); + + if (value === "hello01@browserstack.com") + assert(true) + else + assert(false) + + var back = await $('~UI Elements'); + await back.click(); + }); +}); diff --git a/ios/examples/run-multiple-test/specs/multiple/test_02.js b/ios/examples/run-multiple-test/specs/multiple/test_02.js new file mode 100644 index 0000000..8b1d9dc --- /dev/null +++ b/ios/examples/run-multiple-test/specs/multiple/test_02.js @@ -0,0 +1,26 @@ +var assert = require('assert'); + +describe('Text Verification', () => { + it('should match displayed text with input text', async () => { + var textButton = await $(`~Text Button`); + await textButton.waitForDisplayed({ timeout: 30000 }); + await textButton.click(); + + var textInput = await $(`~Text Input`); + await textInput.waitForDisplayed({ timeout: 30000 }); + await textInput.click() + await textInput.addValue("hello02@browserstack.com"+"\n"); + + var textOutput = await $(`~Text Output`); + await textOutput.waitForDisplayed({ timeout: 30000 }); + var value = await textOutput.getText(); + + if (value === "hello02@browserstack.com") + assert(true) + else + assert(false) + + var back = await $('~UI Elements'); + await back.click(); + }); +}); diff --git a/ios/examples/run-multiple-test/specs/multiple/test_03.js b/ios/examples/run-multiple-test/specs/multiple/test_03.js new file mode 100644 index 0000000..e9862ab --- /dev/null +++ b/ios/examples/run-multiple-test/specs/multiple/test_03.js @@ -0,0 +1,26 @@ +var assert = require('assert'); + +describe('Text Verification', () => { + it('should match displayed text with input text', async () => { + var textButton = await $(`~Text Button`); + await textButton.waitForDisplayed({ timeout: 30000 }); + await textButton.click(); + + var textInput = await $(`~Text Input`); + await textInput.waitForDisplayed({ timeout: 30000 }); + await textInput.click() + await textInput.addValue("hello03@browserstack.com"+"\n"); + + var textOutput = await $(`~Text Output`); + await textOutput.waitForDisplayed({ timeout: 30000 }); + var value = await textOutput.getText(); + + if (value === "hello03@browserstack.com") + assert(true) + else + assert(false) + + var back = await $('~UI Elements'); + await back.click(); + }); +}); diff --git a/ios/tests/specs/multiple_test.js b/ios/examples/run-multiple-test/specs/multiple_test.js similarity index 100% rename from ios/tests/specs/multiple_test.js rename to ios/examples/run-multiple-test/specs/multiple_test.js diff --git a/ios/conf/parallel.conf.js b/ios/examples/run-parallel-test/parallel.conf.js similarity index 67% rename from ios/conf/parallel.conf.js rename to ios/examples/run-parallel-test/parallel.conf.js index 545b447..8012251 100644 --- a/ios/conf/parallel.conf.js +++ b/ios/examples/run-parallel-test/parallel.conf.js @@ -1,28 +1,31 @@ exports.config = { user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', - key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACC_KEY', + key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', updateJob: false, specs: [ - './tests/specs/single_test.js' + './examples/run-parallel-test/specs/single_test.js' ], exclude: [], maxInstances: 10, commonCapabilities: { - name: 'parallel_appium_test', - build: 'webdriver-browserstack', + project: "First Webdriverio iOS Project", + build: 'Webdriverio iOS Parallel', + name: 'parallel_test', app: process.env.BROWSERSTACK_APP_ID || 'bs://', 'browserstack.debug': true }, capabilities: [{ - "device": "iPhone 7" + device: "iPhone 11 Pro", + os_version: "13" }, { - "device": "iPhone 7 Plus" + device: "iPhone 11 Pro Max", + os_version: "13" }], - logLevel: 'verbose', + logLevel: 'info', coloredLogs: true, screenshotPath: './errorShots/', baseUrl: '', diff --git a/ios/examples/run-parallel-test/specs/single_test.js b/ios/examples/run-parallel-test/specs/single_test.js new file mode 100644 index 0000000..ef4e4ac --- /dev/null +++ b/ios/examples/run-parallel-test/specs/single_test.js @@ -0,0 +1,23 @@ +var assert = require('assert'); + +describe('Text Verification', () => { + it('should match displayed text with input text', async () => { + var textButton = await $(`~Text Button`); + await textButton.waitForDisplayed({ timeout: 30000 }); + await textButton.click(); + + var textInput = await $(`~Text Input`); + await textInput.waitForDisplayed({ timeout: 30000 }); + await textInput.click() + await textInput.addValue("hello@browserstack.com"+"\n"); + + var textOutput = await $(`~Text Output`); + await textOutput.waitForDisplayed({ timeout: 30000 }); + var value = await textOutput.getText(); + + if (value === "hello@browserstack.com") + assert(true) + else + assert(false) + }); +}); diff --git a/ios/package.json b/ios/package.json index 4478f17..9b5953d 100644 --- a/ios/package.json +++ b/ios/package.json @@ -4,11 +4,11 @@ "readme": "WendriverIO Integration with [BrowserStack](https://www.browserstack.com)", "description": "Selenium examples for WebdriverIO and BrowserStack App Automate", "scripts": { - "test": "npm run single && npm run local && npm run parallel", - "single": "./node_modules/.bin/wdio conf/single.conf.js", - "parallel": "./node_modules/.bin/wdio conf/parallel.conf.js", - "local": "./node_modules/.bin/wdio conf/local.conf.js", - "multiple": "./node_modules/.bin/wdio conf/multiple.conf.js" + "test": "npm run first && npm run local && npm run parallel", + "first": "./node_modules/.bin/wdio examples/run-first-test/first.conf.js", + "parallel": "./node_modules/.bin/wdio examples/run-parallel-test/parallel.conf.js", + "local": "./node_modules/.bin/wdio examples/run-local-test/local.conf.js", + "multiple": "./node_modules/.bin/wdio examples/run-multiple-test/multiple.conf.js" }, "repository": { "type": "git", @@ -25,10 +25,9 @@ }, "homepage": "https://github.com/browserstack/webdriverio-appium-app-browserstack#readme", "dependencies": { - "browserstack-local": "^1.0.0", - "webdriverio": "^4.0.5" - }, - "devDependencies": { - "wdio-mocha-framework": "^0.2.11" + "browserstack-local": "^1.4.5", + "@wdio/cli": "^5.20.1", + "@wdio/local-runner": "^5.20.1", + "@wdio/mocha-framework": "^5.18.7" } } diff --git a/ios/tests/specs/local_test.js b/ios/tests/specs/local_test.js deleted file mode 100644 index 818003a..0000000 --- a/ios/tests/specs/local_test.js +++ /dev/null @@ -1,34 +0,0 @@ -var path = require('path'); -var assert = require('assert'); - -describe('BrowserStack Local Testing', function () { - it('can check tunnel working', function () { - var searchSelector = `~Test BrowserStackLocal connection`; - browser.waitForVisible(searchSelector, 30000); - browser - .element(searchSelector) - .click(); - - var responseText = `~Response is: Up and running`; - browser.waitForVisible(responseText, 30000); - var allTextElements = browser.elements(responseText).value; - - var testElement = null; - allTextElements.forEach(function (textElement) { - var textContent = browser.elementIdText(textElement['ELEMENT']).value; - if (textContent.indexOf('Up and running') !== -1) { - testElement = textElement; - } - }); - - if (testElement === null) { - var screenshotPath = path.resolve(__dirname, 'screenshot.png'); - browser.saveScreenshot(screenshotPath); - console.log('Screenshot stored at ' + screenshotPath); - throw new Error('Cannot find the Up and running response'); - } - - var matchedString = browser.elementIdText(testElement['ELEMENT']).value; - assert(matchedString == 'Response is: Up and running'); - }); -}); diff --git a/ios/tests/specs/multiple/test_01.js b/ios/tests/specs/multiple/test_01.js deleted file mode 100644 index 5d08446..0000000 --- a/ios/tests/specs/multiple/test_01.js +++ /dev/null @@ -1,28 +0,0 @@ -var assert = require('assert'); - -describe('Text Verification', function () { - it('should match displayed text with input text', function () { - var textButton = `~Text Button`; - browser.waitForVisible(textButton, 30000); - browser - .element(textButton) - .click(); - - var textInput = `~Text Input`; - browser.waitForVisible(textInput, 30000); - browser - .element(textInput) - .click() - .keys("hello01@browserstack.com"+"\n"); - - var textOutput = `~Text Output`; - browser.waitForVisible(textOutput, 30000); - var value = browser.getText(textOutput) - - if (value === "hello01@browserstack.com") - assert(true) - else - assert(false) - - }); -}); diff --git a/ios/tests/specs/multiple/test_02.js b/ios/tests/specs/multiple/test_02.js deleted file mode 100644 index 7b2bebe..0000000 --- a/ios/tests/specs/multiple/test_02.js +++ /dev/null @@ -1,28 +0,0 @@ -var assert = require('assert'); - -describe('Text Verification', function () { - it('should match displayed text with input text', function () { - var textButton = `~Text Button`; - browser.waitForVisible(textButton, 30000); - browser - .element(textButton) - .click(); - - var textInput = `~Text Input`; - browser.waitForVisible(textInput, 30000); - browser - .element(textInput) - .click() - .keys("hello02@browserstack.com"+"\n"); - - var textOutput = `~Text Output`; - browser.waitForVisible(textOutput, 30000); - var value = browser.getText(textOutput) - - if (value === "hello02@browserstack.com") - assert(true) - else - assert(false) - - }); -}); diff --git a/ios/tests/specs/multiple/test_03.js b/ios/tests/specs/multiple/test_03.js deleted file mode 100644 index 219ca3e..0000000 --- a/ios/tests/specs/multiple/test_03.js +++ /dev/null @@ -1,28 +0,0 @@ -var assert = require('assert'); - -describe('Text Verification', function () { - it('should match displayed text with input text', function () { - var textButton = `~Text Button`; - browser.waitForVisible(textButton, 30000); - browser - .element(textButton) - .click(); - - var textInput = `~Text Input`; - browser.waitForVisible(textInput, 30000); - browser - .element(textInput) - .click() - .keys("hello03@browserstack.com"+"\n"); - - var textOutput = `~Text Output`; - browser.waitForVisible(textOutput, 30000); - var value = browser.getText(textOutput) - - if (value === "hello03@browserstack.com") - assert(true) - else - assert(false) - - }); -}); diff --git a/ios/tests/specs/single_test.js b/ios/tests/specs/single_test.js deleted file mode 100644 index ec5db9a..0000000 --- a/ios/tests/specs/single_test.js +++ /dev/null @@ -1,28 +0,0 @@ -var assert = require('assert'); - -describe('Text Verification', function () { - it('should match displayed text with input text', function () { - var textButton = `~Text Button`; - browser.waitForVisible(textButton, 30000); - browser - .element(textButton) - .click(); - - var textInput = `~Text Input`; - browser.waitForVisible(textInput, 30000); - browser - .element(textInput) - .click() - .keys("hello@browserstack.com"+"\n"); - - var textOutput = `~Text Output`; - browser.waitForVisible(textOutput, 30000); - var value = browser.getText(textOutput) - - if (value === "hello@browserstack.com") - assert(true) - else - assert(false) - - }); -});