Skip to content

feat: add 6 tvOS button values for mobile: pressButton#1116

Merged
eglitise merged 5 commits intoappium:masterfrom
eglitise:tvos-pressbutton
Mar 5, 2026
Merged

feat: add 6 tvOS button values for mobile: pressButton#1116
eglitise merged 5 commits intoappium:masterfrom
eglitise:tvos-pressbutton

Conversation

@eglitise
Copy link

@eglitise eglitise commented Mar 3, 2026

Similarly to #1115, this adds support for 6 tvOS buttons to mobile: pressButton:

  • pageUp (tvOS 14.3+)
  • pageDown (tvOS 14.3+)
  • guide (tvOS 14.3+)
  • fourColors (tvOS 18.1+)
  • oneTwoThree (tvOS 18.1+)
  • tvProvider (tvOS 18.1+)

Each button is guarded behind whether the used Xcode SDK includes its enum, and the latter three also behind tvOS 18.1+ (the former three aren't guarded, as we only support tvOS 15+)

Reference: https://developer.apple.com/documentation/xcuiautomation/xcuiremotebutton/home?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 additional tvOS remote button name mappings to mobile: pressButton (via XCUIDevice helper) so Appium/WDA can trigger more Apple TV remote buttons through XCTest/WDA.

Changes:

  • Map pageUp, pageDown, and guide to the corresponding XCUIRemoteButton* enums.
  • Add tvOS 18.1+ button mappings (fourColors, oneTwoThree, tvProvider) behind compile-time and runtime availability checks.

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


// since tvOS 14.3
if ([buttonName.lowercaseString isEqualToString:@"pageup"]) {
remoteButton = XCUIRemoteButtonPageUp;
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.

I have confirmed on my XCTest header note, the blow ones were added in Xcode 15.3

  • XCUIRemoteButtonPageUp
  • XCUIRemoteButtonPageDown
  • XCUIRemoteButtonGuide

This is since Xcode 15.3:

AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h: * @enum XCUIRemoteButton
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:typedef NS_ENUM(NSUInteger, XCUIRemoteButton) {
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonUp          = 0,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonDown        = 1,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonLeft        = 2,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonRight       = 3,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonSelect      = 4,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonMenu        = 5,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonPlayPause   = 6,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonHome        = 7,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonPageUp API_AVAILABLE(tvos(14.3))   = 9,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonPageDown API_AVAILABLE(tvos(14.3)) = 10,
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:    XCUIRemoteButtonGuide API_AVAILABLE(tvos(14.3))    = 11
AppleTVOS/Frameworks/XCTest.framework/Headers/Headers/XCUIRemote.h:- (void)pressButton:(XCUIRemoteButton)remoteButton;

Copy link
Member

@KazuCocoa KazuCocoa left a comment

Choose a reason for hiding this comment

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

I'm fine to add the Xcode version check for the page up/down and guide since our supported Xcode version is the latest two major versions - 26 and 16 for now.

}
[supportedButtonNames addObject:@"select"];

// since tvOS 14.3

Choose a reason for hiding this comment

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

the method is now big and is hard to read. Consider splitting it to smaller ones

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 1 out of 1 changed files in this pull request and generated 3 comments.


💡 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.

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 1 out of 1 changed files in this pull request and generated 5 comments.


💡 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 +29 to 33
#if TARGET_OS_TV
NSDictionary<NSString *, NSNumber *> *availableButtonNames(void) {
static dispatch_once_t onceToken;
static NSDictionary *result;
dispatch_once(&onceToken, ^{
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

availableButtonNames is declared as a global C function in this .m file. Since it’s only used internally, consider marking it static (or giving it an FB-prefixed name) to avoid exporting a generic symbol that could collide at link time.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

I assume it's not exported as it's not included in the headers file

Choose a reason for hiding this comment

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

this comment still makes sense, lets add FB prefix

Comment on lines 286 to 292
NSDictionary<NSString *, NSNumber *> *availableButtons = availableButtonNames();
NSNumber *buttonValue = availableButtons[buttonName.lowercaseString];

if (!buttonValue) {
return [[[FBErrorBuilder builder]
withDescriptionFormat:@"The button '%@' is not supported. The device under test only supports the following buttons: %@", buttonName, supportedButtonNames]
withDescriptionFormat:@"The button '%@' is not supported. The device under test only supports the following buttons: %@", buttonName, availableButtons.allKeys]
buildError:error];
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The unsupported-button error now prints availableButtons.allKeys, which is not ordered and can lead to noisy/non-deterministic messages. Consider sorting the keys (e.g. case-insensitive compare) before including them in the error description to keep output stable and easier to read.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

I could add this, but I'm not sure it's really an issue

Choose a reason for hiding this comment

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

lets add sorting, it's a simple change

Comment on lines +44 to +48
#if __clang_major__ >= 15 // Xcode 15+
buttons[@"pageup"] = @(XCUIRemoteButtonPageUp); // 9
buttons[@"pagedown"] = @(XCUIRemoteButtonPageDown); // 10
buttons[@"guide"] = @(XCUIRemoteButtonGuide); // 11
#endif
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The tvOS button availability is gated using __clang_major__ (Xcode/clang version), but the PR description says the guard should be based on whether the SDK headers include the enum values. Using clang version is an indirect proxy and can unnecessarily disable support when building with an SDK that already contains these enum cases. Prefer guarding with the SDK availability macros (e.g. __TV_OS_VERSION_MAX_ALLOWED) so the checks reflect the actual headers being compiled against.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

We don't use the _VERSION_MAX_ALLOWED macros anywhere, and in this case the clang version actually has a stricter requirement than the tvOS version

Comment on lines +49 to +55
#if __clang_major__ >= 17 // likely Xcode 16.3+
if (@available(tvOS 18.1, *)) {
buttons[@"fourcolors"] = @(XCUIRemoteButtonFourColors); // 12
buttons[@"onetwothree"] = @(XCUIRemoteButtonOneTwoThree); // 13
buttons[@"tvprovider"] = @(XCUIRemoteButtonTVProvider); // 14
}
#endif
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

Same issue for the tvOS 18.1+ remote buttons: __clang_major__ is a brittle proxy for SDK support. Guard these enum references with the corresponding tvOS SDK max-allowed macro (and keep the @available(tvOS 18.1, *) runtime gate) to ensure compilation is tied to header availability rather than compiler version.

Copilot uses AI. Check for mistakes.
Comment on lines 71 to 80
if (@available(iOS 16.0, *)) {
#if defined(XCUIDeviceButtonAction)
#if __clang_major__ >= 15 // likely Xcode 15+
if ([XCUIDevice.sharedDevice hasHardwareButton:XCUIDeviceButtonAction]) {
buttons[@"action"] = @(XCUIDeviceButtonAction);
buttons[@"action"] = @(XCUIDeviceButtonAction); // 4
}
#endif
#if defined(XCUIDeviceButtonCamera)
#if !TARGET_OS_SIMULATOR
#if (!TARGET_OS_SIMULATOR && __clang_major__ >= 16) // likely Xcode 16+
if ([XCUIDevice.sharedDevice hasHardwareButton:XCUIDeviceButtonCamera]) {
buttons[@"camera"] = @(XCUIDeviceButtonCamera);
}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

On iOS, gating XCUIDeviceButtonAction/XCUIDeviceButtonCamera behind __clang_major__ ties the feature to compiler version rather than SDK header availability. To match the intent (“guard behind whether the used Xcode SDK includes its enum”), use the relevant __IPHONE_OS_VERSION_MAX_ALLOWED checks (plus the existing @available(iOS 16.0, *) runtime guard) so the code compiles/behaves correctly across different toolchains.

Copilot uses AI. Check for mistakes.
@eglitise eglitise merged commit efd64ed into appium:master Mar 5, 2026
42 of 43 checks passed
@eglitise eglitise deleted the tvos-pressbutton branch March 5, 2026 20:29
github-actions bot pushed a commit that referenced this pull request Mar 5, 2026
## [11.3.0](v11.2.0...v11.3.0) (2026-03-05)

### Features

* add 6 tvOS button values for `mobile: pressButton` ([#1116](#1116)) ([efd64ed](efd64ed))
@github-actions
Copy link

github-actions bot commented Mar 5, 2026

🎉 This PR is included in version 11.3.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@mykola-mokhnach
Copy link

mykola-mokhnach commented Mar 5, 2026

@eglitise Please don't forget to update docs for the appropriate execute extension in the xcuitest driver

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants