Run your Appium tests on smart TV devices
A quickstart guide to running your Appium tests on smart TV devices with BrowserStack App Automate.
App Automate lets you test your apps on smart TVs. BrowserStack currently supports testing apps on the following smart TVs:
- Amazon Fire TV Stick 4K (Android 7.1)
- Nvidia Shield TV Pro 2019 (Android 11.0)
- Apple TV 4K (tvOS 26)
- Roku TV (RokuOS v15+). Roku TV requires Appium version 2.18.0. For details on the interactions you can perform with Roku devices, see the Appium Roku Driver documentation on GitHub. Roku has two types of devices, Roku Ultra and Roku Express 4K. You can define any one of them.
- Roku devices on the BrowserStack platform are automatically updated with the latest official firmware versions as soon as they become available. You do not need to manually request or manage device updates. The platform maintains current software versions across all Roku devices to ensure optimal testing performance and feature compatibility.
- Network logs and local are not directly supported for Roku devices. To have these features enabled, contact support.
Prerequisites
Before you start, make sure you have the following:
- Access to the smart TV alpha release on your BrowserStack account. To request access, contact support.
- A BrowserStack username and access key. To get your credentials, sign up for a free trial or purchase a plan.
- A smart TV app file —
.apkfor Android-based TVs (Fire TV, Nvidia Shield),.ipafor Apple TV, or.zipfor Roku TV.
Upload your app
Sample apps for different smart TV devices:
- Android-based smart TVs (Fire TV, Nvidia Shield): Download the sample app for Android.
- Apple TV: Download the sample app for tvOS.
- Roku TV: Download the sample app for Roku TV.
Upload your app file (.apk for Android-based smart TVs, .ipa for Apple TV, or .zip for Roku TV) to BrowserStack servers using one of the following methods:
Upload app using the App Automate dashboard
On the App Automate dashboard, click the Upload button on the top-right corner. Select the app you want to upload from your filesystem.

Upload app using App Management UI
To upload an app using the App Management UI, follow these steps:
- Navigate to the App Automate dashboard. On the sidebar, click App Management.
- On the App Management UI, click Upload App.
- Select the app you want to upload from your filesystem. To upload the app using a public URL, paste the URL of your app in the or upload from URL box.
- After selecting the app, choose the App Automate framework you want to use for testing. You can optionally add flags and a custom ID.
- Click Upload. The app is uploaded to the BrowserStack servers, and you receive an App ID that you can use to run tests.

