Skip to content

Commit e445455

Browse files
committed
Merge remote-tracking branch 'origin/main' into refactor/daemon-runtime-no-process-globals
* origin/main: fix(ios-runner): stop wide sliders from wedging tree snapshots (#3776)
2 parents 418b072 + 92db564 commit e445455

7 files changed

Lines changed: 470 additions & 118 deletions

‎apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,31 @@ - (void)viewDidLoad {
848848
}
849849
}
850850

851+
// Overlapping sibling buttons must not become children of an ordinary slider.
852+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-wide-slider"]) {
853+
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(20, 20, 360, 31)];
854+
slider.accessibilityLabel = @"Volume";
855+
[self.view addSubview:slider];
856+
NSArray<NSString *> *titles = @[ @"Left", @"Right" ];
857+
for (NSUInteger i = 0; i < titles.count; i++) {
858+
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
859+
[button setTitle:titles[i] forState:UIControlStateNormal];
860+
button.frame = CGRectMake(30 + i * 170, 20, 100, 30);
861+
[self.view addSubview:button];
862+
}
863+
}
864+
865+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-collapsed-tab-bar"]) {
866+
UITabBar *tabBar = [[UITabBar alloc] initWithFrame:CGRectMake(20, 20, 360, 60)];
867+
tabBar.items = @[
868+
[[UITabBarItem alloc] initWithTitle:@"First tab" image:nil tag:0],
869+
[[UITabBarItem alloc] initWithTitle:@"Second tab" image:nil tag:1],
870+
];
871+
tabBar.isAccessibilityElement = YES;
872+
tabBar.accessibilityLabel = @"Collapsed tabs";
873+
[self.view addSubview:tabBar];
874+
}
875+
851876
BOOL markedButton = [NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-dismiss-popup"];
852877
if (markedButton || [NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-dismiss-popup-window"]) {
853878
UIButton *dismissRegion = [UIButton buttonWithType:UIButtonTypeSystem];

‎apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift‎

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ extension RunnerTests {
2121
struct SnapshotTraversalContext {
2222
let queryRoot: XCUIElement
2323
let rootSnapshot: XCUIElementSnapshot
24+
/// How long reading `rootSnapshot` took: what one more query over the whole app is expected to cost.
25+
let rootReadDuration: TimeInterval
2426
/** Carries which way the app's interface is turned from the device's native space (#2612). */
2527
let viewport: SnapshotViewport
2628
/**
@@ -144,9 +146,11 @@ extension RunnerTests {
144146
min(startedAt.addingTimeInterval(flatInteractiveFallbackBudget), planDeadline)
145147
}
146148

147-
/// Whether a sweep query started at `now` can still finish before the slice `deadline`.
148-
static func querySweepCanStartQuery(deadline: Date, now: Date) -> Bool {
149-
deadline.timeIntervalSince(now) >= flatInteractiveQueryBudget
149+
/// Whether a query started at `now` and expected to take `expectedCost` can still finish before
150+
/// `deadline`. XCTest cannot cancel a query once it starts; the least admitted cost is a sweep
151+
/// query's.
152+
static func xctestQueryCanStart(deadline: Date, now: Date, expectedCost: TimeInterval = 0) -> Bool {
153+
deadline.timeIntervalSince(now) >= max(flatInteractiveQueryBudget, expectedCost)
150154
}
151155

152156
/// What one capture may spend reading the keyboard band before it gives up on the fact and lets the
@@ -181,18 +185,19 @@ extension RunnerTests {
181185
@MainActor
182186
func recursiveTreeSnapshotAcquisition(
183187
context: SnapshotTraversalContext,
184-
hint: CaptureHint
185-
) throws -> SnapshotAcquisition {
186-
var cachedDescendantElements: [XCUIElement]?
187-
func collapsedTabDescendants() -> [XCUIElement] {
188-
if let cachedDescendantElements {
189-
return cachedDescendantElements
190-
}
191-
let result = snapshotElementsQuery {
192-
context.queryRoot.descendants(matching: .any).allElementsBoundByIndex
188+
hint: CaptureHint,
189+
processingDeadline: Date
190+
) throws -> (acquisition: SnapshotAcquisition, outcome: SnapshotTierOutcome) {
191+
var outcome = SnapshotTierOutcome.completed
192+
var cachedCollapsedTabCandidates: [CollapsedTabCandidate]?
193+
func collapsedTabCandidatesOnce() -> [CollapsedTabCandidate] {
194+
if let cachedCollapsedTabCandidates {
195+
return cachedCollapsedTabCandidates
193196
}
194-
cachedDescendantElements = result.elements
195-
return result.elements
197+
let candidates = collapsedTabCandidates(context: context, processingDeadline: processingDeadline)
198+
if candidates == nil { outcome = .deadlineExhausted }
199+
cachedCollapsedTabCandidates = candidates ?? []
200+
return candidates ?? []
196201
}
197202

198203
// Acquisition serializes reported frames only; no coordinate space or fold decision is carried
@@ -212,7 +217,7 @@ extension RunnerTests {
212217
appendCollapsedTabFallbackNodes(
213218
to: &nodes,
214219
containerSnapshot: context.rootSnapshot,
215-
resolveElements: collapsedTabDescendants,
220+
resolveCandidates: collapsedTabCandidatesOnce,
216221
depth: 1,
217222
parentIndex: 0
218223
)
@@ -269,19 +274,22 @@ extension RunnerTests {
269274
appendCollapsedTabFallbackNodes(
270275
to: &nodes,
271276
containerSnapshot: snapshot,
272-
resolveElements: collapsedTabDescendants,
277+
resolveCandidates: collapsedTabCandidatesOnce,
273278
depth: depth + 1,
274279
parentIndex: node.index
275280
)
276281
}
277282
}
278283

279-
return SnapshotAcquisition(
280-
hint: hint,
281-
nodes: nodes,
282-
truncated: false,
283-
effectiveDepth: nil,
284-
viewport: context.viewport
284+
return (
285+
SnapshotAcquisition(
286+
hint: hint,
287+
nodes: nodes,
288+
truncated: outcome == .deadlineExhausted,
289+
effectiveDepth: nil,
290+
viewport: context.viewport
291+
),
292+
outcome
285293
)
286294
}
287295

@@ -469,7 +477,7 @@ extension RunnerTests {
469477
let flatElements = flatInteractiveElements(app: app, deadline: deadline)
470478
var outcome = flatElements.outcome
471479
for element in flatElements.elements {
472-
if !Self.querySweepCanStartQuery(deadline: deadline, now: Date()) {
480+
if !Self.xctestQueryCanStart(deadline: deadline, now: Date()) {
473481
NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_FLAT_FALLBACK_DEADLINE")
474482
outcome = .deadlineExhausted
475483
break

0 commit comments

Comments
 (0)