Skip to content

feat(a11y): complete WASM and Appium validation - #23755

Open
morning4coffe-dev wants to merge 10 commits into
masterfrom
dev/doti/appium-a11y-validation
Open

feat(a11y): complete WASM and Appium validation#23755
morning4coffe-dev wants to merge 10 commits into
masterfrom
dev/doti/appium-a11y-validation

Conversation

@morning4coffe-dev

@morning4coffe-dev morning4coffe-dev commented Jul 14, 2026

Copy link
Copy Markdown
Member

GitHub Issue: closes #23751

PR Type:

✨ Feature

What changed? 🚀

This completes the Skia WebAssembly accessibility object model, including roles, names, relationships, live state, focus and tab order, landmarks, standalone text, hidden-subtree pruning, and virtualized control behavior.

The Appium validation layer now uses canonical accessibility snapshots, actionable element-based differences, strict driver lifecycle handling, and interaction coverage for invoke, toggle, selection, value, and focus behavior. The adapters consistently escape selectors and normalize platform roles, while the dedicated Skia WebAssembly CI path validates the published SamplesApp through ChromeDriver.

Windows UIA and macOS NSAccessibility adapters remain available for host-specific runs. Their baselines must be recorded on matching hosts before those lanes are enabled; the repository does not use synthetic platform baselines.

Validation

  • The focused accessible DataGrid runtime tests pass repeatedly, 3 of 3 per run.
  • All 12 host-independent Appium tests pass.
  • All 8 live WebAssembly Appium snapshot, interaction, and standards tests pass.
  • Skia accessibility projects build successfully.
  • The WebAssembly SamplesApp publishes successfully.
  • The managed macOS accessibility project compiles successfully.

PR Checklist ✅

Copilot AI review requested due to automatic review settings July 14, 2026 08:31
@github-actions github-actions Bot added platform/macos 🍏 Categorizes an issue or PR as relevant to the macOS platform area/automation Categorizes an issue or PR as relevant to project automation kind/documentation labels Jul 14, 2026
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Claude finished @morning4coffe-dev's task in 5m 8s —— View job


Code Review

  • Gather context and read changed files
  • Review infrastructure files
  • Review platform adapters
  • Review test files
  • Review macOS native changes
  • Post inline comments
  • Update summary

Summary

The PR is a well-structured foundation for cross-platform accessibility smoke tests and snapshot baselines. The adapter abstraction, canonical-role normalization, and tree-dumping pipeline are all sound. The macOS native changes (exposing AutomationId through AXIdentifier / accessibilityIdentifier) are the right approach.

Since the PR is explicitly marked draft / not ready for review, findings are filed as early guidance rather than blocking issues.

Issues by severity

Severity Count Topics
Medium 4 Argument-splitting bug in ReadBundleId, tabpaneltabitem semantic mismatch, [CallerFilePath] unreliable on CI, TreatWarningsAsErrors=false + NU190x suppression
Low 5 Dead code (SpawnDotnet/WaitForWindow), WrapperBundleId constant duplication, Thread.Sleep(3s) in baseline test, Assert.Pass() with no assertion, incomplete selector escaping in Mac XPath + WASM CSS
Nit 1 SnapshotComparer.Extras exclusion undocumented

Cross-cutting observations

  • No OutputType=Library: the .csproj declares OutputType=Exe which is unusual for a test project — NUnit tests are typically class-library projects. Verify this is intentional and doesn't cause runner-detection issues.
  • AccessibilityBaselineTests does not inherit AppiumFixtureBase: per-test driver lifecycle is re-implemented inline. That's correct for parameterized snapshot tests (each case needs its own session), but worth noting that the two code paths for driver creation must stay in sync if initialization logic changes.
  • macOS native changes look correct: uno_accessibility_update_identifier wired end-to-end (C# P/Invoke → Objective-C property → accessibilityIdentifier / NSAccessibilityIdentifierAttribute), with the required accessibilityAttributeNames override so Appium/XCUITest's legacy attribute path finds the element. The approach in UNOAccessibility.m is the standard workaround for custom NSAccessibilityElement subclasses not being found by XCUITest's identifier shortcut.

try
{
var psi = new ProcessStartInfo("/usr/bin/defaults",
$"read \"{plist.Replace("\"", "\\\"")}\" CFBundleIdentifier")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argument-splitting bug / potential injection via Arguments string property.

ReadBundleId uses the Arguments string overload of ProcessStartInfo, not ArgumentList. The CLR splits that string on whitespace/double-quotes, so a path with spaces will break even with the \" escaping applied, and characters like `, $, etc. will be passed through to defaults verbatim (no shell, but still mis-split).

Use ArgumentList instead:

var psi = new ProcessStartInfo("/usr/bin/defaults")
{
    UseShellExecute = false,
    RedirectStandardOutput = true,
};
psi.ArgumentList.Add("read");
psi.ArgumentList.Add(plist);
psi.ArgumentList.Add("CFBundleIdentifier");

This is safe for any path the OS considers valid. Fix this →

=> path.EndsWith(".app", StringComparison.OrdinalIgnoreCase)
|| path.TrimEnd('/').EndsWith(".app", StringComparison.OrdinalIgnoreCase);

private static Process SpawnDotnet(string dllPath, string sampleQuery)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code: SpawnDotnet and WaitForWindow are defined but never called.

