@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/index.js CHANGED
@@ -506,16 +506,6 @@ function _define_property(obj, key, value) {
506
506
  return obj;
507
507
  }
508
508
  const debugDevice = (0, logger_namespaceObject.getDebug)('ios:device');
509
- const iosInputParamSchema = core_namespaceObject.z.object({
510
- 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.'),
511
- 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.'),
512
- mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
513
- 'replace',
514
- 'clear',
515
- 'typeOnly'
516
- ]).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.')),
517
- locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
518
- });
519
509
  const WDA_HTTP_METHODS = [
520
510
  'GET',
521
511
  'POST',
@@ -524,96 +514,39 @@ const WDA_HTTP_METHODS = [
524
514
  ];
525
515
  const DEFAULT_WDA_MJPEG_PORT = 9100;
526
516
  class IOSDevice {
517
+ async tapPoint(point) {
518
+ debugDevice(`tap at coordinates (${point.x}, ${point.y})`);
519
+ await this.wdaBackend.tap(Math.round(point.x), Math.round(point.y));
520
+ }
521
+ async doubleTapPoint(point) {
522
+ await this.wdaBackend.doubleTap(Math.round(point.x), Math.round(point.y));
523
+ }
524
+ async longPressPoint(point, duration = 1000) {
525
+ await this.wdaBackend.longPress(Math.round(point.x), Math.round(point.y), duration);
526
+ }
527
+ async swipePoint(start, end, duration = 500) {
528
+ await this.wdaBackend.swipe(Math.round(start.x), Math.round(start.y), Math.round(end.x), Math.round(end.y), duration);
529
+ }
530
+ async clearInputAt(point) {
531
+ if (point) {
532
+ await this.tapPoint(point);
533
+ await (0, utils_namespaceObject.sleep)(100);
534
+ }
535
+ debugDevice('Attempting to clear input with WebDriver Clear API');
536
+ const cleared = await this.wdaBackend.clearActiveElement();
537
+ cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
538
+ }
527
539
  actionSpace() {
540
+ const mobileActionContext = {
541
+ input: this.inputPrimitives,
542
+ size: ()=>this.size(),
543
+ sleep: async (timeMs)=>{
544
+ await (0, utils_namespaceObject.sleep)(timeMs);
545
+ },
546
+ getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard
547
+ };
528
548
  const defaultActions = [
529
- (0, device_namespaceObject.defineActionTap)(async (param)=>{
530
- const element = param.locate;
531
- external_node_assert_default()(element, 'Element not found, cannot tap');
532
- await this.mouseClick(element.center[0], element.center[1]);
533
- }),
534
- (0, device_namespaceObject.defineActionDoubleClick)(async (param)=>{
535
- const element = param.locate;
536
- external_node_assert_default()(element, 'Element not found, cannot double click');
537
- await this.doubleTap(element.center[0], element.center[1]);
538
- }),
539
- (0, device_namespaceObject.defineAction)({
540
- name: 'Input',
541
- description: 'Input text into the input field',
542
- interfaceAlias: 'aiInput',
543
- paramSchema: iosInputParamSchema,
544
- sample: {
545
- value: 'test@example.com',
546
- locate: {
547
- prompt: 'the email input field'
548
- }
549
- },
550
- call: async (param)=>{
551
- const element = param.locate;
552
- if ('typeOnly' !== param.mode) await this.clearInput(element);
553
- if ('clear' === param.mode) return;
554
- if (!param || !param.value) return;
555
- const autoDismissKeyboard = param.autoDismissKeyboard ?? this.options?.autoDismissKeyboard;
556
- await this.typeText(param.value, {
557
- autoDismissKeyboard
558
- });
559
- }
560
- }),
561
- (0, device_namespaceObject.defineActionScroll)(async (param)=>{
562
- const element = param.locate;
563
- const startingPoint = element ? {
564
- left: element.center[0],
565
- top: element.center[1]
566
- } : void 0;
567
- const scrollToEventName = param?.scrollType;
568
- if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
569
- else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
570
- else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
571
- else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
572
- else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
573
- else {
574
- if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
575
- else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
576
- else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
577
- else throw new Error(`Unknown scroll direction: ${param.direction}`);
578
- else await this.scrollDown(param?.distance || void 0, startingPoint);
579
- await (0, utils_namespaceObject.sleep)(500);
580
- }
581
- }),
582
- (0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
583
- const from = param.from;
584
- const to = param.to;
585
- external_node_assert_default()(from, 'missing "from" param for drag and drop');
586
- external_node_assert_default()(to, 'missing "to" param for drag and drop');
587
- await this.swipe(from.center[0], from.center[1], to.center[0], to.center[1], 1000);
588
- }),
589
- (0, device_namespaceObject.defineActionSwipe)(async (param)=>{
590
- const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
591
- for(let i = 0; i < repeatCount; i++)await this.swipe(startPoint.x, startPoint.y, endPoint.x, endPoint.y, duration);
592
- }),
593
- (0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
594
- await this.pressKey(param.keyName);
595
- }),
596
- (0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
597
- const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
598
- const times = param.times ?? 1;
599
- for(let i = 0; i < times; i++){
600
- await this.pressKey(arrowKey);
601
- await (0, utils_namespaceObject.sleep)(100);
602
- }
603
- }),
604
- (0, device_namespaceObject.defineActionLongPress)(async (param)=>{
605
- const element = param.locate;
606
- external_node_assert_default()(element, 'LongPress requires an element to be located');
607
- const [x, y] = element.center;
608
- await this.longPress(x, y, param?.duration);
609
- }),
610
- (0, device_namespaceObject.defineActionPinch)(async (param)=>{
611
- const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
612
- await this.wdaBackend.pinch(centerX, centerY, startDistance, endDistance, duration);
613
- }),
614
- (0, device_namespaceObject.defineActionClearInput)(async (param)=>{
615
- await this.clearInput(param.locate);
616
- })
549
+ ...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext)
617
550
  ];
