appium-mac2-driver 3.1.0 → 3.2.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [3.2.0](https://github.com/appium/appium-mac2-driver/compare/v3.1.0...v3.2.0) (2025-11-11)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add a setting that allows to fetch full element text ([#347](https://github.com/appium/appium-mac2-driver/issues/347)) ([a8b9e7e](https://github.com/appium/appium-mac2-driver/commit/a8b9e7ee1c0b576c04eaafb8af0d8649330ffc3b))
7
+
1
8
  ## [3.1.0](https://github.com/appium/appium-mac2-driver/compare/v3.0.1...v3.1.0) (2025-10-01)
2
9
 
3
10
 
package/README.md CHANGED
@@ -849,6 +849,7 @@ Name | Type | Description
849
849
  --- | --- | ---
850
850
  boundElementsByIndex | boolean | Whether to use elements binding by index (`true`) or by accessibility identifier (the default setting, `false`). It makes sense to switch the binding strategy to workaround stale element reference errors containing `Identity Binding` text in their descriptions. See the corresponding [Stack Overflow discussion](https://stackoverflow.com/questions/49307513/meaning-of-allelementsboundbyaccessibilityelement) to know more details on the difference between these two binding strategies.
851
851
  useDefaultUiInterruptionsHandling | boolean | Whether to use the default XCTest UI interruptions handling (`true`, the default setting) or to disable it for the [Application Under Test](#application-under-test-concept) (`false`). It makes sense to disable the default handler if it is necessary to validate the interrupting element's presence in your test or do some other actions on it rather than just closing the view implicitly. Check [this WWDC presentation](https://developer.apple.com/videos/play/wwdc2020/10220/) from Apple to get more details on the UI interruptions handling.
852
+ fetchFullText | boolean | Whether to use custom snapshotting mechanism to fetch full element's text payload instead of the first 512 chars. By default, this setting is set to false, which makes the driver to use the standard XCTest's snapshotting mechanism. It's fast, but may also cut long textual payloads of various UI element's in order to optimize internal UI hierarchy snapshotting performance. If the performance is less important for you that the ability to validate full element's text then consider enabling this setting while calling [Get Element Text](https://www.w3.org/TR/webdriver1/#dfn-get-element-text) API.
852
853
 
853
854
 
854
855
  ## Scripts
@@ -38,8 +38,7 @@
38
38
 
39
39
  - (void)testSendingTextIntoNonFocusedEdit
40
40
  {
41
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"placeholderValue.length == 0"];
42
- XCUIElement *edit = [self.testedApplication.textFields matchingPredicate:predicate].firstMatch;
41
+ XCUIElement *edit = self.testedApplication.textFields.firstMatch;
43
42
  NSString *text = @"yolo😎";
44
43
  [edit am_setValue:text];
45
44
  XCTAssertTrue(edit.am_hasKeyboardInputFocus);
@@ -50,8 +49,7 @@
50
49
 
51
50
  - (void)testSendingTextIntoNonFocusedEditWithPlaceholderText
52
51
  {
53
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"placeholderValue.length > 0"];
54
- XCUIElement *edit = [self.testedApplication.textFields matchingPredicate:predicate].firstMatch;
52
+ XCUIElement *edit = self.testedApplication.textFields.firstMatch;
55
53
  NSString *text = @"yolo😎";
56
54
  [edit am_setValue:text];
57
55
  XCTAssertTrue(edit.am_hasKeyboardInputFocus);
@@ -34,9 +34,11 @@ NS_ASSUME_NONNULL_BEGIN
34
34
  - (NSDictionary<NSString *, NSNumber *> *)am_rect;
35
35
 
36
36
  /**
37
- Element text
37
+ Element text. If no text is found then an empty string is returned.
38
+
39
+ @throws Error if `fetchFullText` setting is enabled and there was an error while fetching the snapshot
38
40
  */
39
- - (nullable NSString *)am_text;
41
+ - (NSString *)am_text;
40
42
 
41
43
  /**
42
44
  Element type represented as string
@@ -17,10 +17,12 @@
17
17
  #import "XCUIElement+AMAttributes.h"
18
18
 
19
19
  #import "AMGeometryUtils.h"
20
+ #import "FBConfiguration.h"
20
21
  #import "FBElementTypeTransformer.h"
21
22
  #import "FBElementUtils.h"
22
23
  #import "FBExceptions.h"
23
24
  #import "FBMacros.h"
25
+ #import "XCUIElementQuery+AMHelpers.h"
24
26
 
25
27
  @implementation XCUIElement (AMAttributes)
26
28
 
@@ -64,23 +66,20 @@
64
66
 
65
67
  - (NSString *)am_text
66
68
  {
67
- NSString *value = [FBElementUtils stringValueWithValue:self.value];
68
- if (nil != value && value.length > 0) {
69
- return value;
69
+ if (!FBConfiguration.sharedConfiguration.fetchFullText) {
70
+ return [self am_textWithSource:self];
70
71
  }
71
- NSString *label = self.label;
72
- if (nil != label && label.length > 0) {
73
- return label;
74
- }
75
- NSString *placeholderValue = self.placeholderValue;
76
- if (nil != placeholderValue && placeholderValue.length > 0) {
77
- return placeholderValue;
78
- }
79
- NSString *title = self.title;
80
- if (nil != title && title.length > 0) {
81
- return title;
72
+
73
+ NSError *error;
74
+ XCUIElementQuery *query = [self valueForKey:@"query"];
75
+ id<XCUIElementAttributes> snapshot = [query am_uniqueSnapshotWithError:&error];
76
+ if (nil != snapshot) {
77
+ return [self am_textWithSource:snapshot];
82
78
  }
83
- return @"";
79
+
80
+ NSString *reason = [NSString stringWithFormat:@"Cannot extract the full text of '%@' element. Original error: %@",
81
+ self.description, error.description];
82
+ @throw [NSException exceptionWithName:FBInvalidElementStateException reason:reason userInfo:@{}];
84
83
  }
85
84
 
86
85
  - (NSString *)am_type
@@ -94,4 +93,20 @@
94
93
  return [predicate evaluateWithObject:self];
95
94
  }
96
95
 
96
+ - (NSString *)am_textWithSource:(id<XCUIElementAttributes>)source
97
+ {
98
+ NSArray<NSString *> *candidates = @[
99
+ [FBElementUtils stringValueWithValue:source.value],
100
+ source.label,
101
+ source.placeholderValue,
102
+ source.title
103
+ ];
104
+ for (NSString *text in candidates) {
105
+ if (nil != text && text.length > 0) {
106
+ return text;
107
+ }
108
+ }
109
+ return @"";
110
+ }
111
+
97
112
  @end
@@ -34,6 +34,14 @@ NS_ASSUME_NONNULL_BEGIN
34
34
  */
35
35
  - (NSArray<XCUIElement *> *)am_allMatches;
36
36
 
37
+ /**
38
+ Returns single unique matching snapshot for the given query
39
+
40
+ @param error The error instance if there was a failure while retrieveing the snapshot
41
+ @returns The unqiue snapshot or nil if the element is stale
42
+ */
43
+ - (nullable id<XCUIElementSnapshot>)am_uniqueSnapshotWithError:(NSError **)error;
44
+
37
45
  @end
38
46
 
39
47
  NS_ASSUME_NONNULL_END
@@ -32,4 +32,21 @@
32
32
  : self.allElementsBoundByAccessibilityElement;
33
33
  }
34
34
 
35
+ - (id<XCUIElementSnapshot>)am_uniqueSnapshotWithError:(NSError **)error
36
+ {
37
+ SEL selector = NSSelectorFromString(@"uniqueMatchingSnapshotWithError:");
38
+ NSMethodSignature *signature = [self methodSignatureForSelector:selector];
39
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
40
+ invocation.target = self;
41
+ invocation.selector = selector;
42
+
43
+ [invocation setArgument:&error atIndex:2]; // index 0 = self, 1 = _cmd, 2 = first real argument
44
+
45
+ [invocation invoke];
46
+
47
+ __unsafe_unretained id returnValue = nil;
48
+ [invocation getReturnValue:&returnValue];
49
+ return returnValue;
50
+ }
51
+
35
52
  @end
@@ -237,6 +237,7 @@ const static NSString *CAPABILITIES_KEY = @"capabilities";
237
237
  @{
238
238
  AM_BOUND_ELEMENTS_BY_INDEX_SETTING: @(FBSession.activeSession.boundElementsByIndex),
239
239
  AM_USE_DEFAULT_UI_INTERRUPTIONS_HANDLING_SETTING: @(!application.am_doesNotHandleUIInterruptions),
240
+ AM_FETCH_FULL_TEXT: @(FBConfiguration.sharedConfiguration.fetchFullText),
240
241
  }
241
242
  );
242
243
  }
