Skip to content

Commit

Permalink
Merge pull request #344 from immutable/feature/dx-3421-android-browse…
Browse files Browse the repository at this point in the history
…rstack

[DX-3421] android UI test on CI (BrowserStack)
  • Loading branch information
andrew-yangy authored Nov 12, 2024
2 parents c2a7363 + 67e34f7 commit 882897c
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 2 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
- targetPlatform: StandaloneWindows64
buildMethod: WindowsBuilder.BuildForAltTester
buildPath: Windows64
- targetPlatform: Android
buildMethod: MobileBuilder.BuildForAltTester
buildPath: Android
steps:
- uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -65,6 +68,9 @@ jobs:
- targetPlatform: StandaloneWindows64
runs-on: [self-hosted, windows]
test_script: test_windows.ps1
- targetPlatform: Android
runs-on: [ self-hosted, macOS ]
test_script: browserstack-sdk pytest -s ./test/test_android.py
concurrency:
group: test-${{ matrix.targetPlatform }}
runs-on: ${{ matrix.runs-on }}
Expand All @@ -86,6 +92,8 @@ jobs:
UNITY_APP_PATH: SampleApp.app
UNITY_APP_NAME: SampleApp
MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
working-directory: sample/Tests
run: ./${{ matrix.test_script }}
run: ${{ matrix.test_script }}

79 changes: 79 additions & 0 deletions sample/Tests/browserstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# =============================
# Set BrowserStack Credentials
# =============================
# Add your BrowserStack userName and acccessKey here or set BROWSERSTACK_USERNAME and
# BROWSERSTACK_ACCESS_KEY as env variables
#userName: BROWSERSTACK_USERNAME
#accessKey: BROWSERSTACK_ACCESS_KEY

# ======================
# BrowserStack Reporting
# ======================
# The following capabilities are used to set up reporting on BrowserStack:
# Set 'projectName' to the name of your project. Example, Marketing Website
projectName: Unity Sample App
# Set `buildName` as the name of the job / testsuite being run
buildName: browserstack build
# `buildIdentifier` is a unique id to differentiate every execution that gets appended to
# buildName. Choose your buildIdentifier format from the available expressions:
# ${BUILD_NUMBER} (Default): Generates an incremental counter with every execution
# ${DATE_TIME}: Generates a Timestamp with every execution. Eg. 05-Nov-19:30
# Read more about buildIdentifiers here -> https://www.browserstack.com/docs/automate/selenium/organize-tests
buildIdentifier: '#${BUILD_NUMBER}' # Supports strings along with either/both ${expression}
framework: pytest
source: pytest-browserstack:sample-sdk:v1.0

# Set `app` to define the app that is to be used for testing.
# It can either take the id of any uploaded app or the path of the app directly.
#app: ./WikipediaSample.apk
app: ./SampleApp.apk #For running local tests

# =======================================
# Platforms (Browsers / Devices to test)
# =======================================
# Platforms object contains all the browser / device combinations you want to test on.
# Entire list available here -> (https://www.browserstack.com/list-of-browsers-and-platforms/automate)

platforms:
# - deviceName: Samsung Galaxy S22 Ultra
# osVersion: 12.0
# platformName: android
# - deviceName: Samsung Galaxy S21
# osVersion: 11.0
# platformName: android
- deviceName: Google Pixel 6 Pro
osVersion: 12.0
platformName: android

# =======================
# Parallels per Platform
# =======================
# The number of parallel threads to be used for each platform set.
# BrowserStack's SDK runner will select the best strategy based on the configured value
#
# Example 1 - If you have configured 3 platforms and set `parallelsPerPlatform` as 2, a total of 6 (2 * 3) parallel threads will be used on BrowserStack
#
# Example 2 - If you have configured 1 platform and set `parallelsPerPlatform` as 5, a total of 5 (1 * 5) parallel threads will be used on BrowserStack
parallelsPerPlatform: 1

# ==========================================
# BrowserStack Local
# (For localhost, staging/private websites)
# ==========================================
# Set browserStackLocal to true if your website under test is not accessible publicly over the internet
# Learn more about how BrowserStack Local works here -> https://www.browserstack.com/docs/automate/selenium/local-testing-introduction
browserstackLocal: true # <boolean> (Default false)
browserStackLocalOptions:
#Options to be passed to BrowserStack local in-case of advanced configurations
# localIdentifier: # <string> (Default: null) Needed if you need to run multiple instances of local.
forceLocal: true # <boolean> (Default: false) Set to true if you need to resolve all your traffic via BrowserStack Local tunnel.
# Entire list of arguments available here -> https://www.browserstack.com/docs/automate/selenium/manage-incoming-connections

# ===================
# Debugging features
# ===================
debug: false # <boolean> # Set to true if you need screenshots for every selenium command ran
networkLogs: false # <boolean> Set to true to enable HAR logs capturing
consoleLogs: errors # <string> Remote browser's console debug levels to be printed (Default: errors)
# Available options are `disable`, `errors`, `warnings`, `info`, `verbose` (Default: errors)
acceptInsecureCerts: true
4 changes: 3 additions & 1 deletion sample/Tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ protobuf==5.27.2
selenium==4.22.0
pytest==8.2.2
requests==2.32.3
mailslurp-client==15.19.22
mailslurp-client==15.19.22
Appium-Python-Client
browserstack-sdk
76 changes: 76 additions & 0 deletions sample/Tests/test/test_android.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import sys
import time
import unittest
from pathlib import Path

from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from alttester import AltDriver, AltReversePortForwarding, By

sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'src'))
from fetch_otp import EMAIL, fetch_code

# To run this test on an actual Android device: appium --base-path /wd/hub --allow-insecure chromedriver_autodownload
class TestBase(unittest.TestCase):
altdriver = None
appium_driver = None

@classmethod
def setUpClass(cls):
options = UiAutomator2Options()
options.auto_web_view = True
options.ensure_webviews_have_pages = True
options.native_web_screenshot = True
options.new_command_timeout = 3600

cls.appium_driver = webdriver.Remote('https://hub-cloud.browserstack.com/wd/hub/', options=options)

time.sleep(10)
cls.altdriver = AltDriver()

@classmethod
def tearDownClass(cls):
print("\nEnding")
cls.altdriver.stop()
cls.appium_driver.quit()

def test_1_pkce_login(self):
# Select use PKCE auth
self.altdriver.find_object(By.NAME, "PKCE").tap()

# Wait for unauthenticated screen
self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene")

# Login
loginBtn = self.altdriver.wait_for_object(By.NAME, "LoginBtn")
loginBtn.tap()

driver = self.appium_driver

# Wait for the Chrome Custom Tabs context to appear
WebDriverWait(driver, 30).until(lambda d: 'WEBVIEW_chrome' in d.contexts)
driver.switch_to.context("WEBVIEW_chrome")

email_field = driver.find_element(by=AppiumBy.XPATH, value="//input[@name=\"address\"]")
email_field.send_keys(EMAIL)
submit_button = driver.find_element(by=AppiumBy.XPATH, value="//form/div/div/div[2]/button")
submit_button.click()

time.sleep(10) # Wait for OTP

code = fetch_code()
if code:
print(f"Successfully fetched OTP: {code}")
else:
print("Failed to fetch OTP from email")

otp_field = driver.find_element(by=AppiumBy.XPATH, value="//div[@id=\"passwordless_container\"]/div[1]/input")
otp_field.send_keys(code)

# Wait for authenticated screen
self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene")

0 comments on commit 882897c

Please sign in to comment.