(
devices: DeviceInfo[],
selector: DeviceSelector,
context: DeviceSelectionContext = {},
)
| 222 | } |
| 223 | |
| 224 | export async function resolveDevice( |
| 225 | devices: DeviceInfo[], |
| 226 | selector: DeviceSelector, |
| 227 | context: DeviceSelectionContext = {}, |
| 228 | ): Promise<DeviceInfo> { |
| 229 | let candidates = devices.filter((device) => matchesDeviceSelector(device, selector)); |
| 230 | |
| 231 | if (selector.udid) { |
| 232 | const match = candidates.find( |
| 233 | (device) => device.id === selector.udid && isApplePlatform(device.platform), |
| 234 | ); |
| 235 | if (!match) |
| 236 | throw new AppError('DEVICE_NOT_FOUND', `No Apple device with UDID ${selector.udid}`); |
| 237 | return match; |
| 238 | } |
| 239 | |
| 240 | if (selector.serial) { |
| 241 | const match = candidates.find( |
| 242 | (device) => device.id === selector.serial && device.platform === 'android', |
| 243 | ); |
| 244 | if (!match) |
| 245 | throw new AppError('DEVICE_NOT_FOUND', `No Android device with serial ${selector.serial}`); |
| 246 | return match; |
| 247 | } |
| 248 | |
| 249 | if (context.allowStoppedAndroidAvdPlaceholders !== true) { |
| 250 | candidates = candidates.filter((device) => !isStoppedAndroidAvdPlaceholder(device)); |
| 251 | } |
| 252 | |
| 253 | if (selector.deviceName) { |
| 254 | const normalizedName = normalizeDeviceName(selector.deviceName); |
| 255 | const match = candidates.find((device) => normalizeDeviceName(device.name) === normalizedName); |
| 256 | if (!match) throw new AppError('DEVICE_NOT_FOUND', `No device named ${selector.deviceName}`); |
| 257 | return match; |
| 258 | } |
| 259 | |
| 260 | if (isAppleDeviceCandidateSet(candidates)) { |
| 261 | candidates = sortAppleDevicesForSelection(candidates); |
| 262 | } |
| 263 | |
| 264 | const onlyCandidate = candidates[0]; |
| 265 | if (onlyCandidate !== undefined && candidates.length === 1) return onlyCandidate; |
| 266 | |
| 267 | if (candidates.length === 0) { |
| 268 | throwNoDevicesFound(selector, context); |
| 269 | } |
| 270 | |
| 271 | const virtual = candidates.filter((device) => device.kind !== 'device'); |
| 272 | const selectable = virtual.length > 0 ? virtual : candidates; |
| 273 | const booted = selectable.filter((device) => device.booted); |
| 274 | const onlyBooted = booted[0]; |
| 275 | if (onlyBooted && booted.length === 1 && !isAppleDeviceCandidateSet(selectable)) { |
| 276 | return onlyBooted; |
| 277 | } |
| 278 | const selected = isAppleDeviceCandidateSet(selectable) |
| 279 | ? selectable[0] |
| 280 | : (booted[0] ?? selectable[0]); |
| 281 | if (!selected) throwNoDevicesFound(selector, context); |
no test coverage detected