execbro 2.8.3 → 2.8.4

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.
Files changed (74) hide show
  1. package/build/__tests__/unit/metroGateReconnect.test.d.ts +2 -0
  2. package/build/__tests__/unit/metroGateReconnect.test.d.ts.map +1 -0
  3. package/build/__tests__/unit/metroGateReconnect.test.js +98 -0
  4. package/build/__tests__/unit/metroGateReconnect.test.js.map +1 -0
  5. package/build/__tests__/unit/pressablesLongPress.test.d.ts +2 -0
  6. package/build/__tests__/unit/pressablesLongPress.test.d.ts.map +1 -0
  7. package/build/__tests__/unit/pressablesLongPress.test.js +91 -0
  8. package/build/__tests__/unit/pressablesLongPress.test.js.map +1 -0
  9. package/build/__tests__/unit/socketLifecycle.test.d.ts +2 -0
  10. package/build/__tests__/unit/socketLifecycle.test.d.ts.map +1 -0
  11. package/build/__tests__/unit/socketLifecycle.test.js +66 -0
  12. package/build/__tests__/unit/socketLifecycle.test.js.map +1 -0
  13. package/build/__tests__/unit/swipeProbeWithoutRn.test.d.ts +2 -0
  14. package/build/__tests__/unit/swipeProbeWithoutRn.test.d.ts.map +1 -0
  15. package/build/__tests__/unit/swipeProbeWithoutRn.test.js +44 -0
  16. package/build/__tests__/unit/swipeProbeWithoutRn.test.js.map +1 -0
  17. package/build/__tests__/unit/tapAndroidSerial.test.d.ts +2 -0
  18. package/build/__tests__/unit/tapAndroidSerial.test.d.ts.map +1 -0
  19. package/build/__tests__/unit/tapAndroidSerial.test.js +179 -0
  20. package/build/__tests__/unit/tapAndroidSerial.test.js.map +1 -0
  21. package/build/__tests__/unit/tapDuration.test.d.ts +2 -0
  22. package/build/__tests__/unit/tapDuration.test.d.ts.map +1 -0
  23. package/build/__tests__/unit/tapDuration.test.js +168 -0
  24. package/build/__tests__/unit/tapDuration.test.js.map +1 -0
  25. package/build/__tests__/unit/tapLongPressReport.test.d.ts +2 -0
  26. package/build/__tests__/unit/tapLongPressReport.test.d.ts.map +1 -0
  27. package/build/__tests__/unit/tapLongPressReport.test.js +167 -0
  28. package/build/__tests__/unit/tapLongPressReport.test.js.map +1 -0
  29. package/build/core/android.d.ts +1 -1
  30. package/build/core/android.d.ts.map +1 -1
  31. package/build/core/android.js +4 -1
  32. package/build/core/android.js.map +1 -1
  33. package/build/core/connection.d.ts.map +1 -1
  34. package/build/core/connection.js +14 -5
  35. package/build/core/connection.js.map +1 -1
  36. package/build/core/connectionState.d.ts +7 -0
  37. package/build/core/connectionState.d.ts.map +1 -1
  38. package/build/core/connectionState.js +11 -0
  39. package/build/core/connectionState.js.map +1 -1
  40. package/build/core/index.d.ts +1 -1
  41. package/build/core/index.d.ts.map +1 -1
  42. package/build/core/index.js +1 -1
  43. package/build/core/index.js.map +1 -1
  44. package/build/core/nativeOnlyHints.d.ts +7 -1
  45. package/build/core/nativeOnlyHints.d.ts.map +1 -1
  46. package/build/core/nativeOnlyHints.js +32 -4
  47. package/build/core/nativeOnlyHints.js.map +1 -1
  48. package/build/core/pressables.d.ts +1 -0
  49. package/build/core/pressables.d.ts.map +1 -1
  50. package/build/core/pressables.js +32 -8
  51. package/build/core/pressables.js.map +1 -1
  52. package/build/core/state.d.ts +1 -0
  53. package/build/core/state.d.ts.map +1 -1
  54. package/build/core/state.js +4 -0
  55. package/build/core/state.js.map +1 -1
  56. package/build/core/swipeDiagnosis.d.ts +1 -0
  57. package/build/core/swipeDiagnosis.d.ts.map +1 -1
  58. package/build/core/swipeDiagnosis.js +18 -5
  59. package/build/core/swipeDiagnosis.js.map +1 -1
  60. package/build/pro/tap.d.ts +12 -0
  61. package/build/pro/tap.d.ts.map +1 -1
  62. package/build/pro/tap.js +102 -34
  63. package/build/pro/tap.js.map +1 -1
  64. package/build/pro/verifyAction.d.ts +3 -1
  65. package/build/pro/verifyAction.d.ts.map +1 -1
  66. package/build/pro/verifyAction.js +7 -7
  67. package/build/pro/verifyAction.js.map +1 -1
  68. package/build/tools/componentTools.js +4 -4
  69. package/build/tools/componentTools.js.map +1 -1
  70. package/build/tools/interactionTools.d.ts.map +1 -1
  71. package/build/tools/interactionTools.js +20 -5
  72. package/build/tools/interactionTools.js.map +1 -1
  73. package/package.json +1 -1
  74. package/tools.json +1 -0
