appium-webdriveragent 11.0.2 → 11.1.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.
Files changed (27) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/WebDriverAgent.xcodeproj/project.pbxproj +15 -3
  3. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +1 -0
  4. package/WebDriverAgentLib/Categories/XCUIElement+FBCustomActions.h +27 -0
  5. package/WebDriverAgentLib/Categories/XCUIElement+FBCustomActions.m +127 -0
  6. package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +6 -0
  7. package/WebDriverAgentLib/Commands/FBSessionCommands.m +4 -0
  8. package/WebDriverAgentLib/Info.plist +2 -2
  9. package/WebDriverAgentLib/Routing/FBElement.h +3 -0
  10. package/WebDriverAgentLib/Utilities/FBConfiguration.h +11 -0
  11. package/WebDriverAgentLib/Utilities/FBConfiguration.m +11 -0
  12. package/WebDriverAgentLib/Utilities/FBSettings.h +1 -0
  13. package/WebDriverAgentLib/Utilities/FBSettings.m +1 -0
  14. package/WebDriverAgentLib/Utilities/FBXPath.m +23 -0
  15. package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h +4 -0
  16. package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +15 -4
  17. package/WebDriverAgentTests/IntegrationApp/Classes/ViewController.m +22 -0
  18. package/WebDriverAgentTests/IntegrationApp/Resources/Base.lproj/Main.storyboard +43 -40
  19. package/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +10 -0
  20. package/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.h +1 -0
  21. package/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +1 -5
  22. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -0
  23. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -0
  24. package/WebDriverAgentTests/UnitTests/FBXPathTests.m +6 -3
  25. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +1 -0
  26. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.m +1 -0
  27. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [11.1.0](https://github.com/appium/WebDriverAgent/compare/v11.0.2...v11.1.0) (2025-12-28)
2
+
3
+ ### Features
4
+
5
+ * expose customActions on the element ([#1095](https://github.com/appium/WebDriverAgent/issues/1095)) ([3028512](https://github.com/appium/WebDriverAgent/commit/302851237297ee31965c55a75436ad0aea2a8c8f))
6
+
1
7
  ## [11.0.2](https://github.com/appium/WebDriverAgent/compare/v11.0.1...v11.0.2) (2025-12-25)
2
8
 
3
9
  ### Miscellaneous Chores
@@ -529,6 +529,7 @@
529
529
  71F5BE50252F14EB00EE9EBA /* FBExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 71F5BE4D252F14EB00EE9EBA /* FBExceptions.h */; };
530
530
  71F5BE51252F14EB00EE9EBA /* FBExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 71F5BE4E252F14EB00EE9EBA /* FBExceptions.m */; };
531
531
  71F5BE52252F14EB00EE9EBA /* FBExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 71F5BE4E252F14EB00EE9EBA /* FBExceptions.m */; };
532
+ AABBCCDDEEFF001122334457 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AABBCCDDEEFF001122334456 /* SceneDelegate.m */; };
532
533
  AD35D06C1CF1C35500870A75 /* WebDriverAgentLib.framework in Copy frameworks */ = {isa = PBXBuildFile; fileRef = EE158A991CBD452B00A3E3F0 /* WebDriverAgentLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
533
534
  AD6C26941CF2379700F8B5FF /* FBAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = AD6C26921CF2379700F8B5FF /* FBAlert.h */; settings = {ATTRIBUTES = (Public, ); }; };
534
535
  AD6C26951CF2379700F8B5FF /* FBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = AD6C26931CF2379700F8B5FF /* FBAlert.m */; };
@@ -799,7 +800,6 @@
799
800
  EE9B76591CF7987800275851 /* FBRouteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9B76571CF7987300275851 /* FBRouteTests.m */; };
800
801
  EE9B768E1CF7997600275851 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9B76831CF7997600275851 /* AppDelegate.m */; };
801
802
  EE9B768F1CF7997600275851 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9B76851CF7997600275851 /* ViewController.m */; };
802
- AABBCCDDEEFF001122334457 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AABBCCDDEEFF001122334456 /* SceneDelegate.m */; };
803
803
  EE9B76911CF7997600275851 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9B76871CF7997600275851 /* main.m */; };
804
804
  EE9B76941CF7997600275851 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EE9B768C1CF7997600275851 /* Main.storyboard */; };
805
805
  EE9B769A1CF799F400275851 /* FBAlertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9B76991CF799F400275851 /* FBAlertTests.m */; };
@@ -822,6 +822,10 @@
822
822
  EEE3764A1D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = EEE376481D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.m */; };
823
823
  EEE9B4721CD02B88009D2030 /* FBRunLoopSpinner.h in Headers */ = {isa = PBXBuildFile; fileRef = EEE9B4701CD02B88009D2030 /* FBRunLoopSpinner.h */; settings = {ATTRIBUTES = (Public, ); }; };
824
824
  EEE9B4731CD02B88009D2030 /* FBRunLoopSpinner.m in Sources */ = {isa = PBXBuildFile; fileRef = EEE9B4711CD02B88009D2030 /* FBRunLoopSpinner.m */; };
825
+ F59CD6D42EF16E5E00F91287 /* XCUIElement+FBCustomActions.h in Headers */ = {isa = PBXBuildFile; fileRef = F59CD6D22EF16E5E00F91287 /* XCUIElement+FBCustomActions.h */; };
826
+ F59CD6D52EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */ = {isa = PBXBuildFile; fileRef = F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */; };
827
+ F59CD6D62EF16E5E00F91287 /* XCUIElement+FBCustomActions.h in Headers */ = {isa = PBXBuildFile; fileRef = F59CD6D22EF16E5E00F91287 /* XCUIElement+FBCustomActions.h */; };
828
+ F59CD6D72EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */ = {isa = PBXBuildFile; fileRef = F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */; };
825
829
  /* End PBXBuildFile section */
826
830
 
827
831
  /* Begin PBXContainerItemProxy section */
@@ -1110,6 +1114,8 @@
1110
1114
  71F5BE33252E5B2200EE9EBA /* FBElementSwipingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBElementSwipingTests.m; sourceTree = "<group>"; };
1111
1115
  71F5BE4D252F14EB00EE9EBA /* FBExceptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBExceptions.h; sourceTree = "<group>"; };
1112
1116
  71F5BE4E252F14EB00EE9EBA /* FBExceptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBExceptions.m; sourceTree = "<group>"; };
1117
+ AABBCCDDEEFF001122334455 /* SceneDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
1118
+ AABBCCDDEEFF001122334456 /* SceneDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
1113
1119
  AD42DD2A1CF121E600806E5D /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
1114
1120
  AD6C26921CF2379700F8B5FF /* FBAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FBAlert.h; path = WebDriverAgentLib/FBAlert.h; sourceTree = SOURCE_ROOT; };
1115
1121
  AD6C26931CF2379700F8B5FF /* FBAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = FBAlert.m; path = WebDriverAgentLib/FBAlert.m; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
@@ -1369,8 +1375,6 @@
1369
1375
  EE9B76581CF7987300275851 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
1370
1376
  EE9B76821CF7997600275851 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
1371
1377
  EE9B76831CF7997600275851 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
1372
- AABBCCDDEEFF001122334455 /* SceneDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
1373
- AABBCCDDEEFF001122334456 /* SceneDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
1374
1378
  EE9B76841CF7997600275851 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
1375
1379
  EE9B76851CF7997600275851 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
1376
1380
  EE9B76861CF7997600275851 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -1404,6 +1408,8 @@
1404
1408
  EEE9B4701CD02B88009D2030 /* FBRunLoopSpinner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRunLoopSpinner.h; sourceTree = "<group>"; };
1405
1409
  EEE9B4711CD02B88009D2030 /* FBRunLoopSpinner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRunLoopSpinner.m; sourceTree = "<group>"; };
1406
1410
  EEF9882A1C486603005CA669 /* WebDriverAgentRunner.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebDriverAgentRunner.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
1411
+ F59CD6D22EF16E5E00F91287 /* XCUIElement+FBCustomActions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCUIElement+FBCustomActions.h"; sourceTree = "<group>"; };
1412
+ F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "XCUIElement+FBCustomActions.m"; sourceTree = "<group>"; };
1407
1413
  /* End PBXFileReference section */
