Roku Driver is a WebDriver that allows testing channels/screensavers using any webdriver client.
- Appium 2
- Roku Device with fresh OS and mentioned below settings:
appium driver install --source npm @dlenroc/appium-roku-driver
Thanks to the Appium and WebDriver protocol, this driver works just like other web drivers, but there are a couple of things worth mentioning.
Like other drivers, roku-driver by default uses the so-called fast reset
algorithm, in which registries are cleared before each test, and a full reinstallation occurs only if the channel differs from the one already installed.
The following location 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 see many attributes. -
ODC
(WIP) On Device Component is a context that finds elements slower, but see all attributes. (can be tunned usingelementResponseAttributes
setting).
-
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 always dev
for sideloaded channel or a number for channels installed from store (ex: 12
for Netflix).
driver.queryAppState('dev');
driver.queryAppState('12');
Note: most commands only work with SceneGrapth based sideloaded channels.
Given driver allows testing of Screensavers via 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
screensaver
is used, it runs in the context of the channel, so the input interaction does not close it (BACK
andHOME
buttons 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.
So, knowing this, we can significantly speed up the automation by skipping authorization/configuration steps.
Note:
appium:arguments
andappium:registry
will 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'] });
Note:
The following action types are supported:
keyDown
,keyUp
- presses/releases given key.pointerMove
- focuses the element using arrow buttons.pause
- waits given amounts of milliseconds.
Below are the key codes and their equivalents in the 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 |
appiun: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 an 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 an roku command |
performActions | Performs a chain of actions |
releaseActions | Release depressed 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 apium commands, Roku has several additional features that go beyond the appium protocol, so they 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;