appium-webdriveragent 11.0.2 → 11.1.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +12 -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/build/lib/utils.d.ts +0 -12
  28. package/build/lib/utils.d.ts.map +1 -1
  29. package/build/lib/utils.js +0 -51
  30. package/build/lib/utils.js.map +1 -1
  31. package/build/lib/webdriveragent.d.ts.map +1 -1
  32. package/build/lib/webdriveragent.js +0 -1
  33. package/build/lib/webdriveragent.js.map +1 -1
  34. package/build/lib/xcodebuild.d.ts +1 -6
  35. package/build/lib/xcodebuild.d.ts.map +1 -1
  36. package/build/lib/xcodebuild.js +5 -24
  37. package/build/lib/xcodebuild.js.map +1 -1
  38. package/build/tsconfig.tsbuildinfo +1 -1
  39. package/lib/utils.ts +1 -52
  40. package/lib/webdriveragent.ts +0 -1
  41. package/lib/xcodebuild.ts +6 -28
  42. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [11.1.1](https://github.com/appium/WebDriverAgent/compare/v11.1.0...v11.1.1) (2026-01-21)
2
+
3
+ ### Bug Fixes
4
+
5
+ * Avoid modifying WDA sources ([#1101](https://github.com/appium/WebDriverAgent/issues/1101)) ([5f2a00f](https://github.com/appium/WebDriverAgent/commit/5f2a00faa38fac524a8eb229df500cdf6140bc2d))
6
+
7
+ ## [11.1.0](https://github.com/appium/WebDriverAgent/compare/v11.0.2...v11.1.0) (2025-12-28)
8
+
9
+ ### Features
10
+
11
+ * expose customActions on the element ([#1095](https://github.com/appium/WebDriverAgent/issues/1095)) ([3028512](https://github.com/appium/WebDriverAgent/commit/302851237297ee31965c55a75436ad0aea2a8c8f))
12
+
1
13
  ## [11.0.2](https://github.com/appium/WebDriverAgent/compare/v11.0.1...v11.0.2) (2025-12-25)
2
14
 
3
15
  ### 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.1</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.1</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(), ^{