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
7 changes: 4 additions & 3 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ jobs:
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testSnapshotPresentationOwnsBackendNeutralEligibility \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testSnapshotPresentationOwnsScopeAndRelativeDepth \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testPresentationRefusesAnAcquisitionCapturedForTheOtherProjection \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testCaptureHintIsTheOnlyAcquisitionViewOfARequest \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularDepthFrontierSurvivesStructuralWrapperCollapse \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularDepthFrontierKeepsVisibleIndependentChildPastClippedParent \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testCaptureHintIsTheOnlyAcquisitionViewOfARequest \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularDepthCutsPresentationNotAcquisition \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testVisibilityFoldKeepsIndependentChildPastClippedParent \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularDepthKeepsTurnedKeyboardSubtreeAfterOneNormalizationPass \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularFoldClipsScrollOverflowReparentsAndBooksHints \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularFoldKeepsWindowCarriersButNeverHittableOutsideClip \
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testRegularFoldDropsSubPixelContentlessDecorationOnEveryBackend \
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

- Changed (ios): a regular `snapshot --depth N` on the XCTest runner is a presentation cut over a
full acquisition, not a bound on the walk. Acquisition publishes the frames the platform reported,
one normalization pass turns geometry into the app's orientation space and recomputes `hittable`,
and the visibility fold and depth cut run on that array. Presented trees are unchanged on the
screens measured; a boundary container under `--depth N` now carries its scroll hints from its real
children. The runner's regular-depth capability is `presentation-cut` (was `presented-frontier`),
and every `CGRect` becomes a `SnapshotRect` through one initializer (#2661).
- Fixed (daemon): `close` now stops an active app-log stream (and audio probe / perf capture /
recording) on an implicitly cwd-scoped session. Teardown addressed those resources by
`session.name` (`default`) instead of the store address (`cwd:<hash>:default`), so the record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,7 @@ extension RunnerTests {
let viewport = geometry.viewport
let nodes = privateAXAcquisition(
rawRoot: root,
hint: hint,
viewport: viewport,
interfaceOrientation: geometry.interfaceOrientation
hint: hint
)
// Serialization-level emptiness only: an acquired-but-fully-clipped tree is presentation's
// verdict now, surfaced by the plan's sparse classifier on the presented payload (#1797).
Expand Down Expand Up @@ -256,7 +254,8 @@ extension RunnerTests {
customActions: Self.privateAXCustomActionCoverage(
response[RunnerAXSnapshotCustomActionsKey]
),
viewport: viewport
viewport: viewport,
interfaceOrientation: geometry.interfaceOrientation
)
#else
return nil
Expand Down Expand Up @@ -697,9 +696,7 @@ extension RunnerTests {
rawRoot: tree,
hint: CaptureHint(
projection: .regular, depth: nil, regularPresentedDepth: nil,
interactiveOnly: false, customActions: false),
viewport: CGRect(x: 0, y: 0, width: 390, height: 844),
interfaceOrientation: RunnerInterfaceOrientation.portrait
interactiveOnly: false, customActions: false)
)

let card = nodes.first { $0.label == "feedItem-by-whiskers.test" }
Expand Down Expand Up @@ -732,9 +729,7 @@ extension RunnerTests {
scope: "homeScreen",
raw: false
)
),
viewport: .infinite,
interfaceOrientation: RunnerInterfaceOrientation.portrait
)
)