SpawnDotnet (line 396) and WaitForWindow (line 451) are defined but have no call sites in this file. CreateDriver switched to the wrapper-bundle strategy and the code paths that would have called these were removed. Delete both methods to prevent confusion about whether the .dll-launch flow is still supported. Fix this →


const string executableName = "SamplesAppAppium";
const string bundleId = "io.platform.uno.SamplesAppAppium";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WrapperBundleId constant is duplicated here as a local constant.

The class-level constant WrapperBundleId = "io.platform.uno.SamplesAppAppium" (line 22) and the local const string bundleId = "io.platform.uno.SamplesAppAppium" here must be kept in sync manually. Reuse the class constant:

Suggested change
const string executableName = "SamplesAppAppium";
string bundleId = WrapperBundleId;

// `do shell script` routes through the user's login shell, escaping
// the sandboxed launchd domain we inherited from VS Code's helper
// process tree.
psi.ArgumentList.Add($"do shell script \"/usr/bin/open -n '{bundlePath}'\"");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shell script in LaunchBundle embeds bundlePath without single-quote escaping.

The osascript argument is:

$"do shell script \"/usr/bin/open -n '{bundlePath}'\""

If bundlePath contains a ' (single quote), the AppleScript string breaks. The temp path from Path.GetRandomFileName() won't contain one, but this is fragile. Escape the path for AppleScript string context:

var escapedPath = bundlePath.Replace("'", "'\\''");
psi.ArgumentList.Add($"do shell script \"/usr/bin/open -n '{escapedPath}'\"");

["menubar"] = "menubar",
["separator"] = "separator",
["status"] = "statusbar",
["tab"] = "tab",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantic mismatch: tabpanel should not map to tabitem.

A tabpanel is the content pane associated with a tab, not the tab trigger itself. Mapping it to "tabitem" will silently collapse two structurally distinct elements into the same canonical role, making cross-platform diffs misleading.

"tabitem" is the correct mapping for the "tab" role (the clickable tab header). "tabpanel" should map to a distinct canonical role — or if the snapshot suite doesn't model it, it should fall through to the verbatim lowercased value so it surfaces clearly in diffs.

Suggested change
["tab"] = "tab",
["tabpanel"] = "tabpanel",

return Path.Combine(root, flavor, snapshotId + ".json");
}

private static string SourceTreeSnapshotsDir([CallerFilePath] string? thisFile = null)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CallerFilePath] embeds the build-machine path, not the runtime path — unreliable on CI.

[CallerFilePath] is a compile-time constant injected by the compiler. On a CI agent that builds on machine A and tests on machine B (or in a Docker container), thisFile will be the absolute path on machine A, which won't exist at runtime on machine B.

The env-var override (UNO_APPIUM_SNAPSHOTS_DIR) works around this for CI, but relying on [CallerFilePath] as a "preferred" runtime path is misleading. Consider flipping the precedence: use the env var unconditionally, and fall back to a path relative to the test output directory (TestContext.CurrentContext.TestDirectory) when the env var is absent. Fix this →


// Give the SamplesApp shell a moment to navigate and lay out the
// requested sample before we snapshot.
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(3));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded 3-second sleep is fragile for CI and over-waits on fast machines.

On a slow CI agent the sample might not be ready in 3 s; on a fast machine you waste 3 s every run. The base class already has WaitForAutomationId which polls via WebDriverWait. Use it to wait for a known stable element from the target sample instead:

// Wait until a known root element of the sample is visible before snapshotting.
var wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(15))
{
    PollingInterval = TimeSpan.FromMilliseconds(250),
};
wait.IgnoreExceptionTypes(typeof(OpenQA.Selenium.NoSuchElementException));
wait.Until(d => d.FindElement(adapter.ByAutomationId("<known-root-element-id>")));

If no stable root element ID exists for the sample yet, add one to the XAML. Fix this →

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an Appium-driven accessibility validation harness for SamplesApp (smoke tests + golden-file accessibility-tree snapshots) and extends the macOS Skia accessibility backend to expose AutomationProperties.AutomationId via the native NSAccessibility identifier so Appium Mac2/XCUITest can locate elements consistently.

Changes:

  • Expose AutomationId on macOS Skia through -accessibilityIdentifier / AXIdentifier and add a native update hook.
  • Add SamplesApp.AppiumTests with platform adapters (Win32 UIA, macOS NSAccessibility, WASM DOM/ARIA), tree capture/normalize/serialize infrastructure, and baseline comparison tests.
  • Add documentation for running/recording Appium snapshots and line-ending normalization for committed JSON baselines.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Uno.UI.Runtime.Skia.MacOS/UnoNativeMac/UnoNativeMac/UNOAccessibility.m Adds identifier exposure through NSAccessibility and a native update function.
