Roku Driver is a WebDriver that allows testing channels and screensavers using any WebDriver client.
- Appium 2.x or 3.x
- Roku device with a recent OS and the settings mentioned below:
appium driver install --source npm @dlenroc/appium-roku-driverThanks to the Appium and WebDriver protocols, this driver works just like other WebDriver implementations, but there are a couple of things worth mentioning.
Like other drivers, Roku Driver uses the fast reset algorithm by default: registries are cleared before each test, and a full reinstallation occurs only if the channel differs from the one already installed.
The following locator strategies are supported: tag name, link text, partial link text, css selector, and xpath.
-
ECP(default) External Control Protocol is a context that finds elements quickly but does not expose many attributes. -
ODC(WIP) On-Device Component is a context that finds elements more slowly but exposes all attributes. It can be tuned using theelementResponseAttributessetting.
-
input- Sends a custom event to the launched channel.driver.url('roku://input?<key>=<value>');
-
launch- Launches given channel with specific arguments.driver.url('roku://launch/:channel_id?<key>=<value>');
In Roku, appId is dev for a sideloaded channel or a number for channels installed from the store (e.g., 12 for Netflix).
driver.queryAppState('dev');
driver.queryAppState('12');Note: most commands only work with SceneGraph-based sideloaded channels.
This driver allows testing of screensavers via the appium:entryPoint capability.
channel(default) - Opens channel itself.screensaver- Opens your channel screen saver.screensaver-settings- Opens your channel screen saver settings.
Note: Usually screensavers open on their own and close immediately after any user input is sent, but when entryPoint
screensaveris used, it runs in the context of the channel, so the input interaction does not close it (BACKandHOMEbuttons are an exception).
In Roku world:
- Registries are used to store persistent information such as sessions and settings.
- Input / Launch parameters are used for deep linking and/or controlling app behavior.
Knowing this, you can significantly speed up automation by skipping authorization and configuration steps where appropriate.
Note:
appium:argumentsandappium:registrywill contain different values in your case.
const capabilities = {
...commonCapabilities,
// Launch parameters
'appium:arguments': {
contentId: 1234,
mediaType: 'movie',
},
// Registry sections Settings
'appium:registry': {
account: {
token: '<user_token>',
},
},
};// Forward logs to the console
driver.on('log.entryAdded', (entry) => console.log(entry.text));
// Subscribe to BrightScript logs
await driver.sessionSubscribe({ events: ['log.entryAdded'] });
// Unsubscribe from BrightScript logs (optional)
await driver.sessionUnsubscribe({ events: ['log.entryAdded'] });The following action types are supported:
keyDown,keyUp- presses/releases the given key.pointerMove- focuses the element using arrow buttons.pause- waits a given number of milliseconds.
Below are key codes and their equivalents on a Roku remote.
| Code | Keyboard Key | Roku Key |
|---|---|---|
\uE002 |
Help |
Info |
\ue003 |
Backspace |
Backspace |
\ue006 |
Return |
Enter |
\ue007 |
Enter |
Select |
\ue00b |
Pause |
Play |
\uE00C |
Escape |
Back |
\uE00E |
Page Up |
ChannelUp |
\uE00F |
Page Down |
ChannelDown |
\ue011 |
Home |
Home |
\ue012 |
Arrow Left |
Left |
\ue013 |
Arrow Up |
Up |
\ue014 |
Arrow Right |
Right |
\ue015 |
Arrow Down |
Down |
\uE01A |
0 |
InputAV1 |
\uE01B |
1 |
InputHDMI1 |
\uE01C |
2 |
InputHDMI2 |
\uE01D |
3 |
InputHDMI3 |
\uE01E |
4 |
InputHDMI4 |
\uE01F |
5 |
InputTuner |
\uE036 |
F6 |
InstantReplay |
\uE037 |
F7 |
Rev |
\uE038 |
F8 |
Play |
\uE039 |
F9 |
Fwd |
\uE03A |
F10 |
VolumeMute |
\uE03B |
F11 |
VolumeDown |
\uE03C |
F12 |
VolumeUp |
If adding a vendor prefix is a problem, @appium/relaxed-caps-plugin can be used to get rid of them.
| Capability | Required | Type | Description |
|---|---|---|---|
appium:ip |
+ | string | The IP address of the target device |
appium:password |
+ | string | Password for the development environment |
appium:username |
- | string | Username for the development environment |
appium:context |
- | string | Sets the context to be used, default ECP |
appium:registry |
- | object | Pre-fills the registry with the specified sections/keys |
appium:arguments |
- | object | Parameters to be passed to the main method |
appium:entryPoint |
- | string | Specifies the channel entry point, possible values are channel, screensaver, screensaver-settings |
| Capability | Required | Type | Description |
|---|---|---|---|
platformName |
+ | string | Must be roku |
appium:automationName |
+ | string | Must be roku |
appium:deviceName |
+/- | string | Helps webdriver clients understand that they are dealing with appium |
webSocketUrl |
- | boolean | Opt in to the use of the Bidi protocol. Defaults to false. |
appium:app |
- | string | The absolute local path or remote http URL to channel |
appium:noReset |
- | boolean | Do not stop app, do not clear app data, and do not uninstall app |
appium:printPageSourceOnFindFailure |
- | boolean | When a find operation fails, print the current page source. Defaults to false |
appium:newCommandTimeout |
- | number | How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session |
appium:settings[<key>] |
- | any | Update driver settings on session creation |
appium:shouldTerminateApp |
- | boolean | If true, the channel will be closed after the session is finished. Defaults to false |
| Name | Type | Description |
|---|---|---|
elementResponseAttributes |
string | Comma-separated list of element attribute names that will be available in page source and related actions |
The supported commands are listed in the sections below but note that they may have a different name in the client you are using
Example: calling the setContext command
// Java
driver.context('ECP');
// WebdriverIO
driver.switchContext('ECP');| Command | Description |
|---|---|
| createSession | Create a new session |
| deleteSession | End the running session |
| setUrl | Open a deep link |
| active | Get the currently focused element |
| findElement | Search for an element |
| findElements | Search for multiple elements |
| findElementFromElement | Search for an element in parent element |
| findElementsFromElement | Search multiple elements in parent element |
| getAttribute | Get the value of an attribute from a given element |
| getProperty | Get the value of a property from a given element
|
| getText | Get the visible text of a given element |
| getName | Get the tag name of given element |
| getElementRect | Get the position and size of the given element |
| elementDisplayed | Check if the element is displayed |
| click | Presses the Select button on given element |
| clear | Clears the content of the given element |
| setValue | Send a sequence of keystrokes to an element |
| getPageSource | Get the XML representation of the current UI |
| execute | Execute a Roku command |
| performActions | Performs a chain of actions |
| releaseActions | Release pressed key |
| getScreenshot | Take a screenshot |
| Command | Description |
|---|---|
| installApp | Install the channel if it is not installed |
| activateApp | Launch the given channel |
| terminateApp | Terminate the channel (Available since Roku OS 13.0) |
| removeApp | Remove the given channel from the device |
| isAppInstalled | Checks if a channel is installed |
| queryAppState | Queries the channel state |
| pushFile | Push a file to the device |
| pullFile | Pull a file from the device |
| pullFolder | Pull a folder from the device |
| updateSettings | Updates current test session settings |
| getCurrentContext | Get the name of the current context |
| setContext | Switches to the given context |
| getContexts | Get the names of available contexts |
| Command | Description |
|---|---|
| bidiSubscribe | Enables certain events either globally or for a set of contexts |
| bidiUnsubscribe | Disables events either globally or for a set of contexts |
In addition to the standard Appium commands, Roku has several additional features that go beyond the Appium protocol. These are available through a JavaScript executor and a script in the following format: <component>:<command>
The following components are available: ecp, debugServer, developerServer, and odc
Example:
// with args
driver.execute('ecp:launch', [{ appId: 'dev', params: {} }]);
// without args
const playerState = driver.execute('ecp:queryMediaPlayer');
playerState.duration;