package/build/pro/tap.js CHANGED
@@ -87,6 +87,24 @@ export async function analyzeBurstFrames(frames, options) {
87
87
  kind
88
88
  };
89
89
  }
90
+ export function buildLongPressReport(args) {
91
+ if (args.durationMs === undefined)
92
+ return undefined;
93
+ if (args.hasLongPress === undefined) {
94
+ return { durationMs: args.durationMs, handlerFound: null };
95
+ }
96
+ if (args.hasLongPress) {
97
+ return { durationMs: args.durationMs, handlerFound: true };
98
+ }
99
+ const what = args.element ? `<${args.element} />` : "the element";
100
+ return {
101
+ durationMs: args.durationMs,
102
+ handlerFound: false,
103
+ warning: `Held for ${args.durationMs}ms, but ${what} has no onLongPress handler — ` +
104
+ `React Native will have fired its onPress on release instead. The gesture was ` +
105
+ `delivered; if you expected a long-press action, it is not wired to this element.`
106
+ };
107
+ }
90
108
  export function buildQuery(options) {
91
109
  const query = {};
92
110
  if (options.text !== undefined)
@@ -416,7 +434,7 @@ export function findClosestOcrText(ocrResult, query) {
416
434
  }
417
435
  return best;
418
436
  }
419
- async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device) {
437
+ async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device, longPress = false) {
420
438
  if (sink) {
421
439
  sink.fiber.ran = true;
422
440
  sink.fiber.metroConnected = connectedApps.size > 0;
@@ -433,7 +451,7 @@ async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device) {
433
451
  }
434
452
  let lastResult = null;
435
453
  for (const depth of depthAttempts) {
436
- const result = await tryFiberAtDepth(query, index, depth, device);
454
+ const result = await tryFiberAtDepth(query, index, depth, device, longPress);
437
455
  if (sink && result.matches?.length) {
438
456
  sink.fiber.pressables = result.matches.slice(0, 50).map(m => ({
439
457
  label: m.text || undefined,
@@ -456,7 +474,7 @@ async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device) {
456
474
  sink.fiber.durationMs = Date.now() - startedAt;
457
475
  }
458
476
  }
459
- async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
477
+ async function tryFiberAtDepth(query, index, maxTraversalDepth, device, longPress = false) {
460
478
  try {
461
479
  const result = await pressElement({
462
480
  text: query.text,
@@ -464,7 +482,8 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
464
482
  component: query.component,
465
483
  index,
466
484
  maxTraversalDepth,
467
- device
485
+ device,
486
+ longPress
468
487
  });
469
488
  if (!result.success) {
470
489
  return { success: false, reason: result.error || "pressElement failed" };
@@ -508,7 +527,8 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
508
527
  x: parsed.nativeTapTarget.x,
509
528
  y: parsed.nativeTapTarget.y,
510
529
  unit: parsed.nativeTapTarget.unit || "points"
511
- }
530
+ },
531
+ hasLongPress: !!parsed.hasLongPress
512
532
  };
513
533
  }
514
534
  return {
@@ -528,7 +548,7 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
528
548
  };
529
549
  }
530
550
  }
531
- async function tryAccessibilityStrategy(query, index, platform, udid, sink, signal) {
551
+ async function tryAccessibilityStrategy(query, index, platform, udid, sink, signal, deviceId, duration) {
532
552
  if (sink)
533
553
  sink.accessibility.ran = true;
534
554
  const startedAt = Date.now();
@@ -616,7 +636,7 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
616
636
  reason: `Index ${index} out of bounds (${iosEffectiveMatches.length} matches)`
617
637
  };
618
638
  }
619
- await iosTap(match.center.x, match.center.y, { udid });
639
+ await iosTap(match.center.x, match.center.y, { udid, duration });
620
640
  return {
621
641
  success: true,
622
642
  reason: "Tapped via iOS accessibility",
@@ -635,13 +655,13 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
635
655
  searchOptions.textContains = query.text;
636
656
  }
637
657
  const { androidGetUITree } = await import("../core/android.js");
638
- const androidTree = await androidGetUITree(undefined, signal);
639
- let result = await androidFindElement(searchOptions, undefined, signal, androidTree);
658
+ const androidTree = await androidGetUITree(deviceId, signal);
659
+ let result = await androidFindElement(searchOptions, deviceId, signal, androidTree);
640
660
  if (hasTestID && !hasText && (!result.success || !result.allMatches || result.allMatches.length === 0)) {
641
661
  result = await androidFindElement({
642
662
  contentDescContains: query.testID,
643
663
  index
644
- }, undefined, signal, androidTree);
664
+ }, deviceId, signal, androidTree);
645
665
  }
