Goal
Why this matters
Prerequisites
AutomationProperties).Avalonia maps AutomationProperties.AutomationId and control Name directly into Appium selectors. Tests such as AutomationTests.AutomationId rely on FindElementByAccessibilityId (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/AutomationTests.cs:12). Adopt this priority order:
FindElementByAccessibilityId for IDs you own.FindElementByName for localized labels (ElementExtensions.GetName) or menu items.FindElementByXPath as a last resort for structure-dependent lookups (e.g., tray icons on Windows).Annotate controls in XAML with both x:Name and AutomationProperties.AutomationId to keep selectors stable. For templated controls, expose IDs through template parts so they enter the automation tree.
Avalonia’s Appium harness centralizes navigation in TestBase. Each test class inherits and passes the page name, letting TestBase click through the pager with retries (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/TestBase.cs:6). Mirror this structure:
public abstract class CatalogPage : TestBase
{
protected CatalogPage(DefaultAppFixture fixture, string pageName)
: base(fixture, pageName) { }
protected AppiumWebElement Control(string automationId)
=> Session.FindElementByAccessibilityId(automationId);
}
public sealed class WindowPage : CatalogPage
{
public WindowPage(DefaultAppFixture fixture) : base(fixture, "Window") { }
public AppiumWebElement WindowState => Control("CurrentWindowState");
public void SelectState(string id) => Control(id).SendClick();
}
Wrap gestures (click, double-click, modifier shortcuts) in extension methods rather than duplicating Actions blocks. Avalonia’s ElementExtensions.SendClick simulates physical clicks to accommodate controls that resist element.Click() (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs:235).
Virtualized lists only generate visible items. ListBoxTests.Is_Virtualized counts visual children returned by GetChildren to prove virtualization is active (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ListBoxTests.cs:52).
Techniques:
Keys.PageDown) or pointer wheel to materialize items lazily.AppiumWebElement references.public IReadOnlyList<AppiumWebElement> VisibleRows()
=> Session.FindElementByAccessibilityId("BasicListBox").GetChildren();
Combine with helper waits to poll until a desired item appears instead of assuming immediate materialization.
Avalonia ships cross-platform helpers that encapsulate OS-specific attribute quirks:
ElementExtensions.GetComboBoxValue chooses Text on Windows and value on macOS (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs:34).GetCurrentSingleWindow navigates macOS’s duplicated window hierarchy by using a parent XPath (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs:60).TrayIconTests opens nested sessions to access Windows taskbar automation IDs, while macOS uses generic status item XPath (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/TrayIconTests.cs:13).Keep such logic in dedicated helpers; PageObjects should consume a single API regardless of platform. Provide capabilities (e.g., UseOverlayPopups) through fixtures so tests stay declarative (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/OverlayPopupsAppFixture.cs:4).
Animations and popups require waits. The harness uses:
TestBase navigation with Thread.Sleep(1000) between attempts to allow fullscreen transitions (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/TestBase.cs:12).ElementExtensions.OpenWindowWithClick to detect new window handles or child windows, retrying up to ten times (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs:86).external/Avalonia/tests/Avalonia.IntegrationTests.Appium/TrayIconTests.cs:33).Upgrade these patterns using WebDriverWait to poll until predicates succeed:
public static AppiumWebElement WaitForElement(AppiumDriver session, By by, TimeSpan timeout)
{
return new WebDriverWait(session, timeout).Until(driver =>
{
var element = driver.FindElement(by);
return element.Displayed ? element : null;
});
}
Centralize waits so adjustments (timeouts, polling intervals) propagate across the suite.
Large UIs often require multi-step discovery:
MenuTests clicks through root, child, and grandchild items using accessibility IDs and names (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/MenuTests.cs:25). Wrap this into helper methods like OpenMenu("Root", "Child", "Grandchild").GetTrayIconButton first attempts to find the icon, then expands the overflow flyout if absent, handling whitespace quirks in names (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/TrayIconTests.cs:62).OpenWindowWithClick tracks new handles or titles, accommodating macOS fullscreen behavior by ignoring untitled intermediate nodes (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/ElementExtensions.cs:200).Treat these as queries, not static selectors. Accept parameters (icon name, menu path) and apply consistent error messaging when assertions fail.
Selectors often depend on platform capabilities. Decorate tests with [PlatformFact] / [PlatformTheory] to skip unsupported scenarios (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/PlatformFactAttribute.cs:7). This prevents PageObjects from needing conditionals inside every method and ensures pipelines stay green when features diverge.
Group tests requiring special fixtures (e.g., overlay popups) via xUnit collections (external/Avalonia/tests/Avalonia.IntegrationTests.Appium/CollectionDefinitions.cs:4). PageObjects then request the appropriate fixture type through constructor injection.
SendClick actions; some controls ignore element.Click() on macOS.GetSelectedValue). Replace direct selector usage in tests.AutomationId, then Name, then a custom XPath, logging each attempt. Use it to locate menu items with localized labels.ListBox, verifying virtualization by checking GetChildren().Count stays below a threshold while confirming a distant item becomes Selected.Thread.Sleep in one test with a reusable WaitFor method leveraging WebDriverWait. Confirm the test still passes under slower animations by injecting artificial delays.[PlatformFact]. Implement helper methods that throw informative exceptions when run on unsupported platforms.What's next