618
551
  const platformSpecificActions = Object.values(createPlatformActions(this));
619
552
  const customActions = this.customActions || [];
@@ -623,6 +556,27 @@ class IOSDevice {
623
556
  ...customActions
624
557
  ];
625
558
  }
559
+ async performActionScroll(param) {
560
+ const element = param.locate;
561
+ const startingPoint = element ? {
562
+ left: element.center[0],
563
+ top: element.center[1]
564
+ } : void 0;
565
+ const scrollToEventName = param?.scrollType;
566
+ if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
567
+ else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
568
+ else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
569
+ else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
570
+ else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
571
+ else {
572
+ if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
573
+ else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
574
+ else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
575
+ else throw new Error(`Unknown scroll direction: ${param.direction}`);
576
+ else await this.scrollDown(param?.distance || void 0, startingPoint);
577
+ await (0, utils_namespaceObject.sleep)(500);
578
+ }
579
+ }
626
580
  describe() {
627
581
  return this.description || `Device ID: ${this.deviceId}`;
628
582
  }
@@ -734,35 +688,31 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
734
688
  }
735
689
  }
736
690
  async clearInput(element) {
737
- if (element) {
738
- await this.tap(element.center[0], element.center[1]);
739
- await (0, utils_namespaceObject.sleep)(100);
740
- }
741
- debugDevice('Attempting to clear input with WebDriver Clear API');
742
- const cleared = await this.wdaBackend.clearActiveElement();
743
- cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
691
+ await this.clearInputAt(element ? {
692
+ x: element.center[0],
693
+ y: element.center[1]
694
+ } : void 0);
744
695
  }
745
696
  async url() {
746
697
  return '';
747
698
  }
748
699
  async tap(x, y) {
749
- await this.wdaBackend.tap(Math.round(x), Math.round(y));
750
- }
751
- async mouseClick(x, y) {
752
- debugDevice(`mouseClick at coordinates (${x}, ${y})`);
753
- await this.tap(x, y);
754
- }
755
- async doubleTap(x, y) {
756
- await this.wdaBackend.doubleTap(Math.round(x), Math.round(y));
757
- }
758
- async tripleTap(x, y) {
759
- await this.wdaBackend.tripleTap(Math.round(x), Math.round(y));
760
- }
761
- async longPress(x, y, duration = 1000) {
762
- await this.wdaBackend.longPress(Math.round(x), Math.round(y), duration);
700
+ await this.tapPoint({
701
+ x,
702
+ y
703
+ });
763
704
  }
764
705
  async swipe(fromX, fromY, toX, toY, duration = 500) {
765
- await this.wdaBackend.swipe(Math.round(fromX), Math.round(fromY), Math.round(toX), Math.round(toY), duration);
706
+ await this.swipeCoordinates(fromX, fromY, toX, toY, duration);
707
+ }
708
+ async swipeCoordinates(fromX, fromY, toX, toY, duration = 500) {
709
+ await this.swipePoint({
710
+ x: fromX,
711
+ y: fromY
712
+ }, {
713
+ x: toX,
714
+ y: toY
715
+ }, duration);
766
716
  }
767
717
  async typeText(text, options) {
768
718
  if (!text) return;
@@ -791,7 +741,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
791
741
  y: Math.round(height / 2)
792
742
  };
793
743
  const scrollDistance = Math.round(distance || height / 3);
794
- await this.swipe(start.x, start.y, start.x, start.y + scrollDistance);
744
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance);
795
745
  }
796
746
  async scrollDown(distance, startPoint) {
797
747
  const { width, height } = await this.size();
@@ -803,7 +753,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
803
753
  y: Math.round(height / 2)
804
754
  };
