appium-webdriveragent 11.1.7 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [11.3.0](https://github.com/appium/WebDriverAgent/compare/v11.2.0...v11.3.0) (2026-03-05)
2
+
3
+ ### Features
4
+
5
+ * add 6 tvOS button values for `mobile: pressButton` ([#1116](https://github.com/appium/WebDriverAgent/issues/1116)) ([efd64ed](https://github.com/appium/WebDriverAgent/commit/efd64ede7212b322f412cd6b25eab9c8097c286d))
6
+
7
+ ## [11.2.0](https://github.com/appium/WebDriverAgent/compare/v11.1.7...v11.2.0) (2026-03-04)
8
+
9
+ ### Features
10
+
11
+ * add `action` and `camera` values for `mobile: pressButton` ([#1115](https://github.com/appium/WebDriverAgent/issues/1115)) ([3df0284](https://github.com/appium/WebDriverAgent/commit/3df0284d741f8b4a36a9e12e130ecf0711b60366))
12
+
1
13
  ## [11.1.7](https://github.com/appium/WebDriverAgent/compare/v11.1.6...v11.1.7) (2026-03-03)
2
14
 
3
15
  ### Miscellaneous Chores
@@ -95,10 +95,19 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
95
95
  */
96
96
  - (BOOL)fb_openUrl:(NSString *)url withApplication:(NSString *)bundleId error:(NSError **)error;
97
97
 
98
+ /**
99
+ Checks if the device has a specific hardware button available.
100
+
101
+ @param buttonName The name of the button to check (e.g., "home", "volumeUp", "volumeDown", "action", "camera")
102
+ @return YES if the button is available on the device, otherwise NO
103
+ */
104
+ - (BOOL)fb_hasButton:(NSString *)buttonName;
105
+
98
106
  /**
99
107
  Presses the corresponding hardware button on the device with duration.
100
108
 
101
- @param buttonName One of the supported button names: volumeUp (real devices only), volumeDown (real device only), home
109
+ @param buttonName One of the supported button names: volumeUp (real devices only), volumeDown (real device only),
110
+ camera (supported iOS 16+ real devices only), action (supported iOS 16+ devices only), home
102
111
  @param duration Duration in seconds or nil.
103
112
  This argument works only on tvOS. When this argument is nil on tvOS,
104
113
  https://developer.apple.com/documentation/xctest/xcuiremote/1627476-pressbutton will be called.
@@ -26,6 +26,66 @@
26
26
  static const NSTimeInterval FBHomeButtonCoolOffTime = 1.;
27
27
  static const NSTimeInterval FBScreenLockTimeout = 5.;
28
28
 
29
+ #if TARGET_OS_TV
30
+ NSDictionary<NSString *, NSNumber *> *fb_availableButtonNames(void) {
31
+ static dispatch_once_t onceToken;
32
+ static NSDictionary *result;
33
+ dispatch_once(&onceToken, ^{
34
+ NSMutableDictionary *buttons = [NSMutableDictionary dictionary];
35
+ // https://developer.apple.com/design/human-interface-guidelines/remotes
36
+ buttons[@"up"] = @(XCUIRemoteButtonUp); // 0
37
+ buttons[@"down"] = @(XCUIRemoteButtonDown); // 1
38
+ buttons[@"left"] = @(XCUIRemoteButtonLeft); // 2
39
+ buttons[@"right"] = @(XCUIRemoteButtonRight); // 3
40
+ buttons[@"select"] = @(XCUIRemoteButtonSelect); // 4
41
+ buttons[@"menu"] = @(XCUIRemoteButtonMenu); // 5
42
+ buttons[@"playpause"] = @(XCUIRemoteButtonPlayPause); // 6
43
+ buttons[@"home"] = @(XCUIRemoteButtonHome); // 7
44
+ #if __clang_major__ >= 15 // Xcode 15+
45
+ buttons[@"pageup"] = @(XCUIRemoteButtonPageUp); // 9
46
+ buttons[@"pagedown"] = @(XCUIRemoteButtonPageDown); // 10
47
+ buttons[@"guide"] = @(XCUIRemoteButtonGuide); // 11
48
+ #endif
49
+ #if __clang_major__ >= 17 // likely Xcode 16.3+
50
+ if (@available(tvOS 18.1, *)) {
51
+ buttons[@"fourcolors"] = @(XCUIRemoteButtonFourColors); // 12
52
+ buttons[@"onetwothree"] = @(XCUIRemoteButtonOneTwoThree); // 13
53
+ buttons[@"tvprovider"] = @(XCUIRemoteButtonTVProvider); // 14
54
+ }
55
+ #endif
56
+ result = [buttons copy];
57
+ });
58
+ return result;
59
+ }
60
+ #else
61
+ NSDictionary<NSString *, NSNumber *> *fb_availableButtonNames(void) {
62
+ static dispatch_once_t onceToken;
63
+ static NSDictionary *result;
64
+ dispatch_once(&onceToken, ^{
65
+ NSMutableDictionary *buttons = [NSMutableDictionary dictionary];
66
+ buttons[@"home"] = @(XCUIDeviceButtonHome); // 1
67
+ #if !TARGET_OS_SIMULATOR
68
+ buttons[@"volumeup"] = @(XCUIDeviceButtonVolumeUp); // 2
69
+ buttons[@"volumedown"] = @(XCUIDeviceButtonVolumeDown); // 3
70
+ #endif
71
+ if (@available(iOS 16.0, *)) {
72
+ #if __clang_major__ >= 15 // likely Xcode 15+
73
+ if ([XCUIDevice.sharedDevice hasHardwareButton:XCUIDeviceButtonAction]) {
74
+ buttons[@"action"] = @(XCUIDeviceButtonAction); // 4
75
+ }
76
+ #endif
77
+ #if (!TARGET_OS_SIMULATOR && __clang_major__ >= 16) // likely Xcode 16+
78
+ if ([XCUIDevice.sharedDevice hasHardwareButton:XCUIDeviceButtonCamera]) {
79
+ buttons[@"camera"] = @(XCUIDeviceButtonCamera);
80
+ }
81
+ #endif
82
+ }
83
+ result = [buttons copy];
84
+ });
85
+ return result;
86
+ }
87
+ #endif
88
+
29
89
  @implementation XCUIDevice (FBHelpers)
30
90
 
31
91
  static bool fb_isLocked;
@@ -210,6 +270,11 @@ static bool fb_isLocked;
210
270
  }
211
271
  }
212
272
 
273
+ - (BOOL)fb_hasButton:(NSString *)buttonName
274
+ {
275
+ return fb_availableButtonNames()[buttonName.lowercaseString] != nil;
276
+ }
277
+
213
278
  - (BOOL)fb_pressButton:(NSString *)buttonName
214
279
  forDuration:(nullable NSNumber *)duration
215
280
  error:(NSError **)error
@@ -217,71 +282,23 @@ static bool fb_isLocked;
217
282
  #if !TARGET_OS_TV
218
283
  return [self fb_pressButton:buttonName error:error];
219
284
  #else
220
- NSMutableArray<NSString *> *supportedButtonNames = [NSMutableArray array];
221
- NSInteger remoteButton = -1; // no remote button
222
- if ([buttonName.lowercaseString isEqualToString:@"home"]) {
223
- // XCUIRemoteButtonHome = 7
224
- remoteButton = XCUIRemoteButtonHome;
225
- }
226
- [supportedButtonNames addObject:@"home"];
227
-
228
- // https://developer.apple.com/design/human-interface-guidelines/tvos/remote-and-controllers/remote/
229
- if ([buttonName.lowercaseString isEqualToString:@"up"]) {
230
- // XCUIRemoteButtonUp = 0,
231
- remoteButton = XCUIRemoteButtonUp;
232
- }
233
- [supportedButtonNames addObject:@"up"];
234
285
 
235
- if ([buttonName.lowercaseString isEqualToString:@"down"]) {
236
- // XCUIRemoteButtonDown = 1,
237
- remoteButton = XCUIRemoteButtonDown;
238
- }
239
- [supportedButtonNames addObject:@"down"];
240
-
241
- if ([buttonName.lowercaseString isEqualToString:@"left"]) {
242
- // XCUIRemoteButtonLeft = 2,
243
- remoteButton = XCUIRemoteButtonLeft;
244
- }
245
- [supportedButtonNames addObject:@"left"];
246
-
247
- if ([buttonName.lowercaseString isEqualToString:@"right"]) {
248
- // XCUIRemoteButtonRight = 3,
249
- remoteButton = XCUIRemoteButtonRight;
250
- }
251
- [supportedButtonNames addObject:@"right"];
252
-
253
- if ([buttonName.lowercaseString isEqualToString:@"menu"]) {
254
- // XCUIRemoteButtonMenu = 5,
255
- remoteButton = XCUIRemoteButtonMenu;
256
- }
257
- [supportedButtonNames addObject:@"menu"];
258
-
259
- if ([buttonName.lowercaseString isEqualToString:@"playpause"]) {
260
- // XCUIRemoteButtonPlayPause = 6,
261
- remoteButton = XCUIRemoteButtonPlayPause;
262
- }
263
- [supportedButtonNames addObject:@"playpause"];
264
-
265
- if ([buttonName.lowercaseString isEqualToString:@"select"]) {
266
- // XCUIRemoteButtonSelect = 4,
267
- remoteButton = XCUIRemoteButtonSelect;
268
- }
269
- [supportedButtonNames addObject:@"select"];
270
-
271
- if (remoteButton == -1) {
286
+ NSDictionary<NSString *, NSNumber *> *availableButtons = fb_availableButtonNames();
287
+ NSNumber *buttonValue = availableButtons[buttonName.lowercaseString];
288
+
289
+ if (!buttonValue) {
290
+ NSArray *sortedKeys = [availableButtons.allKeys sortedArrayUsingSelector:@selector(compare:)];
272
291
  return [[[FBErrorBuilder builder]
273
- withDescriptionFormat:@"The button '%@' is unknown. Only the following button names are supported: %@", buttonName, supportedButtonNames]
292
+ withDescriptionFormat:@"The button '%@' is not supported. The device under test only supports the following buttons: %@", buttonName, sortedKeys]
274
293
  buildError:error];
275
294
  }
276
-
277
295
  if (duration) {
278
- // https://developer.apple.com/documentation/xctest/xcuiremote/1627475-pressbutton
279
- [[XCUIRemote sharedRemote] pressButton:remoteButton forDuration:duration.doubleValue];
296
+ // https://developer.apple.com/documentation/xcuiautomation/xcuiremote/press(_:forduration:)
297
+ [[XCUIRemote sharedRemote] pressButton:(XCUIRemoteButton)[buttonValue unsignedIntegerValue] forDuration:duration.doubleValue];
280
298
  } else {
281
- // https://developer.apple.com/documentation/xctest/xcuiremote/1627476-pressbutton
282
- [[XCUIRemote sharedRemote] pressButton:remoteButton];
299
+ // https://developer.apple.com/documentation/xcuiautomation/xcuiremote/press(_:)
300
+ [[XCUIRemote sharedRemote] pressButton:(XCUIRemoteButton)[buttonValue unsignedIntegerValue]];
283
301
  }
284
-
285
302
  return YES;
286
303
  #endif
287
304
  }
@@ -290,29 +307,16 @@ static bool fb_isLocked;
290
307
  - (BOOL)fb_pressButton:(NSString *)buttonName
291
308
  error:(NSError **)error
292
309
  {
293
- NSMutableArray<NSString *> *supportedButtonNames = [NSMutableArray array];
294
- XCUIDeviceButton dstButton = 0;
295
- if ([buttonName.lowercaseString isEqualToString:@"home"]) {
296
- dstButton = XCUIDeviceButtonHome;
297
- }
298
- [supportedButtonNames addObject:@"home"];
299
- #if !TARGET_OS_SIMULATOR
300
- if ([buttonName.lowercaseString isEqualToString:@"volumeup"]) {
301
- dstButton = XCUIDeviceButtonVolumeUp;
302
- }
303
- if ([buttonName.lowercaseString isEqualToString:@"volumedown"]) {
304
- dstButton = XCUIDeviceButtonVolumeDown;
305
- }
306
- [supportedButtonNames addObject:@"volumeUp"];
307
- [supportedButtonNames addObject:@"volumeDown"];
308
- #endif
309
-
310
- if (dstButton == 0) {
310
+ NSDictionary<NSString *, NSNumber *> *availableButtons = fb_availableButtonNames();
311
+ NSNumber *buttonValue = availableButtons[buttonName.lowercaseString];
312
+
313
+ if (!buttonValue) {
314
+ NSArray *sortedKeys = [availableButtons.allKeys sortedArrayUsingSelector:@selector(compare:)];
311
315
  return [[[FBErrorBuilder builder]
312
- withDescriptionFormat:@"The button '%@' is unknown. Only the following button names are supported: %@", buttonName, supportedButtonNames]
316
+ withDescriptionFormat:@"The button '%@' is not supported. The device under test only supports the following buttons: %@", buttonName, sortedKeys]
313
317
  buildError:error];
314
318
  }
315
- [self pressButton:dstButton];
319
+ [self pressButton:(XCUIDeviceButton)[buttonValue unsignedIntegerValue]];
316
320
  return YES;
317
321
  }
318
322
  #endif
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>11.1.7</string>
18
+ <string>11.3.0</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>11.1.7</string>
22
+ <string>11.3.0</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -186,6 +186,22 @@
186
186
  XCTAssertNil(error);
187
187
  }
188
188
 
189
+ - (void)testPressingDeviceSpecificButton
190
+ {
191
+ NSError *error;
192
+ BOOL hasActionButton = [XCUIDevice.sharedDevice fb_hasButton:@"action"];
193
+ BOOL didPressButton = [XCUIDevice.sharedDevice fb_pressButton:@"action"
194
+ forDuration:nil
195
+ error:&error];
196
+ if (hasActionButton) {
197
+ XCTAssertTrue(didPressButton);
198
+ XCTAssertNil(error);
199
+ } else {
200
+ XCTAssertFalse(didPressButton);
201
+ XCTAssertNotNil(error);
202
+ }
203
+ }
204
+
189
205
  - (void)testPressingSupportedButtonNumber
190
206
  {
191
207
  NSError *error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "11.1.7",
3
+ "version": "11.3.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",