Vinayak commited on
Commit ·
4a3720d
1
Parent(s): acdbb22
Add E2E test for puppet android app
Browse filesAdds github action workflow to run tests against trigger.
Adds test case to run tests against sauce labs.
Adds necessary boilerplate code to setup test execution.
- .github/workflows/e2e_tests.yml +29 -0
- e2e_tests/README.md +18 -0
- e2e_tests/requirements.txt +1 -0
- e2e_tests/test_sauce_labs.py +125 -0
.github/workflows/e2e_tests.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: E2E Tests
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [ "main", "develop" ]
|
| 6 |
+
pull_request:
|
| 7 |
+
paths:
|
| 8 |
+
- "puppet/**"
|
| 9 |
+
branches: [ "main" ]
|
| 10 |
+
workflow_dispatch:
|
| 11 |
+
jobs:
|
| 12 |
+
build:
|
| 13 |
+
runs-on: ubuntu-latest
|
| 14 |
+
defaults:
|
| 15 |
+
run:
|
| 16 |
+
working-directory: e2_tests
|
| 17 |
+
env:
|
| 18 |
+
SAUCE_USERNAME : ${{ secrets.SAUCE_USERNAME }}
|
| 19 |
+
SAUCE_ACCESS_KEY : ${{ secrets.SAUCE_ACCESS_KEY }}
|
| 20 |
+
TEST_UUID : ${{ secrets.TEST_UUID }}
|
| 21 |
+
steps:
|
| 22 |
+
- uses: actions/checkout@v3
|
| 23 |
+
- name: Setup Python
|
| 24 |
+
- uses: actions/setup-python@v4
|
| 25 |
+
with:
|
| 26 |
+
python-version: '3.10'
|
| 27 |
+
cache: 'pip' # caching pip dependencies
|
| 28 |
+
- run: pip install -r requirements.txt
|
| 29 |
+
- run: python test_sauce_labs.py
|
e2e_tests/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Running E2E Tests
|
| 2 |
+
|
| 3 |
+
This serves as a framework to build regression tests for puppet android app.
|
| 4 |
+
Currently the test supports running the tests against the built android package in dev machine or in sauce labs.
|
| 5 |
+
|
| 6 |
+
Common code to enable/activate privacy setting for puppet app exists in the same file.
|
| 7 |
+
Which can be abstracted away in future to make it reusable across other test files.
|
| 8 |
+
This uses Appium to drive the android app and send instructions.
|
| 9 |
+
|
| 10 |
+
For SauceLabs test assumes the username, accesskey and UUID is available as environment variable.
|
| 11 |
+
|
| 12 |
+
By altering the device name, the tests can be run against an emulator or real android device in saucelabs.
|
| 13 |
+
|
| 14 |
+
For local machine, an appium server, android emulator and Java SDK is required.
|
| 15 |
+
|
| 16 |
+
`pip install -r requirements.txt`
|
| 17 |
+
|
| 18 |
+
`python test_sauce_labs.py`
|
e2e_tests/requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Appium-Python-Client==2.11.1
|
e2e_tests/test_sauce_labs.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python/Pytest
|
| 2 |
+
from contextlib import contextmanager
|
| 3 |
+
import time
|
| 4 |
+
import unittest
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
from appium import webdriver
|
| 8 |
+
from appium.webdriver.common.appiumby import AppiumBy
|
| 9 |
+
from selenium.webdriver.remote.webdriver import WebDriver
|
| 10 |
+
|
| 11 |
+
APPIUM_PORT = 4723
|
| 12 |
+
APPIUM_HOST = '127.0.0.1'
|
| 13 |
+
|
| 14 |
+
SAUCE_USERNAME = os.getenv("SAUCE_USERNAME")
|
| 15 |
+
SAUCE_ACCESS_KEY = os.getenv("SAUCE_ACCESS_KEY")
|
| 16 |
+
TEST_UUID = os.getenv("TEST_UUID", "")
|
| 17 |
+
|
| 18 |
+
def create_android_driver(sauce_labs = False):
|
| 19 |
+
capabilities = dict(
|
| 20 |
+
platformName='Android',
|
| 21 |
+
automationName='uiautomator2',
|
| 22 |
+
deviceName='Android',
|
| 23 |
+
appPackage='com.ttt246.puppet',
|
| 24 |
+
appActivity='.ChatterAct',
|
| 25 |
+
language='en',
|
| 26 |
+
locale='US'
|
| 27 |
+
)
|
| 28 |
+
capabilities["appium:app"] = "app-release-unsigned.apk"
|
| 29 |
+
capabilities["autoGrantPermissions"] = "true"
|
| 30 |
+
connection_url = f'http://{APPIUM_HOST}:{APPIUM_PORT}'
|
| 31 |
+
if sauce_labs:
|
| 32 |
+
capabilities['platformName'] = 'Android'
|
| 33 |
+
capabilities['appium:app'] = 'storage:filename=app-release-unsigned.apk'
|
| 34 |
+
capabilities['appium:deviceName'] = 'Android GoogleAPI Emulator'
|
| 35 |
+
capabilities['appium:deviceOrientation'] = 'portrait'
|
| 36 |
+
capabilities['appium:platformVersion'] = '13.0'
|
| 37 |
+
capabilities['appium:automationName'] = 'uiautomator2'
|
| 38 |
+
capabilities['appPackage'] = 'com.ttt246.puppet'
|
| 39 |
+
capabilities['appActivity'] ='.ChatterAct'
|
| 40 |
+
capabilities["appium:autoGrantPermissions"] = 'true'
|
| 41 |
+
capabilities['sauce:options'] = {}
|
| 42 |
+
capabilities['sauce:options']['username'] = SAUCE_USERNAME;
|
| 43 |
+
capabilities['sauce:options']['accessKey'] = SAUCE_ACCESS_KEY;
|
| 44 |
+
capabilities['sauce:options']['build'] = 'appium-build-HGNZD'
|
| 45 |
+
capabilities['sauce:options']['name'] = 'Automate Tests'
|
| 46 |
+
capabilities['appium:app'] = 'storage:filename=app-release-unsigned.apk'
|
| 47 |
+
capabilities['appium:deviceName'] = 'Android GoogleAPI Emulator'
|
| 48 |
+
|
| 49 |
+
connection_url = 'https://ondemand.us-west-1.saucelabs.com:443/wd/hub'
|
| 50 |
+
|
| 51 |
+
return webdriver.Remote(connection_url, capabilities)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@contextmanager
|
| 55 |
+
def android_driver(options):
|
| 56 |
+
# prefer this fixture if there is no need to customize driver options in tests
|
| 57 |
+
driver = create_android_driver(sauce_labs=True)
|
| 58 |
+
yield driver
|
| 59 |
+
driver.quit()
|
| 60 |
+
|
| 61 |
+
def save_server_settings(driver: WebDriver):
|
| 62 |
+
el8 = driver.find_element(by=AppiumBy.ID, value="com.ttt246.puppet:id/settingsButton")
|
| 63 |
+
el8.click()
|
| 64 |
+
el9 = driver.find_element(by=AppiumBy.ID, value="com.ttt246.puppet:id/serverUrlEditText")
|
| 65 |
+
el9.send_keys("https://posix4e-puppet.hf.space")
|
| 66 |
+
el10 = driver.find_element(by=AppiumBy.ID, value="com.ttt246.puppet:id/uuidEditText")
|
| 67 |
+
el10.send_keys("1608052e-b294-4a6f-a69f-e18c9bedf5c8")
|
| 68 |
+
el11 = driver.find_element(by=AppiumBy.ID, value="com.ttt246.puppet:id/saveButton")
|
| 69 |
+
el11.click()
|
| 70 |
+
|
| 71 |
+
def enable_privacy_settings(driver: WebDriver):
|
| 72 |
+
driver.find_element(by=AppiumBy.XPATH, value='//*[@text="puppet"]').click()
|
| 73 |
+
primary_checkbox = driver.find_element(by=AppiumBy.ID, value='android:id/switch_widget')
|
| 74 |
+
|
| 75 |
+
# Use Puppet button
|
| 76 |
+
if not primary_checkbox.get_attribute("checked") == "true":
|
| 77 |
+
primary_checkbox.click()
|
| 78 |
+
try:
|
| 79 |
+
driver.find_element(by=AppiumBy.XPATH, value="//*[@text='Allow']").click()
|
| 80 |
+
except Exception as e:
|
| 81 |
+
pass
|
| 82 |
+
|
| 83 |
+
# Puppet shortcut button
|
| 84 |
+
secondary_checkbox = driver.find_element(by=AppiumBy.ID, value='com.android.settings:id/switchWidget')
|
| 85 |
+
if not secondary_checkbox.get_attribute("checked") == "true":
|
| 86 |
+
secondary_checkbox.click()
|
| 87 |
+
try:
|
| 88 |
+
driver.find_element(by=AppiumBy.XPATH, value="//*[@text='Got it']").click()
|
| 89 |
+
except Exception as e:
|
| 90 |
+
pass
|
| 91 |
+
|
| 92 |
+
time.sleep(2)
|
| 93 |
+
driver.back()
|
| 94 |
+
time.sleep(2)
|
| 95 |
+
driver.back()
|
| 96 |
+
|
| 97 |
+
class TestAppium(unittest.TestCase):
|
| 98 |
+
def test_tab_4(self):
|
| 99 |
+
import time
|
| 100 |
+
# Usage of the context manager ensures the driver session is closed properly
|
| 101 |
+
# after the test completes. Otherwise, make sure to call `driver.quit()` on teardown.
|
| 102 |
+
with android_driver({}) as driver:
|
| 103 |
+
driver.implicitly_wait(10)
|
| 104 |
+
|
| 105 |
+
enable_privacy_settings(driver)
|
| 106 |
+
|
| 107 |
+
driver.activate_app("com.ttt246.puppet")
|
| 108 |
+
driver.wait_activity(".ChatterAct", 5)
|
| 109 |
+
time.sleep(2)
|
| 110 |
+
|
| 111 |
+
save_server_settings(driver)
|
| 112 |
+
|
| 113 |
+
el14 = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Tab 4"]')
|
| 114 |
+
el14.click()
|
| 115 |
+
el15 = driver.find_element(by=AppiumBy.XPATH, value="//android.widget.EditText[@hint='UID']")
|
| 116 |
+
el15.send_keys(TEST_UUID)
|
| 117 |
+
el16 = driver.find_element(by=AppiumBy.XPATH, value="//android.widget.EditText[@hint='Command']")
|
| 118 |
+
el16.send_keys("test")
|
| 119 |
+
el17 = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Submit"]')
|
| 120 |
+
el17.click()
|
| 121 |
+
time.sleep(5)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
if __name__ == "__main__":
|
| 125 |
+
unittest.main()
|