1408
1414
 
1409
1415
  /* Begin PBXFrameworksBuildPhase section */
@@ -1820,6 +1826,8 @@
1820
1826
  71E75E6C254824230099FC87 /* XCUIElementQuery+FBHelpers.m */,
1821
1827
  13DE7A59287CA444003243C6 /* FBXCElementSnapshotWrapper+Helpers.h */,
1822
1828
  13DE7A5A287CA444003243C6 /* FBXCElementSnapshotWrapper+Helpers.m */,
1829
+ F59CD6D22EF16E5E00F91287 /* XCUIElement+FBCustomActions.h */,
1830
+ F59CD6D32EF16E5E00F91287 /* XCUIElement+FBCustomActions.m */,
1823
1831
  );
1824
1832
  name = Categories;
1825
1833
  path = WebDriverAgentLib/Categories;
@@ -2521,6 +2529,7 @@
2521
2529
  641EE6E42240C5CA00173FCB /* XCKeyboardLayout.h in Headers */,
2522
2530
  641EE6E52240C5CA00173FCB /* XCTAsyncActivity-Protocol.h in Headers */,
2523
2531
  641EE6E62240C5CA00173FCB /* XCActivityRecord.h in Headers */,
2532
+ F59CD6D62EF16E5E00F91287 /* XCUIElement+FBCustomActions.h in Headers */,
2524
2533
  71822765258744C700661B83 /* HTTPDataResponse.h in Headers */,
2525
2534
  641EE6E72240C5CA00173FCB /* XCUIElement+FBFind.h in Headers */,
2526
2535
  641EE6E82240C5CA00173FCB /* XCTestManager_ManagerInterface-Protocol.h in Headers */,
@@ -2556,6 +2565,7 @@
2556
2565
  719CD8F82126C78F00C7D0C2 /* FBAlertsMonitor.h in Headers */,
2557
2566
  EE158AE41CBD456F00A3E3F0 /* FBSession.h in Headers */,
2558
2567
  13DE7A55287CA1EC003243C6 /* FBXCElementSnapshotWrapper.h in Headers */,
2568
+ F59CD6D42EF16E5E00F91287 /* XCUIElement+FBCustomActions.h in Headers */,
2559
2569
  EE35AD0F1E3B77D600A02D78 /* _XCTestImplementation.h in Headers */,
2560
2570
  71241D7B1FAE3D2500B9559F /* FBTouchActionCommands.h in Headers */,
2561
2571
  EE158ACA1CBD456F00A3E3F0 /* FBTouchIDCommands.h in Headers */,
@@ -3117,6 +3127,7 @@
3117
3127
  isa = PBXSourcesBuildPhase;
3118
3128
  buildActionMask = 2147483647;
3119
3129
  files = (
3130
+ F59CD6D72EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */,
3120
3131
  64E3502E2AC0B6EB005F3ACB /* NSDictionary+FBUtf8SafeDictionary.m in Sources */,
3121
3132
  718226CF2587443700661B83 /* GCDAsyncSocket.m in Sources */,
3122
3133
  E444DCBC24917A5E0060D7EB /* HTTPResponseProxy.m in Sources */,
@@ -3323,6 +3334,7 @@
3323
3334
  71D475C42538F5A8008D9401 /* XCUIApplicationProcess+FBQuiescence.m in Sources */,
3324
3335
  641EE7082240CDEB00173FCB /* XCUIElement+FBTVFocuse.m in Sources */,
3325
3336
  71E75E6F254824230099FC87 /* XCUIElementQuery+FBHelpers.m in Sources */,
3337
+ F59CD6D52EF16E5E00F91287 /* XCUIElement+FBCustomActions.m in Sources */,
3326
3338
  71D04DCA25356C43008A052C /* XCUIElement+FBCaching.m in Sources */,
3327
3339
  EE158AEB1CBD456F00A3E3F0 /* FBRuntimeUtils.m in Sources */,
3328
3340
  EEE376461D59F81400ED88DD /* XCUIElement+FBUtilities.m in Sources */,
@@ -204,6 +204,7 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
204
204
  info[@"value"] = FBValueOrNull(wrappedSnapshot.wdValue);
205
205
  info[@"label"] = FBValueOrNull(wrappedSnapshot.wdLabel);
206
206
  info[@"rect"] = wrappedSnapshot.wdRect;
207
+ info[@"customActions"] = FBValueOrNull(wrappedSnapshot.wdCustomActions);
207
208
 
208
209
  NSDictionary<NSString *, NSString *(^)(void)> *attributeBlocks = [self fb_attributeBlockMapForWrappedSnapshot:wrappedSnapshot];
209
210
 
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ #import <WebDriverAgentLib/FBXCElementSnapshotWrapper.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface XCUIElement (FBCustomActions)
14
+
15
+ /*! Custom accessibility actions as a string – may be nil if the element does not have this attribute */
16
+ @property (nonatomic, readonly, nullable) NSString *fb_customActions;
17
+
18
+ @end
19
+
20
+ @interface FBXCElementSnapshotWrapper (FBCustomActions)
21
+
22
+ /*! Custom accessibility actions as a string – may be nil if the element does not have this attribute */
23
+ @property (nonatomic, readonly, nullable) NSString *fb_customActions;
24
+
25
+ @end
26
+
27
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ #import "XCUIElement+FBCustomActions.h"
10
+ #import "XCUIElement+FBUtilities.h"
11
+ #import "FBXCElementSnapshotWrapper+Helpers.h"
12
+ #import "FBLogger.h"
13
+ #import "FBConfiguration.h"
14
+ #import "XCTestPrivateSymbols.h"
15
+
16
+ @interface FBXCElementSnapshotWrapper (FBCustomActionsInternal)
17
+
18
+ - (NSString *)fb_stringAttribute:(NSString *)attributeName
19
+ symbol:(NSNumber *)symbol;
20
+
21
+ @end
22
+
23
+ @implementation XCUIElement (FBCustomActions)
24
+
25
+ - (NSString *)fb_customActions
26
+ {
27
+ @autoreleasepool {
28
+ id<FBXCElementSnapshot> snapshot = [self fb_standardSnapshot];
29
+ return [[FBXCElementSnapshotWrapper ensureWrapped:snapshot]
30
+ fb_customActions];
31
+ }
32
+ }
33
+
34
+ @end
35
+
36
+
37
+ @implementation FBXCElementSnapshotWrapper(FBCustomActions)
38
+
39
+ - (NSString *)fb_customActions
40
+ {
41
+ return [self fb_stringAttribute:FB_XCAXACustomActionsAttributeName
42
+ symbol:FB_XCAXACustomActionsAttribute];
43
+ }
44
+
45
+ - (NSString *)fb_stringAttribute:(NSString *)attributeName
46
+ symbol:(NSNumber *)symbol
47
+ {
48
+ id cached = (self.snapshot.additionalAttributes ?: @{})[symbol];
49
+ if ([cached isKindOfClass:[NSString class]]) {
50
+ return cached;
51
+ }
52
+
53
+ NSError *error = nil;
54
+ id raw = [self fb_attributeValue:attributeName error:&error];
55
+ if (raw == nil) {
56
+ [FBLogger logFmt: @"[FBCustomActions] Cannot determine string value for %@: %@",
57
+ attributeName, error.localizedDescription];
58
+ return nil;
59
+ }
60
+
61
+ // Case 1: Already a string
62
+ if ([raw isKindOfClass:[NSString class]]) {
63
+ return [self retrieveCustomActionsFromString:raw forSymbol:symbol];
64
+ }
65
+
66
+ // Case 2: Array of custom actions
67
+ if ([raw isKindOfClass:[NSArray class]]) {
68
+ return [self retrieveCustomActionsFromArray:raw forSymbol:symbol];
69
+ }
70
+
71
+ // Fallback: Try to cast to string
72
+ return [self retrieveCustomActionsByCastingToString:raw forSymbol:symbol];
73
+ }
74
+
75
+ - (NSString *)retrieveCustomActionsFromString:(NSString *)stringValue
76
+ forSymbol:(NSNumber *)symbol
77
+ {
78
+ NSMutableDictionary *updated =
79
+ (self.additionalAttributes ?: @{}).mutableCopy;
80
+ updated[symbol] = stringValue;
81
+ self.snapshot.additionalAttributes = updated.copy;
82
+ return stringValue;
83
+ }
84
+
85
+ - (NSString *)retrieveCustomActionsFromArray:(NSArray *)arrayValue
86
+ forSymbol:(NSNumber *)symbol
87
+ {
88
+ NSMutableArray *stringified = [NSMutableArray array];
89
+ for (id action in arrayValue) {
90
+ NSString *title = nil;
91
+
92
+ if ([action isKindOfClass:[NSDictionary class]]) {
93
+ title = ((NSDictionary *)action)[@"CustomActionName"];
94
+ }
95
+
96
+ if (!title || ![title isKindOfClass:[NSString class]]) {
97
+ @try {
98
+ title = [action valueForKey:@"title"];
99
+ } @catch (__unused NSException * e) {
100
+ title = @"<unknown>";
101
+ }
102
+ }
103
+
104
+ [stringified addObject:title ?: @"<null>"];
105
+ [FBLogger logFmt: @"[FBCustomActions] Custom action title: %@", title];
106
+ }
107
+
108
+ NSString *joined = [stringified componentsJoinedByString:@","];
109
+ NSMutableDictionary *updated =
110
+ (self.additionalAttributes ?: @{}).mutableCopy;
111
+ updated[symbol] = joined;
112
+ self.snapshot.additionalAttributes = updated.copy;
113
+ return joined;
114
+ }
115
+
116
+ - (NSString *)retrieveCustomActionsByCastingToString:(id)raw
117
+ forSymbol:(NSNumber *)symbol
118
+ {
119
+ NSString *stringValue = [NSString stringWithFormat:@"%@", raw];
120
+ NSMutableDictionary *updated =
121
+ (self.additionalAttributes ?: @{}).mutableCopy;
122
+ updated[symbol] = stringValue;
123
+ self.snapshot.additionalAttributes = updated.copy;
124
+ return stringValue;
125
+ }
126
+
127
+ @end
@@ -24,6 +24,7 @@
24
24
  #import "XCUIHitPointResult.h"
25
25
  #import "FBAccessibilityTraits.h"
26
26
  #import "XCUIElement+FBMinMax.h"
27
+ #import "XCUIElement+FBCustomActions.h"
27
28
 
28
29
  #define BROKEN_RECT CGRectMake(-1, -1, 0, 0)
29
30
 
@@ -285,4 +286,9 @@
285
286
  };
286
287
  }
287
288
 
289
+ - (NSString *)wdCustomActions
290
+ {
291
+ return self.fb_customActions;
292
+ }
293
+
288
294
  @end
@@ -355,6 +355,7 @@
355
355
  FB_SETTING_INCLUDE_HITTABLE_IN_PAGE_SOURCE: @([FBConfiguration includeHittableInPageSource]),
356
356
  FB_SETTING_INCLUDE_NATIVE_FRAME_IN_PAGE_SOURCE: @([FBConfiguration includeNativeFrameInPageSource]),
357
357
  FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE: @([FBConfiguration includeMinMaxValueInPageSource]),
358
+ FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE: @([FBConfiguration includeCustomActionsInPageSource]),
358
359
  FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS: @([FBConfiguration enforceCustomSnapshots]),
359
360
  FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE: @([FBConfiguration limitXpathContextScope]),
360
361
  #if !TARGET_OS_TV
@@ -467,6 +468,9 @@
467
468
  if (nil != [settings objectForKey:FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE]) {
468
469
  [FBConfiguration setIncludeMinMaxValueInPageSource:[[settings objectForKey:FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE] boolValue]];
469
470
  }
471
+ if (nil != [settings objectForKey:FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE]) {
472
+ [FBConfiguration setIncludeCustomActionsInPageSource:[[settings objectForKey:FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE] boolValue]];
473
+ }
470
474
  if (nil != [settings objectForKey:FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS]) {
471
475
  [FBConfiguration setEnforceCustomSnapshots:[[settings objectForKey:FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS] boolValue]];
472
476
  }
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>11.0.2</string>
18
+ <string>11.1.0</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>11.0.2</string>
22
+ <string>11.1.0</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -76,6 +76,9 @@ NS_ASSUME_NONNULL_BEGIN
76
76
  /*! Element's maximum value */
77
77
  @property (nonatomic, readonly, strong, nullable) NSNumber *wdMaxValue;
78
78
 
79
+ /*! Element's custom actions */
80
+ @property (nonatomic, readonly, strong, nullable) NSString *wdCustomActions;
81
+
79
82
  /**
80
83
  Returns value of given property specified in WebDriver Spec
81
84
  Check the FBElement protocol to get list of supported attributes.
@@ -376,6 +376,17 @@ typedef NS_ENUM(NSInteger, FBConfigurationKeyboardPreference) {
376
376
  + (void)setIncludeMinMaxValueInPageSource:(BOOL)enabled;
377
377
  + (BOOL)includeMinMaxValueInPageSource;
378
378
 
379
+ /**
380
+ * Whether to include `customActions` attribute in the XML page source.
381
+ * Custom actions represent accessibility actions available on UI elements.
382
+ * This may affect performance if used on many elements.
383
+ * Disabled by default.
384
+ *
385
+ * @param enabled Either YES or NO
386
+ */
387
+ + (void)setIncludeCustomActionsInPageSource:(BOOL)enabled;
388
+ + (BOOL)includeCustomActionsInPageSource;
389
+
379
390
  /**
380
391
  * Whether to enforce the use of custom snapshots instead of standard snapshots.
381
392
  * When enabled, fb_customSnapshot is always invoked instead of fb_standardSnapshot
@@ -63,6 +63,7 @@ static UIInterfaceOrientation FBScreenshotOrientation;
63
63
  static BOOL FBShouldIncludeHittableInPageSource = NO;
64
64
  static BOOL FBShouldIncludeNativeFrameInPageSource = NO;
65
65
  static BOOL FBShouldIncludeMinMaxValueInPageSource = NO;
66
+ static BOOL FBShouldIncludeCustomActionsInPageSource = NO;
66
67
  static BOOL FBShouldEnforceCustomSnapshots = NO;
67
68
 
68
69
  @implementation FBConfiguration
@@ -687,6 +688,16 @@ static BOOL FBShouldEnforceCustomSnapshots = NO;
687
688
  return FBShouldIncludeMinMaxValueInPageSource;
688
689
  }
689
690
 
691
+ + (void)setIncludeCustomActionsInPageSource:(BOOL)enabled
692
+ {
693
+ FBShouldIncludeCustomActionsInPageSource = enabled;
694
+ }
695
+
696
+ + (BOOL)includeCustomActionsInPageSource
697
+ {
698
+ return FBShouldIncludeCustomActionsInPageSource;
699
+ }
700
+
690
701
  + (void)setEnforceCustomSnapshots:(BOOL)enabled
691
702
  {
692
703
  FBShouldEnforceCustomSnapshots = enabled;
@@ -42,6 +42,7 @@ extern NSString* const FB_SETTING_AUTO_CLICK_ALERT_SELECTOR;
42
42
  extern NSString *const FB_SETTING_INCLUDE_HITTABLE_IN_PAGE_SOURCE;
43
43
  extern NSString *const FB_SETTING_INCLUDE_NATIVE_FRAME_IN_PAGE_SOURCE;
44
44
  extern NSString *const FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE;
45
+ extern NSString *const FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE;
45
46
  extern NSString *const FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS;
46
47
 
47
48
  NS_ASSUME_NONNULL_END
@@ -38,4 +38,5 @@ NSString* const FB_SETTING_AUTO_CLICK_ALERT_SELECTOR = @"autoClickAlertSelector"
38
38
  NSString* const FB_SETTING_INCLUDE_HITTABLE_IN_PAGE_SOURCE = @"includeHittableInPageSource";
39
39
  NSString* const FB_SETTING_INCLUDE_NATIVE_FRAME_IN_PAGE_SOURCE = @"includeNativeFrameInPageSource";
40
40
  NSString* const FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE = @"includeMinMaxValueInPageSource";
41
+ NSString* const FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE = @"includeCustomActionsInPageSource";
41
42
  NSString* const FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS = @"enforceCustomSnapshots";
@@ -131,6 +131,10 @@
131
131
 
132
132
  @end
133
133
 
134
+ @interface FBCustomActionsAttribute : FBElementAttribute
135
+
136
+ @end
137
+
134
138
  #if TARGET_OS_TV
135
139
 
136
140
  @interface FBFocusedAttribute : FBElementAttribute
@@ -397,6 +401,10 @@ static NSString *const topNodeIndexPath = @"top";
397
401
  [includedAttributes removeObject:FBMinValueAttribute.class];
398
402
  [includedAttributes removeObject:FBMaxValueAttribute.class];
399
403
  }
404
+ if (!FBConfiguration.includeCustomActionsInPageSource) {
405
+ // customActions are retrieved from accessibility attributes and may be slow on deep trees
406
+ [includedAttributes removeObject:FBCustomActionsAttribute.class];
407
+ }
400
408
  if (nil != excludedAttributes) {
401
409
  for (NSString *excludedAttributeName in excludedAttributes) {
402
410
  for (Class supportedAttribute in FBElementAttribute.supportedAttributes) {
@@ -660,6 +668,7 @@ static NSString *const FBAbstractMethodInvocationException = @"AbstractMethodInv
660
668
  FBNativeFrameAttribute.class,
661
669
  FBMinValueAttribute.class,
662
670
  FBMaxValueAttribute.class,
671
+ FBCustomActionsAttribute.class,
663
672
  ];
664
673
  }
665
674
 
@@ -954,3 +963,17 @@ static NSString *const FBAbstractMethodInvocationException = @"AbstractMethodInv
954
963
  }
955
964
 
956
965
  @end
966
+
967
+ @implementation FBCustomActionsAttribute
968
+
969
+ + (NSString *)name
970
+ {
971
+ return @"customActions";
972
+ }
973
+
974
+ + (NSString *)valueForElement:(id<FBElement>)element
975
+ {
976
+ return element.wdCustomActions;
977
+ }
978
+
979
+ @end
@@ -29,6 +29,10 @@ extern NSString *FB_XCAXACustomMinValueAttributeName;
29
29
  extern NSNumber *FB_XCAXACustomMaxValueAttribute;
30
30
  extern NSString *FB_XCAXACustomMaxValueAttributeName;
31
31
 
32
+ /*! Accessibility identifier for custom actions attribute */
33
+ extern NSNumber *FB_XCAXACustomActionsAttribute;
34
+ extern NSString *FB_XCAXACustomActionsAttributeName;
35
+
32
36
  /*! Getter for XCTest logger */
33
37
  extern id<XCDebugLogDelegate> (*XCDebugLogger)(void);
34
38
 
@@ -22,6 +22,8 @@ NSNumber *FB_XCAXACustomMinValueAttribute;
22
22
  NSString *FB_XCAXACustomMinValueAttributeName = @"XC_kAXXCAttributeMinValue";
23
23
  NSNumber *FB_XCAXACustomMaxValueAttribute;
24
24
  NSString *FB_XCAXACustomMaxValueAttributeName = @"XC_kAXXCAttributeMaxValue";
25
+ NSNumber *FB_XCAXACustomActionsAttribute;
26
+ NSString *FB_XCAXACustomActionsAttributeName = @"XC_kAXXCAttributeCustomActions";
25
27
 
26
28
  void (*XCSetDebugLogger)(id <XCDebugLogDelegate>);
27
29
  id<XCDebugLogDelegate> (*XCDebugLogger)(void);
@@ -49,12 +51,20 @@ __attribute__((constructor)) void FBLoadXCTestSymbols(void)
49
51
  NSString *XC_kAXXCAttributeMinValue = *(NSString *__autoreleasing *)FBRetrieveXCTestSymbol([FB_XCAXACustomMinValueAttributeName UTF8String]);
50
52
  NSString *XC_kAXXCAttributeMaxValue = *(NSString *__autoreleasing *)FBRetrieveXCTestSymbol([FB_XCAXACustomMaxValueAttributeName UTF8String]);
51
53
 
52
- NSArray<NSNumber *> *minMaxAttrs = XCAXAccessibilityAttributesForStringAttributes(@[XC_kAXXCAttributeMinValue, XC_kAXXCAttributeMaxValue]);
53
- FB_XCAXACustomMinValueAttribute = minMaxAttrs[0];
54
- FB_XCAXACustomMaxValueAttribute = minMaxAttrs[1];
54
+ NSString *XC_kAXXCAttributeCustomActions = *(NSString *__autoreleasing *)FBRetrieveXCTestSymbol([FB_XCAXACustomActionsAttributeName UTF8String]);
55
+
56
+ NSArray<NSNumber *> *customAttrs = XCAXAccessibilityAttributesForStringAttributes(@[
57
+ XC_kAXXCAttributeMinValue,
58
+ XC_kAXXCAttributeMaxValue,
59
+ XC_kAXXCAttributeCustomActions
60
+ ]);
61
+ FB_XCAXACustomMinValueAttribute = customAttrs[0];
62
+ FB_XCAXACustomMaxValueAttribute = customAttrs[1];
63
+ FB_XCAXACustomActionsAttribute = customAttrs[2];
55
64
 
56
65
  NSCAssert(FB_XCAXACustomMinValueAttribute != nil, @"Failed to retrieve FB_XCAXACustomMinValueAttribute", FB_XCAXACustomMinValueAttribute);
57
66
  NSCAssert(FB_XCAXACustomMaxValueAttribute != nil, @"Failed to retrieve FB_XCAXACustomMaxValueAttribute", FB_XCAXACustomMaxValueAttribute);
67
+ NSCAssert(FB_XCAXACustomActionsAttribute != nil, @"Failed to retrieve FB_XCAXACustomActionsAttribute", FB_XCAXACustomActionsAttribute);
58
68
  }
59
69
 
60
70
  void *FBRetrieveXCTestSymbol(const char *name)
@@ -89,7 +99,8 @@ NSArray<NSString*> *FBCustomAttributeNames(void)
89
99
  FB_XCAXAIsVisibleAttributeName,
90
100
  FB_XCAXAIsElementAttributeName,
91
101
  FB_XCAXACustomMinValueAttributeName,
92
- FB_XCAXACustomMaxValueAttributeName
102
+ FB_XCAXACustomMaxValueAttributeName,
103
+ FB_XCAXACustomActionsAttributeName
93
104
  ];
94
105
  });
95
106
  return customNames;
@@ -10,10 +10,32 @@
10
10
 
11
11
  @interface ViewController ()
12
12
  @property (weak, nonatomic) IBOutlet UILabel *orentationLabel;
13
+ @property (weak, nonatomic) IBOutlet UIButton *button;
13
14
  @end
14
15
 
15
16
  @implementation ViewController
16
17
 
18
+ - (void)viewDidLoad
19
+ {
20
+ [super viewDidLoad];
21
+
22
+ UIAccessibilityCustomAction *action1 =
23
+ [[UIAccessibilityCustomAction alloc] initWithName:@"Custom Action 1"
24
+ target:self
25
+ selector:@selector(handleCustomAction:)];
26
+ UIAccessibilityCustomAction *action2 =
27
+ [[UIAccessibilityCustomAction alloc] initWithName:@"Custom Action 2"
28
+ target:self
29
+ selector:@selector(handleCustomAction:)];
30
+ self.button.accessibilityCustomActions = @[action1, action2];
31
+ }
32
+
33
+ - (BOOL)handleCustomAction:(UIAccessibilityCustomAction *)action
34
+ {
35
+ // Custom action handler - just return YES to indicate success
36
+ return YES;
37
+ }
38
+
17
39
  - (IBAction)deadlockApp:(id)sender
18
40
  {
19
41
  dispatch_sync(dispatch_get_main_queue(), ^{
@@ -1,9 +1,9 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="nJd-IZ-bfU">
2
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="nJd-IZ-bfU">
3
3
  <device id="retina6_5" orientation="portrait" appearance="light"/>
4
4
  <dependencies>
5
5
  <deployment identifier="iOS"/>
6
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
6
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
7
7
  <capability name="System colors in document resources" minToolsVersion="11.0"/>
8
8
  <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
9
  </dependencies>
@@ -21,7 +21,7 @@
21
21
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
22
22
  <subviews>
23
23
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nbp-zX-Om1">
24
- <rect key="frame" x="186.66666666666666" y="117" width="41" height="30"/>
24
+ <rect key="frame" x="186.66666666666666" y="161" width="41" height="30"/>
25
25
  <constraints>
26
26
  <constraint firstAttribute="height" constant="30" id="GzF-4f-MaH"/>
27
27
  </constraints>
@@ -31,7 +31,7 @@
31
31
  </connections>
32
32
  </button>
33
33
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YgP-SF-TkS">
34
- <rect key="frame" x="159.66666666666666" y="155" width="95" height="30"/>
34
+ <rect key="frame" x="159.66666666666666" y="199" width="95" height="30"/>
35
35
  <constraints>
36
36
  <constraint firstAttribute="height" constant="30" id="wTu-YB-p22"/>
37
37
  </constraints>
@@ -42,7 +42,7 @@
42
42
  </connections>
43
43
  </button>
44
44
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="M2N-Yn-ytb">
45
- <rect key="frame" x="173" y="193" width="68" height="30"/>
45
+ <rect key="frame" x="173" y="237" width="68" height="30"/>
46
46
  <constraints>
47
47
  <constraint firstAttribute="height" constant="30" id="Sf6-pE-ROp"/>
48
48
  </constraints>
@@ -52,7 +52,7 @@
52
52
  </connections>
53
53
  </button>
54
54
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="S56-6U-3gG">
55
- <rect key="frame" x="177" y="231" width="60" height="30"/>
55
+ <rect key="frame" x="177" y="275" width="60" height="30"/>
56
56
  <constraints>
57
57
  <constraint firstAttribute="height" constant="30" id="7sH-TN-BNa"/>
58
58
  </constraints>
@@ -62,13 +62,13 @@
62
62
  </connections>
63
63
  </button>
64
64
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Orientation" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uiD-R4-b34">
65
- <rect key="frame" x="164.66666666666666" y="269" width="85" height="21"/>
65
+ <rect key="frame" x="164.66666666666666" y="313" width="85" height="21"/>
66
66
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
67
67
  <nil key="textColor"/>
68
68
  <nil key="highlightedColor"/>
69
69
  </label>
70
70
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1Ht-AF-MGW">
71
- <rect key="frame" x="186" y="298" width="42" height="30"/>
71
+ <rect key="frame" x="186" y="342" width="42" height="30"/>
72
72
  <state key="normal" title="Touch"/>
73
73
  <connections>
74
74
  <segue destination="XaE-eF-eIt" kind="show" id="q3u-B9-6R6"/>
@@ -114,7 +114,7 @@
114
114
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
115
115
  <subviews>
116
116
  <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C6B-Wo-jWm" customClass="TouchableView">
117
- <rect key="frame" x="16" y="96.000000000000028" width="382" height="356.66666666666674"/>
117
+ <rect key="frame" x="16" y="140.00000000000003" width="382" height="356.66666666666674"/>
118
118
  <color key="backgroundColor" systemColor="systemBackgroundColor"/>
119
119
  <accessibility key="accessibilityConfiguration" identifier="touchableView"/>
120
120
  <constraints>
@@ -122,14 +122,14 @@
122
122
  </constraints>
123
123
  </view>
124
124
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Taps" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IV8-Ak-Z8e">
125
- <rect key="frame" x="139" y="458.66666666666669" width="131" height="21"/>
125
+ <rect key="frame" x="139" y="502.66666666666674" width="131" height="21"/>
126
126
  <accessibility key="accessibilityConfiguration" identifier="numberOfTapsLabel"/>
127
127
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
128
128
  <nil key="textColor"/>
129
129
  <nil key="highlightedColor"/>
130
130
  </label>
131
131
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Touches" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q4X-EY-aSL">
132
- <rect key="frame" x="125" y="487.33333333333331" width="159" height="21"/>
132
+ <rect key="frame" x="125" y="531.33333333333337" width="159" height="21"/>
133
133
  <accessibility key="accessibilityConfiguration" identifier="numberOfTouchesLabel"/>
134
134
  <fontDescription key="fontDescription" type="system" pointSize="17"/>
135
135
  <nil key="textColor"/>
@@ -165,7 +165,7 @@
165
165
  <objects>
166
166
  <navigationController id="nJd-IZ-bfU" customClass="FBNavigationController" sceneMemberID="viewController">
167
167
  <navigationBar key="navigationBar" contentMode="scaleToFill" id="hZx-8U-FDw">
168
- <rect key="frame" x="0.0" y="44" width="414" height="44"/>
168
+ <rect key="frame" x="0.0" y="88" width="414" height="44"/>
169
169
  <autoresizingMask key="autoresizingMask"/>
170
170
  </navigationBar>
171
171
  <connections>
@@ -189,7 +189,7 @@
189
189
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
190
190
  <subviews>
191
191
  <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="Value" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mxs-lj-ChP">
192
- <rect key="frame" x="20" y="99" width="374" height="34"/>
192
+ <rect key="frame" x="20" y="143" width="374" height="34"/>
193
193
  <accessibility key="accessibilityConfiguration" identifier="" label=""/>
194
194
  <fontDescription key="fontDescription" type="system" pointSize="14"/>
195
195
  <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
@@ -199,19 +199,19 @@
199
199
  <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
200
200
  </pageControl>
201
201
  <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="LZF-72-rfb">
202
- <rect key="frame" x="20" y="499" width="374" height="327"/>
203
- <mutableString key="text">1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901</mutableString>
202
+ <rect key="frame" x="20" y="543" width="374" height="249"/>
203
+ <string key="text">1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901</string>
204
204
  <fontDescription key="fontDescription" type="system" pointSize="14"/>
205
205
  <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
206
206
  </textView>
207
207
  <datePicker contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" datePickerMode="dateAndTime" minuteInterval="1" style="wheels" translatesAutoresizingMaskIntoConstraints="NO" id="dxw-sJ-Dkr">
208
- <rect key="frame" x="20" y="365" width="374" height="126"/>
208
+ <rect key="frame" x="20" y="409" width="374" height="126"/>
209
209
  <constraints>
210
210
  <constraint firstAttribute="height" constant="126" id="QRU-5e-MQt"/>
211
211
  </constraints>
212
212
  </datePicker>
213
213
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Exq-MB-zeu">
214
- <rect key="frame" x="103.66666666666667" y="201" width="46.000000000000014" height="30"/>
214
+ <rect key="frame" x="103.66666666666667" y="245" width="46.000000000000014" height="30"/>
215
215
  <constraints>
216
216
  <constraint firstAttribute="height" constant="30" id="Otl-5O-2Nq"/>
217
217
  </constraints>
@@ -221,7 +221,7 @@
221
221
  </connections>
222
222
  </button>
223
223
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NJh-8E-4En">
224
- <rect key="frame" x="106.66666666666667" y="242" width="42.000000000000014" height="21"/>
224
+ <rect key="frame" x="106.66666666666667" y="286" width="42.000000000000014" height="21"/>
225
225
  <constraints>
226
226
  <constraint firstAttribute="height" constant="21" id="VBZ-ac-GvI"/>
227
227
  </constraints>
@@ -230,7 +230,7 @@
230
230
  <nil key="highlightedColor"/>
231
231
  </label>
232
232
  <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Wim-fT-xNl">
233
- <rect key="frame" x="64" y="267" width="131" height="29"/>
233
+ <rect key="frame" x="64" y="311" width="131" height="29"/>
234
234
  <constraints>
235
235
  <constraint firstAttribute="height" constant="28" id="IoK-dx-Y4W"/>
236
236
  </constraints>
@@ -240,32 +240,32 @@
240
240
  </segments>
241
241
  </segmentedControl>
242
242
  <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="U7D-NR-20N">
243
- <rect key="frame" x="207" y="276" width="118" height="31"/>
243
+ <rect key="frame" x="207" y="320" width="118" height="31"/>
244
244
  <constraints>
245
245
  <constraint firstAttribute="width" constant="114" id="vy6-tS-yHd"/>
246
246
  </constraints>
247
247
  </slider>
248
248
  <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SjL-dx-Zsi">
249
- <rect key="frame" x="235" y="314" width="51" height="31"/>
249
+ <rect key="frame" x="235" y="358" width="51" height="31"/>
250
250
  <constraints>
251
251
  <constraint firstAttribute="width" constant="49" id="dRJ-Hb-qNW"/>
252
252
  </constraints>
253
253
  </switch>
254
254
  <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="w6h-ic-qpa">
255
- <rect key="frame" x="134" y="353" width="150" height="4"/>
255
+ <rect key="frame" x="134" y="397" width="150" height="4"/>
256
256
  <constraints>
257
257
  <constraint firstAttribute="width" constant="150" id="7Tf-hh-LKX"/>
258
258
  </constraints>
259
259
  </progressView>
260
260
  <stepper opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="u8X-Wb-Od3">
261
- <rect key="frame" x="69" y="311" width="94" height="29"/>
261
+ <rect key="frame" x="69" y="355" width="94" height="29"/>
262
262
  <constraints>
263
263
  <constraint firstAttribute="width" constant="94" id="bNi-xp-G14"/>
264
264
  <constraint firstAttribute="height" constant="29" id="f0s-Rr-QTt"/>
265
265
  </constraints>
266
266
  </stepper>
267
267
  <label opaque="NO" userInteractionEnabled="NO" alpha="0.0" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="alpha_invisible" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ucg-0s-c50">
268
- <rect key="frame" x="224.33333333333334" y="197" width="111.66666666666666" height="21"/>
268
+ <rect key="frame" x="224.33333333333334" y="241" width="111.66666666666666" height="21"/>
269
269
  <color key="backgroundColor" red="1" green="0.0" blue="0.041046944598614132" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
270
270
  <constraints>
271
271
  <constraint firstAttribute="height" constant="21" id="664-Z3-V7W"/>
@@ -275,7 +275,7 @@
275
275
  <nil key="highlightedColor"/>
276
276
  </label>
277
277
  <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="hidden_invisible" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vt6-b1-U0h">
278
- <rect key="frame" x="221.66666666666666" y="226" width="122.66666666666666" height="21"/>
278
+ <rect key="frame" x="221.66666666666666" y="270" width="122.66666666666666" height="21"/>
279
279
  <constraints>
280
280
  <constraint firstAttribute="height" constant="21" id="51j-sl-XYd"/>
281
281
  </constraints>
@@ -284,7 +284,7 @@
284
284
  <nil key="highlightedColor"/>
285
285
  </label>
286
286
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GsS-jO-scK">
287
- <rect key="frame" x="174" y="248" width="103" height="30"/>
287
+ <rect key="frame" x="174" y="292" width="103" height="30"/>
288
288
  <accessibility key="accessibilityConfiguration">
289
289
  <bool key="isElement" value="NO"/>
290
290
  </accessibility>
@@ -299,10 +299,10 @@
299
299
  </userDefinedRuntimeAttributes>
300
300
  </button>
301
301
  <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="bQv-RY-wkj">
302
- <rect key="frame" x="171" y="320" width="20" height="20"/>
302
+ <rect key="frame" x="171" y="364" width="20" height="20"/>
303
303
  </activityIndicatorView>
304
304
  <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="Value2" borderStyle="roundedRect" textAlignment="natural" clearsOnBeginEditing="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Rab-I8-2aU">
305
- <rect key="frame" x="20" y="141" width="374" height="34"/>
305
+ <rect key="frame" x="20" y="185" width="374" height="34"/>
306
306
  <accessibility key="accessibilityConfiguration" identifier="aIdentifier" label="aLabel"/>
307
307
  <fontDescription key="fontDescription" type="system" pointSize="14"/>
308
308
  <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
@@ -349,6 +349,9 @@
349
349
  </constraints>
350
350
  </view>
351
351
  <navigationItem key="navigationItem" id="Hk7-AH-JlS"/>
352
+ <connections>
353
+ <outlet property="button" destination="Exq-MB-zeu" id="G1n-jg-1hY"/>
354
+ </connections>
352
355
  </viewController>
353
356
  <placeholder placeholderIdentifier="IBFirstResponder" id="0f2-qL-RU6" userLabel="First Responder" sceneMemberID="firstResponder"/>
354
357
  </objects>
@@ -367,7 +370,7 @@
367
370
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
368
371
  <subviews>
369
372
  <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="y1x-J5-Nkw">
370
- <rect key="frame" x="101.66666666666669" y="113" width="211" height="30"/>
373
+ <rect key="frame" x="101.66666666666669" y="157" width="211" height="30"/>
371
374
  <accessibility key="accessibilityConfiguration" identifier="textField"/>
372
375
  <constraints>
373
376
  <constraint firstAttribute="height" constant="30" id="B7B-wI-RFc"/>
@@ -377,7 +380,7 @@
377
380
  <textInputTraits key="textInputTraits"/>
378
381
  </textField>
379
382
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4VK-4B-FEF">
380
- <rect key="frame" x="149.66666666666666" y="194" width="113.99999999999997" height="30"/>
383
+ <rect key="frame" x="149.66666666666666" y="238" width="113.99999999999997" height="30"/>
381
384
  <constraints>
382
385
  <constraint firstAttribute="height" constant="30" id="xsL-Fq-mly"/>
383
386
  </constraints>
@@ -387,7 +390,7 @@
387
390
  </connections>
388
391
  </button>
389
392
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQt-5y-Tft">
390
- <rect key="frame" x="124" y="232" width="166" height="30"/>
393
+ <rect key="frame" x="124" y="276" width="166" height="30"/>
391
394
  <constraints>
392
395
  <constraint firstAttribute="height" constant="30" id="Y5y-Th-63a"/>
393
396
  </constraints>
@@ -397,7 +400,7 @@
397
400
  </connections>
398
401
  </button>
399
402
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rG5-3k-LFe">
400
- <rect key="frame" x="122" y="270" width="169" height="30"/>
403
+ <rect key="frame" x="122" y="314" width="169" height="30"/>
401
404
  <constraints>
402
405
  <constraint firstAttribute="height" constant="30" id="im5-w3-Pgi"/>
403
406
  </constraints>
@@ -407,7 +410,7 @@
407
410
  </connections>
408
411
  </button>
409
412
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ntr-45-Ycd">
410
- <rect key="frame" x="123" y="308" width="168" height="30"/>
413
+ <rect key="frame" x="123" y="352" width="168" height="30"/>
411
414
  <constraints>
412
415
  <constraint firstAttribute="height" constant="30" id="4B7-LM-UwV"/>
413
416
  </constraints>
@@ -417,7 +420,7 @@
417
420
  </connections>
418
421
  </button>
419
422
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CZ1-7J-OGl">
420
- <rect key="frame" x="66.666666666666671" y="176" width="46" height="30"/>
423
+ <rect key="frame" x="66.666666666666671" y="220" width="46" height="30"/>
421
424
  <accessibility key="accessibilityConfiguration" identifier="button"/>
422
425
  <constraints>
423
426
  <constraint firstAttribute="height" constant="30" id="tJH-wr-O3J"/>
@@ -425,7 +428,7 @@
425
428
  <state key="normal" title="Button"/>
426
429
  </button>
427
430
  <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="plO-2e-XmX">
428
- <rect key="frame" x="304.66666666666669" y="180" width="42" height="21"/>
431
+ <rect key="frame" x="304.66666666666669" y="224" width="42" height="21"/>
429
432
  <accessibility key="accessibilityConfiguration" identifier="label"/>
430
433
  <constraints>
431
434
  <constraint firstAttribute="height" constant="21" id="2qA-NT-ddc"/>
@@ -435,7 +438,7 @@
435
438
  <nil key="highlightedColor"/>
436
439
  </label>
437
440
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3Zk-wE-jwj">
438
- <rect key="frame" x="144" y="346" width="126" height="30"/>
441
+ <rect key="frame" x="144" y="390" width="126" height="30"/>
439
442
  <constraints>
440
443
  <constraint firstAttribute="height" constant="30" id="Mk4-bk-Y0L"/>
441
444
  </constraints>
@@ -445,7 +448,7 @@
445
448
  </connections>
446
449
  </button>
447
450
  <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="D7g-22-s49">
448
- <rect key="frame" x="116" y="384" width="182" height="30"/>
451
+ <rect key="frame" x="116" y="428" width="182" height="30"/>
449
452
  <constraints>
450
453
  <constraint firstAttribute="height" constant="30" id="TzV-CY-64y"/>
451
454
  </constraints>
@@ -493,7 +496,7 @@
493
496
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
494
497
  <subviews>
495
498
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vYb-QB-vwU">
496
- <rect key="frame" x="172.66666666666666" y="108" width="69" height="30"/>
499
+ <rect key="frame" x="172.66666666666666" y="152" width="69" height="30"/>
497
500
  <constraints>
498
501
  <constraint firstAttribute="height" constant="30" id="ymh-D3-SCA"/>
499
502
  </constraints>
@@ -503,7 +506,7 @@
503
506
  </connections>
504
507
  </button>
505
508
  <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FdB-fa-0bl">
506
- <rect key="frame" x="171" y="146" width="72" height="30"/>
509
+ <rect key="frame" x="171" y="190" width="72" height="30"/>
507
510
  <constraints>
508
511
  <constraint firstAttribute="height" constant="30" id="Xas-AZ-Nyw"/>
509
512
  </constraints>
@@ -583,7 +586,7 @@
583
586
  <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
584
587
  <subviews>
585
588
  <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xEQ-MI-a2g">
586
- <rect key="frame" x="0.0" y="0.0" width="414" height="862"/>
589
+ <rect key="frame" x="0.0" y="0.0" width="414" height="828"/>
587
590
  <userDefinedRuntimeAttributes>
588
591
  <userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="scrollView"/>
589
592
  </userDefinedRuntimeAttributes>
@@ -13,6 +13,7 @@
13
13
  #import "FBTestMacros.h"
14
14
  #import "FBXCodeCompatibility.h"
15
15
  #import "XCUIElement+FBAccessibility.h"
16
+ #import "XCUIElement+FBCustomActions.h"
16
17
  #import "XCUIElement+FBIsVisible.h"
17
18
  #import "XCUIElement+FBWebDriverAttributes.h"
18
19
 
@@ -251,4 +252,13 @@
251
252
  XCTAssertEqualObjects(element.wdValue, @"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901");
252
253
  }
253
254
 
255
+ - (void)testCustomActionsAttributes
256
+ {
257
+ XCUIElement *buttonElement = self.testedApplication.buttons[@"Button"];
258
+ XCTAssertTrue(buttonElement.exists);
259
+ NSString *customActions = buttonElement.wdCustomActions;
260
+ XCTAssertNotNil(customActions, @"Button should have custom actions");
261
+ XCTAssertEqualObjects(customActions, @"Custom Action 1,Custom Action 2");
262
+ }
263
+
254
264
  @end
@@ -12,4 +12,5 @@
12
12
  @property (readwrite, nullable) id value;
13
13
  @property (readwrite, nullable, copy) NSString *label;
14
14
  @property (nonatomic, assign) UIAccessibilityTraits traits;
15
+ @property (readwrite, nullable) NSMutableDictionary *additionalAttributes;
15
16
  @end
@@ -19,6 +19,7 @@
19
19
  self = [super init];
20
20
  self->_value = @"magicValue";
21
21
  self->_label = @"testLabel";
22
+ self->_additionalAttributes = [NSMutableDictionary dictionary];
22
23
  return self;
23
24
  }
24
25
 
@@ -72,11 +73,6 @@
72
73
  return YES;
73
74
  }
74
75
 
75
- - (NSDictionary *)additionalAttributes
76
- {
77
- return @{};
78
- }
79
-
80
76
  - (id<FBXCAccessibilityElement>)accessibilityElement
81
77
  {
82
78
  return nil;
@@ -38,6 +38,7 @@
38
38
  @property (nonatomic, readwrite, assign) XCUIElementType elementType;
39
39
  @property (nonatomic, readwrite, getter=isWDAccessibilityContainer) BOOL wdAccessibilityContainer;
40
40
  @property (nonatomic, copy, readwrite, nullable) NSString *wdTraits;
41
+ @property (nonatomic, strong, readwrite, nullable) NSString *wdCustomActions;
41
42
 
42
43
  - (void)resolve;
43
44
  - (id _Nonnull)fb_standardSnapshot;
@@ -25,6 +25,7 @@
25
25
  self.wdValue = @"magicValue";
26
26
  self.wdPlaceholderValue = @"testPlaceholderValue";
27
27
  self.wdTraits = @"testTraits";
28
+ self.wdCustomActions = nil;
28
29
  self.wdVisible = YES;
29
30
  self.wdAccessible = YES;
30
31
  self.wdEnabled = YES;
@@ -14,6 +14,7 @@
14
14
  #import "XCUIElementDouble.h"
15
15
  #import "XCElementSnapshotDouble.h"
16
16
  #import "FBXCElementSnapshotWrapper+Helpers.h"
17
+ #import "XCTestPrivateSymbols.h"
17
18
 
18
19
  @interface FBXPathTests : XCTestCase
19
20
  @end
@@ -68,7 +69,7 @@
68
69
  XCTAssertTrue([resultXml isEqualToString: expectedXml]);
69
70
  }
70
71
 
71
- - (void)testtXPathPresentationWithSomeAttributesExcluded
72
+ - (void)testXPathPresentationWithSomeAttributesExcluded
72
73
  {
73
74
  XCElementSnapshotDouble *snapshot = [XCElementSnapshotDouble new];
74
75
  id<FBElement> element = (id<FBElement>)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot];
@@ -85,12 +86,14 @@
85
86
  XCElementSnapshotDouble *snapshot = [XCElementSnapshotDouble new];
86
87
  snapshot.value = @"йоло<>&\"";
87
88
  snapshot.label = @"a\nb";
89
+ NSString *testCustomActions = @"Custom Action 1, Custom Action 2";
90
+ snapshot.additionalAttributes[FB_XCAXACustomActionsAttribute] = testCustomActions;
88
91
  id<FBElement> element = (id<FBElement>)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot];
89
92
  NSString *resultXml = [self xmlStringWithElement:(id<FBXCElementSnapshot>)element
90
93
  xpathQuery:[NSString stringWithFormat:@"//%@[@*]", element.wdType]
91
94
  excludingAttributes:@[@"visible"]];
92
- NSString *expectedXml = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" hittable=\"%@\" traits=\"%@\" nativeFrame=\"%@\" private_indexPath=\"top\"/>\n",
93
- element.wdType, element.wdType, @"йоло&lt;&gt;&amp;&quot;", element.wdName, @"a&#10;b", FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex, FBBoolToString(element.wdHittable), element.wdTraits, NSStringFromCGRect(element.wdNativeFrame)];
95
+ NSString *expectedXml = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" hittable=\"%@\" traits=\"%@\" nativeFrame=\"%@\" customActions=\"%@\" private_indexPath=\"top\"/>\n",
96
+ element.wdType, element.wdType, @"йоло&lt;&gt;&amp;&quot;", element.wdName, @"a&#10;b", FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex, FBBoolToString(element.wdHittable), element.wdTraits, NSStringFromCGRect(element.wdNativeFrame), element.wdCustomActions];
94
97
  XCTAssertEqualObjects(expectedXml, resultXml);
95
98
  }
96
99
 
@@ -34,6 +34,7 @@
34
34
  @property (copy, nonnull) NSArray *children;
35
35
  @property (nonatomic, readwrite, assign) XCUIElementType elementType;
36
36
  @property (nonatomic, readwrite, getter=isWDAccessibilityContainer) BOOL wdAccessibilityContainer;
37
+ @property (nonatomic, strong, readwrite, nullable) NSString *wdCustomActions;
37
38
 
38
39
  - (void)resolve;
39
40
  - (id _Nonnull)fb_standardSnapshot;
@@ -28,6 +28,7 @@
28
28
  self.wdSelected = YES;
29
29
  self.wdHittable = YES;
30
30
  self.wdIndex = 0;
31
+ self.wdCustomActions = nil;
31
32
  #if TARGET_OS_TV
32
33
  self.wdFocused = YES;
33
34
  #endif
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "11.0.2",
3
+ "version": "11.1.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",