Appium Example

Link to Appium Example copied to clipboard

Supported within:
axeDevTools UIKit framework


Before running your tests in Appium, ensure the application under test is set up to run axe DevTools Mobile by embedding the framework into your application. Resource: Setup Guide for Embedding the framework

Next, replace the call to axe?.showA11yFAB() with axe?.showA11yFAB(customFAB: AutomatedTestFAB()). This provides an invisible floating action button for tests to engage with that won't interfere with any UI assertions. Resource: UITesting with axeDevToolsUIKit


By embedding the framework into your application, Appium can initiate a scan by engaging with the floating action button by its accessibility identifier: com.deque.axeDevTools.accessibilityFab. Engage with the floating action button at any point in your tests you'd like to scan for accessibility issues.

Note: Appium support for accessibility testing is limited to UIKit implementations currently. Support for other languages is coming soon.


Python Client

Resource: Appium Python Client Documentation

Follow the comments marked with TODO to update your specific configurations to start testing with the script as is. Grab a Deque API Key from your axe Account Settings page.

from appium import webdriver
import os

import requests
from appium.webdriver import WebElement
from appium.webdriver.common.appiumby import AppiumBy

## TODO: Update your configurations
app = "com.dequesystems.axe-devtools-ios-sample-app"
udid = "DFB0EB3F-2C3D-4F62-B684-39F3D12F0DCD"
platformVersion = "16.2"
deviceName = "iPhone 14"
dequeAPIKey = ""

## Class Definitions for parsing the result from the server:
class AxeRuleResult:
    def __init__(self, ruleId, ruleSummary, axeViewId, status, impact, props, isVisibleToUser=True):
        self.ruleId = ruleId
        self.ruleSummary = ruleSummary
        self.axeViewId = axeViewId
        self.status = status
        self.impact = impact
        self.props = props
        self.isVisibleToUser = isVisibleToUser
class AxeResult:
    def __init__(self, axeRuleResults, userName, scanName, tags):
        self.axeRuleResults = axeRuleResults
        self.userName = userName
        self.scanName = scanName
        self.tags = tags

class DemoWithAPIRequest:
    def __init__(self):
        self.driver = None
        self.client = requests.Session()

    def setup(self):
        success = True
        desired_caps = {}
        desired_caps['platformName'] = 'iOS'
        desired_caps['platformVersion'] = platformVersion
        desired_caps['deviceName'] = deviceName
        desired_caps['udid'] = udid
        desired_caps['automationName'] = 'XCUITest'
        desired_caps['realDeviceLogger'] = 'idevicesyslog'
        desired_caps['app'] = app
        ## TODO: UPDATE URL for your appium server:
        self.driver = webdriver.Remote('', desired_caps)

    def runA11y(self):
        # Navigate and Click the FAB
        fab = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='com.deque.axeDevTools.accessibilityFab')

        # Wait for network request to finish and FAB to return.

        # Getting Result Key from the FAB
        resultKey = fab.get_attribute("label")

        # Fetch Rule Results from API
        url = ""+resultKey
        headers = {
            "X-Api-Key": dequeAPIKey,
            "Content-Type": "application/json"
            response = self.client.get(url, headers=headers)
            if response.status_code == 200:
                content = response.json()

                # Parse JSON and output the result
                axeResult = AxeResult(
                    axeRuleResults=[AxeRuleResult(**ruleResult) for ruleResult in content['axeRuleResults']],

                for rule in axeResult.axeRuleResults:
                    if rule.status == "FAIL":
                        print(f"rule: {rule.ruleId}")
                print(f"httpCode: {response.status_code}")
        except Exception as e:
            print(f"error: {str(e)}")

demo = DemoWithAPIRequest()

Java Client

Resource: Appium Java Client Documentation


plugins {
    id 'java'
    id 'org.jetbrains.kotlin.jvm' version '1.5.0'

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    maven { url '' }
    maven { url "" }

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib"
    implementation "junit:junit:4.13.2"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2"
    testImplementation "junit:junit:4.13.1"

    implementation "com.github.appium:java-client:8.1.1"
    implementation "org.seleniumhq.selenium:selenium-java:4.2.1"
    implementation ""
    implementation "com.squareup.okhttp3:okhttp:4.10.0"

Full Example

import io.appium.java_client.AppiumBy
import io.appium.java_client.ios.IOSDriver
import io.appium.java_client.remote.MobileCapabilityType
import io.appium.java_client.remote.MobilePlatform
import okhttp3.OkHttpClient
import okhttp3.Request
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.openqa.selenium.WebDriver
import org.openqa.selenium.remote.DesiredCapabilities
import java.time.Duration

class DemoWithAPIRequest {
    private val client = OkHttpClient()
    private lateinit var driver: IOSDriver
    val appFilePath = "path/to/your/"

    fun setup() {
        val capabilities = DesiredCapabilities()

        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone 14")
        capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.IOS)
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "16.0")
        capabilities.setCapability(MobileCapabilityType.APP, File(appFilePath).absolutePath)

        driver = IOSDriver(URL(""), capabilities)

    fun runA11y() {
        // Navigate and Click the FAB

        val webDriverWait = WebDriverWait(driver, Duration.ofSeconds(10))
        webDriverWait.until(ExpectedCondition { input: WebDriver? ->

        // Getting Result Key from the FAB
        val resultKey: String = driver.findElement(

        // Fetch Rule Results from API
        val apiKey = "your-api-key-here"
        val url = "$resultKey"
        val request = Request.Builder()
            .addHeader("X-Api-Key", apiKey)
            .addHeader("Content-Type", "application/json")

        try {
            val response = client.newCall(request).execute()
            if (response.code == 200) {
                val content = response.body?.string()
                // Parse JSON and output the result
                val axeResult = Gson().fromJson(content,

                axeResult.axeRuleResults.forEach {
                    if (it.status == "FAIL") {
                        println("rule: ${it.ruleId}")
            } else {
                println("httpCode: ${response.code}")
        } catch (t: Throwable) {
            println("error: ${t.message}")

data class AxeRuleResult(
    val ruleId: String?,
    val ruleSummary: String?,
    val axeViewId: String?,
    val status: String?, // "PASS", "FAIL", "INCOMPLETE"
    val impact: Int?,
    val props: HashMap<String, Any?>,
    val isVisibileToUser: Boolean = true

data class AxeResult(
    val axeRuleResults: List<AxeRuleResult>,
    val userName: String?,
    val scanName: String?,
    val tags: List<String>?