Roku Сервис
wdio-roku-service — это сторонний пакет, для получения дополнительной информации, пожалуйста, посетите GitHub | npm Этот сервис переопределяет многие части WebdriverIO, чтобы обеспечить их использование с приложениями Roku, и предоставляет доступ к Roku ECP для управления Roku во время тестирования.
Требования
Roku
Тестовый канал/channel.zip и устройство Roku (с включенным режимом разработчика) в той же сети, что и ваш Mac.
WebdriverIO
Это не самостоятельный продукт — он используется как плагин для тестирования WebdriverIO (или Сервис, на их языке). Перед использованием вы должны пройти настройку WDIO, запустив npm init wdio@latest.
При прохождении этапов настройки, чтобы не пришлось проходить через все вопросы/варианты, вы можете просто выбрать следующие пункты во время фазы инициализации:
- Roku Testing (ПРИМЕЧАНИЕ: Используйте это, если ваш репозиторий будет использоваться только для тестирования Roku, так как он станет сервисом по умолчанию и единственным установленным сервисом. В противном случае используйте E2E Testing, чтобы вы могли установить несколько сервисов.)
- On my local machine (только для E2E)
- Web (только для E2E)
- Chrome (только для E2E)
- Mocha
- Typescript [modules работает как для TS, так и для JS, так что выбирайте любой]
- autogenerate some test files (Y) -- default location
- page objects (Y) -- default location
- spec reporter
- additional plugins (N)
- Visual Testing (N)
- services (roku)
- npm install (Y)
Typescript Config
Если вы хотите использовать Typescript для написания тестов, вам необходимо убедиться, что следующие параметры установлены в файле tsconfig.json, сгенерированном Webdriverio.
"moduleResolution": "nodenext",
"module": "NodeNext",
Затем вы можете использовать сервис, импортируя его в свои тесты, как описано ниже.
WDIO Config
В настоящее время тестирование поддерживается только для одного устройства Roku. Требуются следующие обновления конфигурации:
maxInstancesиmaxInstancesPerCapabilityдолжны быть равны 1. Автоматическое тестирование на нескольких устройствах не поддерживается и приведет к дублированию команд, отправляемых на Roku. Должна быть только одна возможность.
//wdio.conf.js
export const config: WebdriverIO.Config = {
maxInstances: 1,
capabilities: [{
browserName: 'chrome'
// или если вы хотите режим headless:
browserName: 'chrome',
'goog:chromeOptions': {
args: ['--headless', '--disable-gpu']
}
}],
//...
}
- Рекомендуется увеличить
waitforIntervalиwaitforTimeout, так как каждый интервал включает загрузку xml с Roku. Чтобы получить больше от функцииbrowser.debug(), вы также можете расширить тайм-аут тестового раннера mocha до 5+ минут для разработки.
//wdio.conf.js
export const config: WebdriverIO.Config = {
waitforTimeout: 30000,
//optional:
mochaOpts: {
ui: 'bdd',
timeout: 600000
},
//...
}
Вы готовы написать свой первый тест!
import { installFromZip } from 'wdio-roku-service/install'
import { exitChannel } from 'wdio-roku-service/channel'
import { Buttons, keyPress, keySequence } from 'wdio-roku-service/controller'
describe('first test', () => {
before('On the landing screen of the test channel', async () => {
await installFromZip(process.env.ROKU_APP_PATH)
})
it('should launch to the homescreen without login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
})
after('should return to home', async () => {
await exitChannel()
})
})
Также рекомендуется использовать функцию browser.debug() в wdio для остановки теста для отладки и создания тестов:
// ...
it('should launch to the homescreen without login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
await browser.debug()
// тест останавливается, становится доступен REPL для команд
Если chrome не в режиме headless, вы можете увидеть последний раз, когда была вызвана openRokuXML() (вероятно, через waitForX или expect). Используя REPL в вашем терминале, вы можете использовать любые допустимые команды $ и несколько ключевых пользовательских команд (browser.openRokuXML() и browser.saveScreenshot('path/to/ss.jpg')) -- класс controller не прикреплен к объекту browser, поэтому вы не можете использовать их в данный момент. К счастью, вы, вероятно, сидите рядом с Roku и у вас есть пульт, который вы можете использовать для навигации и иногда вызывать browser.openRokuXML(), чтобы увидеть, что произошло с состоянием страницы! И помните, что XML работает нативно с xpath в самом браузере chrome, поэтому вы можете непосредственно оценивать/разрабатывать свои селекторы в консоли chrome во время отладки.
.env
См. файл .env.example. Скопируйте его и переименуйте в .env в вашем проекте WebdriverIO, который использует этот сервис. Возможно, вы также захотите добавить его в .gitignore.
ROKU_IPдолжен быть IP-адресом вашего Roku. Команды будут использовать этот IP для связи с ним. Это обязательно.ROKU_USERиROKU_PW: Учетные данные для входа необходимы для установки архива, а также для создания скриншотов.ROKU_APP_PATHдолжен быть абсолютным путем к zip-файлу канала Roku.ROKU_CHANNEL_IDдолжен быть ID вашего канала Roku (обычно это "dev").DEBUG=wdio-roku-serviceвключит отладочные сообщения. Удалите символ '#' в начале строки, если вы хотите их видеть.
Измененные функции
Browser
waitUntilбудет получать xml с Roku при каждой итерации, чтобы проверить изменения.saveScreenshotзагрузит скриншот текущего экрана с Roku. Примечательно, что эти скриншоты имеют формат .jpg, а не .png, который обычно использует WebdriverIO.openRokuXMLполучит xml с Roku, если вам нужно сделать это вручную, а не с помощью ожиданий.
Elements
- Все ожидания поддерживаются так же, как и Browser.
waitForClickableсопоставляется сwaitForDisplayed, аwaitForStableсопоставляется сwaitForExist. click,doubleClickиmoveToне поддерживаются. Вы должны вручную перемещаться по приложению.isFocusedпроверит наличие атрибутаfocusedна элементе, равного true.isDisplayedпроверит наличие атрибутаboundsна элементе и чтоvisibleне установлен на false. Если установленwithinViewport, границы будут сравниваться с размером экрана Roku.getSizeиgetLocationберут значения из атрибутаbounds, возвращая 0 для размера и -Infinity для позиции, если они отсутствуют.
Другие функции не изменились, но многие по-прежнему работают как ожидалось.
Matchers
Большинство матчеров были обновлены для получения xml во время ожидания. Некоторые имеют немного другую функциональность.
toBeDisplayed,toBeDisplayedInViewport,toBeFocused,toBeExisting,toBePresent,toExist,toHaveSize,toHaveWidth,toHaveHeightиtoHaveAttributeработают как ожидается, с учетом изменений в Element.toHaveElementPropertyсопоставляется сtoHaveAttribute.toHaveElementClassпроверяет атрибутnameэлемента.toHaveIdсопоставляется сtoHaveElementClass.toHaveTextпроверяет атрибутtextэлемента.toHaveChildrenпроверяет атрибутchildrenэлемента.toHaveHTMLбудет обрабатывать xml так, как если бы это был HTML, хотя, вероятно, это не очень полезно.
Следующие функции в настоящее время не поддерживаются:
toBeSelected- Может быть поддержано в ближайшее время после определения того, как выглядит xml для выбранных кнопок, если есть разница.toBeChecked- Может быть поддержано в ближайшее время после определения того, как выглядит xml для отмеченных флажков, если есть разница.toHaveComputedLabel- Если у вас есть эквивалент этого на ваших элементах Roku, проверьте атрибут с помощьюtoHaveAttribute.toHaveComputedRole- Если у вас есть эквивалент этого на ваших элементах Roku, проверьте атрибут с помощьюtoHaveAttribute.toHaveHref- Если у вас есть URL на ваших элементах Roku, проверьте атрибут с помощьюtoHaveAttribute.toHaveStyle- Элементы xml не имеют стилей.toHaveClipboardText- Это неизвестно.toHaveTitle- Заголовком будет случайно сгенерированное временное имя файла xml.toHaveUrl- URL будет путем к файлу xml на вашем компьютере.
Использование
Установка канала
Это требует, чтобы ваш канал имел назначенный ID.
import { installByID } from 'wdio-roku-service/install';
async before() {
await installByID(process.env.ROKU_CHANNEL_ID);
}
Установка архива
Рекомендуется хранить путь в .env, особенно если у вас несколько разработчиков, которые могут иметь разные расположения и/или имена файлов.
import { installFromZip } from 'wdio-roku-service/install';
async before() {
await installFromZip(process.env.ROKU_ARCHIVE_PATH);
}
Предустановленный канал
Если вы уже установили канал самостоятельно до тестирования, вы можете просто запустить его.
import { launchChannel, exitChannel } from 'wdio-roku-service/channel';
async before() {
// Закройте канал, если он уже открыт. Если канал поддерживает быстрое возобновление, это просто переместит его в фоновый режим
await exitChannel();
// Использование ID канала 'dev' запустит боковую загрузку приложения.
await launchChannel('dev');
}
Тестирование
wdio-roku-service/controller предоставляет возможность отправлять нажатия кнопок на Roku. keySequence — это основная функция, отправляющая несколько нажатий кнопок последовательно.
import { Buttons, keySequence } from 'wdio-roku-service/controller';
// Навигация по приложению
await keySequence(Buttons.LEFT, Buttons.LEFT, Buttons.SELECT, Buttons.DOWN, Buttons.SELECT);
// Получение текущего UI приложения с Roku и загрузка его в браузер
await browser.openRokuXML();
// Или использ уйте ожидания, которые будут неоднократно загружать XML до истечения тайм-аута или выполнения условия
await browser.waitUntil(condition);
await element.waitForDisplayed();
// используйте матчеры WDIO для roku XML, как если бы это была веб-страница
await expect(element).toHaveAttr('focused');
wdio-roku-service/controller также имеет функции для удержания или отпускания кнопок, а также ввода текста на клавиатуре.
import { Buttons, keyboardInput, keyPress, keySequence } from 'wdio-roku-service/controller';
await keySequence(Buttons.DOWN, Buttons.DOWN, Buttons.SELECT);
await keyboardInput('example');
await keyPress(Buttons.ENTER);
await browser.openRokuXML();
Deeplinking
wdio-roku-service/channel предоставляет функциональность, связанную с каналом. inputChannel позволяет отправлять произвольную информацию в ваше приложение.
import { exitChannel, launchChannel, MediaType } from 'wdio-roku-service/channel';
await exitChannel();
await launchChannel(process.env.ROKU_CHANNEL_ID, myContent, MediaType.MOVIE, {myExtraParameter:true});
await expect(MyContent.header).toBeDisplayed();
Другие функции
wdio-roku-service/info предоставляет разнообразную функциональность, такую как получение иконки приложения или осиротевших узлов.
import { getAppIcon } from 'wdio-roku-service/info';
const response = await getAppIcon(process.env.ROKU_CHANNEL_ID);
expect(response.headers.get('Content-Type')).toBe('image/jpg');
wdio-roku-service/ecp — это прямой интерфейс с ECP, если вам нужно сделать что-то очень специфическое.
import { ECP } from 'wdio-roku-service/ecp';
await ECP('search/browse?keyword=voyage&type=movie&tmsid=MV000058030000', 'POST');