Serviço Roku
wdio-roku-service é um pacote de terceiros, para mais informações, consulte GitHub | npm Este serviço substitui muitas partes do WebdriverIO para permitir que sejam usadas com aplicativos Roku e fornece acesso ao Roku ECP para controlar o Roku durante os testes.
Requisitos
Roku
Um canal de teste/channel.zip e um dispositivo Roku (com o Modo de Desenvolvedor habilitado) na mesma rede que seu mac.
WebdriverIO
Este não é um produto autônomo -- é usado como um plugin de framework de teste WebdriverIO (ou Serviço, em seu vocabulário). Antes de usá-lo, você deve passar pela configuração do WDIO executando npm init wdio@latest
.
Ao passar pelas etapas de configuração, para que você não precise navegar por todas as perguntas/opções, você pode simplesmente escolher as seguintes seleções durante a fase de inicialização:
- Roku Testing (NOTA: Use isso se seu repositório será usado apenas para testes de Roku, pois se tornará o serviço padrão e único instalado. Caso contrário, use E2E Testing para que você possa instalar vários serviços.)
- On my local machine (apenas E2E)
- Web (apenas E2E)
- Chrome (apenas E2E)
- Mocha
- Typescript [módulos funcionam para TS e JS, então escolha qualquer um]
- autogenerate some test files (Y) -- local padrão
- page objects (Y) -- local padrão
- spec reporter
- additional plugins (N)
- Visual Testing (N)
- services (roku)
- npm install (Y)
Configuração do Typescript
Se você deseja usar Typescript para escrever testes, precisará garantir que as seguintes opções estejam definidas no arquivo tsconfig.json gerado pelo Webdriverio.
"moduleResolution": "nodenext",
"module": "NodeNext",
Você pode então usar o serviço importando-o em seus testes conforme detalhado abaixo.
Configuração WDIO
Atualmente, os testes são suportados apenas para um único dispositivo Roku. As seguintes atualizações de configuração são necessárias:
maxInstances
emaxInstancesPerCapability
devem ser 1. Testes em vários dispositivos automaticamente não são suportados e resultarão em comandos duplicados sendo enviados ao Roku. Deve haver apenas uma única capacidade.
//wdio.conf.js
export const config: WebdriverIO.Config = {
maxInstances: 1,
capabilities: [{
browserName: 'chrome'
// ou se você quiser o modo headless:
browserName: 'chrome',
'goog:chromeOptions': {
args: ['--headless', '--disable-gpu']
}
}],
//...
}
- É recomendável aumentar o
waitforInterval
ewaitforTimeout
, pois cada intervalo envolve o download do xml do Roku. Para aproveitar mais o recursobrowser.debug()
, você também pode optar por estender o tempo limite do seu testrunner mocha para 5+ minutos para espaço de desenvolvimento.
//wdio.conf.js
export const config: WebdriverIO.Config = {
waitforTimeout: 30000,
//opcional:
mochaOpts: {
ui: 'bdd',
timeout: 600000
},
//...
}
Você está pronto para escrever seu primeiro teste!
import { installFromZip } from 'wdio-roku-service/install'
import { exitChannel } from 'wdio-roku-service/channel'
import { Buttons, keyPress, keySequence } from 'wdio-roku-service/controller'
describe('primeiro teste', () => {
before('Na tela inicial do canal de teste', async () => {
await installFromZip(process.env.ROKU_APP_PATH)
})
it('deve iniciar na tela inicial sem login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
})
after('deve retornar à tela inicial', async () => {
await exitChannel()
})
})
Também é recomendado que você use o recurso browser.debug()
no wdio para interromper seu teste para depuração e criação de testes:
// ...
it('deve iniciar na tela inicial sem login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
await browser.debug()
// o teste é interrompido, um REPL fica disponível para comandos
Se o chrome não estiver em modo headless, você pode ver a última vez que openRokuXML()
foi chamado (provavelmente através de um waitForX
ou expect
). Usando o REPL em seu terminal, você pode usar qualquer comando $
válido e alguns comandos personalizados adicionados (browser.openRokuXML()
e browser.saveScreenshot('path/to/ss.jpg')
) -- a classe controller
não está anexada ao objeto browser
, então você não pode usar esses comandos atualmente. Felizmente, você provavelmente está sentado ao lado do Roku e tem um controle remoto que pode usar para navegar e, ocasionalmente, chamar browser.openRokuXML()
para ver o que aconteceu com o estado da página! E lembre-se de que o XML funciona nativamente com xpath no próprio navegador chrome, então você pode avaliar/desenvolver seus seletores diretamente no console do chrome durante a depuração.
.env
Veja o arquivo .env.example
. Copie-o e renomeie-o para .env
dentro do seu projeto WebdriverIO que usa este serviço. Você provavelmente vai querer colocá-lo no .gitignore também.
ROKU_IP
deve ser o IP do seu Roku. Os comandos usarão esse IP para se comunicar com ele. Isso é obrigatório.ROKU_USER
eROKU_PW
: Credenciais de login são necessárias para instalar um arquivo, bem como para tirar capturas de tela.ROKU_APP_PATH
deve ser o caminho absoluto do arquivo zip do canal Roku.ROKU_CHANNEL_ID
deve ser o ID do canal do seu canal Roku (geralmente é "dev").DEBUG=wdio-roku-service
habilitará mensagens de depuração. Remova o '#' no início da linha se você quiser essas mensagens.
Funções Modificadas
Browser
waitUntil
buscará o xml do Roku a cada iteração para verificar mudanças.saveScreenshot
baixará uma captura de tela da tela atual do Roku. Notavelmente, essas capturas de tela estão no formato .jpg, em vez do .png que o WebdriverIO normalmente usa.openRokuXML
buscará o xml do Roku se você precisar fazê-lo manualmente, em vez de usar esperas.
Elementos
- Todas as esperas são suportadas da mesma forma que o Browser.
waitForClickable
é mapeado parawaitForDisplayed
, ewaitForStable
é mapeado parawaitForExist
. click
,doubleClick
emoveTo
não são suportados. Você deve navegar manualmente pelo aplicativo.isFocused
verificará se um atributofocused
no elemento é verdadeiro.isDisplayed
verificará se há um atributobounds
no elemento e sevisible
não está definido como falso. SewithinViewport
estiver definido, os limites serão comparados com o tamanho da tela do Roku.getSize
egetLocation
pegam os valores do atributobounds
, retornando 0 para tamanho e -Infinity para posição se não estiver presente.
Outras funções não foram alteradas, mas muitas ainda funcionam como esperado.
Matchers
A maioria dos matchers foi atualizada para buscar o xml durante a espera. Alguns têm funcionalidades ligeiramente diferentes.
toBeDisplayed
,toBeDisplayedInViewport
,toBeFocused
,toBeExisting
,toBePresent
,toExist
,toHaveSize
,toHaveWidth
,toHaveHeight
etoHaveAttribute
funcionam como esperado, considerando as mudanças no Element.toHaveElementProperty
é mapeado paratoHaveAttribute
.toHaveElementClass
verifica o atributoname
do elemento.toHaveId
é mapeado paratoHaveElementClass
.toHaveText
verifica o atributotext
do elemento.toHaveChildren
verifica o atributochildren
do elemento.toHaveHTML
tratará o xml como se fosse HTML, embora provavelmente não seja muito útil.
Os seguintes não são atualmente suportados:
toBeSelected
- Pode ser suportado em breve após determinar como é o xml para botões selecionados, se houver diferença.toBeChecked
- Pode ser suportado em breve após determinar como é o xml para caixas de seleção marcadas, se houver diferença.toHaveComputedLabel
- Se você tiver um equivalente disso em seus elementos Roku, verifique o atributo comtoHaveAttribute
.toHaveComputedRole
- Se você tiver um equivalente disso em seus elementos Roku, verifique o atributo comtoHaveAttribute
.toHaveHref
- Se você tiver URLs em seus elementos Roku, verifique o atributo comtoHaveAttribute
.toHaveStyle
- Os elementos xml não têm estilos.toHaveClipboardText
- Isso não é conhecido.toHaveTitle
- O título será o nome de arquivo temporário gerado aleatoriamente do xml.toHaveUrl
- A URL será o caminho para o arquivo xml em seu computador.
Uso
Instalação do Canal
Isso requer que seu canal tenha um ID atribuído.
import { installByID } from 'wdio-roku-service/install';
async before() {
await installByID(process.env.ROKU_CHANNEL_ID);
}
Instalação de Arquivo
É recomendável armazenar o caminho no .env, especialmente se você tiver vários desenvolvedores que podem ter locais e/ou nomes de arquivo diferentes.
import { installFromZip } from 'wdio-roku-service/install';
async before() {
await installFromZip(process.env.ROKU_ARCHIVE_PATH);
}
Canal Pré-Instalado
Se você já instalou o canal por conta própria antes dos testes, pode simplesmente iniciá-lo.
import { launchChannel, exitChannel } from 'wdio-roku-service/channel';
async before() {
// Feche o canal se já estiver aberto. Se o canal suportar retomada instantânea, isso apenas o colocará em segundo plano
await exitChannel();
// Usar o ID de canal 'dev' iniciará o aplicativo sideloaded.
await launchChannel('dev');
}
Testes
wdio-roku-service/controller
fornece a capacidade de enviar pressionamentos de botão para o Roku. keySequence
é o principal, enviando vários pressionamentos de botão em sequência.
import { Buttons, keySequence } from 'wdio-roku-service/controller';
// Navegue pelo aplicativo
await keySequence(Buttons.LEFT, Buttons.LEFT, Buttons.SELECT, Buttons.DOWN, Buttons.SELECT);
// Busque a UI atual do aplicativo no Roku e carregue-a no navegador
await browser.openRokuXML();
// Ou use esperas, que carregarão repetidamente o XML até que expire o tempo ou a condição seja aprovada
await browser.waitUntil(condition);
await element.waitForDisplayed();
// use os matchers do WDIO no XML do Roku como se fosse uma página da web
await expect(element).toHaveAttr('focused');
wdio-roku-service/controller
também tem funções para segurar ou soltar botões, bem como digitar texto em um teclado.
import { Buttons, keyboardInput, keyPress, keySequence } from 'wdio-roku-service/controller';
await keySequence(Buttons.DOWN, Buttons.DOWN, Buttons.SELECT);
await keyboardInput('exemplo');
await keyPress(Buttons.ENTER);
await browser.openRokuXML();