@midscene/ios 1.8.0 → 1.8.1

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/dist/lib/cli.js CHANGED
@@ -673,16 +673,6 @@ function _define_property(obj, key, value) {
673
673
  return obj;
674
674
  }
675
675
  const debugDevice = (0, logger_namespaceObject.getDebug)('ios:device');
676
- const iosInputParamSchema = core_namespaceObject.z.object({
677
- value: core_namespaceObject.z.string().describe('The text to input. Provide the final content for replace/append modes, or an empty string when using clear mode to remove existing text.'),
678
- autoDismissKeyboard: core_namespaceObject.z.boolean().optional().describe('Whether to dismiss the keyboard after input. Defaults to true if not specified. Set to false to keep the keyboard visible after input.'),
679
- mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
680
- 'replace',
681
- 'clear',
682
- 'typeOnly'
683
- ]).default('replace').optional().describe('Input mode: "replace" (default) - clear the field and input the value; "typeOnly" - type the value directly without clearing the field first; "clear" - clear the field without inputting new text.')),
684
- locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
685
- });
686
676
  const WDA_HTTP_METHODS = [
687
677
  'GET',
688
678
  'POST',
@@ -691,96 +681,39 @@ const WDA_HTTP_METHODS = [
691
681
  ];
692
682
  const DEFAULT_WDA_MJPEG_PORT = 9100;
693
683
  class IOSDevice {
684
+ async tapPoint(point) {
685
+ debugDevice(`tap at coordinates (${point.x}, ${point.y})`);
686
+ await this.wdaBackend.tap(Math.round(point.x), Math.round(point.y));
687
+ }
688
+ async doubleTapPoint(point) {
689
+ await this.wdaBackend.doubleTap(Math.round(point.x), Math.round(point.y));
690
+ }
691
+ async longPressPoint(point, duration = 1000) {
692
+ await this.wdaBackend.longPress(Math.round(point.x), Math.round(point.y), duration);
693
+ }
694
+ async swipePoint(start, end, duration = 500) {
695
+ await this.wdaBackend.swipe(Math.round(start.x), Math.round(start.y), Math.round(end.x), Math.round(end.y), duration);
696
+ }
697
+ async clearInputAt(point) {
698
+ if (point) {
699
+ await this.tapPoint(point);
700
+ await (0, core_utils_namespaceObject.sleep)(100);
701
+ }
702
+ debugDevice('Attempting to clear input with WebDriver Clear API');
703
+ const cleared = await this.wdaBackend.clearActiveElement();
704
+ cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
705
+ }
694
706
  actionSpace() {
707
+ const mobileActionContext = {
708
+ input: this.inputPrimitives,
709
+ size: ()=>this.size(),
710
+ sleep: async (timeMs)=>{
711
+ await (0, core_utils_namespaceObject.sleep)(timeMs);
712
+ },
713
+ getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard
714
+ };
695
715
  const defaultActions = [
696
- (0, device_namespaceObject.defineActionTap)(async (param)=>{
697
- const element = param.locate;
698
- external_node_assert_default()(element, 'Element not found, cannot tap');
699
- await this.mouseClick(element.center[0], element.center[1]);
700
- }),
701
- (0, device_namespaceObject.defineActionDoubleClick)(async (param)=>{
702
- const element = param.locate;
703
- external_node_assert_default()(element, 'Element not found, cannot double click');
704
- await this.doubleTap(element.center[0], element.center[1]);
705
- }),
706
- (0, device_namespaceObject.defineAction)({
707
- name: 'Input',
708
- description: 'Input text into the input field',
709
- interfaceAlias: 'aiInput',
710
- paramSchema: iosInputParamSchema,
711
- sample: {
712
- value: 'test@example.com',
713
- locate: {
714
- prompt: 'the email input field'
715
- }
716
- },
717
- call: async (param)=>{
718
- const element = param.locate;
719
- if ('typeOnly' !== param.mode) await this.clearInput(element);
720
- if ('clear' === param.mode) return;
721
- if (!param || !param.value) return;
722
- const autoDismissKeyboard = param.autoDismissKeyboard ?? this.options?.autoDismissKeyboard;
723
- await this.typeText(param.value, {
724
- autoDismissKeyboard
725
- });
726
- }
727
- }),
728
- (0, device_namespaceObject.defineActionScroll)(async (param)=>{
729
- const element = param.locate;
730
- const startingPoint = element ? {
731
- left: element.center[0],
732
- top: element.center[1]
733
- } : void 0;
734
- const scrollToEventName = param?.scrollType;
735
- if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
736
- else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
737
- else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
738
- else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
739
- else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
740
- else {
741
- if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
742
- else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
743
- else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
744
- else throw new Error(`Unknown scroll direction: ${param.direction}`);
745
- else await this.scrollDown(param?.distance || void 0, startingPoint);
746
- await (0, core_utils_namespaceObject.sleep)(500);
747
- }
748
- }),
749
- (0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
750
- const from = param.from;
751
- const to = param.to;
752
- external_node_assert_default()(from, 'missing "from" param for drag and drop');
753
- external_node_assert_default()(to, 'missing "to" param for drag and drop');
754
- await this.swipe(from.center[0], from.center[1], to.center[0], to.center[1], 1000);
755
- }),
756
- (0, device_namespaceObject.defineActionSwipe)(async (param)=>{
757
- const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
758
- for(let i = 0; i < repeatCount; i++)await this.swipe(startPoint.x, startPoint.y, endPoint.x, endPoint.y, duration);
759
- }),
760
- (0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
761
- await this.pressKey(param.keyName);
762
- }),
763
- (0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
764
- const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
765
- const times = param.times ?? 1;
766
- for(let i = 0; i < times; i++){
767
- await this.pressKey(arrowKey);
768
- await (0, core_utils_namespaceObject.sleep)(100);
769
- }
770
- }),
771
- (0, device_namespaceObject.defineActionLongPress)(async (param)=>{
772
- const element = param.locate;
773
- external_node_assert_default()(element, 'LongPress requires an element to be located');
774
- const [x, y] = element.center;
775
- await this.longPress(x, y, param?.duration);
776
- }),
777
- (0, device_namespaceObject.defineActionPinch)(async (param)=>{
778
- const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
779
- await this.wdaBackend.pinch(centerX, centerY, startDistance, endDistance, duration);
780
- }),
781
- (0, device_namespaceObject.defineActionClearInput)(async (param)=>{
782
- await this.clearInput(param.locate);
783
- })
716
+ ...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext)
784
717
  ];