@@ -252,6 +253,9 @@ const static NSString *CAPABILITIES_KEY = @"capabilities";
252
253
  XCUIApplication *application = FBSession.activeSession.currentApplication;
253
254
  application.am_doesNotHandleUIInterruptions = ![[settings objectForKey:AM_USE_DEFAULT_UI_INTERRUPTIONS_HANDLING_SETTING] boolValue];
254
255
  }
256
+ if (nil != [settings objectForKey:AM_FETCH_FULL_TEXT]) {
257
+ FBConfiguration.sharedConfiguration.fetchFullText = [settings objectForKey:AM_FETCH_FULL_TEXT];
258
+ }
255
259
 
256
260
  return [self handleGetSettings:request];
257
261
  }
@@ -25,4 +25,7 @@ extern NSString* const AM_BOUND_ELEMENTS_BY_INDEX_SETTING;
25
25
  See https://developer.apple.com/videos/play/wwdc2020/10220/ for more details */
26
26
  extern NSString* const AM_USE_DEFAULT_UI_INTERRUPTIONS_HANDLING_SETTING;
27
27
 
28
+ /*! Whether to use custom snapshotting mechanism to fetch full element's text payload instead of the first 512 chars */
29
+ extern NSString* const AM_FETCH_FULL_TEXT;
30
+
28
31
  NS_ASSUME_NONNULL_END
