Skip to content

feat: add action and camera values for mobile: pressButton#1115

Open
eglitise wants to merge 6 commits intoappium:masterfrom
eglitise:pressbutton
Open

feat: add action and camera values for mobile: pressButton#1115
eglitise wants to merge 6 commits intoappium:masterfrom
eglitise:pressbutton

Conversation

@eglitise
Copy link

@eglitise eglitise commented Mar 3, 2026

Currently WDA only supports the home, volumeUp and volumeDown buttons for iOS, but Apple's documentation also lists action and camera. This PR adds support for them.
Since not all devices have these buttons, their use is guarded behind the hasHardwareButton: check, which itself requires iOS 16, so a second guard was also added.

(I don't actually have a way to test this, so any validation would be appreciated)

Reference: https://developer.apple.com/documentation/xcuiautomation/xcuidevice/button?language=objc

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for additional iOS hardware button names (action, camera) to mobile: pressButton in WebDriverAgent by mapping them to the corresponding XCUIDeviceButton values when available on-device.

Changes:

  • Extend XCUIDevice (FBHelpers) button name mapping to include action (iOS 16+) and camera (iOS 16+) gated by hasHardwareButton:.
  • Update the public header docstring to list the newly supported button names.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m Adds runtime-gated mapping for action/camera buttons and updates supported button list construction.
WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h Updates API documentation to include action and camera button names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

dstButton = XCUIDeviceButtonHome;
}
[supportedButtonNames addObject:@"home"];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to extract this logic into a separate private method to simplify this one?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could certainly be made to look nicer, but I'm not really sure of the best approach when using these compiler-level guards

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't change anything, just refactor conditions to a separate method to reduce the cyclomatic complexity of the fb_pressButton one, (e.g. fb_addButtonsIfAvailable)

Copy link
Author

@eglitise eglitise Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two helper methods, one for checking if a button is available, and another for adding supported buttons to the list. The latter method is separated, as I would like to reuse both in the other tvOS PR.

{
NSError *error;
BOOL hasActionButton = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"16.0")
&& [XCUIDevice.sharedDevice hasHardwareButton:XCUIDeviceButtonAction];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

[supportedButtonNames addObject:@"home"];

#if __clang_major__ >= 17 || (__clang_major__ == 16 && __clang_minor__ >= 3)
if (@available(iOS 16.0, *) && [self hasHardwareButton:XCUIDeviceButtonAction]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see headers below in Xcode 15.0 so I guess XCUIDeviceButtonAction exists in Xcode 15 as well.

typedef NS_ENUM(NSInteger, XCUIDeviceButton) {
    XCUIDeviceButtonHome = 1,
    XCUIDeviceButtonVolumeUp XCTEST_SIMULATOR_UNAVAILABLE("This API is not available in the Simulator, see the XCUIDeviceButton documentation for details.") = 2,
    XCUIDeviceButtonVolumeDown XCTEST_SIMULATOR_UNAVAILABLE("This API is not available in the Simulator, see the XCUIDeviceButton documentation for details.") = 3,
#if TARGET_OS_WATCH || TARGET_OS_IOS
    XCUIDeviceButtonAction = 4,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume why Apple docs address they are available since Xcode 16.3 is they moved XCUIAutomation framework from private to public since the version

Copy link
Member

@KazuCocoa KazuCocoa Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1115 (comment)
Hm, maybe it had a case that references didn't work properly(?)
Looks reasonable to requirethe newer versions like current implementation by following Apple's public doc

Copy link
Author

@eglitise eglitise Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI error seems to have been specifically due to XCUIDeviceButtonCamera, so it is likely it was added later than Xcode 15.
My guess is that the target for XCUIDeviceButtonAction is Xcode 15 (coincides with the release of iPhone 15 Pro (Max) which added it), while XCUIDeviceButtonCamera would be Xcode 16 (coincides with the release of the iPhone 16 lineup)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the guards to actually check if the constant is defined, rather than the Clang version

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +191 to +199
NSError *error;
BOOL hasActionButton = [XCUIDevice.sharedDevice fb_hasButton:@"action"];
BOOL didPressButton = [XCUIDevice.sharedDevice fb_pressButton:@"action"
forDuration:nil
error:&error];
if (hasActionButton) {
XCTAssertTrue(didPressButton);
XCTAssertNil(error);
} else {
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NSError *error; is left uninitialized before being passed to fb_pressButton:... error:&error. Since fb_pressButton: does not set *error = nil on success, the subsequent XCTAssertNil(error) can be nondeterministic when the Action button exists and the press succeeds. Initialize error to nil before the call (and consider applying the same pattern in similar tests).

Copilot uses AI. Check for mistakes.
}
}

- (BOOL)fb_hasButton:(NSString *)buttonName
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is expected to be called only for non-tvOS, then wrapping the entire method with #if !TARGET_OS_TV and reduce it inside this method would simplify the context switching when we read the code. Then, we can assume this button is dedicated for non-tvOS env.

Copy link
Author

@eglitise eglitise Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to extend it in the other tvOS PR, which is why I haven't added the target compiler guard for the whole method. Or would it be better to make two separate fb_hasButton methods?

@param buttonName The name of the button to check (e.g., "home", "volumeUp", "volumeDown", "action", "camera")
@return YES if the button is available on the device, otherwise NO
*/
- (BOOL)fb_hasButton:(NSString *)buttonName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to make this as a public method? Current usage is only in this WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m helper, so I assume we don't need to make this public til we need this from public space

[supportedButtonNames addObject:buttonName];
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider moving private methods to the tail of the class definition

[supportedButtonNames addObject:@"volumeUp"];
[supportedButtonNames addObject:@"volumeDown"];
#if defined(XCUIDeviceButtonCamera)
if ([buttonNameLC isEqualToString:@"camera"] && [self fb_hasButton:@"camera"]) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these conditions the same as inside fb_addButtonsIfAvailable ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants