mirror of
https://github.com/appium/appium.git
synced 2026-05-05 09:59:58 -05:00
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:
committed by
Dan Graham
parent
649c5d43d7
commit
cd12ed9a51
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Appium-Python-Client>=0.28
|
||||
pytest
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user