Appium with Java
tip
Codeless accessibility testing via Appium is Coming Soon!
We're developing an Appium Plugin that's set to launch later this year. This plugin will enable you to better integrate accessibility testing for any mobile application throughout your Appium tests, no matter the language they are written in and without access to source code!
Using Appium with axe DevTools Today?
Today Appium support is only available for native Android XML applications via an embedded code element. Checkout the guide to get started with the embedded code element and come back here once you've hit Step 3.
The following Appium example is written in Java and assumes the use of Appium's java-client. The logic is transferable to other clients.
Full Example
import com.deque.axe.android.constants.AxeStatus;
import com.deque.networking.interfaces.AxeDevToolsClient;
import com.deque.networking.interfaces.ConnectionConfig;
import com.deque.networking.interfaces.ResultsDashboard;
import com.deque.networking.interfaces.data.TagsSet;
import com.deque.networking.models.auth.AccessToken;
import com.deque.networking.models.devtools.serializable.AxeDevToolsResult;
import com.deque.networking.models.devtools.serializable.AxeDevToolsResultKey;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
import io.appium.java_client.remote.MobilePlatform;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
public class AppiumTest {
OkHttpClient client = new OkHttpClient();
String apiKey = "your-api-key-here";
String appPath = "path/to/app.apk";
AndroidDriver driver;
AndroidDriver makeDriver() throws MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, new File(appPath).getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
String DEFAULT_APPIUM_ADDRESS = "http://0.0.0.0:4723/";
return new AndroidDriver(new URL(DEFAULT_APPIUM_ADDRESS), capabilities);
}
@Before
public void setup() throws MalformedURLException {
driver = makeDriver();
}
@Test
public void test() {
driver.findElement(
new AppiumBy.ByAccessibilityId("Axe")
).click();
WebDriverWait webDriverWait = new WebDriverWait(driver, Duration.ofSeconds(10));
webDriverWait.until((ExpectedCondition<Boolean>) input -> {
if (input != null) {
input.findElement(AppiumBy.id("result_key_container"));
}
return true;
});
String resultKey = driver.findElement(
AppiumBy.id("result_key_container")
).getAttribute("content-desc");
Request request = new Request.Builder()
.url("https://axe-mobile-backend.deque.com/attest/result/axe/" + resultKey)
.addHeader("X-Api-Key", apiKey)
.addHeader("Content-Type", "application/json")
.build();
try {
Response response = client.newCall(request).execute();
if (response.code() == 200) {
String content = response.body().string();
AxeResult1 axeResult1 = new Gson().fromJson(content, AxeResult1.class);
axeResult1.ruleResults.forEach(it -> {
if (it.status.equals("FAIL")) {
System.out.println("FAILED: " + it.ruleId);
}
});
}
} catch (Throwable throwable) {
System.out.println(throwable.getLocalizedMessage());
}
}
}
class AxeRuleResult1 {
String ruleId;
String ruleSummary;
String axeViewId;
String status;
Integer impact;
HashMap<String, Object> props;
Boolean isVisibleToUser;
AxeRuleResult1(
String ruleId,
String ruleSummary,
String axeViewId,
String status,
Integer impact,
HashMap<String, Object> props,
Boolean isVisibleToUser
) {
this.ruleId = ruleId;
this.ruleSummary = ruleSummary;
this.axeViewId = axeViewId;
this.status = status;
this.impact = impact;
this.props = props;
this.isVisibleToUser = isVisibleToUser;
}
}
class AxeResult1 {
List<AxeRuleResult1> ruleResults;
String userName;
String scanName;
List<String> tags;
AxeResult1(
List<AxeRuleResult1> ruleResults,
String userName,
String scanName,
List<String> tags
) {
this.ruleResults = ruleResults;
this.userName = userName;
this.tags = tags;
this.scanName = scanName;
}
}