646
666
  if (sink && result.allMatches?.length) {
647
667
  sink.accessibility.elements = result.allMatches.slice(0, 50).map(el => ({
@@ -683,7 +703,13 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
683
703
  reason: `Index ${index} out of bounds (${androidEffectiveMatches.length} matches)`
684
704
  };
685
705
  }
686
- await androidTap(match.center.x, match.center.y);
706
+ const a11yTap = await androidTap(match.center.x, match.center.y, deviceId, duration);
707
+ if (!a11yTap.success) {
708
+ return {
709
+ success: false,
710
+ reason: `Accessibility found "${match.text ?? match.contentDesc ?? match.resourceId}" but tap failed: ${a11yTap.error}`
711
+ };
712
+ }
687
713
  return {
688
714
  success: true,
689
715
  reason: "Tapped via Android accessibility",
@@ -705,7 +731,7 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
705
731
  sink.accessibility.durationMs = Date.now() - startedAt;
706
732
  }
707
733
  }
708
- async function tryOcrStrategy(query, platform, udid, sink, signal) {
734
+ async function tryOcrStrategy(query, platform, udid, sink, signal, deviceId, duration) {
709
735
  if (sink)
710
736
  sink.ocr.ran = true;
711
737
  const ocrStartedAt = Date.now();
@@ -729,7 +755,7 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
729
755
  }
730
756
  else {
731
757
  const { androidScreenshot } = await import("../core/android.js");
732
- const screenshot = await androidScreenshot(undefined, undefined, signal);
758
+ const screenshot = await androidScreenshot(undefined, deviceId, signal);
733
759
  if (!screenshot.success || !screenshot.data) {
734
760
  return {
735
761
  success: false,
@@ -776,7 +802,7 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
776
802
  if (platform === "ios") {
777
803
  const { getDevicePixelRatio } = await import("../core/ios.js");
778
804
  const dpr = await getDevicePixelRatio(udid);
779
- const tapResult = await iosTap(Math.round((match.tapCenter.x * scaleFactor) / dpr), Math.round((match.tapCenter.y * scaleFactor) / dpr), { udid });
805
+ const tapResult = await iosTap(Math.round((match.tapCenter.x * scaleFactor) / dpr), Math.round((match.tapCenter.y * scaleFactor) / dpr), { udid, duration });
780
806
  if (!tapResult.success) {
781
807
  return {
782
808
  success: false,
@@ -785,7 +811,13 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
785
811
  }
786
812
  }
787
813
  else {
788
- await androidTap(Math.round(match.tapCenter.x * scaleFactor), Math.round(match.tapCenter.y * scaleFactor));
814
+ const ocrTap = await androidTap(Math.round(match.tapCenter.x * scaleFactor), Math.round(match.tapCenter.y * scaleFactor), deviceId, duration);
815
+ if (!ocrTap.success) {
816
+ return {
817
+ success: false,
818
+ reason: `OCR found "${match.text}" but tap failed: ${ocrTap.error}`
819
+ };
820
+ }
789
821
  }
790
822
  return {
791
823
  success: true,
@@ -809,7 +841,7 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
809
841
  sink.ocr.durationMs = Date.now() - ocrStartedAt;
810
842
  }
811
843
  }
812
- async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, udid) {
844
+ async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, udid, deviceId, duration) {
813
845
  try {
814
846
  if (platform === "ios") {
815
847
  const scaleFactor = lastScreenshot?.scaleFactor ?? 1;
@@ -819,7 +851,7 @@ async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, u
819
851
  : undefined;
820
852
  const devicePixelRatio = await getDevicePixelRatio(udid, dprHint);
821
853
  const converted = convertScreenshotToTapCoords(pixelX, pixelY, "ios", devicePixelRatio, scaleFactor);
822
- const tapResult = await iosTap(converted.x, converted.y, { udid });
854
+ const tapResult = await iosTap(converted.x, converted.y, { udid, duration });
823
855
  if (!tapResult.success) {
824
856
  return {
825
857
  success: false,
@@ -835,7 +867,13 @@ async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, u
835
867
  else {
836
868
  const scaleFactor = lastScreenshot?.scaleFactor ?? 1;
837
869
  const converted = convertScreenshotToTapCoords(pixelX, pixelY, "android", 1, scaleFactor);
838
- await androidTap(converted.x, converted.y);
870
+ const coordTap = await androidTap(converted.x, converted.y, deviceId, duration);
871
+ if (!coordTap.success) {
872
+ return {
873
+ success: false,
874
+ reason: `Coordinate tap failed: ${coordTap.error}`
875
+ };
876
+ }
839
877
  return {
840
878
  success: true,
841
879
  reason: "Tapped at coordinates (Android)",
@@ -1145,12 +1183,13 @@ export async function tap(options) {
1145
1183
  }
1146
1184
  const platform = nativeResolved.target.platform;
1147
1185
  const nativeUdid = nativeResolved.target.iosUdid;
1186
+ const nativeSerial = nativeResolved.target.androidSerial;
1148
1187
  const nativeShouldScreenshot = options.screenshot !== false;
1149
1188
  const nativeShouldVerify = options.verify !== false;
1150
1189
  let nativeBeforeBuffer = null;
1151
1190
  let nativeScreenshotMeta;
1152
1191
  if (nativeShouldVerify) {
1153
- const before = await captureScreenshot(platform, nativeUdid);
1192
+ const before = await captureScreenshot(platform, nativeUdid, nativeSerial);
1154
1193
  nativeBeforeBuffer = before?.buffer || null;
1155
1194
  if (before) {
1156
1195
  nativeScreenshotMeta = {
@@ -1161,7 +1200,7 @@ export async function tap(options) {
1161
1200
  }
1162
1201
  }
1163
1202
  if (!nativeScreenshotMeta) {
1164
- const ref = await captureScreenshot(platform, nativeUdid);
1203
+ const ref = await captureScreenshot(platform, nativeUdid, nativeSerial);
1165
1204
  if (ref) {
1166
1205
  nativeScreenshotMeta = {
1167
1206
  originalWidth: ref.width,
@@ -1175,7 +1214,7 @@ export async function tap(options) {
1175
1214
  }
1176
1215
  let result;
1177
1216
  try {
1178
- result = await withTimeout(tryCoordinateStrategy(query.x, query.y, platform, nativeScreenshotMeta, nativeUdid), remainingMs(), "native-coordinate");
1217
+ result = await withTimeout(tryCoordinateStrategy(query.x, query.y, platform, nativeScreenshotMeta, nativeUdid, nativeSerial, options.duration), remainingMs(), "native-coordinate");
1179
1218
  }
1180
1219
  catch (err) {
1181
1220
  return formatTapFailure({
@@ -1203,6 +1242,7 @@ export async function tap(options) {
1203
1242
  platform,
1204
1243
  beforeBuffer: nativeBeforeBuffer,
1205
1244
  udid: nativeUdid,
1245
+ deviceId: nativeSerial,
1206
1246
  beforeScaleFactor: nativeScreenshotMeta?.scaleFactor,
1207
1247
  markerPx: nativeMarker
1208
1248
  }));
@@ -1216,11 +1256,12 @@ export async function tap(options) {
1216
1256
  shouldScreenshot: nativeShouldScreenshot,
1217
1257
  beforeBuffer: nativeBeforeBuffer,
1218
1258
  udid: nativeUdid,
1259
+ deviceId: nativeSerial,
1219
1260
  beforeScaleFactor: nativeScreenshotMeta?.scaleFactor,
1220
1261
  markerPx: nativeMarker
1221
1262
  }));
1222
1263
  }
1223
- return formatTapSuccess({
1264
+ const nativeSuccess = formatTapSuccess({
1224
1265
  method: "native-coordinate",
1225
1266
  query,
1226
1267
  pressed: result.pressed,
@@ -1229,6 +1270,10 @@ export async function tap(options) {
1229
1270
  screenshot,
1230
1271
  verification
1231
1272
  });
1273
+ const nativeLongPress = buildLongPressReport({ durationMs: options.duration });
1274
+ if (nativeLongPress)
1275
+ nativeSuccess.longPress = nativeLongPress;
1276
+ return nativeSuccess;
1232
1277
  }
1233
1278
  return formatTapFailure({
1234
1279
  query,
@@ -1247,6 +1292,7 @@ export async function tap(options) {
1247
1292
  const deviceNote = resolved.note;
1248
1293
  const platform = resolved.target.platform;
1249
1294
  let targetUdid = resolved.target.iosUdid;
1295
+ const targetSerial = resolved.target.androidSerial;
1250
1296
  const allApps = Array.from(connectedApps.values());
1251
1297
  let hasMetro = allApps.length > 0;
1252
1298
  let app;
@@ -1384,7 +1430,7 @@ export async function tap(options) {
1384
1430
  let beforeScaleFactor;
1385
1431
  let beforeDims;
1386
1432
  {
1387
- const before = await captureScreenshot(platform, targetUdid);
1433
+ const before = await captureScreenshot(platform, targetUdid, targetSerial);
1388
1434
  beforeBuffer = before?.buffer || null;
1389
1435
  beforeScaleFactor = before?.scaleFactor;
1390
1436
  if (before && before.width > 0 && before.height > 0) {
@@ -1407,13 +1453,13 @@ export async function tap(options) {
1407
1453
  try {
1408
1454
  switch (strat) {
1409
1455
  case "fiber":
1410
- result = await withTimeout(tryFiberStrategy(query, index, maxTraversalDepth, evidence, deviceName), budget, `fiber`);
1456
+ result = await withTimeout(tryFiberStrategy(query, index, maxTraversalDepth, evidence, deviceName, options.duration !== undefined), budget, `fiber`);
1411
1457
  break;
1412
1458
  case "accessibility":
1413
- result = await withCancelableTimeout((signal) => tryAccessibilityStrategy(query, index, platform, targetUdid, evidence, signal), budget, `accessibility`);
1459
+ result = await withCancelableTimeout((signal) => tryAccessibilityStrategy(query, index, platform, targetUdid, evidence, signal, targetSerial, options.duration), budget, `accessibility`);
1414
1460
  break;
1415
1461
  case "ocr":
1416
- result = await withCancelableTimeout((signal) => tryOcrStrategy(query, platform, targetUdid, evidence, signal), budget, `ocr`);
1462
+ result = await withCancelableTimeout((signal) => tryOcrStrategy(query, platform, targetUdid, evidence, signal, targetSerial, options.duration), budget, `ocr`);
1417
1463
  break;
1418
1464
  case "coordinate":
1419
1465
  result = await withTimeout(tryCoordinateStrategy(query.x, query.y, platform, beforeScaleFactor != null
@@ -1422,7 +1468,7 @@ export async function tap(options) {
1422
1468
  originalHeight: beforeDims?.height ?? 0,
1423
1469
  scaleFactor: beforeScaleFactor
1424
1470
  }
1425
- : app?.lastScreenshot, targetUdid), budget, `coordinate`);
1471
+ : app?.lastScreenshot, targetUdid, targetSerial, options.duration), budget, `coordinate`);
1426
1472
  break;
1427
1473
  default:
1428
1474
  result = { success: false, reason: `Unknown strategy: ${strat}` };
@@ -1461,6 +1507,7 @@ export async function tap(options) {
1461
1507
  platform,
1462
1508
  beforeBuffer,
1463
1509
  udid: targetUdid,
1510
+ deviceId: targetSerial,
1464
1511
  beforeScaleFactor,
1465
1512
  markerPx: strategyMarker
1466
1513
  }));
@@ -1474,6 +1521,7 @@ export async function tap(options) {
1474
1521
  shouldScreenshot: true,
1475
1522
  beforeBuffer,
1476
1523
  udid: targetUdid,
1524
+ deviceId: targetSerial,
1477
1525
  beforeScaleFactor,
1478
1526
  markerPx: strategyMarker
1479
1527
  }));
@@ -1501,6 +1549,13 @@ export async function tap(options) {
1501
1549
  screenshot,
1502
1550
  verification
1503
1551
  });
1552
+ const strategyLongPress = buildLongPressReport({
1553
+ durationMs: options.duration,
1554
+ hasLongPress: result.hasLongPress,
1555
+ element: result.pressed
1556
+ });
1557
+ if (strategyLongPress)
1558
+ successResult.longPress = strategyLongPress;
1504
1559
  if (shadowWarning) {
1505
1560
  successResult.warning = successResult.warning
1506
1561
  ? `${successResult.warning}\n${shadowWarning}`
@@ -1558,16 +1613,19 @@ export async function tap(options) {
1558
1613
  if (platform === "ios") {
1559
1614
  const safeAreaTop = await getIOSSafeAreaTop(targetUdid);
1560
1615
  const tapY = (safeAreaTop > 0 && coords.y < safeAreaTop) ? coords.y + safeAreaTop : coords.y;
1561
- await iosTap(coords.x, tapY, { udid: targetUdid });
1616
+ await iosTap(coords.x, tapY, { udid: targetUdid, duration: options.duration });
1562
1617
  coords.y = tapY;
1563
1618
  }
1564
1619
  else {
1565
1620
  const { androidGetDensity } = await import("../core/android.js");
1566
- const densityResult = await androidGetDensity();
1621
+ const densityResult = await androidGetDensity(targetSerial);
1567
1622
  const densityScale = (densityResult.density || 420) / 160;
1568
1623
  const pxX = Math.round(coords.x * densityScale);
1569
1624
  const pxY = Math.round(coords.y * densityScale);
1570
- await androidTap(pxX, pxY);
1625
+ const fiberTap = await androidTap(pxX, pxY, targetSerial, options.duration);
1626
+ if (!fiberTap.success) {
1627
+ throw new Error(fiberTap.error || "adb tap failed");
1628
+ }
1571
1629
  coords.x = pxX;
1572
1630
  coords.y = pxY;
1573
1631
  coords.unit = "pixels";
@@ -1588,7 +1646,7 @@ export async function tap(options) {
1588
1646
  else {
1589
1647
  try {
1590
1648
  const { androidGetDensity } = await import("../core/android.js");
1591
- const d = await androidGetDensity();
1649
+ const d = await androidGetDensity(targetSerial);
1592
1650
  fnDensity = (d.density || 420) / 160;
1593
1651
  }
1594
1652
  catch {
@@ -1608,6 +1666,7 @@ export async function tap(options) {
1608
1666
  platform,
1609
1667
  beforeBuffer,
1610
1668
  udid: targetUdid,
1669
+ deviceId: targetSerial,
1611
1670
  beforeScaleFactor,
1612
1671
  markerPx: fiberMarker
1613
1672
  }));
@@ -1619,6 +1678,7 @@ export async function tap(options) {
1619
1678
  shouldScreenshot: true,
1620
1679
  beforeBuffer,
1621
1680
  udid: targetUdid,
1681
+ deviceId: targetSerial,
1622
1682
  beforeScaleFactor,
1623
1683
  markerPx: fiberMarker
1624
1684
  }));
@@ -1632,7 +1692,7 @@ export async function tap(options) {
1632
1692
  scaleFactor: screenshot.scaleFactor
1633
1693
  };
1634
1694
  }
1635
- return formatTapSuccess({
1695
+ const fiberSuccess = formatTapSuccess({
1636
1696
  method: "fiber+native",
1637
1697
  query,
1638
1698
  pressed: result.pressed,
@@ -1646,13 +1706,21 @@ export async function tap(options) {
1646
1706
  screenshot,
1647
1707
  verification
1648
1708
  });
1709
+ const fiberLongPress = buildLongPressReport({
1710
+ durationMs: options.duration,
1711
+ hasLongPress: result.hasLongPress,
1712
+ element: result.pressed
1713
+ });
1714
+ if (fiberLongPress)
1715
+ fiberSuccess.longPress = fiberLongPress;
1716
+ return fiberSuccess;
1649
1717
  }
1650
1718
  catch {
1651
1719
  }
1652
1720
  }
1653
1721
  if (result.matches && result.ambiguous) {
1654
1722
  const { screenshot: matchScreenshot } = shouldScreenshot
1655
- ? await verifyAndCapture({ platform, shouldVerify: false, shouldScreenshot: true, beforeBuffer: null, udid: targetUdid })
1723
+ ? await verifyAndCapture({ platform, shouldVerify: false, shouldScreenshot: true, beforeBuffer: null, udid: targetUdid, deviceId: targetSerial })
1656
1724
  : { screenshot: undefined };
1657
1725
  if (matchScreenshot && app) {
1658
1726
  app.lastScreenshot = {
@@ -1685,7 +1753,7 @@ export async function tap(options) {
1685
1753
  suggestion = `All strategies timed out — the element's presence is UNKNOWN. Retry the tap (transient slowness is common on dense screens), or try a different strategy explicitly (e.g. strategy='fiber' if accessibility timed out). ` + suggestion;
1686
1754
  }
1687
1755
  const { screenshot: failScreenshot } = shouldScreenshot
1688
- ? await verifyAndCapture({ platform, shouldVerify: false, shouldScreenshot: true, beforeBuffer: null, udid: targetUdid })
1756
+ ? await verifyAndCapture({ platform, shouldVerify: false, shouldScreenshot: true, beforeBuffer: null, udid: targetUdid, deviceId: targetSerial })
1689
1757
  : { screenshot: undefined };
1690
1758
  if (failScreenshot && app) {
1691
1759
  app.lastScreenshot = {