Esempio di test in C#
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
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Android;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Threading;
namespace AppiumTests
{
[TestFixture]
public class AndroidDebugTest
{
private AndroidDriver driver;
// The axeSettings object still accepts apiKey and axeServiceUrl but is not required
// if you are going to make one time [OneTimeSetUp] annotated call to 'mobile: axeStartSession'
private Dictionary<string, object> axeSettings;
private const string API_KEY = "<YOUR_API_KEY>";
private const string PROJECT_ID = "<YOUR_DEV_HUB_PROJECT_ID>";
private const string APP_PACKAGE = "<YOUR_APP_PACKAGE_NAME>";
// It is very important to make a call to 'mobile: axeStartSession' inside [OneTimeSetUp] annotated
// method to setup your session for posting to Dev Hub.
[OneTimeSetUp]
public void SetUp()
{
axeSettings = new Dictionary<string, object>
{
{ "tags", new[] { "appium", "qa" } },
{ "uploadToDashboard", true },
{ "ignoreRules", new[] { "ScreenOrientation" } }
};
var options = new AppiumOptions();
options.PlatformName = "Android";
options.AddAdditionalAppiumOption("deviceName", "Android");
options.AddAdditionalAppiumOption("appPackage", APP_PACKAGE);
options.AddAdditionalAppiumOption("appActivity", ".MainActivity");
options.AddAdditionalAppiumOption("automationName", "AxeUiAutomator2");
options.AddAdditionalAppiumOption("uiautomator2ServerLaunchTimeout", 60000);
options.AddAdditionalAppiumOption("uiautomator2ServerInstallTimeout", 60000);
options.AddAdditionalAppiumOption("adbExecTimeout", 60000);
options.AddAdditionalAppiumOption("ignoreHiddenApiPolicyError", true);
options.AddAdditionalAppiumOption("disableWindowAnimation", true);
options.AddAdditionalAppiumOption("waitForIdle", true);
options.AddAdditionalAppiumOption("commandTimeout", 300);
options.AddAdditionalAppiumOption("noReset", false);
options.AddAdditionalAppiumOption("fullReset", false);
driver = new AndroidDriver(new Uri("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.
var axeAuthSettings = new Dictionary<string, object>
{
{ "apiKey", API_KEY },
{ "projectId", PROJECT_ID }
};
driver.ExecuteScript("mobile: axeStartSession", axeAuthSettings);
}
[OneTimeTearDown]
public void TearDown()
{
if (driver != null)
{
driver.Quit();
}
}
private void DismissSystemUIError()
{
try
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
var systemPopup = wait.Until(drv =>
drv.FindElement(By.XPath("//*[contains(@text, 'System UI')]")));
if (systemPopup.Displayed)
{
var waitButton = wait.Until(drv =>
drv.FindElement(By.XPath("//*[contains(@text, 'Wait')]")));
waitButton.Click();
Console.WriteLine("Dismissed the System UI error popup by clicking 'Wait'.");
}
}
catch (Exception)
{
Console.WriteLine("No System UI error popup appeared.");
}
}
private void LaunchApp()
{
try
{
driver.TerminateApp(APP_PACKAGE);
Thread.Sleep(1000); // Give the app time to fully terminate
}
catch (Exception e)
{
Console.WriteLine($"App was not running or failed to terminate: {e.Message}");
}
driver.ActivateApp(APP_PACKAGE);
try
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(drv => drv.FindElement(By.XPath("//*[contains(@text, 'Screen Name')]")));
}
catch (Exception)
{
DismissSystemUIError();
// Try again after dismissing the error (if not, then fail)
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(drv => drv.FindElement(By.XPath("//*[contains(@text, 'Screen Name')]")));
}
}
[SetUp]
public void 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)]
public void Test1()
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var element = wait.Until(drv =>
drv.FindElement(By.XPath("//*[contains(@text, 'Screen Name')]")));
Console.WriteLine(element.Text);
var appiumScanResult = (Dictionary<string, object>)driver.ExecuteScript("mobile: axeScan", axeSettings);
var results = (List<object>)appiumScanResult["axeRuleResults"];
Console.WriteLine($"debug: Total results: {results.Count}");
}
[Test, Order(2)]
public void Test2()
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
var element = wait.Until(drv =>
drv.FindElement(By.XPath("//*[contains(@text, 'Screen Name')]")));
element.Click();
driver.FindElement(By.XPath("//*[contains(@text, 'announced by a screen')]"));
var appiumScanResult = (Dictionary<string, object>)driver.ExecuteScript("mobile: axeScan", axeSettings);
var results = (List<object>)appiumScanResult["axeRuleResults"];
Console.WriteLine($"debug: Total results: {results.Count}");
}
}
}
Esempio completo con XCUITest
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.iOS;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Threading;
namespace AppiumTests
{
[TestFixture]
public class IOSMapsDebugTest
{
private IOSDriver driver;
// The axeSettings object still accepts apiKey and axeServiceUrl but is not required
// if you are going to make one time [OneTimeSetUp] annotated call to 'mobile: axeStartSession'
private Dictionary<string, object> axeSettings;
private const string API_KEY = "<YOUR_API_KEY>";
private const string PROJECT_ID = "<YOUR_DEV_HUB_PROJECT_ID>";
private const string BUNDLE_ID = "com.apple.Maps";
// It is very important to make a call to 'mobile: axeStartSession' inside [OneTimeSetUp] annotated
// method to setup your session for posting to Dev Hub.
[OneTimeSetUp]
public void SetUp()
{
axeSettings = new Dictionary<string, object>
{
{ "tags", new[] { "appium", "qa", "ios" } },
{ "uploadToDashboard", true },
{ "ignoreRules", new[] { "ScreenOrientation" } }
};
// Matching the working sample - minimal capabilities
var options = new AppiumOptions();
options.PlatformName = "iOS";
options.AddAdditionalAppiumOption("automationName", "AxeXCUITest");
options.AddAdditionalAppiumOption("udid", "<YOUR_DEVICE_OR_SIMULATOR_UDID>");
options.AddAdditionalAppiumOption("bundleId", BUNDLE_ID);
options.AddAdditionalAppiumOption("wdaLaunchTimeout", 960000); // 16 minutes like the working sample
// NOT specifying platformVersion - let it auto-detect
driver = new IOSDriver(new Uri("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.
var axeAuthSettings = new Dictionary<string, object>
{
{ "apiKey", API_KEY },
{ "projectId", PROJECT_ID },
{ "axeServiceUrl", "https://mobile-qa.dequelabs.com" }
};
driver.ExecuteScript("mobile: axeStartSession", axeAuthSettings);
}
[OneTimeTearDown]
public void TearDown()
{
if (driver != null)
{
Thread.Sleep(1000);
driver.Quit();
}
}
private void LaunchApp()
{
driver.ActivateApp(BUNDLE_ID);
}
[SetUp]
public void 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(10000)]
public void Test1_ScanMainScreen()
{
var appiumScanResult = (Dictionary<string, object>)driver.ExecuteScript("mobile: axeScan", axeSettings);
var results = (List<object>)appiumScanResult["axeRuleResults"];
Console.WriteLine($"debug: Total results: {results.Count}");
}
[Test, Order(2), Timeout(10000)]
public void Test2_ClickSearchAndScan()
{
var appiumScanResult = (Dictionary<string, object>)driver.ExecuteScript("mobile: axeScan", axeSettings);
var results = (List<object>)appiumScanResult["axeRuleResults"];
Console.WriteLine($"debug: Total results: {results.Count}");
}
}
}
