Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dlenroc/appium-roku-driver
WebDriver for testing channels / screensavers on roku devices
https://github.com/dlenroc/appium-roku-driver
appium roku selenium webdriver
Last synced: 4 days ago
JSON representation
WebDriver for testing channels / screensavers on roku devices
- Host: GitHub
- URL: https://github.com/dlenroc/appium-roku-driver
- Owner: dlenroc
- License: mit
- Created: 2021-03-20T15:17:46.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-05-22T06:27:37.000Z (9 months ago)
- Last Synced: 2024-05-22T07:35:32.557Z (9 months ago)
- Topics: appium, roku, selenium, webdriver
- Language: TypeScript
- Homepage:
- Size: 933 KB
- Stars: 10
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Appium Roku Driver · [![NPM Version](https://img.shields.io/npm/v/@dlenroc/appium-roku-driver?cacheSeconds=86400)](https://www.npmjs.com/package/@dlenroc/appium-roku-driver) ![Node.js Version](https://img.shields.io/node/v/@dlenroc/appium-roku-driver) [![Node.js CI](https://github.com/dlenroc/appium-roku-driver/actions/workflows/nodejs.yml/badge.svg?branch=main)](https://github.com/dlenroc/appium-roku-driver/actions/workflows/nodejs.yml)
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:
- [Roku OS 9.4 or Newest](https://support.roku.com/en-gb/article/208755668)
- [Enable Developer Settings](https://developer.roku.com/en-gb/docs/developer-program/getting-started/developer-setup.md#step-1-set-up-your-roku-device-to-enable-developer-settings)
- [Disable Screensaver](https://www.solveyourtech.com/how-to-disable-the-screensaver-on-a-roku-tv/) (optional)## Installation
```sh
appium driver install --source npm @dlenroc/appium-roku-driver
```## Documentation
Thanks to the [Appium](https://github.com/appium/appium) and [WebDriver](https://www.w3.org/TR/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](https://github.com/dlenroc/node-roku/blob/main/packages/ecp#readme) is a context that finds elements quickly, but does not see many attributes.
- `ODC` (WIP) [On Device Component](https://github.com/dlenroc/node-roku/blob/main/packages/odc#readme) is a context that finds elements slower, but see all attributes. (can be tunned using `elementResponseAttributes` setting).
### Deep linking
- `input` - Sends a custom event to the launched channel.
```js
driver.url('roku://input?=');
```- `launch` - Launches given channel with specific arguments.
```js
driver.url('roku://launch/:channel_id?=');
```### Channels
In roku `appId` is always `dev` for sideloaded channel or a number for channels installed from store (ex: `12` for Netflix).
```js
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](https://developer.roku.com/en-gb/docs/developer-program/media-playback/screensavers.md) 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` and `HOME` buttons are an exception).
### Registries / Arguments
In Roku world:
- [Registries](https://developer.roku.com/en-gb/docs/developer-program/getting-started/architecture/file-system.md) are used to store persistent information such as sessions and settings.
- [Input / Launch parameters](https://developer.roku.com/en-gb/docs/developer-program/discovery/implementing-deep-linking.md) 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` and `appium:registry` will contain different values in your case.
```js
const capabilities = {
...commonCapabilities,// Launch parameters
'appium:arguments': {
contentId: 1234,
mediaType: 'movie',
},// Registry sections Settings
'appium:registry': {
account: {
token: '',
},
},
};
```### BrightScript Logging
```js
// 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](https://www.npmjs.com/package/@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](https://developer.roku.com/en-gb/docs/developer-program/getting-started/developer-setup.md) |
| `appium:username` | - | string | Username for the [development environment](https://developer.roku.com/en-gb/docs/developer-program/getting-started/developer-setup.md) |
| `appium:context` | - | string | Sets the [context](#contexts) 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[]` | - | any | Update [driver settings](#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
```js
// Java
driver.context('ECP');// WebdriverIO
driver.switchContext('ECP');
```### WebDriver Commands
| Command | Description |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [createSession](src/commands/createSession.ts) | Create a new session |
| [deleteSession](src/commands/deleteSession.ts) | End the running session |
| [setUrl](src/commands/setUrl.ts) | Open a deep link |
| [active](src/commands/active.ts) | Get the currently focused element |
| [findElement](src/commands/findElOrEls.ts) | Search for an element |
| [findElements](src/commands/findElOrEls.ts) | Search for multiple elements |
| [findElementFromElement](src/commands/findElOrEls.ts) | Search for an element in parent element |
| [findElementsFromElement](src/commands/findElOrEls.ts) | Search multiple elements in parent element |
| [getAttribute](src/commands/getAttribute.ts) | Get the value of an attribute from a given element |
| [getProperty](src/commands/getProperty.ts) | 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 focused
- `isInFocusHierarchy` - returns `true` if the element or any of its ancestors or descendants is focused
| [getText](src/commands/getText.ts) | Get the visible text of a given element |
| [getName](src/commands/getName.ts) | Get the tag name of given element |
| [getElementRect](src/commands/getElementRect.ts) | Get the position and size of the given element |
| [elementDisplayed](src/commands/elementDisplayed.ts) | Check if the element is displayed |
| [click](src/commands/click.ts) | Presses the `Select` button on given element |
| [clear](src/commands/clear.ts) | Clears the content of the given element |
| [setValue](src/commands/setValue.ts) | Send a sequence of keystrokes to an element |
| [getPageSource](src/commands/getPageSource.ts) | Get the XML representation of the current UI |
| [execute](src/commands/execute.ts) | Execute an roku command |
| [performActions](src/commands/performActions.ts) | Performs a chain of actions |
| [releaseActions](src/commands/releaseActions.ts) | Release depressed key |
| [getScreenshot](src/commands/getScreenshot.ts) | Take a screenshot |
### Appium Commands
| Command | Description |
| ------------------------------------------------------ | ------------------------------------------------------ |
| [installApp](src/commands/installApp.ts) | Install the channel if it is not installed |
| [activateApp](src/commands/activateApp.ts) | Launch the given channel |
| [terminateApp](src/commands/terminateApp.ts) | Terminate the channel (_Available since Roku OS 13.0_) |
| [removeApp](src/commands/removeApp.ts) | Remove the given channel from the device |
| [isAppInstalled](src/commands/isAppInstalled.ts) | Checks if a channel is installed |
| [queryAppState](src/commands/queryAppState.ts) | Queries the channel state |
| [pushFile](src/commands/pushFile.ts) | Push a file to the device |
| [pullFile](src/commands/pullFile.ts) | Pull a file from the device |
| [pullFolder](src/commands/pullFolder.ts) | Pull a folder from the device |
| [updateSettings](src/commands/updateSetting.ts) | Updates current test session settings |
| [getCurrentContext](src/commands/getCurrentContext.ts) | Get the name of the current context |
| [setContext](src/commands/setContext.ts) | Switches to the given context |
| [getContexts](src/commands/getContexts.ts) | Get the names of available contexts |
### BiDi Commands
| Command | Description |
| -------------------------------------------------- | --------------------------------------------------------------- |
| [bidiSubscribe](src/commands/bidiSubscribe.ts) | Enables certain events either globally or for a set of contexts |
| [bidiUnsubscribe](src/commands/bidiUnsubscribe.ts) | 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 `:`
The following components are available: [ecp](https://npmjs.com/package/@dlenroc/roku-ecp/v/2.0.0), [debugServer](https://www.npmjs.com/package/@dlenroc/roku-debug-server/v/2.0.0), [developerServer](https://www.npmjs.com/package/@dlenroc/roku-developer-server/v/2.0.0), and [odc](https://www.npmjs.com/package/@dlenroc/roku-odc/v/2.0.1)
Example:
```js
// with args
driver.execute('ecp:launch', [{ appId: 'dev', params: {} }]);
// without args
const playerState = driver.execute('ecp:queryMediaPlayer');
playerState.duration;
```