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 only)
- Web (E2E only)
- Chrome (E2E only)
- 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'
// or if you want headless mode:
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()
// the test halts, a REPL becomes available for commands
Якщо chrome не запущений у headless режимі, ви можете побачити останній р аз, коли було викликано openRokuXML() (ймовірно через waitForX або expect). Використовуючи REPL у вашому терміналі, ви можете використовувати будь-які дійсні команди $ і кілька ключових спеціальних команд, які додані (browser.openRokuXML() і browser.saveScreenshot('path/to/ss.jpg')) — клас controller не приєднаний до об'єкта browser, тому ви не можете використовувати його зараз. На щастя, ви, ймовірно, сидите поруч з Roku і маєте пульт, яким можете користуватися для навігації і час від часу викликати browser.openRokuXML(), щоб побачити, що сталося зі станом сторінки! І пам'ятайте, що XML працює з xpathing у самому браузері 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-файлу на вашому комп'ютері.
Використання
Встановлення каналу
Це вимагає, щоб вашому каналу був призначений ідентифікатор.
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() {
// Close the channel if it's already open. If the channel supports instant resume, this will merely background it
await exitChannel();
// Using the channel ID of 'dev' will launch the sideloaded application.
await launchChannel('dev');
}
Тестування
wdio-roku-service/controller надає можливість надсилати натискання кнопок на Roku. keySequence є основною, що надсилає кілька натискань кнопок послідовно.
import { Buttons, keySequence } from 'wdio-roku-service/controller';
// Navigate through the app
await keySequence(Buttons.LEFT, Buttons.LEFT, Buttons.SELECT, Buttons.DOWN, Buttons.SELECT);
// Fetch the current app UI from the Roku and load it into the browser
await browser.openRokuXML();
// Or, use waits, which will repeatedly load the XML until it times out or the condition passes
await browser.waitUntil(condition);
await element.waitForDisplayed();
// use WDIO matchers on the roku XML as if it was a webpage
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');
Поширені проблеми
- Елементи Roku мають свій текст у атрибуті 'text', а не між їхніми тегами. При використанні селекторів,
$('element=Text')не працюватиме для майже кожного елемента. Замість цього вам доведеться використовувати$('element[text=Text]').