785
718
  const platformSpecificActions = Object.values(createPlatformActions(this));
786
719
  const customActions = this.customActions || [];
@@ -790,6 +723,27 @@ class IOSDevice {
790
723
  ...customActions
791
724
  ];
792
725
  }
726
+ async performActionScroll(param) {
727
+ const element = param.locate;
728
+ const startingPoint = element ? {
729
+ left: element.center[0],
730
+ top: element.center[1]
731
+ } : void 0;
732
+ const scrollToEventName = param?.scrollType;
733
+ if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
734
+ else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
735
+ else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
736
+ else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
737
+ else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
738
+ else {
739
+ if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
740
+ else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
741
+ else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
742
+ else throw new Error(`Unknown scroll direction: ${param.direction}`);
743
+ else await this.scrollDown(param?.distance || void 0, startingPoint);
744
+ await (0, core_utils_namespaceObject.sleep)(500);
745
+ }
746
+ }
793
747
  describe() {
794
748
  return this.description || `Device ID: ${this.deviceId}`;
795
749
  }
@@ -901,35 +855,31 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
901
855
  }
902
856
  }
903
857
  async clearInput(element) {
904
- if (element) {
905
- await this.tap(element.center[0], element.center[1]);
906
- await (0, core_utils_namespaceObject.sleep)(100);
907
- }
908
- debugDevice('Attempting to clear input with WebDriver Clear API');
909
- const cleared = await this.wdaBackend.clearActiveElement();
910
- cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
858
+ await this.clearInputAt(element ? {
859
+ x: element.center[0],
860
+ y: element.center[1]
861
+ } : void 0);
911
862
  }
