Skip to content

fix: keep the main window identifier and expose workspace descriptions to accessibility - #445

Merged
arzafran merged 7 commits into
mainfrom
fix/uitest-launch-and-description
Oct 19, 2026
Merged

arzafran merged 7 commits into
mainfrom
fix/uitest-launch-and-description

Conversation

@arzafran

Copy link
Copy Markdown
Member

Sometimes a main window came up without its programa.main.<id> identifier, so anything that looks up main windows by identifier (window routing, the UI test harness) could not find it. In CI this showed up as the second app launch in BonsplitTabDragUITests timing out in setup.

The cause is ordering. SwiftUI's AppWindowsController.makeMainWindow writes its own scene identifier onto the window, and that write can land after configureMainWindow has already set ours. WindowAccessor only configures a window once, so nothing put our identifier back. A trace run on macos-26 caught SwiftUI's write 0.14 s after ours. The fix keeps a small KVO guard on each main window that restores our identifier if anything replaces it.

Second fix: the workspace description in the sidebar was invisible to accessibility, because the row combines its children under one label. The row label now ends with the description as plain text, line breaks kept, so VoiceOver reads it. accessibilityValue was tried first, but XCUI never saw it.

Both tests come back into the nightly UI run.

CI on this branch (before a rebase onto main and a one-line reorder in the guard setup):

  • BonsplitTabDragUITests on macos-26: 8 of 9 pass, only the known tab-reorder CGEvent test fails.
  • WorkspaceDescriptionUITests on macos-26: 4 of 4 pass.
  • BonsplitTabDragUITests on macos-15: the second-launch test passes. testMinimalModeCollapsedSidebarKeepsPaneTabBarControlsVisible fails there ("New Terminal Tab" not hittable), and it fails the same way on main, so it is not from this change. The nightly runs on macos-26, where it passes.

The second launch of BonsplitTabDragUITests ends up with a SwiftUI-generated
window identifier. Record identifier changes (with the call stack) and the
saved application state at launch, and include them in the setup timeout.
…y value

The row combines its children into one accessibility element, which hid the
description text from VoiceOver and from UI tests. Expose the description
(markdown rendered to plain text, line breaks kept) as the row value, assert
it in WorkspaceDescriptionUITests, and stop skipping that test nightly.
…dentifier late

SwiftUI makeMainWindow sets the scene identifier after attaching the content
view. When that lands after the first WindowAccessor callback, the window
loses programa.main.<id> and nothing re-applies it, so main-window routing and
the UI test harnesses never find it. Observe the identifier and restore it.
Re-enable the collapsed-sidebar tab-drag UI test that this made flaky.
…body

The added accessibilityValue pushed the body expression past the type checker
limit on the macos-15 toolchain. Group the five accessibility modifiers in one
ViewModifier. The description UI test also dumps the element tree on failure.
…abel

SwiftUI exports accessibilityValue as AXValueDescription, which XCUITest does
not surface (value stayed empty even though the description was saved), so the
row label carries the description after the position instead. This drops the
value modifier and the ViewModifier extraction that only existed for it.
@arzafran
arzafran merged commit 22a4bee into main Oct 19, 2026
15 of 16 checks passed
@arzafran
arzafran deleted the fix/uitest-launch-and-description branch October 19, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant