agent-device 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.0.apk → agent-device-android-ime-helper-0.20.2.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.2.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.0.manifest.json → agent-device-android-ime-helper-0.20.2.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.0.apk → agent-device-android-snapshot-helper-0.20.2.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.2.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.0.manifest.json → agent-device-android-snapshot-helper-0.20.2.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +2 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +30 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -21
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +8 -3
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Orientation.swift +92 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +4 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/android-input-method-overlays.js +1 -1
- package/dist/src/android.js +1 -1
- package/dist/src/app-lifecycle.js +5 -5
- package/dist/src/app-log-request-scope.js +1 -1
- package/dist/src/app-resolution.js +1 -1
- package/dist/src/apple-multitouch-support.js +1 -1
- package/dist/src/apps.js +5 -5
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +81 -24
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +14 -14
- package/dist/src/click-button.d.ts +5 -0
- package/dist/src/client-metro.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/compatibility-policy.js +1 -0
- package/dist/src/context.js +1 -1
- package/dist/src/contracts.d.ts +2 -2
- package/dist/src/debug-symbols.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/device.js +9 -0
- package/dist/src/devices2.js +1 -1
- package/dist/src/devices4.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-plan-types.js +1 -0
- package/dist/src/gesture-plan.js +1 -0
- package/dist/src/index.d.ts +1205 -1309
- package/dist/src/input-actions.js +4 -4
- package/dist/src/install-artifact.js +5 -1
- package/dist/src/install-artifact2.js +1 -0
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.d.ts +3 -6
- package/dist/src/interaction.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -0
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +14 -22
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun.d.ts +361 -0
- package/dist/src/limrun.js +1 -0
- package/dist/src/linux.js +1 -1
- package/dist/src/logcat.js +1 -5
- package/dist/src/method-scope.js +1 -0
- package/dist/src/metro.d.ts +72 -3
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -1
- package/dist/src/notifications.js +1 -1
- package/dist/src/physical-device-control.js +1 -0
- package/dist/src/plist.js +1 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/recording-export-quality.js +15 -0
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +24 -24
- package/dist/src/remote-config.d.ts +5 -2
- package/dist/src/remote-config.js +1 -1
- package/dist/src/remote-config2.js +1 -0
- package/dist/src/reporting.js +8 -8
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -2
- package/dist/src/runner-lease.js +1 -1
- package/dist/src/runner-provider.js +1 -1
- package/dist/src/runtime-transport.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +1 -1
- package/dist/src/sdk-android-adb.d.ts +4 -24
- package/dist/src/sdk-android-adb.js +4 -4
- package/dist/src/sdk-batch-runner.d.ts +13 -3
- package/dist/src/sdk-batch-runner.js +3 -2
- package/dist/src/sdk-contracts.d.ts +31 -91
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +3 -2
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +83 -53
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selector-vocabulary.js +1 -1
- package/dist/src/selectors.d.ts +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session.js +8 -8
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.js +4 -4
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/tool-provider.js +3 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/tv-remote.d.ts +213 -0
- package/dist/src/unsupported-interactor.js +1 -0
- package/dist/src/web.js +1 -1
- package/dist/src/xml.js +2 -0
- package/package.json +41 -19
- package/server.json +2 -2
- package/skills/agent-device/SKILL.md +5 -3
- package/smithery.yaml +1 -1
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.0.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.0.apk.sha256 +0 -1
- package/dist/src/android-system-chrome.js +0 -1
- package/dist/src/client-metro-companion.js +0 -1
- package/dist/src/config.js +0 -1
- package/dist/src/daemon-shutdown-report.js +0 -1
- package/dist/src/project-runtime.js +0 -1
- package/dist/src/scoped-provider.js +0 -1
- package/dist/src/sdk-batch.js +0 -2
- package/dist/src/snapshot-quality.js +0 -1
- package/dist/src/tv-remote.js +0 -15
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Let your coding agent verify its changes in the running app.
|
|
17
17
|
|
|
18
|
-
`agent-device` lets coding agents inspect, control, and verify apps on iOS, Android, TV, web, macOS, and Linux. Agents can read token-efficient accessibility snapshots, find elements by ref or selector, run device actions, and save evidence for review.
|
|
18
|
+
`agent-device` lets coding agents inspect, control, and verify apps on iOS, Android, tvOS, Android TV, Amazon Vega OS TV through the Vega Virtual Device (VVD), web, macOS, and Linux. Agents can read token-efficient accessibility snapshots where supported, find elements by ref or selector, run device actions, and save evidence for review. Initial Vega OS support is VVD-only and covers discovery, app lifecycle, and complete TV-remote control; physical Fire TV, capture, and selector backends remain unsupported.
|
|
19
19
|
|
|
20
20
|
Your coding agent or QA tool reads each result and chooses the next command. `agent-device` runs the command and saves evidence when asked.
|
|
21
21
|
|
|
@@ -28,7 +28,6 @@ Install the CLI and check setup. It requires Node.js 22.12 or newer; web automat
|
|
|
28
28
|
```bash
|
|
29
29
|
npm install -g agent-device@latest
|
|
30
30
|
agent-device doctor
|
|
31
|
-
agent-device --version
|
|
32
31
|
agent-device help workflow
|
|
33
32
|
```
|
|
34
33
|
|
|
@@ -108,7 +107,7 @@ See [Commands](https://oss.callstack.com/agent-device/docs/commands) for the com
|
|
|
108
107
|
|
|
109
108
|
## How it works
|
|
110
109
|
|
|
111
|
-
`agent-device` keeps device state in sessions. It sends commands to XCTest on iOS and tvOS, ADB and the snapshot helper on Android, a local helper on macOS, and AT-SPI on Linux.
|
|
110
|
+
`agent-device` keeps device state in sessions. It sends commands to XCTest on iOS and tvOS, ADB and the snapshot helper on Android, Vega CLI/VDA on the Vega Virtual Device, a local helper on macOS, and AT-SPI on Linux.
|
|
112
111
|
|
|
113
112
|
Node.js apps can use the typed client or public subpaths. `agent-device/android-adb` provides the Android ADB provider interface, helpers for logcat, the clipboard, the keyboard, and apps, and port reverse management.
|
|
114
113
|
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
941f2997c4315e753fb2f5411562a2907b3a188370c3d52e762692843be1b50f agent-device-android-ime-helper-0.20.2.apk
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-ime-helper",
|
|
3
|
-
"version": "0.20.
|
|
4
|
-
"assetName": "agent-device-android-ime-helper-0.20.
|
|
5
|
-
"sha256": "
|
|
3
|
+
"version": "0.20.2",
|
|
4
|
+
"assetName": "agent-device-android-ime-helper-0.20.2.apk",
|
|
5
|
+
"sha256": "941f2997c4315e753fb2f5411562a2907b3a188370c3d52e762692843be1b50f",
|
|
6
6
|
"packageName": "com.callstack.agentdevice.imehelper",
|
|
7
|
-
"versionCode":
|
|
7
|
+
"versionCode": 20002,
|
|
8
8
|
"serviceComponent": "com.callstack.agentdevice.imehelper/.TestInputMethodService",
|
|
9
9
|
"broadcastProtocol": "android-ime-helper-v1"
|
|
10
10
|
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
003859ea5dc5d1ed8ddc5daf786eacb790ff471bbb0c3b0e1239712f73f37684 agent-device-android-snapshot-helper-0.20.2.apk
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-snapshot-helper",
|
|
3
|
-
"version": "0.20.
|
|
4
|
-
"releaseTag": "v0.20.
|
|
5
|
-
"assetName": "agent-device-android-snapshot-helper-0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
|
+
"releaseTag": "v0.20.2",
|
|
5
|
+
"assetName": "agent-device-android-snapshot-helper-0.20.2.apk",
|
|
6
6
|
"apkUrl": null,
|
|
7
|
-
"sha256": "
|
|
8
|
-
"checksumName": "agent-device-android-snapshot-helper-0.20.
|
|
7
|
+
"sha256": "003859ea5dc5d1ed8ddc5daf786eacb790ff471bbb0c3b0e1239712f73f37684",
|
|
8
|
+
"checksumName": "agent-device-android-snapshot-helper-0.20.2.apk.sha256",
|
|
9
9
|
"packageName": "com.callstack.agentdevice.snapshothelper",
|
|
10
|
-
"versionCode":
|
|
10
|
+
"versionCode": 20002,
|
|
11
11
|
"instrumentationRunner": "com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",
|
|
12
12
|
"minSdk": 23,
|
|
13
13
|
"targetSdk": 36,
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift
CHANGED
|
@@ -220,10 +220,12 @@ extension RunnerTests {
|
|
|
220
220
|
"yes",
|
|
221
221
|
"continue",
|
|
222
222
|
"done",
|
|
223
|
+
"open",
|
|
223
224
|
"open settings"
|
|
224
225
|
].contains(normalized) || normalized.hasPrefix("confirm")
|
|
225
226
|
}
|
|
226
227
|
|
|
228
|
+
|
|
227
229
|
private func isDismissButton(_ label: String) -> Bool {
|
|
228
230
|
[
|
|
229
231
|
"cancel",
|
|
@@ -755,6 +755,28 @@ extension RunnerTests {
|
|
|
755
755
|
}
|
|
756
756
|
case .uptime:
|
|
757
757
|
return executeUptime()
|
|
758
|
+
case .activate:
|
|
759
|
+
guard
|
|
760
|
+
let bundleId = command.appBundleId?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
761
|
+
!bundleId.isEmpty
|
|
762
|
+
else {
|
|
763
|
+
return Response(ok: false, error: ErrorPayload(message: "activate requires appBundleId"))
|
|
764
|
+
}
|
|
765
|
+
// prepareActiveCommandContext already activated this bundle. Keep this case as the
|
|
766
|
+
// explicit acknowledgement after that preflight, not as a second activation.
|
|
767
|
+
return Response(ok: true, data: DataPayload(message: "app activated"))
|
|
768
|
+
case .terminate:
|
|
769
|
+
guard
|
|
770
|
+
let bundleId = command.appBundleId?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
771
|
+
!bundleId.isEmpty
|
|
772
|
+
else {
|
|
773
|
+
return Response(ok: false, error: ErrorPayload(message: "terminate requires appBundleId"))
|
|
774
|
+
}
|
|
775
|
+
XCUIApplication(bundleIdentifier: bundleId).terminate()
|
|
776
|
+
if currentBundleId == bundleId {
|
|
777
|
+
invalidateCachedTarget(reason: "target_terminated")
|
|
778
|
+
}
|
|
779
|
+
return Response(ok: true, data: DataPayload(message: "app terminated"))
|
|
758
780
|
default:
|
|
759
781
|
break
|
|
760
782
|
}
|
|
@@ -844,7 +866,7 @@ extension RunnerTests {
|
|
|
844
866
|
) throws -> Response {
|
|
845
867
|
var activeApp = activeApp
|
|
846
868
|
switch command.command {
|
|
847
|
-
case .status, .targetReset, .shutdown, .recordStart, .recordStop, .uptime:
|
|
869
|
+
case .status, .activate, .terminate, .targetReset, .shutdown, .recordStart, .recordStop, .uptime:
|
|
848
870
|
return Response(
|
|
849
871
|
ok: false,
|
|
850
872
|
error: ErrorPayload(
|
|
@@ -1231,6 +1253,12 @@ extension RunnerTests {
|
|
|
1231
1253
|
guard let pngData = runnerPngData(for: screenshot.image) else {
|
|
1232
1254
|
return Response(ok: false, error: ErrorPayload(message: "Failed to encode screenshot as PNG"))
|
|
1233
1255
|
}
|
|
1256
|
+
if command.inlineScreenshot == true {
|
|
1257
|
+
return Response(
|
|
1258
|
+
ok: true,
|
|
1259
|
+
data: DataPayload(imageBase64: pngData.base64EncodedString())
|
|
1260
|
+
)
|
|
1261
|
+
}
|
|
1234
1262
|
let fileName = "screenshot-\(Int(Date().timeIntervalSince1970 * 1000)).png"
|
|
1235
1263
|
let filePath = (NSTemporaryDirectory() as NSString).appendingPathComponent(fileName)
|
|
1236
1264
|
do {
|
|
@@ -1259,21 +1287,7 @@ extension RunnerTests {
|
|
|
1259
1287
|
pressHomeButton()
|
|
1260
1288
|
return Response(ok: true, data: DataPayload(message: "home"))
|
|
1261
1289
|
case .rotate:
|
|
1262
|
-
|
|
1263
|
-
!orientation.isEmpty
|
|
1264
|
-
else {
|
|
1265
|
-
return Response(ok: false, error: ErrorPayload(message: "rotate requires orientation"))
|
|
1266
|
-
}
|
|
1267
|
-
if rotateDevice(to: orientation) {
|
|
1268
|
-
return Response(
|
|
1269
|
-
ok: true,
|
|
1270
|
-
data: DataPayload(message: "rotate", orientation: orientation)
|
|
1271
|
-
)
|
|
1272
|
-
}
|
|
1273
|
-
return Response(
|
|
1274
|
-
ok: false,
|
|
1275
|
-
error: ErrorPayload(message: "unsupported rotate orientation: \(orientation)")
|
|
1276
|
-
)
|
|
1290
|
+
return executeRotateCommand(command)
|
|
1277
1291
|
case .appSwitcher:
|
|
1278
1292
|
performAppSwitcherGesture(app: activeApp)
|
|
1279
1293
|
return Response(ok: true, data: DataPayload(message: "appSwitcher"))
|
|
@@ -147,7 +147,7 @@ final class RunnerCommandJournal {
|
|
|
147
147
|
.remotePress, .type, .swipe, .scroll, .desktopScroll, .findText, .querySelector, .readText, .back,
|
|
148
148
|
.backInApp, .backSystem, .home, .rotate, .appSwitcher, .keyboardDismiss, .keyboardReturn,
|
|
149
149
|
.alert, .sequence, .gesture, .gestureViewport, .recordStart, .recordStop,
|
|
150
|
-
.status, .uptime, .targetReset, .shutdown:
|
|
150
|
+
.status, .uptime, .activate, .terminate, .targetReset, .shutdown:
|
|
151
151
|
return true
|
|
152
152
|
}
|
|
153
153
|
}
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift
CHANGED
|
@@ -118,27 +118,6 @@ extension RunnerTests {
|
|
|
118
118
|
#endif
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
func rotateDevice(to orientationName: String) -> Bool {
|
|
122
|
-
#if os(macOS) || os(tvOS) || os(visionOS)
|
|
123
|
-
return false
|
|
124
|
-
#else
|
|
125
|
-
switch orientationName {
|
|
126
|
-
case "portrait":
|
|
127
|
-
XCUIDevice.shared.orientation = .portrait
|
|
128
|
-
case "portrait-upside-down":
|
|
129
|
-
XCUIDevice.shared.orientation = .portraitUpsideDown
|
|
130
|
-
case "landscape-left":
|
|
131
|
-
XCUIDevice.shared.orientation = .landscapeLeft
|
|
132
|
-
case "landscape-right":
|
|
133
|
-
XCUIDevice.shared.orientation = .landscapeRight
|
|
134
|
-
default:
|
|
135
|
-
return false
|
|
136
|
-
}
|
|
137
|
-
sleepFor(0.2)
|
|
138
|
-
return true
|
|
139
|
-
#endif
|
|
140
|
-
}
|
|
141
|
-
|
|
142
121
|
func findElement(app: XCUIApplication, text: String) -> XCUIElement? {
|
|
143
122
|
let predicate = NSPredicate(format: "label CONTAINS[c] %@ OR identifier CONTAINS[c] %@ OR value CONTAINS[c] %@", text, text, text)
|
|
144
123
|
let element = app.descendants(matching: .any).matching(predicate).firstMatch
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift
CHANGED
|
@@ -31,6 +31,8 @@ enum CommandType: String, Codable {
|
|
|
31
31
|
case recordStop
|
|
32
32
|
case status
|
|
33
33
|
case uptime
|
|
34
|
+
case activate
|
|
35
|
+
case terminate
|
|
34
36
|
case targetReset
|
|
35
37
|
case shutdown
|
|
36
38
|
}
|
|
@@ -90,7 +92,7 @@ extension CommandType {
|
|
|
90
92
|
return CommandTraits(isInteraction: false, readOnly: .conditional, isLifecycle: false)
|
|
91
93
|
|
|
92
94
|
// Runner-lifecycle commands: skip the app-activation preflight.
|
|
93
|
-
case .recordStop, .uptime, .targetReset, .shutdown:
|
|
95
|
+
case .recordStop, .uptime, .terminate, .targetReset, .shutdown:
|
|
94
96
|
return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: true)
|
|
95
97
|
|
|
96
98
|
case .status:
|
|
@@ -101,7 +103,7 @@ extension CommandType {
|
|
|
101
103
|
// guard interacts with bespoke macOS activation, so classifying it needs a macOS smoke
|
|
102
104
|
// check first (tracked as a follow-up). Also preserved: querySelector is NOT read-only;
|
|
103
105
|
// recordStart is NOT a lifecycle command; home/alert remain non-interaction by design.
|
|
104
|
-
case .mouseClick, .querySelector, .home, .recordStart:
|
|
106
|
+
case .mouseClick, .querySelector, .home, .recordStart, .activate:
|
|
105
107
|
return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: false)
|
|
106
108
|
}
|
|
107
109
|
}
|
|
@@ -118,7 +120,6 @@ struct Command: Codable {
|
|
|
118
120
|
let allowNonHittableCoordinateFallback: Bool?
|
|
119
121
|
let delayMs: Int?
|
|
120
122
|
let textEntryMode: String?
|
|
121
|
-
let clearFirst: Bool?
|
|
122
123
|
let action: String?
|
|
123
124
|
let x: Double?
|
|
124
125
|
let y: Double?
|
|
@@ -141,6 +142,7 @@ struct Command: Codable {
|
|
|
141
142
|
let scope: String?
|
|
142
143
|
let raw: Bool?
|
|
143
144
|
let fullscreen: Bool?
|
|
145
|
+
let inlineScreenshot: Bool?
|
|
144
146
|
let synthesized: Bool?
|
|
145
147
|
let steps: [SequenceStep]?
|
|
146
148
|
}
|
|
@@ -228,6 +230,7 @@ extension Response {
|
|
|
228
230
|
|
|
229
231
|
struct DataPayload: Codable {
|
|
230
232
|
let message: String?
|
|
233
|
+
let imageBase64: String?
|
|
231
234
|
let text: String?
|
|
232
235
|
let found: Bool?
|
|
233
236
|
let items: [String]?
|
|
@@ -267,6 +270,7 @@ struct DataPayload: Codable {
|
|
|
267
270
|
|
|
268
271
|
init(
|
|
269
272
|
message: String? = nil,
|
|
273
|
+
imageBase64: String? = nil,
|
|
270
274
|
text: String? = nil,
|
|
271
275
|
found: Bool? = nil,
|
|
272
276
|
items: [String]? = nil,
|
|
@@ -305,6 +309,7 @@ struct DataPayload: Codable {
|
|
|
305
309
|
sequenceResults: [SequenceStepResult]? = nil
|
|
306
310
|
) {
|
|
307
311
|
self.message = message
|
|
312
|
+
self.imageBase64 = imageBase64
|
|
308
313
|
self.text = text
|
|
309
314
|
self.found = found
|
|
310
315
|
self.items = items
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Orientation.swift
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
|
|
3
|
+
private enum OrientationObservationTiming {
|
|
4
|
+
static let pollInterval: TimeInterval = 0.05
|
|
5
|
+
static let timeout: TimeInterval = 2
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
extension RunnerTests {
|
|
9
|
+
func executeRotateCommand(_ command: Command) -> Response {
|
|
10
|
+
guard let orientation = command.orientation?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
11
|
+
!orientation.isEmpty
|
|
12
|
+
else {
|
|
13
|
+
return Response(ok: false, error: ErrorPayload(message: "rotate requires orientation"))
|
|
14
|
+
}
|
|
15
|
+
let supportedOrientations = [
|
|
16
|
+
"portrait",
|
|
17
|
+
"portrait-upside-down",
|
|
18
|
+
"landscape-left",
|
|
19
|
+
"landscape-right",
|
|
20
|
+
]
|
|
21
|
+
guard supportedOrientations.contains(orientation) else {
|
|
22
|
+
return Response(
|
|
23
|
+
ok: false,
|
|
24
|
+
error: ErrorPayload(message: "unsupported rotate orientation: \(orientation)")
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
guard let observedOrientation = rotateDevice(to: orientation) else {
|
|
28
|
+
return Response(
|
|
29
|
+
ok: false,
|
|
30
|
+
error: ErrorPayload(message: "unable to observe device orientation after rotate")
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
guard observedOrientation == orientation else {
|
|
34
|
+
return Response(
|
|
35
|
+
ok: false,
|
|
36
|
+
error: ErrorPayload(
|
|
37
|
+
message: "device orientation is \(observedOrientation), expected \(orientation)"
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
return Response(
|
|
42
|
+
ok: true,
|
|
43
|
+
data: DataPayload(message: "rotate", orientation: observedOrientation)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private func rotateDevice(to orientationName: String) -> String? {
|
|
48
|
+
#if os(macOS) || os(tvOS) || os(visionOS)
|
|
49
|
+
return nil
|
|
50
|
+
#else
|
|
51
|
+
switch orientationName {
|
|
52
|
+
case "portrait":
|
|
53
|
+
XCUIDevice.shared.orientation = .portrait
|
|
54
|
+
case "portrait-upside-down":
|
|
55
|
+
XCUIDevice.shared.orientation = .portraitUpsideDown
|
|
56
|
+
case "landscape-left":
|
|
57
|
+
XCUIDevice.shared.orientation = .landscapeLeft
|
|
58
|
+
case "landscape-right":
|
|
59
|
+
XCUIDevice.shared.orientation = .landscapeRight
|
|
60
|
+
default:
|
|
61
|
+
return nil
|
|
62
|
+
}
|
|
63
|
+
let deadline = Date().addingTimeInterval(OrientationObservationTiming.timeout)
|
|
64
|
+
repeat {
|
|
65
|
+
if observedDeviceOrientation() == orientationName {
|
|
66
|
+
return orientationName
|
|
67
|
+
}
|
|
68
|
+
sleepFor(OrientationObservationTiming.pollInterval)
|
|
69
|
+
} while Date() < deadline
|
|
70
|
+
return observedDeviceOrientation()
|
|
71
|
+
#endif
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private func observedDeviceOrientation() -> String? {
|
|
75
|
+
#if os(macOS) || os(tvOS) || os(visionOS)
|
|
76
|
+
return nil
|
|
77
|
+
#else
|
|
78
|
+
switch XCUIDevice.shared.orientation {
|
|
79
|
+
case .portrait:
|
|
80
|
+
return "portrait"
|
|
81
|
+
case .portraitUpsideDown:
|
|
82
|
+
return "portrait-upside-down"
|
|
83
|
+
case .landscapeLeft:
|
|
84
|
+
return "landscape-left"
|
|
85
|
+
case .landscapeRight:
|
|
86
|
+
return "landscape-right"
|
|
87
|
+
default:
|
|
88
|
+
return nil
|
|
89
|
+
}
|
|
90
|
+
#endif
|
|
91
|
+
}
|
|
92
|
+
}
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift
CHANGED
|
@@ -57,12 +57,16 @@ extension RunnerTests {
|
|
|
57
57
|
case .collectionView: return "CollectionView"
|
|
58
58
|
case .table: return "Table"
|
|
59
59
|
case .scrollView: return "ScrollView"
|
|
60
|
+
case .toolbar: return "Toolbar"
|
|
60
61
|
case .searchField: return "SearchField"
|
|
61
62
|
case .segmentedControl: return "SegmentedControl"
|
|
62
63
|
case .stepper: return "Stepper"
|
|
63
64
|
case .picker: return "Picker"
|
|
65
|
+
case .activityIndicator: return "ActivityIndicator"
|
|
66
|
+
case .progressIndicator: return "ProgressIndicator"
|
|
64
67
|
case .checkBox: return "CheckBox"
|
|
65
68
|
case .menuItem: return "MenuItem"
|
|
69
|
+
case .webView: return "WebView"
|
|
66
70
|
case .other: return "Other"
|
|
67
71
|
default:
|
|
68
72
|
switch type.rawValue {
|
|
@@ -70,8 +74,6 @@ extension RunnerTests {
|
|
|
70
74
|
return "Keyboard"
|
|
71
75
|
case 20:
|
|
72
76
|
return "Key"
|
|
73
|
-
case 24:
|
|
74
|
-
return "SearchField"
|
|
75
77
|
default:
|
|
76
78
|
return "Element(\(type.rawValue))"
|
|
77
79
|
}
|
|
@@ -121,7 +121,8 @@ final class RunnerTests: XCTestCase {
|
|
|
121
121
|
.tabBar,
|
|
122
122
|
.textField,
|
|
123
123
|
.secureTextField,
|
|
124
|
-
.textView
|
|
124
|
+
.textView,
|
|
125
|
+
.webView
|
|
125
126
|
]
|
|
126
127
|
// Keep blocker actions narrow to avoid false positives from generic hittable containers.
|
|
127
128
|
let actionableTypes: Set<XCUIElement.ElementType> = [
|