src/Uno.UI.Runtime.Skia.MacOS/UnoNativeMac/UnoNativeMac/UNOAccessibility.h Declares unoIdentifier and the new update API.
src/Uno.UI.Runtime.Skia.MacOS/Native/NativeUno.cs Adds P/Invoke for uno_accessibility_update_identifier.
src/Uno.UI.Runtime.Skia.MacOS/Accessibility/MacOSAccessibility.cs Pushes AutomationId into the native accessibility element.
src/SamplesApp/SamplesApp.AppiumTests/Tests/AutomationTreeSmokeTests.cs Adds cross-platform smoke tests validating tree presence and basic interaction.
src/SamplesApp/SamplesApp.AppiumTests/Tests/AccessibilityBaselineTests.cs Adds golden-file snapshot comparisons with optional record mode.
src/SamplesApp/SamplesApp.AppiumTests/Snapshots/.gitattributes Forces LF for committed snapshot JSON files.
src/SamplesApp/SamplesApp.AppiumTests/SamplesApp.AppiumTests.csproj New Appium/NUnit-based test project.
src/SamplesApp/SamplesApp.AppiumTests/README.md Documents prerequisites, platform setup, and baseline workflows.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/WindowsAdapter.cs Windows UIA adapter for role/name/value/pattern extraction and locators.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/WasmAdapter.cs WASM adapter using DOM/ARIA + xamlname-based locators.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/TreeDumper.cs Walks the automation tree and builds normalized snapshot nodes.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/SnapshotSerializer.cs Deterministic JSON serialization for snapshots.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/SnapshotComparer.cs Structural diffing for snapshots.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/MacAdapter.cs macOS Mac2 adapter with wrapper-bundle launching and AX queries.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/IPlatformAdapter.cs Common adapter contract.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/CanonicalRole.cs Normalizes platform-specific roles into shared tokens.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/AppiumPlatform.cs Platform selection and env-var configuration.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/AppiumFixtureBase.cs Shared fixture lifecycle and wait helpers.
src/SamplesApp/SamplesApp.AppiumTests/Infrastructure/AccessibilityNode.cs Platform-neutral accessibility node model for snapshots.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +538 to +548
var automationId = owner is not null
? AutomationProperties.GetAutomationId(owner)
: null;
if (string.IsNullOrEmpty(automationId))
{
automationId = peer.GetAutomationId();
}
if (!string.IsNullOrEmpty(automationId))
{
NativeUno.uno_accessibility_update_identifier(handle, automationId);
}
Comment on lines +212 to +222
public By ByAutomationId(string automationId)
{
// Mac2's MobileBy.AccessibilityId maps to XCUIElement.identifier, which
// only works for elements XCUITest has fully snapshotted into its own
// element store. Custom NSAccessibilityElement subclasses (like Uno's
// UNOAccessibilityElement) are reachable via XPath but not always via
// the identifier shortcut, so we filter by the underlying AXIdentifier
// attribute that Uno publishes from AutomationProperties.AutomationId.
var escaped = automationId.Replace("'", "&apos;");
return By.XPath($"//*[@AXIdentifier='{escaped}']");
}
_spawnedApp.Kill(entireProcessTree: true);
}

TerminateBundle(WrapperBundleId);
Comment on lines +41 to +43
// TextBox template parts
"TextBox",
// Other framework-injected template parts that aren't sample content.
Comment on lines +42 to +47
public string GetRole(IWebElement element)
{
// UIAutomation surfaces the control type as LocalizedControlType / ControlType.
var localized = element.GetAttribute("LocalizedControlType");
return string.IsNullOrWhiteSpace(localized) ? string.Empty : localized.ToLowerInvariant();
}
// We're not asserting a side-effect (the button is purely a target for
// visibility toggles by sibling buttons); the assertion is that
// Click() round-trips through the driver without throwing.
Assert.Pass();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.Pass() means this test can never fail — it verifies nothing.

The comment says "the assertion is that Click() round-trips without throwing." That is the implicit behavior of any unguarded call; NUnit will fail the test automatically if Click() throws. The explicit Assert.Pass() call is redundant and signals to readers that something was verified, which is misleading.

Either remove the Assert.Pass() and add a meaningful assertion (e.g. re-query the element's enabled state or check a side effect), or add a [Description] attribute that clearly documents what is being exercised so reviewers don't assume the absence of a side-effect check is an oversight. Fix this →

<RollForward>Major</RollForward>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TreatWarningsAsErrors=false and silent NoWarn additions.

TreatWarningsAsErrors=false is never set like this in other test projects in the repo — they inherit the CI gate from Directory.Build.props. Setting it to false here permanently weakens the warning policy for this project on CI.

NU1903/NU1902 are vulnerability-related NuGet warnings; suppressing them silently hides package-vulnerability alerts. If a specific package version is intentionally pinned below the advisory threshold, document that as a comment instead of suppressing globally.

CS1591 (missing XML doc) is fine to suppress in test projects, but prefer a #pragma warning disable CS1591 scoped at the file level, or omit altogether since test assemblies are not published.

Consider removing TreatWarningsAsErrors=false and addressing the NU190x warnings individually if they arise. Fix this →

// the identifier shortcut, so we filter by the underlying AXIdentifier
// attribute that Uno publishes from AutomationProperties.AutomationId.
var escaped = automationId.Replace("'", "&apos;");
return By.XPath($"//*[@AXIdentifier='{escaped}']");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XPath attribute injection: &apos; escaping is incomplete.

The current escaping only replaces ' with &apos;:

var escaped = automationId.Replace("'", "&apos;");
return By.XPath($"//*[@AXIdentifier='{escaped}']");

An automationId containing " will break out of the XPath attribute context: @AXIdentifier='foo"bar' is valid XPath, but @AXIdentifier='"' terminates the outer string and mangles the query. A fully correct approach uses XPath concat() to handle both quote types:

// Simple case: no double-quote, use double-quoted attribute
if (!automationId.Contains('"'))
    return By.XPath($"//*[@AXIdentifier=\"{automationId.Replace("'", "&apos;")}\"]");
// Fallback: build concat() expression
var parts = automationId.Split('"');
var concat = string.Join(", '\"', ", parts.Select(p => $"'{p}'"));
return By.XPath($"//*[@AXIdentifier=concat({concat})]");

In practice, AutomationIds won't contain quotes, but defensive correctness prevents surprise failures. Fix this →

}
}

