Test Example in Python
Not for use with personal data
Be sure to check out the full Appium setup guide with axe DevTools Mobile if you're just getting started, or more examples of axe DevTools Mobile for Appium in other languages.
Full Example with UIAutomator2
import pytest
from appium import webdriver
from appium.options.android import UiAutomator2Options
class TestAndroidAxe:
driver = None
# The axe_settings object still accepts apiKey and axeServiceUrl but is not required
# if you are going to make one time setup_class call to 'mobile: axeStartSession'
axe_settings = {
'tags': ['appium', 'qa'],
'uploadToDashboard': True,
'ignoreRules': ['ScreenOrientation']
}
api_key = '<YOUR_API_KEY>'
project_id = '<YOUR_DEV_HUB_PROJECT_ID>'
app_package = '<YOUR_APP_PACKAGE_NAME>'
@classmethod
def setup_class(cls):
"""
It is very important to make a call to 'mobile: axeStartSession' inside setup_class
to setup your session for posting to Dev Hub.
"""
options = UiAutomator2Options()
options.platform_name = 'Android'
options.device_name = 'Android'
options.app_package = cls.app_package
options.app_activity = '.MainActivity'
options.automation_name = 'AxeUiAutomator2'
options.uiautomator2_server_launch_timeout = 60000
options.uiautomator2_server_install_timeout = 60000
options.adb_exec_timeout = 60000
options.set_capability('ignoreHiddenApiPolicyError', True)
options.set_capability('disableWindowAnimation', True)
options.set_capability('waitForIdle', True)
options.set_capability('commandTimeout', 300)
options.no_reset = False
options.full_reset = False
cls.driver = webdriver.Remote(
command_executor='http://localhost:4723',
options=options
)
# Make one time call to setup your session for posting to Dev Hub.
# This also accepts axeServiceUrl in case of private instance.
axe_auth_settings = {
'apiKey': cls.api_key,
'projectId': cls.project_id
}
cls.driver.execute_script('mobile: axeStartSession', axe_auth_settings)
@classmethod
def teardown_class(cls):
if cls.driver:
cls.driver.quit()
def dismiss_system_ui_error(self):
"""Dismiss System UI error popup if it appears"""
try:
system_popup = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "System UI")]'
)
system_popup.is_displayed()
wait_button = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "Wait")]'
)
wait_button.click()
print("Dismissed the System UI error popup by clicking 'Wait'.")
except Exception as e:
print('No System UI error popup appeared.')
def launch_app(self):
"""Launch the app, handling potential System UI errors"""
try:
self.driver.terminate_app(self.app_package)
self.driver.implicitly_wait(1) # Give the app time to fully terminate
except Exception as e:
print(f"App was not running or failed to terminate: {str(e)}")
self.driver.activate_app(self.app_package)
try:
element = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "Screen Name")]'
)
# Wait for element to be displayed (timeout 30 seconds)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.appiumby import AppiumBy
WebDriverWait(self.driver, 30).until(
EC.visibility_of(element)
)
except Exception as e:
self.dismiss_system_ui_error()
# Try again after dismissing the error (if not, then fail)
element = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "Screen Name")]'
)
WebDriverWait(self.driver, 30).until(
EC.visibility_of(element)
)
def setup_method(self):
"""Launch app before each test"""
self.launch_app()
def test_test1(self):
"""
Now since your session is authenticated you can keep making 'mobile: axeScan' calls.
The scans will be uploaded to the dashboard and also grouped in Dev Hub.
"""
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "Screen Name")]'
)
WebDriverWait(self.driver, 10).until(
EC.visibility_of(element)
)
print(element.text)
appium_scan_result = self.driver.execute_script('mobile: axeScan', self.axe_settings)
results = appium_scan_result['axeRuleResults']
print(f'debug: Total results: {len(results)}')
def test_test2(self):
"""Second test with interaction"""
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = self.driver.find_element(
by='xpath',
value='//*[contains(@text, "Screen Name")]'
)
WebDriverWait(self.driver, 10).until(
EC.visibility_of(element)
)
element.click()
self.driver.find_element(
by='xpath',
value='//*[contains(@text, "announced by a screen")]'
)
appium_scan_result = self.driver.execute_script('mobile: axeScan', self.axe_settings)
results = appium_scan_result['axeRuleResults']
print(f'debug: Total results: {len(results)}')Full Example with XCUITest
import pytest
from appium import webdriver
from appium.options.ios import XCUITestOptions
class TestIOSMapsAxe:
driver = None
# The axe_settings object still accepts apiKey and axeServiceUrl but is not required
# if you are going to make one time setup_class call to 'mobile: axeStartSession'
axe_settings = {
'tags': ['appium', 'qa', 'ios'],
'uploadToDashboard': True,
'ignoreRules': ['ScreenOrientation']
}
api_key = '<YOUR_API_KEY>'
project_id = '<YOUR_DEV_HUB_PROJECT_ID>'
bundle_id = 'com.apple.Maps'
@classmethod
def setup_class(cls):
"""
It is very important to make a call to 'mobile: axeStartSession' inside setup_class
to setup your session for posting to Dev Hub.
"""
options = XCUITestOptions()
options.platform_name = 'iOS'
options.automation_name = 'AxeXCUITest'
options.udid = '<YOUR_DEVICE_OR_SIMULATOR_UDID>'
options.bundle_id = cls.bundle_id
options.set_capability('wdaLaunchTimeout', 960000) # 16 minutes
# NOT specifying platformVersion - let it auto-detect
cls.driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
options=options
)
# Make one time call to setup your session for posting to Dev Hub.
# This also accepts axeServiceUrl in case of private instance.
axe_auth_settings = {
'apiKey': cls.api_key,
'projectId': cls.project_id,
'axeServiceUrl': 'https://mobile-qa.dequelabs.com'
}
cls.driver.execute_script('mobile: axeStartSession', axe_auth_settings)
@classmethod
def teardown_class(cls):
if cls.driver:
cls.driver.implicitly_wait(1)
cls.driver.quit()
def launch_app(self):
"""Launch the Maps app"""
self.driver.activate_app(self.bundle_id)
def setup_method(self):
"""Launch app before each test"""
self.launch_app()
def test_test1_scan_main_screen(self):
"""
Now since your session is authenticated you can keep making 'mobile: axeScan' calls.
The scans will be uploaded to the dashboard and also grouped in Dev Hub.
"""
appium_scan_result = self.driver.execute_script('mobile: axeScan', self.axe_settings)
results = appium_scan_result['axeRuleResults']
print(f'debug: Total results: {len(results)}')
def test_test2_click_search_and_scan(self):
"""Second test - click search and scan"""
appium_scan_result = self.driver.execute_script('mobile: axeScan', self.axe_settings)
results = appium_scan_result['axeRuleResults']
print(f'debug: Total results: {len(results)}')