805
755
  const scrollDistance = Math.round(distance || height / 3);
806
- await this.swipe(start.x, start.y, start.x, start.y - scrollDistance);
756
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance);
807
757
  }
808
758
  async scrollLeft(distance, startPoint) {
809
759
  const { width, height } = await this.size();
@@ -815,7 +765,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
815
765
  y: Math.round(height / 2)
816
766
  };
817
767
  const scrollDistance = Math.round(distance || 0.7 * width);
818
- await this.swipe(start.x, start.y, start.x + scrollDistance, start.y);
768
+ await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y);
819
769
  }
820
770
  async scrollRight(distance, startPoint) {
821
771
  const { width, height } = await this.size();
@@ -827,7 +777,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
827
777
  y: Math.round(height / 2)
828
778
  };
829
779
  const scrollDistance = Math.round(distance || 0.7 * width);
830
- await this.swipe(start.x, start.y, start.x - scrollDistance, start.y);
780
+ await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y);
831
781
  }
832
782
  async scrollUntilTop(startPoint) {
833
783
  debugDevice('Using screenshot-based scroll detection for better reliability');
@@ -923,16 +873,16 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
923
873
  debugDevice(`Performing scroll: ${direction}, distance: ${scrollDistance}`);
924
874
  switch(direction){
925
875
  case 'up':
926
- await this.swipe(start.x, start.y, start.x, start.y + scrollDistance, 300);
876
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance, 300);
927
877
  break;
928
878
  case 'down':
929
- await this.swipe(start.x, start.y, start.x, start.y - scrollDistance, 300);
879
+ await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance, 300);
930
880
  break;
931
881
  case 'left':
932
- await this.swipe(start.x, start.y, start.x + scrollDistance, start.y, 300);
882
+ await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y, 300);
933
883
  break;
934
884
  case 'right':
935
- await this.swipe(start.x, start.y, start.x - scrollDistance, start.y, 300);
885
+ await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y, 300);
936
886
  break;
937
887
  }
938
888
  debugDevice('Waiting for scroll and inertia to complete...');
@@ -989,7 +939,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
989
939
  const centerX = Math.round(windowSize.width / 2);
990
940
  const startY = Math.round(0.9 * windowSize.height);
991
941
  const endY = Math.round(0.5 * windowSize.height);
992
- await this.swipe(centerX, startY, centerX, endY, 300);
942
+ await this.swipeCoordinates(centerX, startY, centerX, endY, 300);
993
943
  debugDevice('Dismissed keyboard with swipe up gesture from bottom of screen');
994
944
  await (0, utils_namespaceObject.sleep)(500);
995
945
  return true;
@@ -1066,6 +1016,45 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
1066
1016
  _define_property(this, "interfaceType", 'ios');
1067
1017
  _define_property(this, "uri", void 0);
1068
1018
  _define_property(this, "options", void 0);
1019
+ _define_property(this, "inputPrimitives", {
1020
+ pointer: {
1021
+ tap: (point)=>this.tapPoint(point),
1022
+ doubleClick: (point)=>this.doubleTapPoint(point),
1023
+ longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
1024
+ dragAndDrop: (from, to)=>this.swipePoint(from, to, 1000)
1025
+ },
1026
+ keyboard: {
1027
+ keyboardPress: (keyName)=>this.pressKey(keyName),
1028
+ typeText: async (value, opts)=>{
1029
+ const target = opts?.target;
1030
+ if (target && opts?.replace !== false) await this.clearInput(target);
1031
+ else if (target) await this.tapPoint({
1032
+ x: target.center[0],
1033
+ y: target.center[1]
1034
+ });
1035
+ if (opts?.focusOnly) return;
1036
+ await this.typeText(value, opts);
1037
+ },
1038
+ clearInput: (target)=>this.clearInput(target),
1039
+ cursorMove: async (direction, times = 1)=>{
1040
+ const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
1041
+ for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
1042
+ }
1043
+ },
1044
+ touch: {
1045
+ swipe: async (start, end, opts)=>{
1046
+ const duration = opts?.duration ?? 300;
1047
+ const repeat = opts?.repeat ?? 1;
1048
+ for(let i = 0; i < repeat; i++)await this.swipePoint(start, end, duration);
1049
+ },
1050
+ pinch: async (center, opts)=>{
1051
+ await this.wdaBackend.pinch(Math.round(center.x), Math.round(center.y), opts.startDistance, opts.endDistance, opts.duration);
1052
+ }
1053
+ },
1054
+ scroll: {
1055
+ scroll: (param)=>this.performActionScroll(param)
1056
+ }
1057
+ });
1069
1058
  this.deviceId = 'pending-connection';
1070
1059
  this.options = options;
1071
1060
  this.customActions = options?.customActions;