private static string Escape(string value) => value.Replace("\"", "\\\"");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS attribute selector injection: Escape only handles ", not ] or \.

private static string Escape(string value) => value.Replace("\"", "\\\"");

A value containing ] terminates the CSS attribute selector early: [xamlname="foo]bar"] becomes [xamlname="foo] — the bar"] part is parsed as a tag selector. The CSS spec requires \ to escape ] and \ itself inside attribute selectors.

Minimal fix:

private static string Escape(string value)
    => value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("]", "\\]");

Again, developer-controlled AutomationIds are unlikely to contain these, but defensive correctness avoids obscure test failures. Fix this →

/// </summary>
public static class SnapshotComparer
{
public static SnapshotDiff Compare(AccessibilityNode expected, AccessibilityNode actual)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extras dict is silently excluded from comparison — this should be documented on the method.

AccessibilityNode.Extras is populated by all three adapters and serialized to JSON, but SnapshotComparer.Compare never touches it. A future maintainer reading the snapshot JSON will see extras present but won't understand why diffs on those fields never fire. Add a note to the Compare XML doc (or an inline comment at the call site) explaining the deliberate exclusion:

/// <remarks>
/// <see cref="AccessibilityNode.Extras"/> is intentionally excluded from the
/// comparison — it holds platform-specific raw attributes for debugging only
/// and should not gate snapshot equality.
/// </remarks>

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23755/wasm-skia-net9/index.html

morning4coffe-dev and others added 4 commits July 30, 2026 18:00
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added platform/wasm 🌐 Categorizes an issue or PR as relevant to the WebAssembly platform area/build Categorizes an issue or PR as relevant to build infrastructure labels Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Claude finished @morning4coffe-dev's task in 5m 0s —— View job


Code Review

  • Read changed files
  • Review infrastructure
  • Review platform adapters
  • Review test files
  • Review macOS/WASM native changes
  • Post inline comments
  • Update summary

Summary

The PR is still in draft state so these are early-guidance findings. The prior review pass covered the main medium-severity issues well; these comments add four new items not previously filed.

New findings

Severity File Finding
Medium CanonicalRole.cs:50 s_win32["tabitem"]"tabpanel" is a semantic mismatch — WinUI TabItem is the clickable tab header (ARIA "tab"), not the content pane. s_win32["tab"] should also be "tablist", not "tab".
Medium MacAdapter.cs:421 sampleQuery embedded in the bash wrapper script without shell-escaping — a value containing ", $, or backtick breaks or injects into the script.
Low WindowsAdapter.cs:213 AddIfTrue private helper is dead code — no call sites remain after GetSupportedPatterns was refactored.
Low WasmAccessibilityStandardsTests.cs:19 Wrong-platform guard throws InvalidOperationException (test ERROR) instead of Assert.Inconclusive (test SKIP/inconclusive).

Cross-cutting observations

