@@ -133,6 +133,24 @@ extension RunnerTests {
133133 return Response ( ok: true , data: data)
134134 }
135135
136+ /// Gesture plans already return canonical centroid endpoints from the portable runtime.
137+ /// Keep runner timing/fallback diagnostics, but do not leak the coordinate-drag adapter's
138+ /// visualization frame into only the fast-fling response shape.
139+ private func canonicalPlannedGestureResponse( _ response: Response ) -> Response {
140+ guard response. ok, let data = response. data else { return response }
141+ return Response (
142+ ok: true ,
143+ data: DataPayload (
144+ message: data. message,
145+ gestureStartUptimeMs: data. gestureStartUptimeMs,
146+ gestureEndUptimeMs: data. gestureEndUptimeMs,
147+ gestureFallback: data. gestureFallback,
148+ gestureFallbackMessage: data. gestureFallbackMessage,
149+ gestureFallbackHint: data. gestureFallbackHint
150+ )
151+ )
152+ }
153+
136154#if AGENT_DEVICE_RUNNER_UNIT_TESTS
137155 func testGestureResponseIncludesSynthesizedTapFallbackDiagnostics( ) {
138156 let response = gestureResponse (
@@ -165,6 +183,42 @@ extension RunnerTests {
165183 XCTAssertEqual ( response. data? . maestroNonHittableCoordinateFallbackUsed, true )
166184 }
167185
186+ func testCanonicalPlannedGestureResponseOmitsDragFrameAndPreservesDiagnostics( ) {
187+ let response = gestureResponse (
188+ message: " fling " ,
189+ timing: ( gestureStartUptimeMs: 1 , gestureEndUptimeMs: 2 ) ,
190+ frame: . drag(
191+ DragVisualizationFrame (
192+ x: 160 ,
193+ y: 150 ,
194+ x2: 40 ,
195+ y2: 150 ,
196+ referenceWidth: 200 ,
197+ referenceHeight: 300
198+ )
199+ ) ,
200+ fallback: GestureFallback (
201+ strategy: " xctest-coordinate-drag " ,
202+ message: " Private synthesis unavailable " ,
203+ hint: " Using XCTest coordinate fallback. "
204+ )
205+ )
206+
207+ let canonical = canonicalPlannedGestureResponse ( response)
208+
209+ XCTAssertEqual ( canonical. data? . gestureStartUptimeMs, 1 )
210+ XCTAssertEqual ( canonical. data? . gestureEndUptimeMs, 2 )
211+ XCTAssertEqual ( canonical. data? . gestureFallback, " xctest-coordinate-drag " )
212+ XCTAssertEqual ( canonical. data? . gestureFallbackMessage, " Private synthesis unavailable " )
213+ XCTAssertEqual ( canonical. data? . gestureFallbackHint, " Using XCTest coordinate fallback. " )
214+ XCTAssertNil ( canonical. data? . x)
215+ XCTAssertNil ( canonical. data? . y)
216+ XCTAssertNil ( canonical. data? . x2)
217+ XCTAssertNil ( canonical. data? . y2)
218+ XCTAssertNil ( canonical. data? . referenceWidth)
219+ XCTAssertNil ( canonical. data? . referenceHeight)
220+ }
221+
168222 func testXCTestRecordedFailureResponseFailsMutatingSuccesses( ) throws {
169223 let command = try runnerCommandFixture ( #"{"command":"tap","commandId":"tap-1"}"# )
170224 let response = Response ( ok: true , data: DataPayload ( message: " tapped " ) )
@@ -1482,8 +1536,27 @@ extension RunnerTests {
14821536 error: ErrorPayload ( code: " INVALID_ARGS " , message: validationError)
14831537 )
14841538 }
1539+ if plannedGestureExecution ( for: plan) == . fastSwipe {
1540+ // Validation above guarantees a non-empty, single-pointer path for this execution kind.
1541+ let first = plan. pointers [ 0 ] . samples. first!. point
1542+ let last = plan. pointers [ 0 ] . samples. last!. point
1543+ return canonicalPlannedGestureResponse (
1544+ executeDragGesture (
1545+ activeApp: activeApp,
1546+ x: first. x,
1547+ y: first. y,
1548+ x2: last. x,
1549+ y2: last. y,
1550+ durationMs: plan. durationMs,
1551+ synthesized: true ,
1552+ message: plan. intent,
1553+ synthesizedPolicyKind: . synthesizedDrag,
1554+ synthesizedProfile: . fastSwipe
1555+ )
1556+ )
1557+ }
14851558 let ( timing, outcome) = performGesture ( activeApp, idleTimeout: false ) {
1486- plannedGesture ( app: activeApp, plan: plan)
1559+ sampledPlannedGesture ( app: activeApp, plan: plan)
14871560 }
14881561 if let response = unsupportedResponse ( for: outcome) {
14891562 return response
@@ -1513,7 +1586,8 @@ extension RunnerTests {
15131586 synthesized: Bool ,
15141587 message: String ,
15151588 synthesizedContext: SynthesizedCoordinateContext ? = nil ,
1516- synthesizedPolicyKind: SynthesizedGesturePolicyKind
1589+ synthesizedPolicyKind: SynthesizedGesturePolicyKind ,
1590+ synthesizedProfile: SynthesizedDragProfile = . continuous
15171591 ) -> Response {
15181592 let commandName = dragCommandName ( message: message)
15191593 guard x. isFinite, y. isFinite, x2. isFinite, y2. isFinite else {
@@ -1531,7 +1605,8 @@ extension RunnerTests {
15311605 durationMs: durationMs,
15321606 message: message,
15331607 context: synthesizedContext,
1534- policyKind: synthesizedPolicyKind
1608+ policyKind: synthesizedPolicyKind,
1609+ profile: synthesizedProfile
15351610 ) {
15361611 return synthesizedResponse
15371612 }
@@ -1555,6 +1630,7 @@ extension RunnerTests {
15551630 x2: dragPoints. x2,
15561631 y2: dragPoints. y2,
15571632 durationMs: durationMs,
1633+ profile: synthesizedProfile,
15581634 context: context
15591635 )
15601636 }
@@ -1596,7 +1672,8 @@ extension RunnerTests {
15961672 durationMs: Double ? ,
15971673 message: String ,
15981674 context: SynthesizedCoordinateContext ? ,
1599- policyKind: SynthesizedGesturePolicyKind
1675+ policyKind: SynthesizedGesturePolicyKind ,
1676+ profile: SynthesizedDragProfile
16001677 ) -> Response ? {
16011678#if os(iOS)
16021679 let policy = synthesizedGesturePolicy ( policyKind)
@@ -1648,6 +1725,7 @@ extension RunnerTests {
16481725 x2: plan. points. x2,
16491726 y2: plan. points. y2,
16501727 durationMs: durationMs,
1728+ profile: profile,
16511729 context: plan. context
16521730 )
16531731 }
0 commit comments