@@ -17,5 +17,5 @@
17
17
  #import "AMSettings.h"
18
18
 
19
19
  NSString* const AM_BOUND_ELEMENTS_BY_INDEX_SETTING = @"boundElementsByIndex";
20
-
21
20
  NSString* const AM_USE_DEFAULT_UI_INTERRUPTIONS_HANDLING_SETTING = @"useDefaultUiInterruptionsHandling";
21
+ NSString* const AM_FETCH_FULL_TEXT = @"fetchFullText";
@@ -30,6 +30,9 @@ NS_ASSUME_NONNULL_BEGIN
30
30
  /*! Enables XCTest automated screen recordings taking in Xcode 15+ */
31
31
  @property BOOL automaticScreenRecordings;
32
32
 
33
+ /*! Whether to use custom snapshotting mechanism to fetch full element's text payload instead of the first 512 chars */
34
+ @property BOOL fetchFullText;
35
+
33
36
  /**
34
37
  The range of ports that the HTTP Server should attempt to bind on launch
35
38
  */
@@ -11,6 +11,7 @@
11
11
 
12
12
  static NSUInteger const DefaultStartingPort = 10100;
13
13
  static NSUInteger const DefaultPortRange = 100;
14
+ static BOOL FBFetchFullText = NO;
14
15
 
15
16
  @implementation FBConfiguration
16
17
 
@@ -75,6 +76,16 @@ static FBConfiguration *instance;
75
76
  forKey:@"DisableDiagnosticScreenRecordings"];
76
77
  }
77
78
 
79
+ - (BOOL)fetchFullText
80
+ {
81
+ return FBFetchFullText;
82
+ }
83
+
84
+ - (void)setFetchFullText:(BOOL)fetchFullText
85
+ {
86
+ FBFetchFullText = fetchFullText;
87
+ }
88
+
78
89
  - (NSRange)bindingPortRange
79
90
  {
80
91
  // 'WebDriverAgent --port 8080' can be passed via the arguments to the process