  • SnapshotPaths.cs [CallerFilePath]: the prior review already flagged this. The env-var override (UNO_APPIUM_SNAPSHOTS_DIR) is the right CI path; the compile-time [CallerFilePath] fallback only works when build and test run on the same machine.
  • TreatWarningsAsErrors=false + NU190x suppression in .csproj: also flagged in the prior review. The vulnerability NuGet warnings (NU1902/NU1903) should not be globally suppressed — if a specific package version is intentionally below a vulnerability advisory, document the reason inline instead.
  • SnapshotComparer.Compare silently skips Extras: the prior review requested a doc comment explaining the intentional exclusion. Still missing.
  • s_win32 tab-container vs WASM tablist: the s_win32 dict has no "tablist" entry at all, while s_wasm correctly maps "tablist""tablist". Once "tab" is corrected to "tablist" in s_win32, cross-platform snapshot comparison for tab strips will be meaningful.

exec ""{dotnetPath}"" ""{dllPath}""
"
: $@"#!/bin/bash
exec ""{dotnetPath}"" ""{dllPath}"" ""{sampleQuery}""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: sampleQuery embedded in bash exec line without shell-escaping (fourth pass — still unaddressed).

A sampleQuery value containing ", $, or backtick produces a malformed bash script. For example, sample=Category/My"Test" becomes:

exec "/path/dotnet" "/path/app" "sample=Category/My"Test""

The shell splits this as three separate tokens — the argument the app receives is wrong.

Suggested change
exec ""{dotnetPath}"" ""{dllPath}"" ""{sampleQuery}""
static string BashSingleQuote(string s) => "'" + s.Replace("'", "'\\''") + "'";
var script = string.IsNullOrEmpty(sampleQuery)
? $@"#!/bin/bash
exec ""{dotnetPath}"" ""{dllPath}""
"
: $@"#!/bin/bash
exec ""{dotnetPath}"" ""{dllPath}"" {BashSingleQuote(sampleQuery)}
";

}
if (!string.IsNullOrEmpty(automationId))
{
NativeUno.uno_accessibility_update_identifier(handle, automationId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: Stale native identifier when AutomationId is cleared (fourth pass — still unaddressed).

uno_accessibility_update_identifier is only called when automationId is non-empty. If an element's AutomationId is later removed (set to "" or null), the native UNOAccessibilityElement keeps its old identifier indefinitely — Appium/XCUITest can then resolve the wrong element by the stale ID.

Call unconditionally so an empty string clears the identifier on the native side — the same pattern already used by uno_accessibility_update_help and uno_accessibility_update_description:

Suggested change
NativeUno.uno_accessibility_update_identifier(handle, automationId);
NativeUno.uno_accessibility_update_identifier(handle, automationId ?? string.Empty);

<RollForward>Major</RollForward>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: TreatWarningsAsErrors=false weakens the repo-wide CI gate; NU1902/NU1903 silences vulnerability alerts (fourth pass — still unaddressed).

Directory.Build.props sets the repo-wide warning policy. Overriding it per-project with false means this project's warnings never break CI, diverging from every other project in the solution.

NU1902 and NU1903 are NuGet's moderate/high-severity vulnerability warnings. Suppressing them globally means any future dependency audit will silently pass even when a known-vulnerable package version is pinned.

  • Remove TreatWarningsAsErrors=false and let the root policy apply.
  • Remove NU1902;NU1903 from NoWarn. If a specific transitive dependency triggers these today and cannot be upgraded, document the reason with an inline comment on the <PackageReference> entry instead of suppressing globally.
  • CS1591 (missing XML doc) is acceptable to suppress in a test assembly.

@@ -1,4 +1,5 @@
using Uno.Extensions;
using System;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: using System; is unused — CS8019 build failure on CI (fourth pass — still unaddressed).

Nothing in this file references any System type directly. With TreatWarningsAsErrors active on CI, this produces CS8019 and breaks the build.

Suggested change
using System;
using Uno.Extensions;

@@ -1,12 +1,19 @@
using System;
using System.Reflection;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: using System.Reflection; is unused — CS8019 build failure on CI (fourth pass — still unaddressed).

No type from System.Reflection is referenced anywhere in this file. With TreatWarningsAsErrors active on CI, this produces CS8019 and breaks the main solution build.

Suggested change
using System.Reflection;
using System;

};

private static string EscapeCssAttribute(string value)
=> value.Replace("\\", "\\\\").Replace("\"", "\\\"");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: EscapeCssAttribute still does not escape ] — CSS attribute selector injection (fourth pass — still unaddressed).

A xamlautomationid value containing ] terminates the attribute selector early:

[xamlautomationid="foo]bar"]  →  [xamlautomationid="foo]  bar"]  (garbage)

The CSS spec requires \ and ] to be escaped inside attribute value strings.

Suggested change
=> value.Replace("\\", "\\\\").Replace("\"", "\\\"");
private static string EscapeCssAttribute(string value)
=> value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("]", "\\]");

if (Session.Options.Platform != AppiumPlatform.Wasm)
{
throw new InvalidOperationException(
$"{nameof(WasmAccessibilityStandardsTests)} requires {AppiumTestOptions.EnvVarPlatform}=wasm.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: Wrong-platform guard throws InvalidOperationException (test ERROR) instead of Assert.Inconclusive (test SKIP) (fourth pass — still unaddressed).

When this test runs against a non-WASM session, NUnit/MSTest records it as an unexpected ERROR rather than a deliberate skip, polluting the test report with noise.

Suggested change
$"{nameof(WasmAccessibilityStandardsTests)} requires {AppiumTestOptions.EnvVarPlatform}=wasm.");
Assert.Inconclusive($"{nameof(WasmAccessibilityStandardsTests)} requires {AppiumTestOptions.EnvVarPlatform}=wasm.");

}

return violations.sort().join('\n');
""") as string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: violations may be null — as string returns null when script returns non-string (fourth pass — still unaddressed).

ExecuteScript returns object?. If the script throws on the JS side or returns null, as string yields null. The .Should().BeEmpty() call on line 114 will then throw NullReferenceException with no useful diagnostic.

Suggested change
""") as string;
""") as string ?? string.Empty;

{
}

private static void AddIfTrue(IWebElement element, string attr, string pattern, List<string> sink)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: AddIfTrue is dead code — no call sites remain (fourth pass — still unaddressed).

This private helper has no call sites in the file after GetSupportedPatterns was refactored to inline the check. Remove it to avoid confusion.

Suggested change
private static void AddIfTrue(IWebElement element, string attr, string pattern, List<string> sink)

{
if (_isDisposed)
var generation = ++_politeAnnouncementGeneration;
_politeDebounceTimer = new Timer(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: Timer created without disposing the prior instance — potential timer leak (fourth pass — still unaddressed).

_politeDebounceTimer is overwritten without calling ?.Dispose() first. Add defensive disposal before creating the new timer:

Suggested change
_politeDebounceTimer = new Timer(
private void SchedulePoliteAnnouncement(int delay)
{
var generation = ++_politeAnnouncementGeneration;
_politeDebounceTimer?.Dispose();
_politeDebounceTimer = new Timer(
_ => RunOnDispatcher(() => FlushPoliteAnnouncement(generation)),
null,
delay,
Timeout.Infinite);
}

Apply the same pattern to ScheduleAssertiveAnnouncement (line ~890).

var content = _pendingPoliteContent;
_pendingPoliteContent = null;
var generation = ++_politeGeneration;
_politeDebounceTimer = new Timer(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: Timer created without disposing the prior instance — same pattern as SkiaAccessibilityBase (fourth pass — still unaddressed).

_politeDebounceTimer is overwritten without ?.Dispose(). Add defensive disposal before assigning the new timer:

Suggested change
_politeDebounceTimer = new Timer(
private void SchedulePolite(int delay)
{
var generation = ++_politeGeneration;
_politeDebounceTimer?.Dispose();
_politeDebounceTimer = new Timer(
_ => NativeDispatcher.Main.Enqueue(() => FlushPolite(generation)),
null,
delay,
Timeout.Infinite);
}

Apply the same pattern to ScheduleAssertive (line ~174).

=> GetOrCreateRelationshipCollection<UIElement>(element, ControlledPeersProperty, AutomationElementIdentifiers.ControlledPeersProperty);

internal static IList<UIElement> TryGetControlledPeers(DependencyObject element)
=> element.GetValue(ControlledPeersProperty) as IList<UIElement>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: TryGetControlledPeers may dereference a null element.

FrameworkElementAutomationPeer.GetControlledPeersCore calls this with Owner as UIElement, which can be null when Owner is not a UIElement. The current implementation would throw NullReferenceException on element.GetValue(...).

Suggested change
=> element.GetValue(ControlledPeersProperty) as IList<UIElement>;
internal static IList<UIElement>? TryGetControlledPeers(DependencyObject? element)
=> element?.GetValue(ControlledPeersProperty) as IList<UIElement>;

allElements.forEach((el: HTMLElement) => {
if (el !== modalElement && !modalElement.contains(el)) {
let current: HTMLElement | null = modalElement;
while (current && current !== semanticsRoot) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: current && is always true at loop entry — redundant condition (fourth pass — still unaddressed).

current is assigned modalElement on line 35, and the outer if (semanticsRoot && modalElement) guard already ensures it is non-null at entry. At each iteration end, current = parent only executes after the if (!parent) { break; } guard fires — so current is never null when the condition is re-evaluated.

Suggested change
while (current && current !== semanticsRoot) {
while (current !== semanticsRoot) {

Directory.CreateDirectory(macOS);

const string executableName = "SamplesAppAppium";
const string bundleId = "io.platform.uno.SamplesAppAppium";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: const string bundleId duplicates the class-level WrapperBundleId constant (fourth pass — still unaddressed).

The literal "io.platform.uno.SamplesAppAppium" is already defined as WrapperBundleId (line 21). If one is updated the other silently diverges.

Suggested change
const string bundleId = "io.platform.uno.SamplesAppAppium";
const string executableName = "SamplesAppAppium";
string bundleId = WrapperBundleId;

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 85 out of 86 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.wasm.cs:2

  • using System; is unused in this file (no System types referenced). With code-style analyzers enabled in CI, unnecessary usings can fail the build; please remove it.
    src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Automation/Given_AccessibilityAnnouncements.cs:3
  • using System.Reflection; appears unused in this test file. Please remove it to avoid analyzer failures (unnecessary using directives).
    src/Uno.UI.Runtime.Skia.WebAssembly.Browser/ts/Runtime/FocusTrap.ts:54
  • inert is not supported uniformly across all browsers. Switching from the previous tabindex="-1" approach to inert only can allow keyboard focus to escape the modal on browsers that ignore inert (background semantic elements remain tabbable/click-focusable even though they’re aria-hidden). Consider feature-detecting inert and falling back to the prior tabindex-based hiding (or another cross-browser focus-blocking strategy) when inert isn’t available.

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23755/wasm-skia-net9/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-23755/docs/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 225242 found UI Test snapshots differences: skia-linux-screenshots: 57, skia-windows-screenshots: 2348, wasm: 11

Details
  • skia-linux-screenshots: 57 changed over 2348

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Examples.png-dark
    • Examples.png
    • ExpanderColorValidationPage.png-dark
    • ExpanderColorValidationPage.png
    • ContextRequested.png-dark
    • ContextRequested.png
    • DropDownButtonPage.png-dark
    • DropDownButtonPage.png
    • DisplayInformation.png-dark
    • ImageIconPage.png-dark
    • ClipboardTests.png-dark
    • ElementLevelTheme.png-dark
    • ElementLevelTheme.png
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • Focus_FocusVisual_Properties.png-dark
    • Buttons.png-dark
    • Buttons.png
  • skia-windows-screenshots: 2348 changed over 2394

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • AnimatedIconPage.png
    • ApplicationViewSizing.png
    • AppWindowTitleBar Properties.png
    • Attributed_text_Simple.png
    • AutoBorderStretchwithtopmargin.png-dark
    • AutoSizedTopLeft.png
    • BackGesture.png-dark
    • BasicAutoSuggestBox.png-dark
    • Battery.png-dark
    • Battery.png
    • BitmapIcon_Monochromatic.png-dark
    • BitmapIcon_Monochromatic.png
    • BorderLeftwithmargins.png-dark
    • BorderLeftwithmargins.png
    • Border_BorderThickness.png-dark
    • Border_BorderThickness.png
    • Border_Corner_Overlap.png-dark
    • Border_Corner_Overlap.png
    • Border_With_TranslateTransform.png-dark
    • Border_With_TranslateTransform.png
  • wasm: 11 changed over 1076

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Minimal
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Ogg_Extension
    • UITests.Windows_UI_Xaml_Controls.CalendarView.CalendarView_Theming
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • SamplesApp.Windows_UI_Xaml_Controls.ListView.ListViewSelectedItems
    • UITests.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_NavigationProperties
    • UITests.Shared.Microsoft_UI_Xaml_Controls.ExpanderTests.WinUIExpanderPage
    • UITests.Uno_Web.Http.CookieManagerTests
    • UITests.Windows_UI_Xaml_Media_Animation.ColorAnimation_Background
    • Uno.UI.Samples.Content.UITests.WebView.WebView_AnchorNavigation
    • SamplesApp.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_EnableDevTools

@unodevops

Copy link
Copy Markdown
Contributor

⚠️⚠️ The build 225242 has failed on Uno.UI - CI.

Copilot AI review requested due to automatic review settings August 1, 2026 08:59
@morning4coffe-dev morning4coffe-dev changed the title feat(a11y): Complete WASM and Appium validation feat(a11y): complete WASM and Appium validation Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @morning4coffe-dev's task in 4m 58s —— View job


Code Review (pass 6)

  • Read changed files and gather context
  • Review infrastructure files (MacAdapter, CanonicalRole, WasmAdapter, WindowsAdapter)
  • Review test files and CI configuration
  • Review WASM/native accessibility changes
  • Post inline comments
  • Update summary

Summary

This pass is a significant improvement over previous rounds. Every issue flagged across the five prior reviews has been addressed in the latest commits.

All previously flagged issues are resolved ✅

Was Issue Status
High ReadBundleId throws on missing key (defaults read exits 1) Fixed — throwOnNonZeroExit: false
High IsBundleRunning propagates osascript exceptions instead of returning false Fixed — throwOnNonZeroExit: false + diagnostic out param
Medium RunProcess deadlock (stdout/stderr read after WaitForExit) Fixed — async ReadToEndAsync before WaitForExit
Medium sampleQuery embedded in bash script without shell-escaping Fixed — BashSingleQuote helper + test
Medium bundleId / sampleQuery injection in AppleScript string literals Fixed — ToAppleScriptStringLiteral helper
Medium CanonicalRole Win32 tab/tabitem semantic mismatch Fixed — ["tab"] = "tablist", ["tabitem"] = "tab" + test
Medium EscapeCssAttribute missing ] escape Fixed — Replace("]", "\\]") + test
Medium MacOSAccessibility stale identifier when AutomationId cleared Fixed — unconditional call with null allowed
Medium TreatWarningsAsErrors=false + NU1902/NU1903 suppression Removed
Low Wrong-platform guard throws InvalidOperationException instead of Assert.Inconclusive Fixed
Low violations nullable as string NRE Fixed — if (scriptResult is not string violations) guard
Low WrapperBundleId constant duplicated Removed
Low AddIfTrue dead code in WindowsAdapter Removed
Low using System; unused in TextBox.wasm.cs (CS8019) Removed
Low using System.Reflection; unused in Given_AccessibilityAnnouncements.cs (CS8019) Removed
Low Timer-without-dispose in SkiaAccessibilityBase Fixed — ?.Dispose() added
Low Timer-without-dispose in LiveRegionManager Fixed — ?.Dispose() added
Low TryGetControlledPeers null dereference Fixed — ?.GetValue(...)
Nit FocusTrap.ts current && always-true condition Fixed

New in this pass: AdapterEscapingTests.cs and CanonicalRoleTests.cs add host-independent unit tests that cover the bash/CSS escaping and tab role mapping fixes — good addition.

Remaining issues (two)

Severity File Finding
Low WindowsAdapter.cs:51 LocalizedControlType tried before ControlType — Windows baselines are locale-dependent and will diverge on non-English CI
Nit SnapshotComparer.cs:45 No doc comment explaining that Extras is intentionally excluded from comparison

The LocalizedControlType ordering is the only substantive remaining concern: any Windows baseline recorded on an English-language CI agent will fail on a German/French/other-locale agent without any real regression, because GetRole returns the localized string. Swapping the lookup order to prefer ControlType (and adding the corresponding ControlType.* entries to s_win32) would close this gap before Windows baselines are committed.

element.SendKeys(value);
}

public string GetRole(IWebElement element) => GetAttributeAny(element, "LocalizedControlType", "ControlType") ?? string.Empty;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: LocalizedControlType is locale-dependent — baselines will diverge on non-English Windows hosts.

LocalizedControlType is tried first, which returns the human-readable control type in the OS UI language ("button" in English, "Schaltfläche" in German). Committed baselines recorded on an English Windows CI agent will fail on any other locale without any real accessibility regression.

ControlType returns the culture-invariant programmatic name (e.g. "ControlType.Button"). Swap the lookup order so it is preferred:

Suggested change
public string GetRole(IWebElement element) => GetAttributeAny(element, "LocalizedControlType", "ControlType") ?? string.Empty;
public string GetRole(IWebElement element) => GetAttributeAny(element, "ControlType", "LocalizedControlType") ?? string.Empty;

This also requires adding ControlType.* entries to CanonicalRole.s_win32 (e.g. ["ControlType.Button"] = "button") and keeping the existing LocalizedControlType-keyed entries as case-insensitive fallbacks so existing English recordings do not immediately break.

/// </summary>
public static class SnapshotComparer
{
public static SnapshotDiff Compare(AccessibilitySnapshot expected, AccessibilitySnapshot actual)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Extras intentionally excluded from comparison — document it.

AccessibilityNode.Extras is populated by all three adapters and serialized to the snapshot JSON, but Compare never inspects it. A future maintainer reading the snapshot file will see extras present and wonder why diffs on those fields never fire.

Suggested change
public static SnapshotDiff Compare(AccessibilitySnapshot expected, AccessibilitySnapshot actual)
/// <summary>
/// Compares committed canonical snapshots by element id and reports explicit,
/// actionable semantic diffs. <see cref="AccessibilityElementSnapshot.Extras"/> is
/// intentionally excluded — it holds platform-specific raw attributes for debugging
/// only and must not gate snapshot equality.
/// </summary>
public static SnapshotDiff Compare(AccessibilitySnapshot expected, AccessibilitySnapshot actual)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 89 out of 90 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/Uno.UI/UI/Xaml/Automation/AutomationProperties.cs:548

  • These TryGet* helpers can return null via as casts, but their return types are non-nullable. This makes nullability analysis incorrect and hides the fact callers must handle the unset case.
    src/Uno.UI/UI/Xaml/Automation/AutomationProperties.cs:435
  • TryGetControlledPeers uses an as cast that can return null, but its return type is non-nullable. This makes the API contract misleading (especially in nullable-enabled builds) and contradicts the TryGet* naming convention.

This issue also appears on line 538 of the same file.
src/Uno.UI/UI/Xaml/Automation/Peers/PasswordBoxAutomationPeer.cs:92

  • MaskPasswordValue defensively handles null (via password ?? string.Empty), but its parameter type is non-nullable. Making it string? better reflects the intended contract and avoids nullable-analysis warnings at call sites like (Owner as PasswordBox)?.Password.

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23755/wasm-skia-net9/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-23755/docs/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 225355 found UI Test snapshots differences: skia-linux-screenshots: 57, skia-windows-screenshots: 2348, wasm: 11

Details
  • skia-linux-screenshots: 57 changed over 2348

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Gamepad_CurrentReading.png-dark
    • Gamepad_CurrentReading.png
    • Gamepad_Enumeration.png-dark
    • Gamepad_Enumeration.png
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • Examples.png-dark
    • Examples.png
    • ExpanderColorValidationPage.png-dark
    • ExpanderColorValidationPage.png
    • Focus_FocusVisual_Properties.png-dark
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • ContextRequested.png-dark
    • ContextRequested.png
    • ImageIconPage.png-dark
    • DropDownButtonPage.png-dark
    • DropDownButtonPage.png
    • ClipboardTests.png-dark
    • DisplayInformation.png-dark
  • skia-windows-screenshots: 2348 changed over 2394

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • AppBar_KeyBoard.png
    • ApplicationViewSpanningRectsPage.png
    • Attributed_text_FontSize_Changing.png-dark
    • AutoSuggestBox_Reason.png-dark
    • Basics Pivot Test.png-dark
    • Battery.png-dark
    • BindableDrawerLayout_ChangePane.png-dark
    • BitmapImage_vs_SvgImageSource.png-dark
    • BorderRightwithmargins.png-dark
    • BorderRightwithmargins.png
    • Border_CornerRadius_Binding.png-dark
    • Border_CornerRadius_Binding.png
    • Border_Simple_No_Background_With_Content_Border_With_Background.png-dark
    • Border_Simple_No_Background_With_Content_Border_With_Background.png
    • BreadcrumbBarPage.png-dark
    • BreadcrumbBarPage.png
    • Button_UseUWPDefaultStyles.png
    • CalendarDatePicker_Basics.png-dark
    • Clipping4273.png-dark
    • Clipping4273.png
  • wasm: 11 changed over 1076

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • UITests.Windows_UI_Xaml_Media_Animation.ColorAnimation_Background
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • UITests.Shared.Microsoft_UI_Xaml_Controls.ExpanderTests.WinUIExpanderPage
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Ogg_Extension
    • UITests.Windows_UI_Xaml_Controls.CalendarView.CalendarView_Theming
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Minimal
    • UITests.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_NavigationProperties
    • SamplesApp.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_EnableDevTools
    • Uno.UI.Samples.Content.UITests.WebView.WebView_AnchorNavigation
    • SamplesApp.Windows_UI_Xaml_Controls.ListView.ListViewSelectedItems
    • UITests.Uno_Web.Http.CookieManagerTests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/automation Categorizes an issue or PR as relevant to project automation area/build Categorizes an issue or PR as relevant to build infrastructure kind/documentation platform/macos 🍏 Categorizes an issue or PR as relevant to the macOS platform platform/wasm 🌐 Categorizes an issue or PR as relevant to the WebAssembly platform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Appium accessibility tree validation for SamplesApp

4 participants