912
863
  async url() {
913
864
  return '';
914
865
  }
915
866
  async tap(x, y) {
916
- await this.wdaBackend.tap(Math.round(x), Math.round(y));
917
- }
918
- async mouseClick(x, y) {
919
- debugDevice(`mouseClick at coordinates (${x}, ${y})`);
920
- await this.tap(x, y);
921
- }
922
- async doubleTap(x, y) {
923
- await this.wdaBackend.doubleTap(Math.round(x), Math.round(y));
924
- }
925
- async tripleTap(x, y) {
926
- await this.wdaBackend.tripleTap(Math.round(x), Math.round(y));
927
- }
928
- async longPress(x, y, duration = 1000) {
929
- await this.wdaBackend.longPress(Math.round(x), Math.round(y), duration);
867
+ await this.tapPoint({
868
+ x,
869
+ y
870
+ });
930
871
  }
931
872
  async swipe(fromX, fromY, toX, toY, duration = 500) {
932
- await this.wdaBackend.swipe(Math.round(fromX), Math.round(fromY), Math.round(toX), Math.round(toY), duration);
873
+ await this.swipeCoordinates(fromX, fromY, toX, toY, duration);
874
+ }
875
+ async swipeCoordinates(fromX, fromY, toX, toY, duration = 500) {
876
+ await this.swipePoint({
877
+ x: fromX,
878
+ y: fromY
879
+ }, {
880
+ x: toX,
881
+ y: toY
882
+ }, duration);
933
883
  }
934
884
  async typeText(text, options) {
935
885
  if (!text) return;
@@ -958,7 +908,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
958
908
  y: Math.round(height / 2)
959
909
  };
960
910
  const scrollDistance = Math.round(distance || height / 3);
961
- await this.swipe(start.x, start.y, start.x, start.y + scrollDistance);
911
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance);
962
912
  }
963
913
  async scrollDown(distance, startPoint) {
964
914
  const { width, height } = await this.size();
@@ -970,7 +920,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
970
920
  y: Math.round(height / 2)
971
921
  };
972
922
  const scrollDistance = Math.round(distance || height / 3);
973
- await this.swipe(start.x, start.y, start.x, start.y - scrollDistance);
923
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance);
974
924
  }
975
925
  async scrollLeft(distance, startPoint) {
976
926
  const { width, height } = await this.size();
@@ -982,7 +932,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
982
932
  y: Math.round(height / 2)
983
933
  };
984
934
  const scrollDistance = Math.round(distance || 0.7 * width);
985
- await this.swipe(start.x, start.y, start.x + scrollDistance, start.y);
935
+ await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y);
986
936
  }
987
937
  async scrollRight(distance, startPoint) {
988
938
  const { width, height } = await this.size();
@@ -994,7 +944,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
994
944
  y: Math.round(height / 2)
995
945
  };
996
946
  const scrollDistance = Math.round(distance || 0.7 * width);
997
- await this.swipe(start.x, start.y, start.x - scrollDistance, start.y);
947
+ await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y);
998
948
  }
999
949
  async scrollUntilTop(startPoint) {
1000
950
  debugDevice('Using screenshot-based scroll detection for better reliability');
@@ -1090,16 +1040,16 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
1090
1040
  debugDevice(`Performing scroll: ${direction}, distance: ${scrollDistance}`);
1091
1041
  switch(direction){
1092
1042
  case 'up':
1093
- await this.swipe(start.x, start.y, start.x, start.y + scrollDistance, 300);
1043
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance, 300);
1094
1044
  break;
1095
1045
  case 'down':
1096
- await this.swipe(start.x, start.y, start.x, start.y - scrollDistance, 300);
1046
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance, 300);
1097
1047
  break;
