Esempio di test in Kotlin
Not for use with personal data
Si assicuri di consultare la guida completa all'installazione di Appium con axe DevTools Mobile se è agli inizi, o altri 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 axeServiceUrl 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 Dev 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 axeServiceUrl 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) {
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 Dev 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 axeServiceUrl 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 axeServiceUrl in case of private instance.
val axeAuthSettings = mapOf(
"apiKey" to API_KEY,
"projectId" to PROJECT_ID,
"axeServiceUrl" to "https://mobile-qa.dequelabs.com"
)
driver.executeScript("mobile: axeStartSession", axeAuthSettings)
}
@JvmStatic
@AfterAll
fun tearDown() {
if (::driver.isInitialized) {
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 Dev 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}")
}
}
