Test Example in C#

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard
Not for use with personal data

Be sure to check out the full Appium setup guide with Axe DevTools Mobile if you're just getting started, or more examples of Axe DevTools Mobile for Appium in other languages.

Full Example with 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;

        private static readonly string[] Tags = { "appium", "qa" };
        // ignoreRules is passed directly into each 'mobile: axeScan' call
        private Dictionary<string, object> scanSettings;
        private const string API_KEY = "<DEQUE_APIKEY>";
        private const string PROJECT_ID = "<DEQUE_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 set up your session for posting to Axe Developer Hub
        [OneTimeSetUp]
        public void SetUp()
        {
            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);

            scanSettings = new Dictionary<string, object>
            {
                // tags and ignoreRules are deprecated and will be removed once we fully transition to Axe Developer Hub
                { "ignoreRules", new[] { "ScreenOrientation" } },
                { "tags", Tags }
            };

            // Make a one-time call to set up your session for posting to Axe Developer Hub
            // This also accepts `axeAccountURL` in case of a private instance
            // The `axeSettings` object still accepts `apiKey` with `axeAccountURL`, but is not required
            // if you are going to make one time [OneTimeSetUp] annotated call to 'mobile: axeStartSession'
            var axeSettings = new Dictionary<string, object>
            {
                { "apiKey", API_KEY },
                { "projectId", PROJECT_ID },
                { "axeUploadResults", true } // default - set to false to keep results local only
            };
            driver.ExecuteScript("mobile: axeStartSession", axeSettings);
        }

        [OneTimeTearDown]
        public void TearDown()
        {
            if (driver != null)
            {
                // Generate an HTML report from all accumulated scans before quitting
                // The report aggregates every 'mobile: axeScan' call made during this session
                try
                {
                    var reportSettings = new Dictionary<string, object>
                    {
                        { "scanName", "My Accessibility Report" },
                        { "axeHtmlReportPath", "build/AxeDevToolsMobileResults" }
                    };

                    var reportResult = (Dictionary<string, object>)driver.ExecuteScript(
                        "mobile: axeGenerateHtmlReportAndSummary", reportSettings);

                    if (reportResult.ContainsKey("axeError"))
                    {
                        Console.WriteLine($"Report generation failed: {reportResult["axeError"]}");
                    }
                    else
                    {
                        Console.WriteLine($"HTML report saved to: {reportResult["localDirectory"]}");
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Failed to generate HTML report: {e.Message}");
                }

                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 Developer 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", scanSettings);
            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", scanSettings);
            var results = (List<object>)appiumScanResult["axeRuleResults"];
            Console.WriteLine($"debug: Total results: {results.Count}");
        }
    }
}

Full Example with 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;

        private static readonly string[] Tags = { "appium", "qa", "ios" };
        // ignoreRules is passed directly into each 'mobile: axeScan' call
        private Dictionary<string, object> scanSettings;
        private const string API_KEY = "<DEQUE_APIKEY>";
        private const string PROJECT_ID = "<DEQUE_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 set up your session for posting to Axe Developer Hub
        [OneTimeSetUp]
        public void SetUp()
        {
            // 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);

            scanSettings = new Dictionary<string, object>
            {
                // tags and ignoreRules are deprecated and will be removed once we fully transition to Axe Developer Hub
                { "ignoreRules", new[] { "ScreenOrientation" } },
                { "tags", Tags }
            };

            // Make a one-time call to set up your session for posting to Axe Developer Hub
            // This also accepts `axeAccountURL` in case of a private instance
            // The `axeSettings` object still accepts `apiKey` with `axeAccountURL`, but is not required
            // if you are going to make one time [OneTimeSetUp] annotated call to 'mobile: axeStartSession'
            var axeSettings = new Dictionary<string, object>
            {
                { "apiKey", API_KEY },
                { "projectId", PROJECT_ID },
                { "axeAccountURL", "https://mobile-qa.dequelabs.com" },
                { "axeUploadResults", true } // default - set to false to keep results local only
            };
            driver.ExecuteScript("mobile: axeStartSession", axeSettings);
        }

        [OneTimeTearDown]
        public void TearDown()
        {
            if (driver != null)
            {
                // Generate HTML reports before quitting the driver
                driver.ExecuteScript("mobile: axeGenerateHtmlReportAndSummary", new Dictionary<string, object>());

                // Alternative: Generate HTML reports to a custom path
                // driver.ExecuteScript("mobile: axeGenerateHtmlReportAndSummary", new Dictionary<string, object>
                // {
                //     { "outputPath", "/Users/me/MyReports" }
                // });

                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 Developer Hub.
        [Test, Order(1), Timeout(10000)]
        public void Test1_ScanMainScreen()
        {
            var appiumScanResult = (Dictionary<string, object>)driver.ExecuteScript("mobile: axeScan", scanSettings);
            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", scanSettings);
            var results = (List<object>)appiumScanResult["axeRuleResults"];
            Console.WriteLine($"debug: Total results: {results.Count}");
        }
    }
}