Add python sample code (#11208)

* add initial python sample

* add all of ios and android tests

* apply formatter

* add >=0.28 to avoid version error

* tweak versions of default OS

* convert some tests to unittest based ones

* use single quote mainly

* use {} format style for string

* use format syntax

* apply format and tweak assertions

* use is None

* use assert raise

* speficy a number of elements

* tweak exception

* move app path to helper

* tweak assertion conditions

* remove .close since with open() close file automatically
This commit is contained in:
Kazuaki Matsuo
2018-08-23 03:48:58 +09:00
committed by Dan Graham
parent 649c5d43d7
commit cd12ed9a51
13 changed files with 466 additions and 2 deletions
+3
View File
@@ -31,6 +31,7 @@ build/
.idea
*DerivedData
__pycache__
*.pyc
old
.tern-project
coverage
@@ -39,4 +40,6 @@ sample-code/javascript-wd/node_modules
sample-code/php/vendor
sample-code/php/composer.lock
sample-code/java/out/
sample-code/python/test/results/
sample-code/python/.pytest_cache/
appium.zip
+24 -2
View File
@@ -1,5 +1,27 @@
# Python Sample Code
## Setup
* <Setup instructions>
```
pip install -r requirements.txt
```
## Run tests
### Run all tests
```
py.test test
```
### Run an arbitrary file
```
py.test test/test_ios_selectors.py
```
## TestCase
### unittest based
- test/test_android_create_session.py
- test/test_ios_create_session.py
### pytest based
- Rest of the above
+2
View File
@@ -0,0 +1,2 @@
Appium-Python-Client>=0.28
pytest
+32
View File
@@ -0,0 +1,32 @@
import pytest
import datetime
import os
from helpers import ensure_dir
def pytest_configure(config):
if not hasattr(config, 'slaveinput'):
current_day = '{:%Y_%m_%d_%H_%S}'.format(datetime.datetime.now())
ensure_dir('results')
ensure_dir(os.path.join('slaveinput', current_day))
result_dir = os.path.join(os.path.dirname(__file__), 'results', current_day)
ensure_dir(result_dir)
result_dir_test_run = result_dir
ensure_dir(os.path.join(result_dir_test_run, 'screenshots'))
ensure_dir(os.path.join(result_dir_test_run, 'logcat'))
config.screen_shot_dir = os.path.join(result_dir_test_run, 'screenshots')
config.logcat_dir = os.path.join(result_dir_test_run, 'logcat')
class DeviceLogger:
def __init__(self, logcat_dir, screenshot_dir):
self.screenshot_dir = screenshot_dir
self.logcat_dir = logcat_dir
@pytest.fixture(scope='function')
def device_logger(request):
logcat_dir = request.config.logcat_dir
screenshot_dir = request.config.screen_shot_dir
return DeviceLogger(logcat_dir, screenshot_dir)
+44
View File
@@ -0,0 +1,44 @@
import os
from selenium.common.exceptions import InvalidSessionIdException
ANDROID_APP_PATH = 'http://appium.github.io/appium/assets/ApiDemos-debug.apk' if os.getenv(
'SAUCE_LABS') else os.path.abspath('../apps/ApiDemos-debug.apk')
IOS_APP_PATH = 'http://appium.github.io/appium/assets/TestApp7.1.app.zip' if os.getenv(
'SAUCE_LABS') else os.path.abspath('../apps/TestApp.app.zip')
if os.getenv('SAUCE_USERNAME') and os.getenv('SAUCE_ACCESS_KEY'):
EXECUTOR = 'http://{}:{}@ondemand.saucelabs.com:80/wd/hub'.format(
os.getenv('SAUCE_USERNAME'), os.getenv('SAUCE_ACCESS_KEY'))
else:
EXECUTOR = 'http://127.0.0.1:4723/wd/hub'
def ensure_dir(directory):
if not os.path.exists(directory):
os.makedirs(directory)
def take_screenhot_and_logcat(driver, device_logger, calling_request):
__save_log_type(driver, device_logger, calling_request, 'logcat')
def take_screenhot_and_syslog(driver, device_logger, calling_request):
__save_log_type(driver, device_logger, calling_request, 'syslog')
def __save_log_type(driver, device_logger, calling_request, type):
logcat_dir = device_logger.logcat_dir
screenshot_dir = device_logger.screenshot_dir
try:
driver.save_screenshot(os.path.join(screenshot_dir, calling_request + '.png'))
logcat_data = driver.get_log(type)
except InvalidSessionIdException:
logcat_data = ''
with open(os.path.join(logcat_dir, '{}_{}.log'.format(calling_request, type)), 'wb') as logcat_file:
for data in logcat_data:
data_string = '{}: {}'.format(data['timestamp'], data['message'])
logcat_file.write((data_string + '\n').encode('UTF-8'))
@@ -0,0 +1,64 @@
import pytest
import os
import textwrap
from appium import webdriver
from helpers import take_screenhot_and_logcat, ANDROID_APP_PATH, EXECUTOR
class TestAndroidBasicInteractions():
PACKAGE = 'io.appium.android.apis'
SEARCH_ACTIVITY = '.app.SearchInvoke'
ALERT_DIALOG_ACTIVITY = '.app.AlertDialogSamples'
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': ANDROID_APP_PATH,
'platformName': 'Android',
'automationName': 'UIAutomator2',
'platformVersion': os.getenv('ANDROID_PLATFORM_VERSION') or '7.1',
'deviceName': os.getenv('ANDROID_DEVICE_VERSION') or 'Android',
'appActivity': self.SEARCH_ACTIVITY
}
)
def fin():
take_screenhot_and_logcat(driver, device_logger, calling_request)
driver.quit()
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_send_keys_to_search_box_and_then_check_the_value(self, driver):
search_box_element = driver.find_element_by_id('txt_query_prefill')
search_box_element.send_keys('Hello world!')
on_search_requested_button = driver.find_element_by_id('btn_start_search')
on_search_requested_button.click()
search_text = driver.find_element_by_id('android:id/search_src_text')
search_text_value = search_text.text
assert 'Hello world!' == search_text_value
def test_should_click_a_button_that_opens_an_alert_and_then_dismisses_it(self, driver):
driver.start_activity(self.PACKAGE, self.ALERT_DIALOG_ACTIVITY)
open_dialog_button = driver.find_element_by_id('io.appium.android.apis:id/two_buttons')
open_dialog_button.click()
alert_element = driver.find_element_by_id('android:id/alertTitle')
alert_text = alert_element.text
assert textwrap.dedent('''\
Lorem ipsum dolor sit aie consectetur adipiscing
Plloaso mako nuto siwuf cakso dodtos anr koop.''') == alert_text
close_dialog_button = driver.find_element_by_id('android:id/button1')
close_dialog_button.click()
@@ -0,0 +1,35 @@
import unittest
import os
from appium import webdriver
from helpers import take_screenhot_and_logcat, ANDROID_APP_PATH, EXECUTOR
from selenium.common.exceptions import InvalidSessionIdException
# Run standard unittest base.
class TestAndroidSelectors(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': ANDROID_APP_PATH,
'platformName': 'Android',
'automationName': 'UIAutomator2',
'platformVersion': os.getenv('ANDROID_PLATFORM_VERSION') or '7.1',
'deviceName': os.getenv('ANDROID_DEVICE_VERSION') or 'Android',
}
)
self.driver.implicitly_wait(10)
def test_should_create_and_destroy_android_session(self):
activity = self.driver.current_activity
pkg = self.driver.current_package
self.assertEquals('io.appium.android.apis.ApiDemos', '{}{}'.format(pkg, activity))
self.driver.quit()
with self.assertRaises(InvalidSessionIdException) as excinfo:
self.driver.title
self.assertEquals('A session is either terminated or not started', excinfo.exception.msg)
@@ -0,0 +1,41 @@
import pytest
import os
from appium import webdriver
from helpers import take_screenhot_and_logcat, EXECUTOR
from selenium.common.exceptions import InvalidSessionIdException
class TestAndroidCreateWebSession():
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'platformName': 'Android',
'automationName': 'UIAutomator2',
'platformVersion': os.getenv('ANDROID_PLATFORM_VERSION') or '7.1',
'deviceName': os.getenv('ANDROID_DEVICE_VERSION') or 'Android',
'browserName': 'Chrome'
}
)
def fin():
take_screenhot_and_logcat(driver, device_logger, calling_request)
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_create_and_destroy_android_session(self, driver):
driver.get('https://www.google.com')
title = driver.title
assert 'Google' == title
with pytest.raises(InvalidSessionIdException) as excinfo:
driver.title
assert 'A session is either terminated or not started' == excinfo.value.msg
@@ -0,0 +1,47 @@
import pytest
import os
from appium import webdriver
from helpers import take_screenhot_and_logcat, ANDROID_APP_PATH, EXECUTOR
class TestAndroidBasicInteractions():
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': ANDROID_APP_PATH,
'platformName': 'Android',
'automationName': 'UIAutomator2',
'platformVersion': os.getenv('ANDROID_PLATFORM_VERSION') or '7.1',
'deviceName': os.getenv('ANDROID_DEVICE_VERSION') or 'Android'
}
)
def fin():
take_screenhot_and_logcat(driver, device_logger, calling_request)
driver.quit()
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_find_elements_by_accessibility_id(self, driver):
search_parameters_element = driver.find_elements_by_accessibility_id('Content')
assert 1 == len(search_parameters_element)
def test_should_find_elements_by_id(self, driver):
action_bar_container_elements = driver.find_elements_by_id('android:id/action_bar_container')
assert 1 == len(action_bar_container_elements)
def test_should_find_elements_by_class_name(self, driver):
action_bar_container_elements = driver.find_elements_by_class_name('android.widget.FrameLayout')
assert 3 == len(action_bar_container_elements)
def test_should_find_elements_by_xpath(self, driver):
action_bar_container_elements = driver.find_elements_by_xpath('//*[@class="android.widget.FrameLayout"]')
assert 3 == len(action_bar_container_elements)
@@ -0,0 +1,47 @@
import pytest
import os
from appium import webdriver
from helpers import take_screenhot_and_syslog, IOS_APP_PATH, EXECUTOR
class TestIOSBasicInteractions():
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': IOS_APP_PATH,
'platformName': 'iOS',
'automationName': 'XCUITest',
'platformVersion': os.getenv('IOS_PLATFORM_VERSION') or '11.1',
'deviceName': os.getenv('IOS_DEVICE_NAME') or 'iPhone 6s',
}
)
def fin():
take_screenhot_and_syslog(driver, device_logger, calling_request)
driver.quit()
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_send_keys_to_inputs(self, driver):
text_field_el = driver.find_element_by_id('TextField1')
assert text_field_el.get_attribute('value') is None
text_field_el.send_keys('Hello World!')
assert 'Hello World!' == text_field_el.get_attribute('value')
def test_should_click_a_button_that_opens_an_alert(self, driver):
button_element_id = 'show alert'
button_element = driver.find_element_by_accessibility_id(button_element_id)
button_element.click()
alert_title_element_id = 'Cool title'
alert_title_element = driver.find_element_by_accessibility_id(alert_title_element_id)
alert_title = alert_title_element.get_attribute('name')
assert 'Cool title' == alert_title
@@ -0,0 +1,34 @@
import unittest
import os
from appium import webdriver
from helpers import take_screenhot_and_syslog, IOS_APP_PATH, EXECUTOR
from selenium.common.exceptions import InvalidSessionIdException
# Run standard unittest base.
class TestIOSSelectors(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': IOS_APP_PATH,
'platformName': 'iOS',
'automationName': 'XCUITest',
'platformVersion': os.getenv('IOS_PLATFORM_VERSION') or '11.1',
'deviceName': os.getenv('IOS_DEVICE_NAME') or 'iPhone 6s',
}
)
self.driver.implicitly_wait(10)
def test_should_create_and_destroy_ios_session(self):
app_element = self.driver.find_element_by_class_name('XCUIElementTypeApplication')
app_element_name = app_element.get_attribute('name')
self.assertEquals('TestApp', app_element_name)
self.driver.quit()
with self.assertRaises(InvalidSessionIdException) as excinfo:
self.driver.title
self.assertEquals('A session is either terminated or not started', excinfo.exception.msg)
@@ -0,0 +1,42 @@
import pytest
import os
from appium import webdriver
from helpers import take_screenhot_and_syslog, EXECUTOR
from selenium.common.exceptions import InvalidSessionIdException
class TestIOSCreateWebSession():
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'platformName': 'iOS',
'automationName': 'XCUITest',
'platformVersion': os.getenv('IOS_PLATFORM_VERSION') or '10.3',
'deviceName': os.getenv('IOS_DEVICE_NAME') or 'iPhone 6s',
'browserName': 'Safari'
}
)
def fin():
take_screenhot_and_syslog(driver, device_logger, calling_request)
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_create_and_destroy_android_session(self, driver):
driver.get('https://www.google.com')
title = driver.title
assert 'Google' == title
driver.quit()
with pytest.raises(InvalidSessionIdException) as excinfo:
driver.title
assert 'A session is either terminated or not started' == excinfo.value.msg
@@ -0,0 +1,51 @@
import pytest
import os
from appium import webdriver
from helpers import take_screenhot_and_syslog, IOS_APP_PATH, EXECUTOR
class TestIOSBasicInteractions():
@pytest.fixture(scope='function')
def driver(self, request, device_logger):
calling_request = request._pyfuncitem.name
driver = webdriver.Remote(
command_executor=EXECUTOR,
desired_capabilities={
'app': IOS_APP_PATH,
'platformName': 'iOS',
'automationName': 'XCUITest',
'platformVersion': os.getenv('IOS_PLATFORM_VERSION') or '11.1',
'deviceName': os.getenv('IOS_DEVICE_NAME') or 'iPhone 6s',
}
)
def fin():
take_screenhot_and_syslog(driver, device_logger, calling_request)
driver.quit()
request.addfinalizer(fin)
driver.implicitly_wait(10)
return driver
def test_should_find_elements_by_accessibility_id(self, driver):
search_parameters_element = driver.find_elements_by_accessibility_id('ComputeSumButton')
assert 1 == len(search_parameters_element)
def test_should_find_elements_by_class_name(self, driver):
window_elements = driver.find_elements_by_class_name('XCUIElementTypeWindow')
assert 2 == len(window_elements)
def test_should_find_elements_by_nspredicate(self, driver):
all_visible_elements = driver.find_elements_by_ios_predicate('visible = 1')
assert 27 == len(all_visible_elements)
def test_should_find_elements_by_class_chain(self, driver):
window_element = driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow[1]/*[2]')
assert 1 == len(window_element)
def test_should_find_elements_by_xpath(self, driver):
action_bar_container_elements = driver.find_elements_by_xpath('//XCUIElementTypeWindow//XCUIElementTypeButton')
assert 8 == len(action_bar_container_elements)