let labels = nodes.compactMap { $0.label ?? $0.identifier }
Expand Down Expand Up @@ -812,9 +807,11 @@ extension RunnerTests {
let hint = CaptureHint(
projection: .regular, depth: nil, regularPresentedDepth: nil,
interactiveOnly: true, customActions: false)
let acquired = privateAXAcquisition(
rawRoot: tree, hint: hint, viewport: viewport,
interfaceOrientation: RunnerInterfaceOrientation.portrait)
let acquired = SnapshotGeometrySpace.normalized(
nodes: privateAXAcquisition(rawRoot: tree, hint: hint),
viewport: viewport,
interfaceOrientation: RunnerInterfaceOrientation.portrait
)
// Acquisition serializes the drawer too; the shared fold is what hides it (#1797).
XCTAssertTrue(acquired.compactMap(\.label).contains("Admin settings"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ extension RunnerTests {
label: label.isEmpty ? nil : label,
identifier: identifier.isEmpty ? nil : identifier,
value: valueText.isEmpty ? nil : valueText,
rect: snapshotRect(from: element.frame),
rect: SnapshotRect(element.frame),
enabled: element.isEnabled,
focused: nil,
selected: element.isSelected ? true : nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,26 @@ extension RunnerTests {
/// depth -- membership, the clip fold, scroll hints, and collapsed depth are
/// `SnapshotPresentation`'s alone (#1797). The traversal-depth cut is the backend's one
/// narrowing, complete for raw (raw depth *is* traversal depth) and a declared residue for
/// regular; `hittable` is the shared geometric fact the fold recomputes for effective geometry.
/// regular; the frame carried here is the one the platform reported, and
/// `SnapshotGeometrySpace.normalized` turns it once, after this walk, before presentation (#2661).
func privateAXAcquisition(
rawRoot: [String: Any],
hint: CaptureHint,
viewport: CGRect,
interfaceOrientation: Int
hint: CaptureHint
) -> [RawAXNode] {
var nodes: [RawAXNode] = []
appendPrivateAXNode(rawRoot, to: &nodes, hint: hint, viewport: viewport,
interfaceOrientation: interfaceOrientation, geometrySpace: .appOrientation,
parentIsWindow: false, depth: 0, parentIndex: nil)
appendPrivateAXNode(rawRoot, to: &nodes, hint: hint, depth: 0, parentIndex: nil)
return nodes
}

private func appendPrivateAXNode(_ raw: [String: Any], to nodes: inout [RawAXNode],
hint: CaptureHint, viewport: CGRect, interfaceOrientation: Int,
geometrySpace: SnapshotGeometrySpace, parentIsWindow: Bool, depth: Int, parentIndex: Int?)
hint: CaptureHint, depth: Int, parentIndex: Int?)
{
if let limit = hint.rawTraversalDepth, depth > limit { return }
let fields = privateAXFields(raw)
let nodeSpace = SnapshotGeometrySpace.space(
reportedBySurfaceHost: SnapshotGeometrySpace.isSurfaceHost(
isWindow: isWindowElement(fields.elementType),
parentIsWindow: parentIsWindow
),
reportedFrame: fields.rect,
inheritedFrom: geometrySpace,
appFrame: viewport,
interfaceOrientation: interfaceOrientation
)
let index = nodes.count
nodes.append(
privateAXNode(
fields,
index: index,
depth: depth,
parentIndex: parentIndex,
viewport: viewport,
geometrySpace: nodeSpace
)
)
nodes.append(privateAXNode(fields, index: index, depth: depth, parentIndex: parentIndex))
for child in fields.children {
appendPrivateAXNode(child, to: &nodes, hint: hint, viewport: viewport,
interfaceOrientation: interfaceOrientation, geometrySpace: nodeSpace,
parentIsWindow: isWindowElement(fields.elementType), depth: depth + 1, parentIndex: index)
appendPrivateAXNode(child, to: &nodes, hint: hint, depth: depth + 1, parentIndex: index)
}
}

Expand All @@ -87,22 +62,17 @@ extension RunnerTests {
)
}

private func privateAXNode(_ fields: PrivateAXFields, index: Int, depth: Int, parentIndex: Int?,
viewport: CGRect, geometrySpace: SnapshotGeometrySpace) -> RawAXNode
private func privateAXNode(_ fields: PrivateAXFields, index: Int, depth: Int,
parentIndex: Int?) -> RawAXNode
{
let frame = geometrySpace.orientedFrame(of: fields.rect)
return RawAXNode(index: index,
type: fields.elementType.map(elementTypeName) ?? "Element(\(fields.rawType))",
label: fields.label.isEmpty ? nil : fields.label,
identifier: fields.identifier.isEmpty ? nil : fields.identifier,
value: fields.value.isEmpty ? nil : fields.value,
rect: snapshotRect(from: frame), enabled: fields.enabled,
rect: SnapshotRect(fields.rect), enabled: fields.enabled,
focused: fields.focused, selected: fields.selected,
hittable: parentIndex != nil && SnapshotGeometry.isGeometricallyActionable(
enabled: fields.enabled,
frame: frame,
viewport: viewport
),
hittable: false,
depth: depth, parentIndex: parentIndex, hiddenContentAbove: nil, hiddenContentBelow: nil,
actions: fields.actions)
}
Expand Down Expand Up @@ -145,8 +115,9 @@ extension RunnerTests {
"frame": frame(16, 900, 360, 44)]]]]]
}

