├── .github └── workflows │ └── Semgrep.yml ├── .gitignore ├── .travis.yml ├── CODEOWNERS ├── README.md ├── android ├── examples │ ├── run-first-test │ │ ├── first.conf.js │ │ └── specs │ │ │ └── first_test.js │ ├── run-local-test │ │ ├── local.conf.js │ │ └── specs │ │ │ └── local_test.js │ ├── run-multiple-test │ │ ├── multiple.conf.js │ │ └── specs │ │ │ ├── multiple │ │ │ ├── test_01.js │ │ │ ├── test_02.js │ │ │ └── test_03.js │ │ │ └── multiple_test.js │ └── run-parallel-test │ │ ├── parallel.conf.js │ │ └── specs │ │ └── single_test.js └── package.json └── ios ├── examples ├── run-first-test │ ├── first.conf.js │ └── specs │ │ └── first_test.js ├── run-local-test │ ├── local.conf.js │ └── specs │ │ └── local_test.js ├── run-multiple-test │ ├── multiple.conf.js │ └── specs │ │ ├── multiple │ │ ├── test_01.js │ │ ├── test_02.js │ │ └── test_03.js │ │ └── multiple_test.js └── run-parallel-test │ ├── parallel.conf.js │ └── specs │ └── single_test.js └── package.json /.github/workflows/Semgrep.yml: -------------------------------------------------------------------------------- 1 | # Name of this GitHub Actions workflow. 2 | name: Semgrep 3 | 4 | on: 5 | # Scan changed files in PRs (diff-aware scanning): 6 | # The branches below must be a subset of the branches above 7 | pull_request: 8 | branches: ["master", "main"] 9 | push: 10 | branches: ["master", "main"] 11 | schedule: 12 | - cron: '0 6 * * *' 13 | 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | semgrep: 20 | # User definable name of this GitHub Actions job. 21 | permissions: 22 | contents: read # for actions/checkout to fetch code 23 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 24 | name: semgrep/ci 25 | # If you are self-hosting, change the following `runs-on` value: 26 | runs-on: ubuntu-latest 27 | 28 | container: 29 | # A Docker image with Semgrep installed. Do not change this. 30 | image: returntocorp/semgrep 31 | 32 | # Skip any PR created by dependabot to avoid permission issues: 33 | if: (github.actor != 'dependabot[bot]') 34 | 35 | steps: 36 | # Fetch project source with GitHub Actions Checkout. 37 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 38 | # Run the "semgrep ci" command on the command line of the docker image. 39 | - run: semgrep ci --sarif --output=semgrep.sarif 40 | env: 41 | # Add the rules that Semgrep uses by setting the SEMGREP_RULES environment variable. 42 | SEMGREP_RULES: p/default # more at semgrep.dev/explore 43 | 44 | - name: Upload SARIF file for GitHub Advanced Security Dashboard 45 | uses: github/codeql-action/upload-sarif@6c089f53dd51dc3fc7e599c3cb5356453a52ca9e # v2.20.0 46 | with: 47 | sarif_file: semgrep.sarif 48 | if: always() -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | local.log 3 | errorShots 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.3" 4 | - "4.0" 5 | - "0.12" 6 | - "0.10" 7 | 8 | before_install: 9 | - true && `base64 --decode <<< ZXhwb3J0IEJST1dTRVJTVEFDS19BQ0NFU1NfS0VZPUh5VmZydXJvb3dYb041eGhLZEs2Cg==` 10 | 11 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @browserstack/app-automate-public-repos 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webdriverio-appium-app-browserstack 2 | This repository demonstrates how to run Appium tests using [WebdriverIO](http://webdriver.io/) on BrowserStack App Automate. 3 | 4 |
5 |
6 | 7 |
8 | 9 | Code samples to get started with Appium tests for your Native App using WebdriverIO. 10 | 11 | ## Setup 12 | 13 | ### Requirements 14 | 15 | * Node.js 8.11.2+ 16 | - If you don't have Node installed, download it from [here](https://nodejs.org/en/) 17 | 18 | ### Install the dependencies 19 | 20 | For Android tests, run the following command in project's base directory : 21 | 22 | ```sh 23 | cd android 24 | npm i 25 | ``` 26 | 27 | Or, 28 | 29 | For dependencies for iOS tests, run following command in project's base directory : 30 | 31 | ```sh 32 | cd ios 33 | npm i 34 | ``` 35 | 36 | ## Getting Started 37 | 38 | Getting Started with Appium tests using WebdriverIO on BrowserStack couldn't be easier! 39 | 40 | ### Run first test: 41 | - Test script is available in `run-first-test` directory under [Android examples](./android) or [iOS examples](./ios) 42 | - 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) 43 | 44 | ### Speed up test execution with parallel testing : 45 | 46 | - Test script is available in `run-parallel-test` directory under [Android examples](./android) or [iOS examples](./ios) 47 | - 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) 48 | 49 | ### Use Local testing for apps that access resources hosted in development or testing environments : 50 | 51 | - Test script is available in `run-local-test` directory under [Android examples](./android) or [iOS examples](./ios) 52 | - 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) 53 | 54 | **Note**: For other test frameworks supported by App-Automate refer our [Developer documentation](https://www.browserstack.com/docs/) 55 | 56 | ## Getting Help 57 | 58 | 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). 59 | 60 | -------------------------------------------------------------------------------- /android/examples/run-first-test/first.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-first-test/specs/first_test.js' 8 | ], 9 | exclude: [], 10 | 11 | capabilities: [{ 12 | project: "First Webdriverio Android Project", 13 | build: 'Webdriverio Android', 14 | name: 'first_test', 15 | device: 'Google Pixel 3', 16 | os_version: "9.0", 17 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 18 | 'browserstack.debug': true 19 | }], 20 | 21 | logLevel: 'info', 22 | coloredLogs: true, 23 | screenshotPath: './errorShots/', 24 | baseUrl: '', 25 | waitforTimeout: 10000, 26 | connectionRetryTimeout: 90000, 27 | connectionRetryCount: 3, 28 | 29 | framework: 'mocha', 30 | mochaOpts: { 31 | ui: 'bdd', 32 | timeout: 20000 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /android/examples/run-first-test/specs/first_test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Search Wikipedia Functionality', () => { 4 | it('can find search results', async () => { 5 | var searchSelector = await $(`~Search Wikipedia`); 6 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 7 | await searchSelector.click(); 8 | 9 | var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); 10 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 11 | 12 | await insertTextSelector.addValue("Browsertack"); 13 | await browser.pause(5000); 14 | 15 | var allProductsName = await $$(`android.widget.TextView`); 16 | assert(allProductsName.length > 0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /android/examples/run-local-test/local.conf.js: -------------------------------------------------------------------------------- 1 | var browserstack = require('browserstack-local'); 2 | 3 | exports.config = { 4 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 5 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 6 | 7 | updateJob: false, 8 | specs: [ 9 | './examples/run-local-test/specs/local_test.js' 10 | ], 11 | exclude: [], 12 | 13 | capabilities: [{ 14 | project: "First Webdriverio Android Project", 15 | build: 'Webdriverio Android Local', 16 | name: 'local_test', 17 | device: 'Google Pixel 3', 18 | os_version: "9.0", 19 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 20 | 'browserstack.local': true, 21 | 'browserstack.debug': true 22 | }], 23 | 24 | logLevel: 'info', 25 | coloredLogs: true, 26 | screenshotPath: './errorShots/', 27 | baseUrl: '', 28 | waitforTimeout: 10000, 29 | connectionRetryTimeout: 90000, 30 | connectionRetryCount: 3, 31 | 32 | framework: 'mocha', 33 | mochaOpts: { 34 | ui: 'bdd', 35 | timeout: 20000 36 | }, 37 | 38 | // Code to start browserstack local before start of test 39 | onPrepare: (config, capabilities) => { 40 | console.log("Connecting local"); 41 | return new Promise( (resolve, reject) => { 42 | exports.bs_local = new browserstack.Local(); 43 | exports.bs_local.start({'key': exports.config.key }, (error) => { 44 | if (error) return reject(error); 45 | console.log('Connected. Now testing...'); 46 | 47 | resolve(); 48 | }); 49 | }); 50 | }, 51 | 52 | // Code to stop browserstack local after end of test 53 | onComplete: (capabilties, specs) => { 54 | console.log("Closing local tunnel"); 55 | return new Promise( (resolve, reject) => { 56 | exports.bs_local.stop( (error) => { 57 | if (error) return reject(error); 58 | console.log("Stopped BrowserStackLocal"); 59 | 60 | resolve(); 61 | }); 62 | }); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /android/examples/run-local-test/specs/local_test.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var assert = require('assert'); 3 | 4 | describe('BrowserStack Local Testing', () => { 5 | it('can check tunnel working', async () => { 6 | var searchSelector = await $('android=new UiSelector().resourceId("com.example.android.basicnetworking:id/test_action")'); 7 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 8 | await searchSelector.click(); 9 | 10 | var insertTextSelector = await $(`android.widget.TextView`); 11 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 12 | 13 | var testElement = null; 14 | 15 | try { 16 | var textElement = await $('android=new UiSelector().textContains("active connection is")'); 17 | await textElement.waitForDisplayed({ timeout: 30000 }); 18 | testElement = textElement; 19 | } 20 | catch { 21 | var screenshotPath = path.resolve(__dirname, 'screenshot.png'); 22 | await browser.saveScreenshot(screenshotPath); 23 | console.log('Screenshot stored at ' + screenshotPath); 24 | throw new Error('Cannot find the needed TextView element from app'); 25 | } 26 | 27 | var matchedString = await testElement.getText(); 28 | console.log(matchedString); 29 | assert(matchedString.indexOf('The active connection is wifi') !== -1); 30 | assert(matchedString.indexOf('Up and running') !== -1); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /android/examples/run-multiple-test/multiple.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-multiple-test/specs/multiple_test.js' 8 | ], 9 | exclude: [], 10 | 11 | capabilities: [{ 12 | project: "First Webdriverio Android Project", 13 | build: 'Webdriverio Android Multiple', 14 | name: 'multiple_test', 15 | device: 'Google Pixel 3', 16 | os_version: "9.0", 17 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 18 | 'browserstack.debug': true 19 | }], 20 | 21 | logLevel: 'info', 22 | coloredLogs: true, 23 | screenshotPath: './errorShots/', 24 | baseUrl: '', 25 | waitforTimeout: 10000, 26 | connectionRetryTimeout: 90000, 27 | connectionRetryCount: 3, 28 | 29 | framework: 'mocha', 30 | mochaOpts: { 31 | ui: 'bdd', 32 | timeout: 30000 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /android/examples/run-multiple-test/specs/multiple/test_01.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Search Wikipedia Functionality', () => { 4 | it('can find search results', async () => { 5 | var searchSelector = await $(`~Search Wikipedia`); 6 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 7 | await searchSelector.click(); 8 | 9 | var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); 10 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 11 | 12 | await insertTextSelector.addValue("Browsertack01"); 13 | await browser.pause(5000); 14 | 15 | var allProductsName = await $$(`android.widget.TextView`); 16 | assert(allProductsName.length > 0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /android/examples/run-multiple-test/specs/multiple/test_02.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Search Wikipedia Functionality', () => { 4 | it('can find search results', async () => { 5 | var searchSelector = await $(`~Search Wikipedia`); 6 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 7 | await searchSelector.click(); 8 | 9 | var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); 10 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 11 | 12 | await insertTextSelector.addValue("Browsertack02"); 13 | await browser.pause(5000); 14 | 15 | var allProductsName = await $$(`android.widget.TextView`); 16 | assert(allProductsName.length > 0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /android/examples/run-multiple-test/specs/multiple/test_03.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Search Wikipedia Functionality', () => { 4 | it('can find search results', async () => { 5 | var searchSelector = await $(`~Search Wikipedia`); 6 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 7 | await searchSelector.click(); 8 | 9 | var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); 10 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 11 | 12 | await insertTextSelector.addValue("Browsertack03"); 13 | await browser.pause(5000); 14 | 15 | var allProductsName = await $$(`android.widget.TextView`); 16 | assert(allProductsName.length > 0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /android/examples/run-multiple-test/specs/multiple_test.js: -------------------------------------------------------------------------------- 1 | var specs = [ 2 | './multiple/test_01.js', 3 | './multiple/test_02.js', 4 | './multiple/test_03.js' 5 | ]; 6 | 7 | for (var i = specs.length - 1; i >= 0; i--) { 8 | require(specs[i]); 9 | } 10 | -------------------------------------------------------------------------------- /android/examples/run-parallel-test/parallel.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-parallel-test/specs/single_test.js' 8 | ], 9 | exclude: [], 10 | 11 | maxInstances: 10, 12 | commonCapabilities: { 13 | project: "First Webdriverio Android Project", 14 | build: 'Webdriverio Android Parallel', 15 | name: 'parallel_test', 16 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 17 | 'browserstack.debug': true 18 | }, 19 | 20 | capabilities: [{ 21 | device: 'Google Pixel 3', 22 | os_version: "9.0" 23 | }, { 24 | device: 'Samsung Galaxy S10e', 25 | os_version: "9.0" 26 | }], 27 | 28 | logLevel: 'info', 29 | coloredLogs: true, 30 | screenshotPath: './errorShots/', 31 | baseUrl: '', 32 | waitforTimeout: 10000, 33 | connectionRetryTimeout: 90000, 34 | connectionRetryCount: 3, 35 | 36 | framework: 'mocha', 37 | mochaOpts: { 38 | ui: 'bdd', 39 | timeout: 20000 40 | } 41 | }; 42 | 43 | // Code to support common capabilities 44 | exports.config.capabilities.forEach(function(caps){ 45 | for(var i in exports.config.commonCapabilities) caps[i] = caps[i] || exports.config.commonCapabilities[i]; 46 | }); 47 | -------------------------------------------------------------------------------- /android/examples/run-parallel-test/specs/single_test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Search Wikipedia Functionality', () => { 4 | it('can find search results', async () => { 5 | var searchSelector = await $(`~Search Wikipedia`); 6 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 7 | await searchSelector.click(); 8 | 9 | var insertTextSelector = await $('android=new UiSelector().resourceId("org.wikipedia.alpha:id/search_src_text")'); 10 | await insertTextSelector.waitForDisplayed({ timeout: 30000 }); 11 | 12 | await insertTextSelector.addValue("Browsertack"); 13 | await browser.pause(5000); 14 | 15 | var allProductsName = await $$(`android.widget.TextView`); 16 | assert(allProductsName.length > 0); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /android/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webdriverio-appium-app-browserstack", 3 | "version": "0.1.0", 4 | "readme": "WendriverIO Integration with [BrowserStack](https://www.browserstack.com)", 5 | "description": "Selenium examples for WebdriverIO and BrowserStack App Automate", 6 | "scripts": { 7 | "test": "npm run first && npm run local && npm run parallel", 8 | "first": "./node_modules/.bin/wdio examples/run-first-test/first.conf.js", 9 | "parallel": "./node_modules/.bin/wdio examples/run-parallel-test/parallel.conf.js", 10 | "local": "./node_modules/.bin/wdio examples/run-local-test/local.conf.js", 11 | "multiple": "./node_modules/.bin/wdio examples/run-multiple-test/multiple.conf.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/browserstack/webdriverio-appium-app-browserstack.git" 16 | }, 17 | "keywords": [ 18 | "webdriverio", 19 | "browserstack", 20 | "appium", 21 | "tests" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/browserstack/webdriverio-appium-app-browserstack/issues" 25 | }, 26 | "homepage": "https://github.com/browserstack/webdriverio-appium-app-browserstack#readme", 27 | "dependencies": { 28 | "@wdio/cli": "^5.20.1", 29 | "@wdio/local-runner": "^5.20.1", 30 | "@wdio/mocha-framework": "^5.18.7", 31 | "browserstack-local": "^1.4.5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ios/examples/run-first-test/first.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-first-test/specs/first_test.js' 8 | ], 9 | exclude: [], 10 | 11 | capabilities: [{ 12 | project: "First Webdriverio iOS Project", 13 | build: 'Webdriverio iOS', 14 | name: 'single_test', 15 | device: 'iPhone 11 Pro', 16 | os_version: "13", 17 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 18 | 'browserstack.debug': true 19 | }], 20 | 21 | logLevel: 'info', 22 | coloredLogs: true, 23 | screenshotPath: './errorShots/', 24 | baseUrl: '', 25 | waitforTimeout: 10000, 26 | connectionRetryTimeout: 90000, 27 | connectionRetryCount: 3, 28 | 29 | framework: 'mocha', 30 | mochaOpts: { 31 | ui: 'bdd', 32 | timeout: 40000 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /ios/examples/run-first-test/specs/first_test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Text Verification', () => { 4 | it('should match displayed text with input text', async () => { 5 | var textButton = await $(`~Text Button`); 6 | await textButton.waitForDisplayed({ timeout: 30000 }); 7 | await textButton.click(); 8 | 9 | var textInput = await $(`~Text Input`); 10 | await textInput.waitForDisplayed({ timeout: 30000 }); 11 | await textInput.click() 12 | await textInput.addValue("hello@browserstack.com"+"\n"); 13 | 14 | var textOutput = await $(`~Text Output`); 15 | await textOutput.waitForDisplayed({ timeout: 30000 }); 16 | var value = await textOutput.getText(); 17 | 18 | if (value === "hello@browserstack.com") 19 | assert(true) 20 | else 21 | assert(false) 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /ios/examples/run-local-test/local.conf.js: -------------------------------------------------------------------------------- 1 | var browserstack = require('browserstack-local'); 2 | 3 | exports.config = { 4 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 5 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 6 | 7 | updateJob: false, 8 | specs: [ 9 | './examples/run-local-test/specs/local_test.js' 10 | ], 11 | exclude: [], 12 | 13 | capabilities: [{ 14 | project: "First Webdriverio iOS Project", 15 | build: 'Webdriverio iOS Local', 16 | name: 'local_test', 17 | device: 'iPhone 11 Pro', 18 | os_version: "13", 19 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 20 | 'browserstack.local': true, 21 | 'browserstack.debug': true 22 | }], 23 | 24 | logLevel: 'info', 25 | coloredLogs: true, 26 | screenshotPath: './errorShots/', 27 | baseUrl: '', 28 | waitforTimeout: 10000, 29 | connectionRetryTimeout: 90000, 30 | connectionRetryCount: 3, 31 | 32 | framework: 'mocha', 33 | mochaOpts: { 34 | ui: 'bdd', 35 | timeout: 30000 36 | }, 37 | 38 | // Code to start browserstack local before start of test 39 | onPrepare: (config, capabilities) => { 40 | console.log("Connecting local"); 41 | return new Promise( (resolve, reject) => { 42 | exports.bs_local = new browserstack.Local(); 43 | exports.bs_local.start({'key': exports.config.key }, (error) => { 44 | if (error) return reject(error); 45 | console.log('Connected. Now testing...'); 46 | 47 | resolve(); 48 | }); 49 | }); 50 | }, 51 | 52 | // Code to stop browserstack local after end of test 53 | onComplete: (capabilties, specs) => { 54 | console.log("Closing local tunnel"); 55 | return new Promise( (resolve, reject) => { 56 | exports.bs_local.stop( (error) => { 57 | if (error) return reject(error); 58 | console.log("Stopped BrowserStackLocal"); 59 | 60 | resolve(); 61 | }); 62 | }); 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /ios/examples/run-local-test/specs/local_test.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var assert = require('assert'); 3 | 4 | describe('BrowserStack Local Testing', () => { 5 | it('can check tunnel working', async () => { 6 | var searchSelector = await $(`~Test BrowserStackLocal connection`); 7 | await searchSelector.waitForDisplayed({ timeout: 30000 }); 8 | await searchSelector.click(); 9 | 10 | var textElements = await $(`~ResultBrowserStackLocal`); 11 | await textElements.waitForDisplayed({ timeout: 30000 }); 12 | 13 | var testElement = null; 14 | 15 | var textContent = await textElements.getText(); 16 | if (textContent.indexOf('Up and running') !== -1) { 17 | testElement = textElements; 18 | } 19 | 20 | if (testElement === null) { 21 | var screenshotPath = path.resolve(__dirname, 'screenshot.png'); 22 | await browser.saveScreenshot(screenshotPath); 23 | console.log('Screenshot stored at ' + screenshotPath); 24 | throw new Error('Cannot find the Up and running response'); 25 | } 26 | 27 | var matchedString = await testElement.getText(); 28 | assert(matchedString == 'Response is: Up and running'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /ios/examples/run-multiple-test/multiple.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-multiple-test/specs/multiple_test.js' 8 | ], 9 | exclude: [], 10 | 11 | capabilities: [{ 12 | project: "First Webdriverio iOS Project", 13 | build: 'Webdriverio iOS Multiple', 14 | name: 'multiple_test', 15 | device: 'iPhone 11 Pro', 16 | os_version: "13", 17 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 18 | 'browserstack.debug': true 19 | }], 20 | 21 | logLevel: 'info', 22 | coloredLogs: true, 23 | screenshotPath: './errorShots/', 24 | baseUrl: '', 25 | waitforTimeout: 10000, 26 | connectionRetryTimeout: 90000, 27 | connectionRetryCount: 3, 28 | 29 | framework: 'mocha', 30 | mochaOpts: { 31 | ui: 'bdd', 32 | timeout: 30000 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /ios/examples/run-multiple-test/specs/multiple/test_01.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Text Verification', () => { 4 | it('should match displayed text with input text', async () => { 5 | var textButton = await $(`~Text Button`); 6 | await textButton.waitForDisplayed({ timeout: 30000 }); 7 | await textButton.click(); 8 | 9 | var textInput = await $(`~Text Input`); 10 | await textInput.waitForDisplayed({ timeout: 30000 }); 11 | await textInput.click() 12 | await textInput.addValue("hello01@browserstack.com"+"\n"); 13 | 14 | var textOutput = await $(`~Text Output`); 15 | await textOutput.waitForDisplayed({ timeout: 30000 }); 16 | var value = await textOutput.getText(); 17 | 18 | if (value === "hello01@browserstack.com") 19 | assert(true) 20 | else 21 | assert(false) 22 | 23 | var back = await $('~UI Elements'); 24 | await back.click(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /ios/examples/run-multiple-test/specs/multiple/test_02.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Text Verification', () => { 4 | it('should match displayed text with input text', async () => { 5 | var textButton = await $(`~Text Button`); 6 | await textButton.waitForDisplayed({ timeout: 30000 }); 7 | await textButton.click(); 8 | 9 | var textInput = await $(`~Text Input`); 10 | await textInput.waitForDisplayed({ timeout: 30000 }); 11 | await textInput.click() 12 | await textInput.addValue("hello02@browserstack.com"+"\n"); 13 | 14 | var textOutput = await $(`~Text Output`); 15 | await textOutput.waitForDisplayed({ timeout: 30000 }); 16 | var value = await textOutput.getText(); 17 | 18 | if (value === "hello02@browserstack.com") 19 | assert(true) 20 | else 21 | assert(false) 22 | 23 | var back = await $('~UI Elements'); 24 | await back.click(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /ios/examples/run-multiple-test/specs/multiple/test_03.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Text Verification', () => { 4 | it('should match displayed text with input text', async () => { 5 | var textButton = await $(`~Text Button`); 6 | await textButton.waitForDisplayed({ timeout: 30000 }); 7 | await textButton.click(); 8 | 9 | var textInput = await $(`~Text Input`); 10 | await textInput.waitForDisplayed({ timeout: 30000 }); 11 | await textInput.click() 12 | await textInput.addValue("hello03@browserstack.com"+"\n"); 13 | 14 | var textOutput = await $(`~Text Output`); 15 | await textOutput.waitForDisplayed({ timeout: 30000 }); 16 | var value = await textOutput.getText(); 17 | 18 | if (value === "hello03@browserstack.com") 19 | assert(true) 20 | else 21 | assert(false) 22 | 23 | var back = await $('~UI Elements'); 24 | await back.click(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /ios/examples/run-multiple-test/specs/multiple_test.js: -------------------------------------------------------------------------------- 1 | var specs = [ 2 | './multiple/test_01.js', 3 | './multiple/test_02.js', 4 | './multiple/test_03.js' 5 | ]; 6 | 7 | for (var i = specs.length - 1; i >= 0; i--) { 8 | require(specs[i]); 9 | } 10 | -------------------------------------------------------------------------------- /ios/examples/run-parallel-test/parallel.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | user: process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME', 3 | key: process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY', 4 | 5 | updateJob: false, 6 | specs: [ 7 | './examples/run-parallel-test/specs/single_test.js' 8 | ], 9 | exclude: [], 10 | 11 | maxInstances: 10, 12 | commonCapabilities: { 13 | project: "First Webdriverio iOS Project", 14 | build: 'Webdriverio iOS Parallel', 15 | name: 'parallel_test', 16 | app: process.env.BROWSERSTACK_APP_ID || 'bs://', 17 | 'browserstack.debug': true 18 | }, 19 | 20 | capabilities: [{ 21 | device: "iPhone 11 Pro", 22 | os_version: "13" 23 | }, { 24 | device: "iPhone 11 Pro Max", 25 | os_version: "13" 26 | }], 27 | 28 | logLevel: 'info', 29 | coloredLogs: true, 30 | screenshotPath: './errorShots/', 31 | baseUrl: '', 32 | waitforTimeout: 10000, 33 | connectionRetryTimeout: 90000, 34 | connectionRetryCount: 3, 35 | 36 | framework: 'mocha', 37 | mochaOpts: { 38 | ui: 'bdd', 39 | timeout: 40000 40 | } 41 | }; 42 | 43 | // Code to support common capabilities 44 | exports.config.capabilities.forEach(function(caps){ 45 | for(var i in exports.config.commonCapabilities) caps[i] = caps[i] || exports.config.commonCapabilities[i]; 46 | }); 47 | -------------------------------------------------------------------------------- /ios/examples/run-parallel-test/specs/single_test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | describe('Text Verification', () => { 4 | it('should match displayed text with input text', async () => { 5 | var textButton = await $(`~Text Button`); 6 | await textButton.waitForDisplayed({ timeout: 30000 }); 7 | await textButton.click(); 8 | 9 | var textInput = await $(`~Text Input`); 10 | await textInput.waitForDisplayed({ timeout: 30000 }); 11 | await textInput.click() 12 | await textInput.addValue("hello@browserstack.com"+"\n"); 13 | 14 | var textOutput = await $(`~Text Output`); 15 | await textOutput.waitForDisplayed({ timeout: 30000 }); 16 | var value = await textOutput.getText(); 17 | 18 | if (value === "hello@browserstack.com") 19 | assert(true) 20 | else 21 | assert(false) 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /ios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webdriverio-appium-app-browserstack", 3 | "version": "0.1.0", 4 | "readme": "WendriverIO Integration with [BrowserStack](https://www.browserstack.com)", 5 | "description": "Selenium examples for WebdriverIO and BrowserStack App Automate", 6 | "scripts": { 7 | "test": "npm run first && npm run local && npm run parallel", 8 | "first": "./node_modules/.bin/wdio examples/run-first-test/first.conf.js", 9 | "parallel": "./node_modules/.bin/wdio examples/run-parallel-test/parallel.conf.js", 10 | "local": "./node_modules/.bin/wdio examples/run-local-test/local.conf.js", 11 | "multiple": "./node_modules/.bin/wdio examples/run-multiple-test/multiple.conf.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/browserstack/webdriverio-appium-app-browserstack.git" 16 | }, 17 | "keywords": [ 18 | "webdriverio", 19 | "browserstack", 20 | "appium", 21 | "tests" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/browserstack/webdriverio-appium-app-browserstack/issues" 25 | }, 26 | "homepage": "https://github.com/browserstack/webdriverio-appium-app-browserstack#readme", 27 | "dependencies": { 28 | "browserstack-local": "^1.4.5", 29 | "@wdio/cli": "^5.20.1", 30 | "@wdio/local-runner": "^5.20.1", 31 | "@wdio/mocha-framework": "^5.18.7" 32 | } 33 | } 34 | --------------------------------------------------------------------------------