Skip to content

fix: resolve nested window offsets for widget elements in dump ui - #55

Merged
gmegidish merged 1 commit into
mainfrom
fix/widget-window-context-offset
Jul 31, 2026
Merged

fix: resolve nested window offsets for widget elements in dump ui#55
gmegidish merged 1 commit into
mainfrom
fix/widget-window-context-offset

Conversation

@gmegidish

Copy link
Copy Markdown
Member

Summary

  • device.dump.ui reported wrong screen coordinates for elements hosted inside a nested window (e.g. a home screen widget's WidgetKit extension) — frames came back relative to that window's own origin instead of the screen, since XCTest's snapshot frame is only screen-absolute up to the point where windowContextID changes.
  • Added AXElement.resolvingNestedWindowOffsets(), which walks the tree and, on a nonzero-to-different-nonzero windowContextID transition, rebases that subtree's frames onto the screen-absolute position the parent already resolved — carrying the same offset through every descendant still inside that window.
  • Wired into DumpUI.swift's elementHierarchy.

Root cause

Confirmed via raw format dump of a home screen with a Calendar widget: the widget's date label reported x=17.67, y=27.99 (relative to the widget's own WidgetKit extension window), while the widget itself sits at x=204, y=67 on screen. Also confirmed this is not something WebDriverAgent/Appium handles correctly either — same bug reproduces there.

Test plan

  • Verified live against a booted simulator: with the fix, the widget's date label resolves to x=221.67, y=95.0, matching the hand-computed expected screen position (204+17.67, 67+28).
  • Confirmed non-widget elements are unaffected (offset stays 0 when windowContextID never changes).

Related: mobile-next/mobilewright#238

XCTest reports frames relative to the screen, except for elements hosted
in a nested window (e.g. a WidgetKit extension), where frames reset to
be relative to that window's own origin. This made home screen widget
elements (like a Calendar widget's date label) report coordinates near
0,0 instead of their real screen position.

windowContextID marks the boundary between windows: when it changes
between a nonzero parent and a different nonzero child, rebase that
subtree's frames onto the screen-absolute position the parent already
resolved, and carry the same offset down through every descendant still
inside that window.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Walkthrough

The change adds AXElement.resolvingNestedWindowOffsets(). The method recursively adjusts element frames when traversal enters a distinct nonzero windowContextID and propagates resolved offsets through descendants. elementHierarchy now applies this method before returning the accessibility tree.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the fix for incorrect nested-window offsets in widget elements during UI dumping.
Description check ✅ Passed The description directly explains the nested-window coordinate bug, the implementation, integration point, root cause, and verification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/widget-window-context-offset

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DeviceKitTests/XCTest/AXElement.swift`:
- Around line 241-246: Remove the trailing comma after the "Height" entry in the
resolvedFrame AXFrame literal, leaving all other frame values unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c296f0ee-02f7-4f8c-a2b0-5cedc53f82ce

📥 Commits

Reviewing files that changed from the base of the PR and between 4f7e98c and 1d1d858.

📒 Files selected for processing (2)
  • DeviceKitTests/JSONRPC/Handlers/DumpUI.swift
  • DeviceKitTests/XCTest/AXElement.swift

Comment on lines +241 to +246
let resolvedFrame: AXFrame = [
"X": (frame["X"] ?? 0) + offsetX,
"Y": (frame["Y"] ?? 0) + offsetY,
"Width": frame["Width"] ?? 0,
"Height": frame["Height"] ?? 0,
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the trailing comma flagged by SwiftLint.

SwiftLint's trailing_comma rule flags line 245. Remove the trailing comma after the last element of the resolvedFrame literal.

🧹 Proposed fix
         let resolvedFrame: AXFrame = [
             "X": (frame["X"] ?? 0) + offsetX,
             "Y": (frame["Y"] ?? 0) + offsetY,
             "Width": frame["Width"] ?? 0,
-            "Height": frame["Height"] ?? 0,
+            "Height": frame["Height"] ?? 0
         ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let resolvedFrame: AXFrame = [
"X": (frame["X"] ?? 0) + offsetX,
"Y": (frame["Y"] ?? 0) + offsetY,
"Width": frame["Width"] ?? 0,
"Height": frame["Height"] ?? 0,
]
let resolvedFrame: AXFrame = [
"X": (frame["X"] ?? 0) + offsetX,
"Y": (frame["Y"] ?? 0) + offsetY,
"Width": frame["Width"] ?? 0,
"Height": frame["Height"] ?? 0
]
🧰 Tools
🪛 SwiftLint (0.65.0)

[Warning] 245-245: Collection literals should not have trailing commas

(trailing_comma)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DeviceKitTests/XCTest/AXElement.swift` around lines 241 - 246, Remove the
trailing comma after the "Height" entry in the resolvedFrame AXFrame literal,
leaving all other frame values unchanged.

Source: Linters/SAST tools

@gmegidish
gmegidish merged commit 391d746 into main Jul 31, 2026
5 checks passed
@gmegidish
gmegidish deleted the fix/widget-window-context-offset branch July 31, 2026 10:09
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