/// Acquire with the private-AX serializer, then present through the shared regular fold --
/// the production route for this backend since the fold moved into presentation (#1797).
/// Acquire with the private-AX serializer, run the one normalization pass the production capture
/// plan runs (`captureWithBackend`), then present through the shared regular fold -- the production
/// route for this backend since the fold moved into presentation (#1797, #2661).
fileprivate func privateAXRegularPresentation(
rawRoot: [String: Any],
viewport: CGRect,
Expand All @@ -155,21 +126,36 @@ extension RunnerTests {
let hint = CaptureHint(
projection: .regular, depth: nil, regularPresentedDepth: nil,
interactiveOnly: interactiveOnly, customActions: false)
let acquired = privateAXAcquisition(
let nodes = privateAXNormalizedAcquisition(
rawRoot: rawRoot, hint: hint, viewport: viewport,
interfaceOrientation: RunnerInterfaceOrientation.portrait)
return try SnapshotPresentation.presentRegular(
SnapshotAcquisition(
hint: hint, nodes: acquired, truncated: false, effectiveDepth: nil, viewport: viewport),
hint: hint, nodes: nodes, truncated: false, effectiveDepth: nil, viewport: viewport,
interfaceOrientation: RunnerInterfaceOrientation.portrait),
options: PresentationOptions(
interactiveOnly: interactiveOnly, depth: nil, scope: nil, raw: false),
policy: .cursorProjected
).nodes
}

/// The walk's space declaration has to reach the node it publishes: this asserts the rotated rect of
/// a key under a turned surface host, and an untouched sibling under the app's own window, so a walk
/// that drops the space it computed fails here.
/// Acquire, then normalize once -- the exact pair `captureWithBackend` runs for this backend.
fileprivate func privateAXNormalizedAcquisition(
rawRoot: [String: Any],
hint: CaptureHint,
viewport: CGRect,
interfaceOrientation: Int
) -> [RawAXNode] {
SnapshotGeometrySpace.normalized(
nodes: privateAXAcquisition(rawRoot: rawRoot, hint: hint),
viewport: viewport,
interfaceOrientation: interfaceOrientation
)
}

/// The one normalization pass has to reach the node it publishes: this asserts the rotated rect of
/// a key under a turned surface host, and an untouched sibling under the app's own window, so a
/// pass that drops the space a subtree declared fails here.
func testPrivateAXAcquisitionPublishesATurnedSurfaceHostInAppOrientationSpace() {
let frame = Self.privateAXFrame
let appWindow: [String: Any] = [
Expand All @@ -195,7 +181,7 @@ extension RunnerTests {
let hint = CaptureHint(
projection: .raw, depth: nil, regularPresentedDepth: nil,
interactiveOnly: false, customActions: false)
let nodes = privateAXAcquisition(
let nodes = privateAXNormalizedAcquisition(
rawRoot: [
"type": Int(XCUIElement.ElementType.application.rawValue),
"label": "Element", "frame": frame(0, 0, 874, 402),
Expand Down Expand Up @@ -236,7 +222,7 @@ extension RunnerTests {
let root = Self.privateAXScrolledFixture
let regular = try privateAXRegularPresentation(rawRoot: root, viewport: viewport,
interactiveOnly: true)
let raw = privateAXAcquisition(rawRoot: root,
let raw = privateAXNormalizedAcquisition(rawRoot: root,
hint: CaptureHint(
projection: .raw, depth: nil, regularPresentedDepth: nil,
interactiveOnly: false, customActions: false),
Expand Down Expand Up @@ -265,7 +251,7 @@ extension RunnerTests {
/// Raw depth is traversal depth, so a raw `--depth` request is the one narrowing this backend
/// can prove complete.
func testPrivateAXRawProjectionAppliesRequestedTraversalDepth() {
let raw = privateAXAcquisition(rawRoot: Self.privateAXScrolledFixture,
let raw = privateAXNormalizedAcquisition(rawRoot: Self.privateAXScrolledFixture,
hint: CaptureHint(
projection: .raw, depth: 2, regularPresentedDepth: nil,
interactiveOnly: false, customActions: false),
Expand Down
Loading
Loading