@dlenroc/appium-roku-driver
v0.12.0
Published
Appium Roku Driver
Downloads
25
Readme
Appium Roku Driver ·
Roku Driver is a WebDriver that allows testing channels/screensavers using any webdriver client.
Prerequisites
- Appium 2
- Roku Device with fresh OS and mentioned below settings:
Installation
appium driver install --source npm @dlenroc/appium-roku-driver
Documentation
Thanks to the Appium and WebDriver protocol, this driver works just like other web drivers, but there are a couple of things worth mentioning.
Initialization
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.
Locators
The following location strategies are supported: tag name
, link text
, partial link text
, css selector
and xpath
.
Contexts
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).
Deep linking
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>');
Channels
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.
Screensaver / Screensaver Settings
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).
Registries / Arguments
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>',
},
},
};
BrightScript Logging
// 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:
Actions
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
|
Capabilities
If adding a vendor prefix is a problem, @appium/relaxed-caps-plugin can be used to get rid of them.
Roku Capabilities
| 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
|
Appium Capabilities
| 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
|
Settings
| Name | Type | Description |
| --------------------------- | ------ | --------------------------------------------------------------------------------------------------------- |
| elementResponseAttributes
| string | Comma-separated list of element attribute names that will be available in page source and related actions |
Supported Commands
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');
WebDriver Commands
| 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 isFocused
- returns true
if the element is focused.isInFocusChain
- returns true
if the element or any of its descendants are focusedisInFocusHierarchy
- returns true
if the element or any of its ancestors or descendants is focused |
| 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 |
Appium Commands
| 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 |
BiDi Commands
| 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 |
Roku Commands
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;