To manage your apps, see the documentation on managing apps using App Management UI.
Upload app using REST API
To upload an app from your filesystem or a public URL using the REST API, run the following cURL command:
curl -u "YOUR_USERNAME:YOUR_ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
-F "file=@/path/to/app/file"
# Ensure that `@` symbol is prepended to the file path in the request.
curl -u "YOUR_USERNAME:YOUR_ACCESS_KEY" ^
-X POST "https://api-cloud.browserstack.com/app-automate/upload" ^
-F "file=@/path/to/app/file"
# Ensure that `@` symbol is prepended to the file path in the request.
A sample response is as follows:
{
"app_url":"bs://j3c874f21852ba57957a3fdc33f47514288c4ba4"
}
Save the app_url value from the response. You use it in the next step to specify which app to test.
App upload might take a few seconds to about a minute depending on the size of your app. Do not interrupt the cURL command until you get the response in your command-line/terminal.
Configure your Appium capabilities
Configure your Appium test script with the following capabilities to target a BrowserStack smart TV device:
- Set the
appcapability to theapp_urlof the app you uploaded. - Set the
devicecapability to one of the following:-
Amazon Fire TV Stick 4K— to run tests on Fire TV -
Nvidia Shield TV Pro 2019— to run tests on Nvidia Shield TV -
Apple TV 4K— to run tests on Apple TV -
Roku TV— to run tests on Roku TV (RokuOS v15+)
-
- For Apple TV, also set
automationNametoxcuitestandplatformNametotvos. - Initialize an Appium driver using a remote BrowserStack hub URL along with your BrowserStack credentials:
https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub
Run a sample test script
Choose your target device, then select your preferred language (Java, Ruby, Node.js, or Python) to view a complete sample test script with the required device capabilities:
import io.appium.java_client.AppiumBy;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.nativekey.AndroidKey;
import io.appium.java_client.android.nativekey.KeyEvent;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.openqa.selenium.By;
import org.openqa.selenium.MutableCapabilities;
import io.appium.java_client.android.AndroidDriver;
import java.net.URL;
import static org.openqa.selenium.By.*;
public class SmartTVTest {
public void testSmartTV() throws Exception {
AndroidDriver driver;
MutableCapabilities caps = new UiAutomator2Options();
caps.setCapability("build", "Smart TV Test");
caps.setCapability("deviceName", "Amazon Fire TV Stick 4K");
caps.setCapability("osVersion", "7.1");
caps.setCapability("appium:browserstack.dedicatedDevice", true);
caps.setCapability("app", APP_ID);
driver = new AndroidDriver(new URL("https://" +
BROWSERSTACK_USER + ":" + BROWSERSTACK_ACCESS_KEY +
"@hub.browserstack.com/wd/hub"), caps);
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_LEFT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_LEFT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(10000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.MEDIA_PLAY_PAUSE));
driver.quit();
}
}
require 'rubygems'
require 'appium_lib'
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
desired_caps = {
'platformName' => 'Android',
'deviceName' => 'Amazon Fire TV Stick 4K',
'osVersion' => '7.1',
'browserstack.debug' => 'true',
'app' => '<app_hashed_id>'
}
appium_driver = Appium::Driver.new({
caps: desired_caps,
appium_lib: {
server_url: "https://#{username}:#{access_key}@hub-cloud.browserstack.com/wd/hub"
}
}, true)
driver = appium_driver.start_driver
sleep 5
driver.press_keycode(20) # DPAD_DOWN
driver.press_keycode(22) # DPAD_RIGHT
video_element = driver.find_element(:xpath, "//android.widget.FrameLayout[@focused = 'true']")
video_name = video_element.attribute('content-desc')
puts "Selected Video Name: #{video_name}"
driver.press_keycode(23) # DPAD_CENTER
sleep(5)
driver.press_keycode(85) # MEDIA_PLAY_PAUSE
sleep(3)
driver.press_keycode(85) # MEDIA_PLAY_PAUSE
sleep(3)
driver.press_keycode(89) # MEDIA_REWIND
sleep(3)
driver.press_keycode(4) # BACK
focussed_element = driver.find_element(:xpath, "//android.widget.FrameLayout[@focused = 'true']")
focussed_video_name = focussed_element.attribute('content-desc')
if focussed_video_name == video_name
puts "Video played - Test passed"
else
puts "Video Could not be played - Test Failed"
end
driver.quit
const webdriverio = require('webdriverio');
const opts = {
capabilities: {
platformName: 'Android',
platformVersion: '7.1',
deviceName: 'Amazon Fire TV Stick 4K',
app: '<app_hashed_id>',
'browserstack.debug': 'true',
},
path: '/wd/hub',
user: 'YOUR_USERNAME',
key: 'YOUR_ACCESS_KEY',
};
(async () => {
const client = await webdriverio.remote(opts);
await client.pause(5000);
await client.pressKeyCode(20); // DPAD_DOWN
await client.pressKeyCode(22); // DPAD_RIGHT
const videoElement = await client.$(
'//android.widget.FrameLayout[@focused = "true"]',
);
const videoName = await videoElement.getAttribute('content-desc');
console.log(`Selected Video Name: ${videoName}`);
await client.pressKeyCode(23); // DPAD_CENTER
await client.pause(5000);
await client.pressKeyCode(85); // MEDIA_PLAY_PAUSE
await client.pause(3000);
await client.pressKeyCode(85); // MEDIA_PLAY_PAUSE
await client.pause(3000);
await client.pressKeyCode(89); // MEDIA_REWIND
await client.pause(3000);
await client.pressKeyCode(4); // BACK
const focussedElement = await client.$(
'//android.widget.FrameLayout[@focused = "true"]',
);
const focussedVideoName = await focussedElement.getAttribute('content-desc');
if (focussedVideoName === videoName) {
console.log('Video played - Test passed');
} else {
console.log('Video Could not be played - Test Failed');
}
await client.deleteSession();
})();
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.extensions.android.nativekey import AndroidKey
import time
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
options = UiAutomator2Options()
options.set_capability('build', 'Python Appium Sample')
options.set_capability('deviceName', 'Amazon Fire TV Stick 4K')
options.set_capability('osVersion', '7.1')
options.set_capability('browserstack.debug', 'true')
options.set_capability('app', '<app_hashed_id>')
driver = webdriver.Remote(
command_executor=f'https://{username}:{access_key}@hub-cloud.browserstack.com/wd/hub',
options=options
)
time.sleep(5)
driver.press_keycode(AndroidKey.DPAD_DOWN)
driver.press_keycode(AndroidKey.DPAD_RIGHT)
video_element = driver.find_element('xpath', "//android.widget.FrameLayout[@focused='true']")
video_name = video_element.get_attribute('content-desc')
print(f'Selected Video Name: {video_name}')
driver.press_keycode(AndroidKey.DPAD_CENTER)
time.sleep(5)
driver.press_keycode(AndroidKey.MEDIA_PLAY_PAUSE)
time.sleep(3)
driver.press_keycode(AndroidKey.MEDIA_PLAY_PAUSE)
time.sleep(3)
driver.press_keycode(AndroidKey.MEDIA_REWIND)
time.sleep(3)
driver.press_keycode(AndroidKey.BACK)
focussed_element = driver.find_element('xpath', "//android.widget.FrameLayout[@focused='true']")
focussed_video_name = focussed_element.get_attribute('content-desc')
if focussed_video_name == video_name:
print('Video played - Test passed')
else:
print('Video Could not be played - Test Failed')
driver.quit()
import io.appium.java_client.AppiumBy;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.nativekey.AndroidKey;
import io.appium.java_client.android.nativekey.KeyEvent;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.openqa.selenium.By;
import org.openqa.selenium.MutableCapabilities;
import io.appium.java_client.android.AndroidDriver;
import java.net.URL;
import static org.openqa.selenium.By.*;
public class SmartTVTest {
public void testSmartTV() throws Exception {
AndroidDriver driver;
MutableCapabilities caps = new UiAutomator2Options();
caps.setCapability("build", "Smart TV Test");
caps.setCapability("deviceName", "Nvidia Shield TV Pro 2019");
caps.setCapability("osVersion", "11.0");
caps.setCapability("appium:browserstack.dedicatedDevice", true);
caps.setCapability("app", APP_ID);
driver = new AndroidDriver(new URL("https://" +
BROWSERSTACK_USER + ":" + BROWSERSTACK_ACCESS_KEY +
"@hub.browserstack.com/wd/hub"), caps);
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_LEFT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_LEFT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_RIGHT));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(5000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.DPAD_CENTER));
Thread.sleep(10000);
driver.pressKey(new KeyEvent().withKey(AndroidKey.MEDIA_PLAY_PAUSE));
driver.quit();
}
}
require 'rubygems'
require 'appium_lib'
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
desired_caps = {
'platformName' => 'Android',
'deviceName' => 'Nvidia Shield TV Pro 2019',
'osVersion' => '11.0',
'browserstack.debug' => 'true',
'app' => '<app_hashed_id>'
}
appium_driver = Appium::Driver.new({
caps: desired_caps,
appium_lib: {
server_url: "https://#{username}:#{access_key}@hub-cloud.browserstack.com/wd/hub"
}
}, true)
driver = appium_driver.start_driver
sleep 5
driver.press_keycode(20) # DPAD_DOWN
driver.press_keycode(22) # DPAD_RIGHT
video_element = driver.find_element(:xpath, "//android.widget.FrameLayout[@focused = 'true']")
video_name = video_element.attribute('content-desc')
puts "Selected Video Name: #{video_name}"
driver.press_keycode(23) # DPAD_CENTER
sleep(5)
driver.press_keycode(85) # MEDIA_PLAY_PAUSE
sleep(3)
driver.press_keycode(85) # MEDIA_PLAY_PAUSE
sleep(3)
driver.press_keycode(89) # MEDIA_REWIND
sleep(3)
driver.press_keycode(4) # BACK
focussed_element = driver.find_element(:xpath, "//android.widget.FrameLayout[@focused = 'true']")
focussed_video_name = focussed_element.attribute('content-desc')
if focussed_video_name == video_name
puts "Video played - Test passed"
else
puts "Video Could not be played - Test Failed"
end
driver.quit
const webdriverio = require('webdriverio');
const opts = {
capabilities: {
platformName: 'Android',
platformVersion: '11.0',
deviceName: 'Nvidia Shield TV Pro 2019',
app: '<app_hashed_id>',
'browserstack.debug': 'true',
},
path: '/wd/hub',
user: 'YOUR_USERNAME',
key: 'YOUR_ACCESS_KEY',
};
(async () => {
const client = await webdriverio.remote(opts);
await client.pause(5000);
await client.pressKeyCode(20); // DPAD_DOWN
await client.pressKeyCode(22); // DPAD_RIGHT
const videoElement = await client.$(
'//android.widget.FrameLayout[@focused = "true"]',
);
const videoName = await videoElement.getAttribute('content-desc');
console.log(`Selected Video Name: ${videoName}`);
await client.pressKeyCode(23); // DPAD_CENTER
await client.pause(5000);
await client.pressKeyCode(85); // MEDIA_PLAY_PAUSE
await client.pause(3000);
await client.pressKeyCode(85); // MEDIA_PLAY_PAUSE
await client.pause(3000);
await client.pressKeyCode(89); // MEDIA_REWIND
await client.pause(3000);
await client.pressKeyCode(4); // BACK
const focussedElement = await client.$(
'//android.widget.FrameLayout[@focused = "true"]',
);
const focussedVideoName = await focussedElement.getAttribute('content-desc');
if (focussedVideoName === videoName) {
console.log('Video played - Test passed');
} else {
console.log('Video Could not be played - Test Failed');
}
await client.deleteSession();
})();
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.extensions.android.nativekey import AndroidKey
import time
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
options = UiAutomator2Options()
options.set_capability('build', 'Python Appium Sample')
options.set_capability('deviceName', 'Nvidia Shield TV Pro 2019')
options.set_capability('osVersion', '11.0')
options.set_capability('browserstack.debug', 'true')
options.set_capability('app', '<app_hashed_id>')
driver = webdriver.Remote(
command_executor=f'https://{username}:{access_key}@hub-cloud.browserstack.com/wd/hub',
options=options
)
time.sleep(5)
driver.press_keycode(AndroidKey.DPAD_DOWN)
driver.press_keycode(AndroidKey.DPAD_RIGHT)
video_element = driver.find_element('xpath', "//android.widget.FrameLayout[@focused='true']")
video_name = video_element.get_attribute('content-desc')
print(f'Selected Video Name: {video_name}')
driver.press_keycode(AndroidKey.DPAD_CENTER)
time.sleep(5)
driver.press_keycode(AndroidKey.MEDIA_PLAY_PAUSE)
time.sleep(3)
driver.press_keycode(AndroidKey.MEDIA_PLAY_PAUSE)
time.sleep(3)
driver.press_keycode(AndroidKey.MEDIA_REWIND)
time.sleep(3)
driver.press_keycode(AndroidKey.BACK)
focussed_element = driver.find_element('xpath', "//android.widget.FrameLayout[@focused='true']")
focussed_video_name = focussed_element.get_attribute('content-desc')
if focussed_video_name == video_name:
print('Video played - Test passed')
else:
print('Video Could not be played - Test Failed')
driver.quit()
Appium 2.0 is the default and the only version supported by App Automate on tvOS, which comes with W3C capabilities.
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSElement;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import io.appium.java_client.ios.IOSDriver;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
public class TVOSTest {
public static String USERNAME = "<your-username>";
public static String ACCESS_KEY = "<your-access-key>";
public static void main(String[] args) throws Exception {
DesiredCapabilities capabilities = new DesiredCapabilities();
HashMap<String, Object> browserstackOptions = new HashMap<String, Object>();
browserstackOptions.put("projectName" , "TVOS-PROJECT");
browserstackOptions.put("buildName" , "TVOS-BUILD");
browserstackOptions.put("sessionName" , "TVOS-SESSION");
browserstackOptions.put("networkLogs" , true);
capabilities.setCapability("bstack:options" , browserstackOptions);
capabilities.setCapability("platformName" , "tvOS");
capabilities.setCapability("platformVersion" , "26");
capabilities.setCapability("deviceName" , "Apple TV 4K");
capabilities.setCapability(MobileCapabilityType.APP , "<enter app url here>");
capabilities.setCapability("automationName" , "XCUITest");
IOSDriver driver = new IOSDriver(new URL("https://" + USERNAME + ":" + ACCESS_KEY +
"@hub-cloud.browserstack.com/wd/hub"), capabilities);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
System.out.println(driver.getPageSource());
driver.getScreenshotAs(OutputType.FILE);
driver.quit();
}
}
require 'rubygems'
require 'appium_lib'
require 'selenium-webdriver'
# Use Ruby Client version v9.8.1 or above
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
caps = {
'platformName' => 'tvos',
'platformVersion' => '26',
'deviceName' => 'Apple TV 4K',
'app' => '<enter app url here>',
'automationName' => 'xcuitest',
'bstack:options' => {
'networkLogs' => 'true',
'projectName' => 'TVOS-PROJECT',
'buildName' => 'TVOS-BUILD',
'sessionName' => 'TVOS-SESSION',
},
}
appium_driver = Appium::Driver.new({
caps: caps,
appium_lib: {
server_url: "https://#{username}:#{access_key}@hub-cloud.browserstack.com/wd/hub",
}
}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(:timeout => 30)
driver.page_source
driver.execute_script 'mobile: pressButton', { name: 'Down' }
driver.execute_script 'mobile: pressButton', { name: 'Down' }
driver.execute_script 'mobile: pressButton', { name: 'Left' }
driver.execute_script 'mobile: pressButton', { name: 'Left' }
driver.execute_script 'mobile: pressButton', { name: 'Select' }
sleep(5)
playButton = driver.find_element(:xpath, '//XCUIElementTypeButton[@name="Play"]')
puts playButton.text
playButton.click()
sleep(10)
driver.quit
const webdriver = require('selenium-webdriver');
const { Builder } = webdriver;
const username = 'YOUR_USERNAME';
const accessKey = 'YOUR_ACCESS_KEY';
const capabilities = {
'platformName': 'tvos',
'platformVersion': '26',
'deviceName': 'Apple TV 4K',
'app': '<enter app url here>',
'automationName': 'xcuitest',
'bstack:options': {
'networkLogs': 'true',
'projectName': 'TVOS-PROJECT',
'buildName': 'TVOS-BUILD',
'sessionName': 'TVOS-SESSION'
}
};
const driver = new Builder()
.usingServer(`https://${username}:${accessKey}@hub-cloud.browserstack.com/wd/hub`)
.withCapabilities(capabilities)
.build();
driver.getPageSource();
driver.executeScript('mobile: pressButton', { name: 'Down' });
driver.executeScript('mobile: pressButton', { name: 'Down' });
driver.executeScript('mobile: pressButton', { name: 'Left' });
driver.executeScript('mobile: pressButton', { name: 'Left' });
driver.executeScript('mobile: pressButton', { name: 'Select' });
driver.sleep(5000);
const playButton = driver.findElement(webdriver.By.xpath('//XCUIElementTypeButton[@name="Play"]'));
playButton.getText().then(text => {
console.log(text);
playButton.click();
driver.sleep(10000);
driver.quit();
});
from appium import webdriver
from appium.options.ios import XCUITestOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
import time
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
options = XCUITestOptions()
options.set_capability('platformName', 'tvos')
options.set_capability('platformVersion', '26')
options.set_capability('deviceName', 'Apple TV 4K')
options.set_capability('app', '<enter app url here>')
options.set_capability('automationName', 'xcuitest')
options.set_capability('bstack:options', {
'networkLogs': 'true',
'projectName': 'TVOS-PROJECT',
'buildName': 'TVOS-BUILD',
'sessionName': 'TVOS-SESSION',
})
driver = webdriver.Remote(
command_executor=f'https://{username}:{access_key}@hub-cloud.browserstack.com/wd/hub',
options=options
)
wait = WebDriverWait(driver, 30)
driver.page_source
driver.execute_script('mobile: pressButton', {'name': 'Down'})
driver.execute_script('mobile: pressButton', {'name': 'Down'})
driver.execute_script('mobile: pressButton', {'name': 'Left'})
driver.execute_script('mobile: pressButton', {'name': 'Left'})
driver.execute_script('mobile: pressButton', {'name': 'Select'})
time.sleep(5)
play_button = driver.find_element(By.XPATH, '//XCUIElementTypeButton[@name="Play"]')
print(play_button.text)
play_button.click()
time.sleep(10)
driver.quit()
For Roku TV, you require Appium version 2.18.0.
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class RokuTest {
public static void main(String[] args) {
String username = "YOUR_USERNAME";
String accessKey = "YOUR_ACCESS_KEY";
String app_url = "<AppURL>";
String device_ID = "<DeviceID>";
AppiumDriver driver = null;
try {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Roku");
capabilities.setCapability("appium:deviceName", "Roku Express 4K");
capabilities.setCapability("appium:app", app_url);
capabilities.setCapability("appium:automationName", "Roku");
capabilities.setCapability("appium:platform", "roku");
Map<String, Object> bstackOptions = new HashMap<>();
bstackOptions.put("projectName", "Roku");
bstackOptions.put("buildName", "<your build name>");
bstackOptions.put("idleTimeout", "300");
bstackOptions.put("dedicatedDevice", true);
bstackOptions.put("deviceId", device_ID);
bstackOptions.put("osVersion", "14.6");
capabilities.setCapability("bstack:options", bstackOptions);
String serverUrl = "https://" + username + ":" + accessKey + "@hub-cloud.browserstack.com/wd/hub";
driver = new AppiumDriver(new URL(serverUrl), capabilities);
// Activate app
Map<String, Object> activateAppArgs = new HashMap<>();
activateAppArgs.put("appId", "dev");
driver.executeScript("roku: activateApp", activateAppArgs);
// Get page source
String pageSource = driver.getPageSource();
System.out.println("Page Source:\n" + pageSource);
// Find label element
WebElement label = driver.findElement(By.xpath("//Label[contains(@text, 'Hello World')]"));
System.out.println("Label text: " + label.getAttribute("text"));
System.out.println("Label bounds: " + label.getAttribute("bounds"));
driver.findElement(By.xpath("//HelloWorld"));
WebElement screen = driver.findElement(By.xpath("//screen"));
System.out.println("Screen focused? " + screen.getAttribute("focused"));
// Press Home key
Map<String, Object> pressKeyArgs = new HashMap<>();
pressKeyArgs.put("key", "Home");
driver.executeScript("roku: pressKey", pressKeyArgs);
} catch (MalformedURLException e) {
System.err.println("Invalid URL: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
System.err.println("An error occurred: " + e.getMessage());
e.printStackTrace();
} finally {
// Invoke driver.quit() after the test is done to indicate that the test is completed.
if (driver != null) {
try {
driver.quit();
// Give threads time to cleanup
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
require 'rubygems'
require 'appium_lib'
require 'selenium-webdriver'
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
device_id = '<DEVICE_ID>'
app_url = '<APP_URL>'
capabilities = {
'platformName' => 'Roku',
'appium:deviceName' => 'Roku Express 4K',
'appium:app' => app_url, # local zip
'appium:automationName' => 'Roku',
'bstack:options' => {
'projectName' => 'Roku',
'buildName' => 'RokuTest1',
'idleTimeout' => '300',
'dedicatedDevice' => true,
'deviceId' => device_id
},
'appium:platform' => 'roku',
'device' => 'Roku Express 4K',
'os_version' => '14.6'
}
# BrowserStack's Appium server URL (not localhost)
server_url = "https://#{username}:#{access_key}@hub-cloud.browserstack.com/wd/hub"
# Initialize the driver with W3C capabilities
appium_driver = Appium::Driver.new({
caps: capabilities,
appium_lib: {
server_url: server_url
}
}, true)
driver = appium_driver.start_driver
begin
driver.execute_script('roku: activateApp', { appId: 'dev' })
page_source = driver.page_source
puts "Page Source:\n#{page_source}"
label = driver.find_element(:xpath, "//Label[contains(@text, 'Hello World')]")
puts "Label text: #{label.attribute('text')}"
puts "Label bounds: #{label.attribute('bounds')}"
driver.find_element(:xpath, '//HelloWorld')
screen = driver.find_element(:xpath, '//screen')
puts "Screen focused? #{screen.attribute('focused')}"
driver.execute_script('roku: pressKey', { key: 'Home' })
rescue StandardError => e
puts "An error occurred: #{e.message} e.backtrace: #{e.backtrace.join("\n")}"
end
# Invoke driver.quit() after the test is done to indicate that the test is completed.
driver.quit
const { remote } = require("webdriverio");
const assert = require("assert");
const username = "YOUR_USERNAME";
const accessKey = "YOUR_ACCESS_KEY";
const app_url = "<AppURL>";
const device_ID = "<DeviceID>";
const capabilities = {
platformName: "Roku",
"appium:deviceName": "Roku Express 4K",
"appium:app": app_url,
"appium:automationName": "Roku",
"appium:platform": "roku",
"bstack:options": {
projectName: "Roku",
buildName: "<your build name>",
idleTimeout: "300",
dedicatedDevice: true,
deviceId: device_ID,
osVersion: "14.6",
},
};
const serverUrl = `https://${username}:${accessKey}@hub-cloud.browserstack.com/wd/hub`;
async function runRokuTest() {
let driver;
try {
driver = await remote({
protocol: "https",
hostname: "hub-cloud.browserstack.com",
port: 443,
path: "/wd/hub",
user: username,
key: accessKey,
capabilities: capabilities,
logLevel: "info",
});
try {
// Get device info for logging
const deviceName = capabilities["appium:deviceName"];
const deviceVersion = capabilities["bstack:options"].osVersion;
console.log(
`Running Roku TV Test on ${deviceName} - ${deviceVersion}`
);
// Activate App
await driver.pause(2000);
await driver.execute("roku: activateApp", { appId: "dev" });
// Get the current page source
const pageSource = await driver.getPageSource();
assert(
pageSource.includes('name="Hello World"'),
"Page source should include Hello World!"
);
// Locate Label element by XPath
const label = await driver.$("//label[contains(@text, 'Hello World')]");
const labelText = await label.getText();
const labelTextAttr = await label.getAttribute("text");
const labelBounds = await label.getAttribute("bounds");
assert(
labelText.includes("Hello World!"),
labelText + " should include Hello World!"
);
assert(
labelTextAttr.includes("Hello World!"),
labelTextAttr + " should include Hello World!"
);
assert(labelBounds.includes("{0, 0, 1280, 720}"));
// Take screenshot as base64
const screenshot = await driver.takeScreenshot();
if (screenshot) {
console.log("Screenshot data:", screenshot);
}
// Locate scene and screen elements
const scene = await driver.$("//HelloWorld");
const sceneFocused = await scene.getAttribute("focused");
assert(sceneFocused.includes("true"), "Scene should be focused!");
// Press Home key on Roku device
await driver.execute("roku: pressKey", { key: "Home" });
console.log("Home key pressed");
console.log("Waiting for 5 seconds to observe the Roku device...");
// roku: deviceInfo
const requiredKeys = [
"device-id",
"model-name",
"model-number",
"model-region",
];
const deviceInfo = await driver.execute("roku: deviceInfo");
requiredKeys.forEach((key) => {
assert(
deviceInfo.hasOwnProperty(key),
`${key} should be present in deviceInfo`
);
});
// roku: getApps
const apps = await driver.execute("roku: getApps");
const appExists = apps.some((app) => app.name === "Hello World");
assert(
appExists,
"Hello World app should be installed on the Roku device"
);
// await driver.pause(100000);
await driver.execute(
'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status": "passed", "reason": "Roku TV Test Passed" }}'
);
} catch (err) {
console.log(err);
message = err.message.replace(/[^a-zA-Z0-9 ]/g, "");
await driver.execute(
'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status": "failed", "reason": "' +
message +
'" }}'
);
assert(false, err.message);
}
} finally {
// Invoke driver.quit() after the test is done to indicate that the test is completed.
if (driver) {
await driver.deleteSession();
}
}
}
runRokuTest();
from appium import webdriver
from appium.options.common.base import AppiumOptions
from selenium.webdriver.common.by import By
username = 'YOUR_USERNAME'
access_key = 'YOUR_ACCESS_KEY'
device_id = '<DEVICE_ID>'
app_url = '<APP_URL>'
options = AppiumOptions()
options.set_capability('platformName', 'Roku')
options.set_capability('appium:deviceName', 'Roku Express 4K')
options.set_capability('appium:app', app_url)
options.set_capability('appium:automationName', 'Roku')
options.set_capability('appium:platform', 'roku')
options.set_capability('device', 'Roku Express 4K')
options.set_capability('os_version', '14.6')
options.set_capability('bstack:options', {
'projectName': 'Roku',
'buildName': 'RokuTest1',
'idleTimeout': '300',
'dedicatedDevice': True,
'deviceId': device_id
})
# BrowserStack's Appium server URL (not localhost)
server_url = f'https://{username}:{access_key}@hub-cloud.browserstack.com/wd/hub'
driver = webdriver.Remote(command_executor=server_url, options=options)
try:
driver.execute_script('roku: activateApp', {'appId': 'dev'})
page_source = driver.page_source
print(f'Page Source:\n{page_source}')
label = driver.find_element(By.XPATH, "//Label[contains(@text, 'Hello World')]")
print(f"Label text: {label.get_attribute('text')}")
print(f"Label bounds: {label.get_attribute('bounds')}")
driver.find_element(By.XPATH, '//HelloWorld')
screen = driver.find_element(By.XPATH, '//screen')
print(f"Screen focused? {screen.get_attribute('focused')}")
driver.execute_script('roku: pressKey', {'key': 'Home'})
except Exception as e:
print(f'An error occurred: {e}')
# Invoke driver.quit() after the test is done to indicate that the test is completed.
driver.quit()
View test execution results
After your tests start running, view results on the App Automate dashboard.
Open a specific test session to see execution details and debugging information, including video recordings, screenshots, and Appium logs.
You can also fetch results programmatically using the REST API.
Frequently asked questions
Why does my Roku app close immediately after the session starts?
This behavior is expected. The Appium driver closes the app when you call start_driver. To reopen the app, call activateApp at the start of your script:
Need help?
If you have any questions, contact support.
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!