Esempio di Test in Kotlin
Not for use with personal data
Assicurati di consultare la guida completa all'installazione di Appium con axe DevTools Mobile se stai appena iniziando, oppure più esempi di axe DevTools Mobile per Appium in altre lingue.
Esempio Completo con UIAutomator2
import io.appium.java_client.android.AndroidDriver
import io.appium.java_client.android.options.UiAutomator2Options
import org.junit.jupiter.api.*
import org.openqa.selenium.By
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import java.net.URL
import java.time.Duration
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
class AndroidDebugTest {
companion object {
private lateinit var driver: AndroidDriver
// The axeSettings object still accepts apiKey and axeAccountURL but is not required
// if you are going to make one time @BeforeAll annotated call to 'mobile: axeStartSession'
private lateinit var axeSettings: Map<String, Any>
private const val API_KEY = "<YOUR_API_KEY>"
private const val PROJECT_ID = "<YOUR_DEV_HUB_PROJECT_ID>"
private const val APP_PACKAGE = "<YOUR_APP_PACKAGE_NAME>"
// It is very important to make a call to 'mobile: axeStartSession' inside @BeforeAll annotated
// method to setup your session for posting to Developer Hub.
@JvmStatic
@BeforeAll
fun setUp() {
axeSettings = mapOf(
"tags" to listOf("appium", "qa"),
"uploadToDashboard" to true,
"ignoreRules" to listOf("ScreenOrientation")
)
val options = UiAutomator2Options()
.setPlatformName("Android")
.setDeviceName("Android")
.setAppPackage(APP_PACKAGE)
.setAppActivity(".MainActivity")
.setAutomationName("AxeUiAutomator2")
.setUiautomator2ServerLaunchTimeout(Duration.ofMillis(60000))
.setUiautomator2ServerInstallTimeout(Duration.ofMillis(60000))
.setAdbExecTimeout(Duration.ofMillis(60000))
.setIgnoreHiddenApiPolicyError(true)
.setDisableWindowAnimation(true)
.setCapability("waitForIdle", true)
.setNewCommandTimeout(Duration.ofSeconds(300))
.setNoReset(false)
.setFullReset(false)
driver = AndroidDriver(URL("http://localhost:4723/"), options)
// Make one time call to setup your session for posting to Dev Hub.
// This also accepts axeAccountURL in case of private instance.
val axeAuthSettings = mapOf(
"apiKey" to API_KEY,
"projectId" to PROJECT_ID
)
driver.executeScript("mobile: axeStartSession", axeAuthSettings)
}
@JvmStatic
@AfterAll
fun tearDown() {
if (::driver.isInitialized) {
// Generate an HTML report from all accumulated scans before quitting.
// The report aggregates every 'mobile: axeScan' call made during this session.
try {
val reportSettings = mapOf(
"scanName" to "My Accessibility Report",
"axeHtmlReportPath" to "build/AxeDevToolsMobileResults"
)
val reportResult = driver.executeScript(
"mobile: axeGenerateHtmlReportAndSummary", reportSettings
) as Map<*, *>
if (reportResult.containsKey("axeError")) {
println("Report generation failed: ${reportResult["axeError"]}")
} else {
println("HTML report saved to: ${reportResult["localDirectory"]}")
}
} catch (e: Exception) {
println("Failed to generate HTML report: ${e.message}")
}
driver.quit()
}
}
}
private fun dismissSystemUIError() {
try {
val wait = WebDriverWait(driver, Duration.ofSeconds(5))
val systemPopup = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'System UI')]")
)
)
if (systemPopup.isDisplayed) {
val waitButton = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'Wait')]")
)
)
waitButton.click()
println("Dismissed the System UI error popup by clicking 'Wait'.")
}
} catch (e: Exception) {
println("No System UI error popup appeared.")
}
}
private fun launchApp() {
try {
driver.terminateApp(APP_PACKAGE)
Thread.sleep(1000) // Give the app time to fully terminate
} catch (e: Exception) {
println("App was not running or failed to terminate: ${e.message}")
}
driver.activateApp(APP_PACKAGE)
try {
val wait = WebDriverWait(driver, Duration.ofSeconds(30))
wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'Screen Name')]")
)
)
} catch (e: Exception) {
dismissSystemUIError()
// Try again after dismissing the error (if not, then fail)
val wait = WebDriverWait(driver, Duration.ofSeconds(30))
wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'Screen Name')]")
)
)
}
}
@BeforeEach
fun beforeEach() {
launchApp()
}
// Now since your session is authenticated you can keep making 'mobile: axeScan' call
// like below in test1 and test2. The scans will be uploaded to the dashboard and also grouped in Developer Hub.
@Test
@Order(1)
fun test1() {
val wait = WebDriverWait(driver, Duration.ofSeconds(10))
val element = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'Screen Name')]")
)
)
println(element.text)
val appiumScanResult = driver.executeScript("mobile: axeScan", axeSettings) as Map<*, *>
val results = appiumScanResult["axeRuleResults"] as List<*>
println("debug: Total results: ${results.size}")
}
@Test
@Order(2)
fun test2() {
val wait = WebDriverWait(driver, Duration.ofSeconds(10))
val element = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[contains(@text, 'Screen Name')]")
)
)
element.click()
driver.findElement(By.xpath("//*[contains(@text, 'announced by a screen')]"))
val appiumScanResult = driver.executeScript("mobile: axeScan", axeSettings) as Map<*, *>
val results = appiumScanResult["axeRuleResults"] as List<*>
println("debug: Total results: ${results.size}")
}
}
Esempio Completo con XCUITest
import io.appium.java_client.ios.IOSDriver
import io.appium.java_client.ios.options.XCUITestOptions
import org.junit.jupiter.api.*
import java.net.URL
import java.time.Duration
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
class IOSMapsDebugTest {
companion object {
private lateinit var driver: IOSDriver
// The axeSettings object still accepts apiKey and axeAccountURL but is not required
// if you are going to make one time @BeforeAll annotated call to 'mobile: axeStartSession'
private lateinit var axeSettings: Map<String, Any>
private const val API_KEY = "<YOUR_API_KEY>"
private const val PROJECT_ID = "<YOUR_DEV_HUB_PROJECT_ID>"
private const val BUNDLE_ID = "com.apple.Maps"
// It is very important to make a call to 'mobile: axeStartSession' inside @BeforeAll annotated
// method to setup your session for posting to Dev Hub.
@JvmStatic
@BeforeAll
fun setUp() {
axeSettings = mapOf(
"tags" to listOf("appium", "qa", "ios"),
"uploadToDashboard" to true,
"ignoreRules" to listOf("ScreenOrientation")
)
// Matching the working sample - minimal capabilities
val options = XCUITestOptions()
.setPlatformName("iOS")
.setAutomationName("AxeXCUITest")
.setUdid("<YOUR_DEVICE_OR_SIMULATOR_UDID>")
.setBundleId(BUNDLE_ID)
.setWdaLaunchTimeout(Duration.ofMillis(960000)) // 16 minutes like the working sample
// NOT specifying platformVersion - let it auto-detect
driver = IOSDriver(URL("http://127.0.0.1:4723/"), options)
// Make one time call to setup your session for posting to Dev Hub.
// This also accepts axeAccountURL in case of private instance.
val axeAuthSettings = mapOf(
"apiKey" to API_KEY,
"projectId" to PROJECT_ID,
"axeAccountURL" to "https://mobile-qa.dequelabs.com"
)
driver.executeScript("mobile: axeStartSession", axeAuthSettings)
}
@JvmStatic
@AfterAll
fun tearDown() {
if (::driver.isInitialized) {
// Generate HTML reports before quitting the driver
driver.executeScript("mobile: axeGenerateHtmlReportAndSummary", emptyMap<String, Any>())
// Alternative: Generate HTML reports to a custom path
// driver.executeScript("mobile: axeGenerateHtmlReportAndSummary", mapOf(
// "outputPath" to "/Users/me/MyReports"
// ))
Thread.sleep(1000)
driver.quit()
}
}
}
private fun launchApp() {
driver.activateApp(BUNDLE_ID)
}
@BeforeEach
fun beforeEach() {
launchApp()
}
// Now since your session is authenticated you can keep making 'mobile: axeScan' call
// like below in test1 and test2. The scans will be uploaded to the dashboard and also grouped in Developer Hub.
@Test
@Order(1)
@Timeout(10)
fun test1ScanMainScreen() {
val appiumScanResult = driver.executeScript("mobile: axeScan", axeSettings) as Map<*, *>
val results = appiumScanResult["axeRuleResults"] as List<*>
println("debug: Total results: ${results.size}")
}
@Test
@Order(2)
@Timeout(10)
fun test2ClickSearchAndScan() {
val appiumScanResult = driver.executeScript("mobile: axeScan", axeSettings) as Map<*, *>
val results = appiumScanResult["axeRuleResults"] as List<*>
println("debug: Total results: ${results.size}")
}
}
