Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DeviceKitTests/JSONRPC/Handlers/DumpUI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,6 @@ struct DumpUIMethodHandler: RPCMethodHandler {

private func elementHierarchy(xcuiElement: XCUIElement) throws -> AXElement {
let snapshotDictionary = try xcuiElement.snapshot().dictionaryRepresentation
return AXElement(snapshotDictionary)
return AXElement(snapshotDictionary).resolvingNestedWindowOffsets()
}
}
60 changes: 60 additions & 0 deletions DeviceKitTests/XCTest/AXElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,64 @@ struct AXElement: Codable {

return max ?? 1
}

// XCTest reports frames relative to the screen, except when an element is hosted in a
// nested window (e.g. a WidgetKit extension) - there, frames reset to be relative to that
// window's own origin. windowContextID marks the boundary: fix it up by re-basing the
// subtree's frames onto where the parent element already placed it on screen.
// windowContextID == 0 shows up on placeholder/group nodes with no real window of their
// own, so only a nonzero-to-different-nonzero transition counts as a real boundary.
func resolvingNestedWindowOffsets(
parentWindowContextID: Double? = nil,
parentResolvedFrame: AXFrame? = nil,
inheritedOffsetX: Double = 0,
inheritedOffsetY: Double = 0
) -> AXElement {
var offsetX = inheritedOffsetX
var offsetY = inheritedOffsetY
if let parentWindowContextID, parentWindowContextID != 0,
windowContextID != 0, windowContextID != parentWindowContextID,
let parentResolvedFrame {
// Crossing into a nested window: its frames are relative to its own origin, not
// the parent's. Compute a fresh offset that rebases this node onto the
// screen-absolute position the parent already resolved, and carry that same
// offset down to every descendant still inside this window.
offsetX = (parentResolvedFrame["X"] ?? 0) - (frame["X"] ?? 0)
offsetY = (parentResolvedFrame["Y"] ?? 0) - (frame["Y"] ?? 0)
}

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

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


let resolvedChildren = children?.map {
$0.resolvingNestedWindowOffsets(
parentWindowContextID: windowContextID,
parentResolvedFrame: resolvedFrame,
inheritedOffsetX: offsetX,
inheritedOffsetY: offsetY
)
}

return AXElement(
identifier: identifier,
frame: resolvedFrame,
value: value,
title: title,
label: label,
elementType: elementType,
enabled: enabled,
horizontalSizeClass: horizontalSizeClass,
verticalSizeClass: verticalSizeClass,
placeholderValue: placeholderValue,
selected: selected,
hasFocus: hasFocus,
displayID: displayID,
windowContextID: windowContextID,
children: resolvedChildren
)
}
}
Loading