1098
1048
  case 'left':
1099
- await this.swipe(start.x, start.y, start.x + scrollDistance, start.y, 300);
1049
+ await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y, 300);
1100
1050
  break;
1101
1051
  case 'right':
1102
- await this.swipe(start.x, start.y, start.x - scrollDistance, start.y, 300);
1052
+ await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y, 300);
1103
1053
  break;
1104
1054
  }
1105
1055
  debugDevice('Waiting for scroll and inertia to complete...');
@@ -1156,7 +1106,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
1156
1106
  const centerX = Math.round(windowSize.width / 2);
1157
1107
  const startY = Math.round(0.9 * windowSize.height);
1158
1108
  const endY = Math.round(0.5 * windowSize.height);
1159
- await this.swipe(centerX, startY, centerX, endY, 300);
1109
+ await this.swipeCoordinates(centerX, startY, centerX, endY, 300);
1160
1110
  debugDevice('Dismissed keyboard with swipe up gesture from bottom of screen');
1161
1111
  await (0, core_utils_namespaceObject.sleep)(500);
1162
1112
  return true;
@@ -1233,6 +1183,45 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
1233
1183
  _define_property(this, "interfaceType", 'ios');
1234
1184
  _define_property(this, "uri", void 0);
1235
1185
  _define_property(this, "options", void 0);
1186
+ _define_property(this, "inputPrimitives", {
1187
+ pointer: {
1188
+ tap: (point)=>this.tapPoint(point),
1189
+ doubleClick: (point)=>this.doubleTapPoint(point),
1190
+ longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
1191
+ dragAndDrop: (from, to)=>this.swipePoint(from, to, 1000)
1192
+ },
1193
+ keyboard: {
1194
+ keyboardPress: (keyName)=>this.pressKey(keyName),
1195
+ typeText: async (value, opts)=>{
1196
+ const target = opts?.target;
1197
+ if (target && opts?.replace !== false) await this.clearInput(target);
1198
+ else if (target) await this.tapPoint({
1199
+ x: target.center[0],
1200
+ y: target.center[1]
1201
+ });
1202
+ if (opts?.focusOnly) return;
1203
+ await this.typeText(value, opts);
1204
+ },
1205
+ clearInput: (target)=>this.clearInput(target),
1206
+ cursorMove: async (direction, times = 1)=>{
1207
+ const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
1208
+ for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
1209
+ }
1210
+ },
1211
+ touch: {
1212
+ swipe: async (start, end, opts)=>{
1213
+ const duration = opts?.duration ?? 300;
1214
+ const repeat = opts?.repeat ?? 1;
1215
+ for(let i = 0; i < repeat; i++)await this.swipePoint(start, end, duration);
1216
+ },
1217
+ pinch: async (center, opts)=>{
1218
+ await this.wdaBackend.pinch(Math.round(center.x), Math.round(center.y), opts.startDistance, opts.endDistance, opts.duration);
1219
+ }
1220
+ },
1221
+ scroll: {
1222
+ scroll: (param)=>this.performActionScroll(param)
1223
+ }
1224
+ });
1236
1225
  this.deviceId = 'pending-connection';
1237
1226
  this.options = options;
1238
1227
  this.customActions = options?.customActions;
@@ -1471,7 +1460,7 @@ class IOSMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools {
1471
1460
  const tools = new IOSMidsceneTools();
1472
1461
  (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-ios', {
1473
1462
  stripPrefix: 'ios_',
1474
- version: "1.8.0",
1463
+ version: "1.8.1",
1475
1464
  extraCommands: (0, core_namespaceObject.createReportCliCommands)()
1476
1465
  }).catch((e)=>{
1477
1466
  process.exit((0, cli_namespaceObject.reportCLIError)(e));