Skip to content

Commit 882897c

Browse files
authored
Merge pull request #344 from immutable/feature/dx-3421-android-browserstack
[DX-3421] android UI test on CI (BrowserStack)
2 parents c2a7363 + 67e34f7 commit 882897c

File tree

4 files changed

+167
-2
lines changed

4 files changed

+167
-2
lines changed

.github/workflows/ui-tests.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424
- targetPlatform: StandaloneWindows64
2525
buildMethod: WindowsBuilder.BuildForAltTester
2626
buildPath: Windows64
27+
- targetPlatform: Android
28+
buildMethod: MobileBuilder.BuildForAltTester
29+
buildPath: Android
2730
steps:
2831
- uses: actions/checkout@v3
2932
with:
@@ -65,6 +68,9 @@ jobs:
6568
- targetPlatform: StandaloneWindows64
6669
runs-on: [self-hosted, windows]
6770
test_script: test_windows.ps1
71+
- targetPlatform: Android
72+
runs-on: [ self-hosted, macOS ]
73+
test_script: browserstack-sdk pytest -s ./test/test_android.py
6874
concurrency:
6975
group: test-${{ matrix.targetPlatform }}
7076
runs-on: ${{ matrix.runs-on }}
@@ -86,6 +92,8 @@ jobs:
8692
UNITY_APP_PATH: SampleApp.app
8793
UNITY_APP_NAME: SampleApp
8894
MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
95+
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
96+
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
8997
working-directory: sample/Tests
90-
run: ./${{ matrix.test_script }}
98+
run: ${{ matrix.test_script }}
9199

sample/Tests/browserstack.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# =============================
2+
# Set BrowserStack Credentials
3+
# =============================
4+
# Add your BrowserStack userName and acccessKey here or set BROWSERSTACK_USERNAME and
5+
# BROWSERSTACK_ACCESS_KEY as env variables
6+
#userName: BROWSERSTACK_USERNAME
7+
#accessKey: BROWSERSTACK_ACCESS_KEY
8+
9+
# ======================
10+
# BrowserStack Reporting
11+
# ======================
12+
# The following capabilities are used to set up reporting on BrowserStack:
13+
# Set 'projectName' to the name of your project. Example, Marketing Website
14+
projectName: Unity Sample App
15+
# Set `buildName` as the name of the job / testsuite being run
16+
buildName: browserstack build
17+
# `buildIdentifier` is a unique id to differentiate every execution that gets appended to
18+
# buildName. Choose your buildIdentifier format from the available expressions:
19+
# ${BUILD_NUMBER} (Default): Generates an incremental counter with every execution
20+
# ${DATE_TIME}: Generates a Timestamp with every execution. Eg. 05-Nov-19:30
21+
# Read more about buildIdentifiers here -> https://www.browserstack.com/docs/automate/selenium/organize-tests
22+
buildIdentifier: '#${BUILD_NUMBER}' # Supports strings along with either/both ${expression}
23+
framework: pytest
24+
source: pytest-browserstack:sample-sdk:v1.0
25+
26+
# Set `app` to define the app that is to be used for testing.
27+
# It can either take the id of any uploaded app or the path of the app directly.
28+
#app: ./WikipediaSample.apk
29+
app: ./SampleApp.apk #For running local tests
30+
31+
# =======================================
32+
# Platforms (Browsers / Devices to test)
33+
# =======================================
34+
# Platforms object contains all the browser / device combinations you want to test on.
35+
# Entire list available here -> (https://www.browserstack.com/list-of-browsers-and-platforms/automate)
36+
37+
platforms:
38+
# - deviceName: Samsung Galaxy S22 Ultra
39+
# osVersion: 12.0
40+
# platformName: android
41+
# - deviceName: Samsung Galaxy S21
42+
# osVersion: 11.0
43+
# platformName: android
44+
- deviceName: Google Pixel 6 Pro
45+
osVersion: 12.0
46+
platformName: android
47+
48+
# =======================
49+
# Parallels per Platform
50+
# =======================
51+
# The number of parallel threads to be used for each platform set.
52+
# BrowserStack's SDK runner will select the best strategy based on the configured value
53+
#
54+
# 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
55+
#
56+
# 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
57+
parallelsPerPlatform: 1
58+
59+
# ==========================================
60+
# BrowserStack Local
61+
# (For localhost, staging/private websites)
62+
# ==========================================
63+
# Set browserStackLocal to true if your website under test is not accessible publicly over the internet
64+
# Learn more about how BrowserStack Local works here -> https://www.browserstack.com/docs/automate/selenium/local-testing-introduction
65+
browserstackLocal: true # <boolean> (Default false)
66+
browserStackLocalOptions:
67+
#Options to be passed to BrowserStack local in-case of advanced configurations
68+
# localIdentifier: # <string> (Default: null) Needed if you need to run multiple instances of local.
69+
forceLocal: true # <boolean> (Default: false) Set to true if you need to resolve all your traffic via BrowserStack Local tunnel.
70+
# Entire list of arguments available here -> https://www.browserstack.com/docs/automate/selenium/manage-incoming-connections
71+
72+
# ===================
73+
# Debugging features
74+
# ===================
75+
debug: false # <boolean> # Set to true if you need screenshots for every selenium command ran
76+
networkLogs: false # <boolean> Set to true to enable HAR logs capturing
77+
consoleLogs: errors # <string> Remote browser's console debug levels to be printed (Default: errors)
78+
# Available options are `disable`, `errors`, `warnings`, `info`, `verbose` (Default: errors)
79+
acceptInsecureCerts: true

sample/Tests/requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ protobuf==5.27.2
55
selenium==4.22.0
66
pytest==8.2.2
77
requests==2.32.3
8-
mailslurp-client==15.19.22
8+
mailslurp-client==15.19.22
9+
Appium-Python-Client
10+
browserstack-sdk

sample/Tests/test/test_android.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import sys
2+
import time
3+
import unittest
4+
from pathlib import Path
5+
6+
from appium import webdriver
7+
from appium.options.android import UiAutomator2Options
8+
from appium.webdriver.common.appiumby import AppiumBy
9+
from appium.webdriver.webdriver import WebDriver
10+
from selenium.webdriver.support.ui import WebDriverWait
11+
from selenium.webdriver.support import expected_conditions as EC
12+
13+
from alttester import AltDriver, AltReversePortForwarding, By
14+
15+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'src'))
16+
from fetch_otp import EMAIL, fetch_code
17+
18+
# To run this test on an actual Android device: appium --base-path /wd/hub --allow-insecure chromedriver_autodownload
19+
class TestBase(unittest.TestCase):
20+
altdriver = None
21+
appium_driver = None
22+
23+
@classmethod
24+
def setUpClass(cls):
25+
options = UiAutomator2Options()
26+
options.auto_web_view = True
27+
options.ensure_webviews_have_pages = True
28+
options.native_web_screenshot = True
29+
options.new_command_timeout = 3600
30+
31+
cls.appium_driver = webdriver.Remote('https://hub-cloud.browserstack.com/wd/hub/', options=options)
32+
33+
time.sleep(10)
34+
cls.altdriver = AltDriver()
35+
36+
@classmethod
37+
def tearDownClass(cls):
38+
print("\nEnding")
39+
cls.altdriver.stop()
40+
cls.appium_driver.quit()
41+
42+
def test_1_pkce_login(self):
43+
# Select use PKCE auth
44+
self.altdriver.find_object(By.NAME, "PKCE").tap()
45+
46+
# Wait for unauthenticated screen
47+
self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene")
48+
49+
# Login
50+
loginBtn = self.altdriver.wait_for_object(By.NAME, "LoginBtn")
51+
loginBtn.tap()
52+
53+
driver = self.appium_driver
54+
55+
# Wait for the Chrome Custom Tabs context to appear
56+
WebDriverWait(driver, 30).until(lambda d: 'WEBVIEW_chrome' in d.contexts)
57+
driver.switch_to.context("WEBVIEW_chrome")
58+
59+
email_field = driver.find_element(by=AppiumBy.XPATH, value="//input[@name=\"address\"]")
60+
email_field.send_keys(EMAIL)
61+
submit_button = driver.find_element(by=AppiumBy.XPATH, value="//form/div/div/div[2]/button")
62+
submit_button.click()
63+
64+
time.sleep(10) # Wait for OTP
65+
66+
code = fetch_code()
67+
if code:
68+
print(f"Successfully fetched OTP: {code}")
69+
else:
70+
print("Failed to fetch OTP from email")
71+
72+
otp_field = driver.find_element(by=AppiumBy.XPATH, value="//div[@id=\"passwordless_container\"]/div[1]/input")
73+
otp_field.send_keys(code)
74+
75+
# Wait for authenticated screen
76+
self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene")

0 commit comments

Comments
 (0)