diff --git a/.github/workflows/sdk-sample-test.yml b/.github/workflows/sdk-sample-test.yml new file mode 100644 index 0000000..3af18ca --- /dev/null +++ b/.github/workflows/sdk-sample-test.yml @@ -0,0 +1,75 @@ +# Runs the BrowserStack SDK sample against a given commit and reports a status check. +# Trigger: Actions tab -> "Pabot (Robot) Appium App Automate SDK sample test" -> Run workflow -> paste the PR's full commit SHA. +# Requires repo secrets: BROWSERSTACK_USERNAME, BROWSERSTACK_ACCESS_KEY. +# NOTE (App Automate): the app under test is referenced via `app: bs://...` in browserstack.yml; +# ensure that uploaded app exists on the account whose secrets are used (re-upload + update if expired). +name: Pabot (Robot) Appium App Automate SDK sample test + +on: + workflow_dispatch: + inputs: + commit_sha: + description: 'The full commit id to build' + required: true + +permissions: + contents: read # checkout + checks: write # github-script creates the status check + +jobs: + sdk-sample: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + max-parallel: 3 + matrix: + os: [ubuntu-latest] + python: ['3.10', '3.11'] + name: pabot-appium Python ${{ matrix.python }} sample + env: + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + defaults: + run: + working-directory: android + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.commit_sha }} + - name: Mark status check in_progress + uses: actions/github-script@v7 + env: + job_name: pabot-appium Python ${{ matrix.python }} sample + commit_sha: ${{ github.event.inputs.commit_sha }} + with: + github-token: ${{ github.token }} + script: | + await github.rest.checks.create({ + owner: context.repo.owner, repo: context.repo.repo, + name: process.env.job_name, head_sha: process.env.commit_sha, + status: 'in_progress' + }).catch(e => console.log('check create failed:', e.status)); + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Install + run: | + pip install -r requirements.txt + - name: Run sample test + run: | + browserstack-sdk pabot --processes 1 tests/wikipedia_sample.robot + - name: Mark status check completed + if: always() + uses: actions/github-script@v7 + env: + conclusion: ${{ job.status }} + job_name: pabot-appium Python ${{ matrix.python }} sample + commit_sha: ${{ github.event.inputs.commit_sha }} + with: + github-token: ${{ github.token }} + script: | + await github.rest.checks.create({ + owner: context.repo.owner, repo: context.repo.repo, + name: process.env.job_name, head_sha: process.env.commit_sha, + status: 'completed', conclusion: process.env.conclusion + }).catch(e => console.log('check create failed:', e.status)); diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d154a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.vscode +__pycache__ +.pytest_cache +.venv +env +output.xml +log.html +report.html +pabot_results +log/ +local.log diff --git a/README.md b/README.md index 836ed0e..0cbb0e1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,57 @@ -# pabot-appium-app-browserstack -We require the following new public repositories under the browserstack GitHub organization to host customer-facing sample projects for the BrowserStack SDK. +# Robot Framework (Pabot) + Appium with BrowserStack App Automate + +Run Appium mobile-app tests on real devices on [BrowserStack App Automate](https://app-automate.browserstack.com/) +using the BrowserStack SDK with Robot Framework, executed in parallel via **Pabot**. + +This repo is self-contained per platform: `android/` (and `ios/` for completeness) each carry their own +`browserstack.yml`, Robot suite, and dependency file. + +## Prerequisites + +- A [BrowserStack](https://www.browserstack.com/) account (App Automate). +- Python 3.8+. +- The sample apps are pre-uploaded to BrowserStack and referenced by `bs://` URL in `browserstack.yml`. + +## Setup + +```bash +git clone +cd pabot-appium-app-browserstack/android + +python3 -m venv .venv +source .venv/bin/activate # activate so the SDK CLI resolves from this venv +pip install -r requirements.txt +``` + +> Activate the virtualenv (`source .venv/bin/activate`) rather than calling +> `.venv/bin/browserstack-sdk` directly. Pabot spawns worker processes that re-invoke +> `browserstack-sdk` by name, so the venv's `bin/` must be first on `PATH`; otherwise a +> system-wide `browserstack-sdk` (e.g. a Ruby gem) can shadow it and the worker never starts a session. + +Configure credentials via environment variables (preferred) or by editing `userName`/`accessKey` in +`browserstack.yml`: + +```bash +export BROWSERSTACK_USERNAME="YOUR_USERNAME" +export BROWSERSTACK_ACCESS_KEY="YOUR_ACCESS_KEY" +``` + +## Run Sample Test + +From inside the `android/` directory (with the venv activated): + +```bash +browserstack-sdk pabot --processes 1 tests/ +``` + +The BrowserStack SDK reads `browserstack.yml`, injects the app + device capabilities into each Appium +session, runs the Robot suite on a real **Samsung Galaxy S22 Ultra**, and reports test context (name, +status) plus Test Observability data to BrowserStack. + +## Notes / Dashboard + +- Watch your runs live and replay sessions at . +- Test Observability is enabled (`testObservability: true`) — analytics appear at + . +- `--processes N` controls Pabot parallelism; this sample uses `1`. Increase it (and + `parallelsPerPlatform`) to fan out across more sessions. diff --git a/android/LocalSample.apk b/android/LocalSample.apk new file mode 100644 index 0000000..f31c574 Binary files /dev/null and b/android/LocalSample.apk differ diff --git a/android/WikipediaSample.apk b/android/WikipediaSample.apk new file mode 100644 index 0000000..03d19e6 Binary files /dev/null and b/android/WikipediaSample.apk differ diff --git a/android/browserstack.yml b/android/browserstack.yml new file mode 100644 index 0000000..840e172 --- /dev/null +++ b/android/browserstack.yml @@ -0,0 +1,48 @@ +# ============================= +# Set BrowserStack Credentials +# ============================= +# Add your BrowserStack userName and accessKey here or set BROWSERSTACK_USERNAME and +# BROWSERSTACK_ACCESS_KEY as env variables. +userName: YOUR_USERNAME +accessKey: YOUR_ACCESS_KEY + +# ====================== +# BrowserStack Reporting +# ====================== +projectName: BrowserStack Samples +buildName: appauto-pabot-appium +buildIdentifier: '#${BUILD_NUMBER}' +# `framework` lets the SDK send test context (name, status) to BrowserStack. +framework: robotframework + +# ========================================== +# Application under test (pre-uploaded APK) +# ========================================== +# WikipediaSample.apk — pre-uploaded to BrowserStack. The SDK uses this app for every session. +app: ./WikipediaSample.apk + +# ======================================= +# Platforms (Devices to test on) +# ======================================= +platforms: + - deviceName: Samsung Galaxy S22 Ultra + osVersion: "12.0" + platformName: android + +# ======================= +# Parallels per Platform +# ======================= +parallelsPerPlatform: 1 + +source: robotframework:appium-sample-sdk:v1.0 + +# ====================== +# Test Observability +# ====================== +testObservability: true + +# =================== +# Debugging features +# =================== +debug: true +networkLogs: true diff --git a/android/requirements.txt b/android/requirements.txt new file mode 100644 index 0000000..e872475 --- /dev/null +++ b/android/requirements.txt @@ -0,0 +1,8 @@ +Appium-Python-Client +selenium>=4.0.0 +robotframework +robotframework-appiumlibrary +robotframework-seleniumlibrary +robotframework-pabot +browserstack-local +browserstack-sdk @ https://sdk-assets.browserstack.com/python/browserstack_sdk-latest.tar.gz diff --git a/android/tests/wikipedia_sample.robot b/android/tests/wikipedia_sample.robot new file mode 100644 index 0000000..6b7d567 --- /dev/null +++ b/android/tests/wikipedia_sample.robot @@ -0,0 +1,28 @@ +*** Settings *** +Documentation WikipediaSample.apk sample test on BrowserStack App Automate. +... The BrowserStack SDK injects the app and device capabilities from +... browserstack.yml; the test only drives the app UI. +Library AppiumLibrary +Suite Teardown Close All Applications + +*** Variables *** +${REMOTE_URL} https://hub.browserstack.com/wd/hub + +*** Test Cases *** +Search Wikipedia For BrowserStack + [Documentation] Tap search, type "BrowserStack", assert result text views appear. + Open Application ${REMOTE_URL} platformName=android automationName=UiAutomator2 + Wait Until Page Contains Element accessibility_id=Search Wikipedia timeout=30 + Click Element accessibility_id=Search Wikipedia + Wait Until Page Contains Element id=org.wikipedia.alpha:id/search_src_text timeout=30 + Input Text id=org.wikipedia.alpha:id/search_src_text BrowserStack + Sleep 5s + ${results}= Get Webelements class=android.widget.TextView + Length Should Be Greater Than ${results} 0 + +*** Keywords *** +Length Should Be Greater Than + [Arguments] ${container} ${count} + ${length}= Get Length ${container} + Should Be True ${length} > ${count} + ... msg=Expected more than ${count} TextView elements, found ${length} diff --git a/ios/BStackSampleApp.ipa b/ios/BStackSampleApp.ipa new file mode 100644 index 0000000..c1891b8 Binary files /dev/null and b/ios/BStackSampleApp.ipa differ diff --git a/ios/LocalSample.ipa b/ios/LocalSample.ipa new file mode 100644 index 0000000..a937349 Binary files /dev/null and b/ios/LocalSample.ipa differ diff --git a/ios/browserstack.yml b/ios/browserstack.yml new file mode 100644 index 0000000..4afec86 --- /dev/null +++ b/ios/browserstack.yml @@ -0,0 +1,45 @@ +# ============================= +# Set BrowserStack Credentials +# ============================= +userName: YOUR_USERNAME +accessKey: YOUR_ACCESS_KEY + +# ====================== +# BrowserStack Reporting +# ====================== +projectName: BrowserStack Samples +buildName: appauto-pabot-appium +buildIdentifier: '#${BUILD_NUMBER}' +framework: robotframework + +# ========================================== +# Application under test +# ========================================== +# Public sample app committed in this repo (relative path); the SDK uploads it at run time. +app: ./BStackSampleApp.ipa + +# ======================================= +# Platforms (Devices to test on) +# ======================================= +platforms: + - deviceName: iPhone 14 Pro + osVersion: "16" + platformName: ios + +# ======================= +# Parallels per Platform +# ======================= +parallelsPerPlatform: 1 + +source: robotframework:appium-sample-sdk:v1.0 + +# ====================== +# Test Observability +# ====================== +testObservability: true + +# =================== +# Debugging features +# =================== +debug: true +networkLogs: true diff --git a/ios/requirements.txt b/ios/requirements.txt new file mode 100644 index 0000000..e872475 --- /dev/null +++ b/ios/requirements.txt @@ -0,0 +1,8 @@ +Appium-Python-Client +selenium>=4.0.0 +robotframework +robotframework-appiumlibrary +robotframework-seleniumlibrary +robotframework-pabot +browserstack-local +browserstack-sdk @ https://sdk-assets.browserstack.com/python/browserstack_sdk-latest.tar.gz diff --git a/ios/tests/bstack_sample.robot b/ios/tests/bstack_sample.robot new file mode 100644 index 0000000..feec0bb --- /dev/null +++ b/ios/tests/bstack_sample.robot @@ -0,0 +1,19 @@ +*** Settings *** +Documentation BStackSampleApp.ipa sample test on BrowserStack App Automate. +... The BrowserStack SDK injects the app and device capabilities from +... browserstack.yml; the test only drives the app UI. +Library AppiumLibrary +Suite Teardown Close All Applications + +*** Variables *** +${REMOTE_URL} https://hub.browserstack.com/wd/hub + +*** Test Cases *** +Submit Text And Assert Output + [Documentation] Tap Text Button, type an email, assert the output label echoes it. + Open Application ${REMOTE_URL} platformName=ios automationName=XCUITest + Wait Until Page Contains Element accessibility_id=Text Button timeout=30 + Click Element accessibility_id=Text Button + Input Text accessibility_id=Text Input hello@browserstack.com\n + ${output}= Get Text accessibility_id=Text Output + Should Be Equal ${output} hello@browserstack.com