Selenium é um projeto que abrange uma variedade de ferramentas e bibliotecas
que permitem e suportam a automação de navegadores da web.
Ele fornece extensões para emular a interação do usuário com os navegadores,
um servidor de distribuição para escalonar a alocação do navegador,
e a infraestrutura para implementações da Especificação W3C WebDriver
que permite escrever código intercambiável para todos os principais navegadores da web.
Este projeto é possível graças a colaboradores voluntários
que dedicam milhares de horas de seu próprio tempo,
e disponibilizaram o código-fonte disponível gratuitamente
para qualquer um usar, aproveitar e melhorar.
Selenium reúne criadores de navegadores, engenheiros e entusiastas
para promover uma discussão aberta sobre a automação da plataforma da web.
O projeto organiza uma conferência anual
para ensinar e nutrir a comunidade.
No núcleo do Selenium está WebDriver,
uma interface para escrever conjuntos de instruções que podem ser executados alternadamente em muitos
navegadores. Aqui está uma das instruções mais simples que você pode fazer:
Consulte a Visão Geral para verificar os diferentes componentes do projeto
e decidir se o Selenium é a ferramenta certa para você.
Você deve continuar no Guia de Introdução
para entender como instalar o Selenium e usá-lo com sucesso como uma
ferramenta de automação de teste e dimensionar testes simples como esse para serem executados em ambientes grandes
e distribuídos em vários navegadores e em vários sistemas operacionais diferentes.
1 - Resumo
Será Selenium a ferramenta para você? Veja um resumo dos componentes do projecto.
Selenium não é só uma ferramenta ou API,
mas sim uma composição de várias ferramentas.
WebDriver
Se você está começando com automação de testes de um site de desktop ou site para celular, então
vai usar as APIs WebDriver. O WebDriver
usa APIs de automação de navegador disponibilizadas por fornecedores de navegador para o controlar e
executar testes. É como se um usuário real o estivesse operando. Como o
WebDriver não exige que sua API seja compilada com o código do aplicativo,
não é intrusivo. Portanto, você está testando o
mesmo aplicativo que você envia aos ambientes de produção.
IDE
IDE (Ambiente de Desenvolvimento Integrado, em português)
é a ferramenta que você usa para desenvolver seus casos de teste Selenium. É uma extensão para Chrome
e Firefox fácil de usar e geralmente é a maneira mais eficiente de desenvolver
casos de teste. Ela registra as ações dos usuários no navegador para você, usando
comandos Selenium existentes, com parâmetros definidos pelo contexto daquele
elemento. Isso não é apenas uma economia de tempo, mas também uma maneira excelente
de aprender a sintaxe de script do Selenium.
Grid
Selenium Grid permite que você execute casos de teste em diferentes
máquinas em diferentes plataformas. O controle para
acionar os casos de teste está na extremidade local, e
quando os casos de teste são acionados, eles são automaticamente
executados pela extremidade remota.
Após o desenvolvimento dos testes WebDriver, você pode enfrentar
a necessidade de executar seus testes em vários navegadores e
combinações de sistemas operacionais.
É aqui que o Grid entra em cena.
1.1 - Entendendo os componentes
Construir um conjunto de testes usando WebDriver exigirá que você entenda e
use efetivamente uma série de componentes diferentes. Como com tudo em
software, pessoas diferentes usam termos diferentes para a mesma ideia. Abaixo está
uma análise de como os termos são usados nesta descrição.
Terminologia
API: interface de programação de aplicativo. Este é o conjunto de “comandos” que
você usa para manipular o WebDriver.
Biblioteca: um módulo de código que contém as APIs e o código necessário
para implementá-los. As bibliotecas são específicas para cada linguagem, por exemplo arquivos
.jar para Java, arquivos .dll para .NET, etc.
Driver: responsável por controlar o navegador atual. A maioria dos drivers
são criados pelos próprios fornecedores de navegadores. Os drivers são geralmente
módulos executáveis que são executados no sistema com o próprio navegador,
não no sistema que está executando o conjunto de testes. (Embora esses possam ser
mesmo sistema.) NOTA: Algumas pessoas se referem aos drivers como proxies.
Framework: uma biblioteca adicional usada como suporte para suítes do WebDriver.
Essas estruturas podem ser estruturas de teste, como JUnit ou NUnit.
Eles também podem ser estruturas que suportam recursos de linguagem natural, como
como Cucumber ou Robotium. Frameworks também podem ser escritos e usados para
coisas como manipulação ou configuração do sistema em teste,
criação de dados, oráculos de teste, etc.
As partes e peças
No mínimo, o WebDriver se comunica com um navegador por meio de um driver. Comunicação
é bidirecional: o WebDriver passa comandos para o navegador por meio do driver e
recebe informações de volta pela mesma rota.
O driver é específico para o navegador, como ChromeDriver para Google
Chrome / Chromium, GeckoDriver para Mozilla Firefox, etc. O driver é
executado no mesmo sistema do navegador. Este pode, ou não ser, o mesmo sistema onde
os próprios testes estão sendo executados.
Este exemplo simples acima é comunicação direta. Comunicação para o
navegador também pode ser comunicação remota através do servidor Selenium ou
RemoteWebDriver. RemoteWebDriver roda no mesmo sistema que o driver
e o navegador.
A comunicação remota também pode ocorrer usando Selenium Server ou Selenium
Grid, que, por sua vez, fala com o driver no sistema host
Onde frameworks se encaixam
O WebDriver tem um trabalho e apenas um trabalho: comunicar-se com o navegador por meio de qualquer um
dos métodos acima. O WebDriver não sabe nada sobre testes: ele não
sabe como comparar coisas, afirmar passa ou falha, e certamente não sabe
uma coisa sobre relatórios ou gramática Dado / Quando / Então.
É aqui que vários frameworks entram em cena. No mínimo, você precisará de um framework de
teste que corresponde às linguagens, por exemplo, NUnit para .NET, JUnit
para Java, RSpec para Ruby, etc.
O framework de teste é responsável por rodar e executar seu WebDriver
e etapas relacionadas em seus testes. Como tal, você pode pensar nele parecendo a imagem seguinte.
Frameworks/ferramentas de linguagem natural, como Cucumber, podem existir como parte desse
framework de teste na figura acima, ou eles podem envolver o framework de teste
inteiramente em sua própria implementação.
1.2 - Detalhes
Selenium é um projeto abrangente para uma gama de ferramentas e bibliotecas que permitem e suportam a automação de navegadores da web.
Selenium controla navegadores
Selenium é muitas coisas
mas, em sua essência, é um conjunto de ferramentas para automação de navegador da web
que usa as melhores técnicas disponíveis
para controlar remotamente as instâncias do navegador
e emular a interação do usuário com o navegador.
Ele permite que os usuários simulem atividades comuns realizadas por usuários finais;
inserir texto em campos,
selecionando valores suspensos e caixas de seleção,
e clicar em links em documentos.
Ele também fornece muitos outros controles, como o movimento do mouse,
execução arbitrária de JavaScript e muito mais.
Embora seja usado principalmente para testes de front-end de sites,
Selenium é basicamente uma biblioteca de agente de usuário de navegador.
As interfaces são onipresentes em seus aplicativos,
o que incentiva a composição com outras bibliotecas para atender a sua finalidade.
Uma interface para tudo
Um dos princípios norteadores do projeto
é oferecer suporte a uma interface comum para todas as tecnologias de navegador (principais).
Os navegadores da web são aplicativos incrivelmente complexos e altamente projetados,
realizando suas operações de maneiras completamente diferentes
mas que frequentemente têm a mesma aparência ao fazê-lo.
Mesmo que o texto seja renderizado com as mesmas fontes,
as imagens sejam exibidas no mesmo lugar
e os links levem você ao mesmo destino.
O que está acontecendo por baixo é tão diferente quanto noite e dia.
Selenium “abstrai” essas diferenças,
esconde seus detalhes e complexidades da pessoa que está escrevendo o código.
Isso permite que você escreva várias linhas de código para realizar um fluxo de trabalho complicado,
mas essas mesmas linhas serão executadas no Firefox,
Internet Explorer, Chrome e todos os outros navegadores compatíveis.
Ferramentas e suporte
A abordagem de design minimalista do Selenium lhe dá a
versatilidade para ser incluído como um componente em aplicações maiores.
A infraestrutura circundante fornecida sob o Selenium
dá a você as ferramentas para montar
sua Grid de navegadores
para que os testes possam ser executados em diferentes navegadores e sistemas operacionais
em uma variedade de máquinas.
Imagine um banco de computadores em sua sala de servidores ou data center
todos abrindo navegadores ao mesmo tempo
acessando links, formulários,
e tabelas — testando seu aplicativo 24 horas por dia.
Por meio da interface de programação simples
fornecido para os idiomas mais comuns,
esses testes serão executados incansavelmente em paralelo,
reportando de volta para você quando ocorrerem erros.
É o objetivo de ajudar a tornar isso uma realidade para você,
fornecendo aos usuários ferramentas e documentação não apenas para controlar os navegadores
mas para tornar mais fácil dimensionar e implantar essas grades.
Quem usa Selenium
Muitas das empresas mais importantes do mundo
adotaram o Selenium para seus testes baseados em navegador,
frequentemente substituindo esforços de anos envolvendo outras ferramentas proprietárias.
À medida que sua popularidade cresceu, seus requisitos e desafios se multiplicaram.
Conforme a web se torna mais complicada
e novas tecnologias são adicionadas aos sites,
é a missão deste projeto acompanhá-los sempre que possível.
Sendo um projeto de código aberto,
este apoio é fornecido por meio da generosa doação de tempo de muitos voluntários,
cada um deles tem um “trabalho diurno”.
Outra missão do projeto é incentivar
mais voluntários para participar deste esforço,
e construir uma comunidade forte
para que o projeto possa continuar a acompanhar as tecnologias emergentes
e permanecer uma plataforma dominante para automação de teste funcional.
2 - WebDriver
WebDriver manipula um navegador nativamente, aprenda mais sobre isso.
O WebDriver manipula um navegador nativamente, como um usuário faria, seja localmente
ou em uma máquina remota usando o servidor Selenium,
marca um salto em termos de automação do navegador.
Selenium WebDriver refere-se a ambas as ligações de linguagem
e as implementações do código de controle do navegador individual.
Isso é comumente referido como apenas WebDriver.
WebDriver é projetado como uma interface de programação simples e mais concisa.
WebDriver é uma API compacta orientada a objetos.
Ele manipula o navegador de forma eficaz.
2.1 - Começando
Se você é novo no Selenium, nós temos alguns recursos que podem te ajudar a se atualizar imediatamente.
Selenium suporta automação de todos os principais navegadores do mercado
por meio do uso do WebDriver.
WebDriver é uma API e protocolo que define uma interface de linguagem neutra
para controlar o comportamento dos navegadores da web.
Cada navegador é apoiado por uma implementação WebDriver específica, chamada de driver.
O driver é o componente responsável por delegar ao navegador,
e lida com a comunicação de e para o Selenium e o navegador.
Essa separação é parte de um esforço consciente para que os fornecedores de navegadores
assumam a responsabilidade pela implementação de seus navegadores.
Selenium faz uso desses drivers de terceiros sempre que possível,
mas também fornece seus próprios drivers mantidos pelo projeto
para os casos em que isso não é uma realidade.
A estrutura do Selenium une todas essas peças
por meio de uma interface voltada para o usuário que permite aos diferentes back-ends de navegador
serem usados de forma transparente,
permitindo a automação entre navegadores e plataformas cruzadas.
A configuração do Selenium é bastante diferente da configuração de outras ferramentas comerciais.
Para usar Selenium em seu projeto de automação, você precisa instalar as
bibliotecas de linguagem para sua linguagem de escolha. Além disso, você precisará dos
binários WebDriver para os navegadores que você deseja automatizar e executar testes.
(Opcional) Escolha e configure Selenium Grid se você quiser tornar seus testes escaláveis.
Se você deseja iniciar com ferramenta low-code / gravação e reprodução, por favor veja:
Selenium IDE
Depois de completar as etapas de configuração, você pode executar o snippet de codigo em
starting page na documentação. Então siga para seção
WebDriver para aprender mais sobre automação de navegadores com Selenium.
2.1.1 - Instalando bibliotecas do Selenium
Configurando a biblioteca Selenium para sua linguagem de programação favorita.
Primeiro você precisa instalar as bibliotecas Selenium para seu projeto de automação.
O processo de instalação de bibliotecas depende da linguagem que você escolher usar.
Outras observações para usar o Visual Studio Code (vscode) e C#
Instale a versão compatível do .NET SDK conforme a seção acima.
Instale também as extensões do vscode (Ctrl-Shift-X) para C# e NuGet.
Siga as instruções aqui para criar e rodar o seu projeto de “Hello World” no console usando C#.
Você também pode criar um projeto inicial do NUnit usando a linha de comando dotnet new NUnit.
Certifique-se de que o arquivo %appdata%\NuGet\nuget.config esteja configurado corretamente, pois alguns desenvolvedores relataram que ele estará vazio devido a alguns problemas.
Se o nuget.config estiver vazio ou não estiver configurado corretamente, as compilações .NET falharão para projetos que estiverem usando Selenium.
Adicione a seguinte seção ao arquivo nuget.config se esse estiver vazio:
Para mais informações sobre nuget.configclique aqui.
Você pode ter que customizar nuget.config para atender às suas necessidades.
Agora, volte para o vscode, aperte Ctrl-Shift-P, e digite “NuGet Add Package”, e adicione os pacotes necessários para
o Selenium como o Selenium.WebDriver.
Aperte Enter e selecione a versão.
Agora você pode usar os exemplos da documentação relacionados ao C# com o vscode.
Você pode ver a minima versão suportada do Ruby para cada versão do Selenium em
rubygems.org
O Selenium pode ser instalado de duas formas diferentes.
Configurando seu navegador para ficar preparado para ser automatizado.
Através do WebDriver, o Selenium suporta todos os principais navegadores do mercado
como Chrome/Chromium, Firefox, Internet Explorer, Edge e Safari.
Sempre que possível, o WebDriver conduz o navegador
usando o suporte integrado do navegador para automação.
Como todas as implementações do driver, exceto a do Internet Explorer, são fornecidas pelos próprios
desenvolvedores dos navegadores, elas não estão incluídas na distribuição padrão do Selenium.
Esta seção explica os requisitos básicos para você começar a usar os diferentes navegadores.
Leia mais sobre opções avançadas para iniciar um driver
na nossa documentação de configuração de driver.
Selenium Manager helps you to get a working environment to run Selenium out of the box
(no additional downloads! no additional configurations!).
Selenium Manager attempts to obtain the most correct driver for any browser
supported by Selenium in a performant way.
Selenium Manager is currently “opt-in,” which means
that it is only used if code would otherwise fail.
That means if you manage drivers by one of the approaches below, Selenium Manager
will not be used.
2. Software de gerenciamento de Driver
Before Selenium Manager was created, many users turned to other projects to automatically
manage their drivers. Most of the functionality of these libraries exists natively in
the latest version of Selenium.
If you can’t use Selenium Manager because you are using
an older version of Selenium (please upgrade),
or need an advanced feature not yet implemented by Selenium Manager,
you might try one of these tools:
Esta é uma opção flexível para alterar a localização dos drivers sem precisar atualizar seu código e funcionará
em várias máquinas sem exigir que cada máquina coloque os drivers no mesmo lugar.
Você pode colocar os drivers em um diretório que já está listado em
PATH, ou você pode colocá-los em um diretório
e acrescenta-lo ao PATH.
chromedriver.exe : The term 'chromedriver.exe' is not recognized as the name of a cmdlet, function, script file, or operable program
4. Localização definida no código
Note: we highly recommend not directly referencing the drivers and using Selenium Manager if possible.
Semelhante à opção 3 acima, você precisará baixar manualmente o driver (Vejá a sessão de Consulta de referencia rápida para links).
Especificar a localização no próprio código tem a vantagem de você não precisar se preocupar em descobrir variáveis de ambiente no
seu sistema, mas tem a desvantagem de tornar o código muito menos flexível.
Tudo que o Selenium faz é enviar comandos ao navegador de internet para fazer algo ou solicitar informações dele.
A maior parte do que você irá fazer com o Selenium é uma combinação desses comandos básicos:
1. Iniciando uma sessão
Para ter mais detalhes sobre como iniciar uma sessão, leia nossa documentação em driver sessions
3. Solicitando informação do navegador de internet
Existem diversos tipos de informação sobre o navegador de internet que você
pode solicitar, incluindo window handles, tamanho / posição do navegador, cookies, alertas e etc.
Sincronizar o código ao estado atual do navegador é um dos maiores
desafios
quando se trabalha com o Selenium, fazer isso de maneira bem feita é um tópico avançado.
Essencialmente, você quer ter certeza absoluta de que o elemento está na página antes de tentar localizá-lo
e o elemento está em um estado interativo antes de você tentar interagir com ele.
Uma espera implícita raramente é a melhor solução, mas é a mais fácil de demonstrar aqui, então
vamos usá-la como um substituto.
A maioria dos comandos na maior parte das sessões do Selenium são relacionados a elementos e você não pode
interagir
com um sem o primeiro encontrando um elemento
Se você esta usando selenium para realizar testes,
você deverá executar seu código usando feramentas para executar testes.
Muitos exemplos de código encontrado nessa documentação podem ser encontrado no nosso repositório de exemplos.
Existem múltiplas opções em cada linguagem, mas esta será qual usaremos em nossos exemplos:
Install Mocha Test runner using below command in your terminal
npm install mocha
and run your tests using below command
mocha firstScript.spec.js
// Add instructions
Próximos Passos
Use o que você aprendeu e construa o seu proprio código Selenium.
À medida que você encontrar mais funcionalidades de que necessita, leia o restante da nossa documentação do WebDriver.
2.1.4 - Como atualizar para Selenium 4
Interessado no Selenium 4? Veja este guia para realizar o upgrade para a ultima versão!
Atualizar para o Selenium 4 deve ser um processo sem dificuldades se você estiver usando uma das linguagens oficialmente suportadas
(Ruby, JavaScript, C#, Python, and Java). Pode haver alguns casos em que alguns problemas podem acontecer,
este guia irá ajudar você a resolvê-los. Vamos passar as etapas para atualizar as dependências do seu
projeto e entender as depreciações e também as mudanças trazidas pela versão atualizada.
Estas são as etapas que seguiremos para atualizar para o Selenium 4:
Preparando nosso código de teste
Atualizando as dependências
Possíveis erros e mensagens de suspensão de uso
Nota: enquanto as versões do Selenium 3.x estavam sendo desenvolvidas, foi implementado o suporte padrão para W3C WebDriver.
Este novo protocolo e o legado JSON Wire Protocol foram suportados. Através da versão 3.11, o código do Selenium passou a ser compátivel com o nível 1 da especificação W3C.
A compatibilidade do código W3C na ultima versão do Selenium 3 irá funcionar como esperado na versão 4.
Preparando nosso código de teste
Selenium 4 remove suporte para protocolos legados e usa o W3C Webdriver por padrão.
Para a maioria das coisas, essa implementação não irá afetar usuários finais.
As maiores exeções são Capabilities e a classe Actions.
Recursos
Se os recursos de teste não forem estruturados para serem compatíveis com W3C, pode fazer com que uma sessão não
seja iniciada. Aqui está a lista de recursos padrão do W3C WebDriver:
browserName
browserVersion (replaces version)
platformName (replaces platform)
acceptInsecureCerts
pageLoadStrategy
proxy
timeouts
unhandledPromptBehavior
Uma lista atualizada de recursos padrão pode ser encontrada aqui:
W3C WebDriver.
Qualquer recurso que não esteja incluido na lista acima, precisa ser incluido um prefixo de fornecedor.
Isso se aplica aos recursos específicos do navegador, bem como aos recursos específicos do fornecedor da nuvem.
Por exemplo, se o seu fornecedor de nuvem usa os recursos build e name para seus testes, você precisa
envolvê-los em um bloco cloud: options (verifique com seu fornecedor de nuvem o prefixo apropriado).
O utilitário para localizar elementos no Java (interfaces FindsBy) foram removidos
visto que se destinavam apenas a uso interno. Os exemplos de código a seguir explicam isso melhor.
Verifique as subseções abaixo para isntalar o Selenium 4 e atualizar as dependências do seu projeto
Java
O processo de atualização do Selenium depende de qual ferramenta de compilação está sendo usada. Vamos mostrar as mais comuns para Java, como Maven e Gradle. A versão minínma do Java ainda é 8.
Maven
Antes
<dependencies><!-- more dependencies ... --><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.141.59</version></dependency><!-- more dependencies ... --></dependencies>
Depois
<dependencies><!-- more dependencies ... --><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.4.0</version></dependency><!-- more dependencies ... --></dependencies>
Após realizar a mudança, você pode executar mvn clean compile no mesmo diretório, onde o
arquivo pom.xml está.
Gradle
Antes
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59'
}
test {
useJUnitPlatform()
}
Depois
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.4.0'
}
test {
useJUnitPlatform()
}
Após realizar a mudança, você pode executar ./gradlew clean build no mesmo diretório onde o arquivo build.gradleestá.
Para verifica todas as versões do Java, você pode ir até MVNRepository.
C#
O local para obter atualizações para Selenium 4 em C# é NuGet
Dentro do pacaote Selenium.WebDriver você pode seguir as instruções para atualizar para ultima versão.
Dentro do Visual Studio, através do NuGet Package Manager você pode executar:
A mudança mais importante para usar o Python é a versão minima requerida. Para Selenium 4 a versão miníma requerida será Python3.7 ou superior.
Mais detalhes podem ser encontrados aqui:Python Package Index.
Para atualizar através da linha de comando, você pode executar:
pip install selenium==4.4.3
Ruby
Detalhes para atualizar para o Selenium 4 podem ser vistos aqui:
selenium-webdriver gem in RubyGems
Para instalar a ultima versão, você pode executar:
gem install selenium-webdriver
Para adicioná-lo ao seu Gemfile:
gem 'selenium-webdriver', '~> 4.4.0'
JavaScript
O pacote selenium-webdriver pode ser encontrado pelo Node package manager,
npmjs. Selenium 4 pode ser encontrado aqui.
Para instalar, você pode executar:
npm install selenium-webdriver
Ou, atualize o seu package.json e execute npm install:
Aqui temos um conjunto de exemplos de código que o ajudarão a superar as mensagens de descontinuação, que você pode
encontrar após atualizar para o Selenium 4.
Java
Waits e Timeout
Os parametros que eram esperados de ser recebidos em um Timeout trocaram de (long time, TimeUnit unit) para
o (Duration duration).
As esperas(waits) também esperam parâmetros diferentes agora. O WebDriverWait
agora espera uma Duration em vez de um tempo limite long em segundos e milissegundos.
Os métodos utilitários withTimeout e pollingEvery do FluentWait passaram do
(long time, TimeUnit unit) para o (Duration duration).
A fusão de recursos não estã mais alterando o objeto de invocação
Antes era possível fundir um conjunto diferente de recursos em outro counjunto, e isso
alterava o objeto de chamada. Agora, o resultado da operação de fusão precisa ser atribuído.
O resultado da chamada merge precisa ser atribuído a um objeto.
Firefox Legacy
Antes do GeckoDriver existir, o projeto Selenium tinha uma implementação de driver para automatizar
o Firefox(versão<48). Entretanto, esta implementação não é mais necessária, pois não funciona
nas versões mais recentes do Firefox. Para evitar graves problemas ao atualizar para o Selenium 4,
a opção setLegacy será mostrada como obsoleta. A recomendação é parar de utilizar a implementação
antiga e depender apenas do GeckoDriver. O código a seguir mostrará a linha setLegacy obsoleta após
atualizar.
executable_path foi descontinuada, por favor, passe um Service object
No Selenium 4, você precisara definir o executable_path a partir de um objeto Service para evitar avisos de depreciação.
(Ou não defina o caminho e, em vez disso, certifique-se de que o driver que você precisa esteja no System PATH.)
Passamos pelas principais mudanças a serem levadas em consideração ao atualizar para o Selenium 4.
Cobrimos os diferentes aspectos a serem cobertos quando o código de teste é preparado para a atualização, incluindo
sugestões sobre como evitar possíveis problemas que podem aparecer ao usar a nova versão do
Selenium. Para finalizar, também abordamos um conjunto de possíveis problemas com os quais você pode se deparar depois
da atualização e compartilhamos possíveis correções para esses problemas.
The primary unique argument for starting a remote driver includes information about where to execute the code.
Read the details in the Remote Driver Section
Page being translated from English to Portuguese.
Do you speak Portuguese? Help us to translate
it by sending us pull requests!
In Selenium 3, capabilities were defined in a session by using Desired Capabilities classes.
As of Selenium 4, you must use the browser options classes.
For remote driver sessions, a browser options instance is required as it determines which browser will be used.
These options are described in the w3c specification for Capabilities.
Each browser has custom options that may be defined in addition to the ones defined in the specification.
browserName
This capability is used to set the browserName for a given session.
If the specified browser is not installed at the
remote end, the session creation will fail.
browserVersion
This capability is optional, this is used to
set the available browser version at remote end.
For Example, if ask for Chrome version 75 on a system that
only has 80 installed, the session creation will fail.
pageLoadStrategy
Three types of page load strategies are available.
The page load strategy queries the
document.readyState
as described in the table below:
Strategy
Ready State
Notes
normal
complete
Used by default, waits for all resources to download
eager
interactive
DOM access is ready, but other resources like images may still be loading
none
Any
Does not block WebDriver at all
The document.readyState property of a document describes the loading state of the current document.
When navigating to a new page via URL, by default, WebDriver will hold off on completing a navigation
method (e.g., driver.navigate().get()) until the document ready state is complete. This does not
necessarily mean that the page has finished loading, especially for sites like Single Page Applications
that use JavaScript to dynamically load content after the Ready State returns complete. Note also
that this behavior does not apply to navigation that is a result of clicking an element or submitting a form.
If a page takes a long time to load as a result of downloading assets (e.g., images, css, js)
that aren’t important to the automation, you can change from the default parameter of normal to
eager or none to speed up the session. This value applies to the entire session, so make sure
that your waiting strategy is sufficient to minimize
flakiness.
normal (default)
WebDriver waits until the load
event fire is returned.
importorg.openqa.selenium.PageLoadStrategy;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.chrome.ChromeOptions;importorg.openqa.selenium.chrome.ChromeDriver;publicclasspageLoadStrategy{publicstaticvoidmain(String[]args){ChromeOptionschromeOptions=newChromeOptions();chromeOptions.setPageLoadStrategy(PageLoadStrategy.NORMAL);WebDriverdriver=newChromeDriver(chromeOptions);try{// Navigate to Url
driver.get("https://google.com");}finally{driver.quit();}}}
it('Navigate using normal page loading strategy',asyncfunction(){letdriver=awaitenv.builder().setChromeOptions(options.setPageLoadStrategy('normal')).build();awaitdriver.get('https://www.google.com');
importorg.openqa.selenium.PageLoadStrategy;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.chrome.ChromeOptions;importorg.openqa.selenium.chrome.ChromeDriver;publicclasspageLoadStrategy{publicstaticvoidmain(String[]args){ChromeOptionschromeOptions=newChromeOptions();chromeOptions.setPageLoadStrategy(PageLoadStrategy.EAGER);WebDriverdriver=newChromeDriver(chromeOptions);try{// Navigate to Url
driver.get("https://google.com");}finally{driver.quit();}}}
importorg.openqa.selenium.PageLoadStrategy;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.chrome.ChromeOptions;importorg.openqa.selenium.chrome.ChromeDriver;publicclasspageLoadStrategy{publicstaticvoidmain(String[]args){ChromeOptionschromeOptions=newChromeOptions();chromeOptions.setPageLoadStrategy(PageLoadStrategy.NONE);WebDriverdriver=newChromeDriver(chromeOptions);try{// Navigate to Url
driver.get("https://google.com");}finally{driver.quit();}}}
This identifies the operating system at the remote-end,
fetching the platformName returns the OS name.
In cloud-based providers,
setting platformName sets the OS at the remote-end.
acceptInsecureCerts
This capability checks whether an expired (or)
invalid TLS Certificate is used while navigating
during a session.
If the capability is set to false, an
insecure certificate error
will be returned as navigation encounters any domain
certificate problems. If set to true, invalid certificate will be
trusted by the browser.
All self-signed certificates will be trusted by this capability by default.
Once set, acceptInsecureCerts capability will have an
effect for the entire session.
timeouts
A WebDriver session is imposed with a certain session timeout
interval, during which the user can control the behaviour
of executing scripts or retrieving information from the browser.
Each session timeout is configured with
combination of different timeouts as described below:
Script Timeout
Specifies when to interrupt an executing script in
a current browsing context. The default timeout 30,000
is imposed when a new session is created by WebDriver.
Page Load Timeout
Specifies the time interval in which web page
needs to be loaded in a current browsing context.
The default timeout 300,000 is imposed when a
new session is created by WebDriver. If page load limits
a given/default time frame, the script will be stopped by
TimeoutException.
Implicit Wait Timeout
This specifies the time to wait for the
implicit element location strategy when
locating elements. The default timeout 0
is imposed when a new session is created by WebDriver.
unhandledPromptBehavior
Specifies the state of current session’s user prompt handler.
Defaults to dismiss and notify state
User Prompt Handler
This defines what action must take when a
user prompt encounters at the remote-end. This is defined by
unhandledPromptBehavior capability and has the following states:
This new capability indicates if strict interactability checks
should be applied to input type=file elements. As strict interactability
checks are off by default, there is a change in behaviour
when using Element Send Keys with hidden file upload controls.
proxy
A proxy server acts as an intermediary for
requests between a client and a server. In simple,
the traffic flows through the proxy server
on its way to the address you requested and back.
A proxy server for automation scripts
with Selenium could be helpful for:
Capture network traffic
Mock backend calls made by the website
Access the required website under complex network
topologies or strict corporate restrictions/policies.
If you are in a corporate environment, and a
browser fails to connect to a URL, this is most
likely because the environment needs a proxy to be accessed.
Selenium WebDriver provides a way to proxy settings:
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
Você pode usar o WebDriver remotamente da mesma forma que o usaria
localmente. A principal diferença é que um WebDriver remoto precisa ser
configurado para que possa executar seus testes em uma máquina separada.
Um WebDriver remoto é composto por duas peças: um cliente e um
servidor. O cliente é o seu teste WebDriver e o servidor é simplesmente um
Servlet Java, que pode ser hospedado em qualquer servidor de aplicativo JEE moderno.
Para executar um cliente WebDriver remoto, primeiro precisamos nos conectar ao RemoteWebDriver.
Fazemos isso apontando a URL para o endereço do servidor que está executando nossos testes.
Para personalizar nossa configuração, definimos os recursos desejados.
Abaixo está um exemplo de como instanciar um objeto WebDriver remoto
apontando para nosso servidor remoto da web, www.example.com,
executando nossos testes no Firefox.
O Detector de Arquivo Local permite a transferência de arquivos da máquina do cliente para o servidor remoto. Por exemplo, se um teste precisa carregar um
arquivo para um aplicativo da web, um WebDriver remoto pode transferir automaticamente
o arquivo da máquina local para o servidor web remoto durante
o tempo de execução. Isso permite que o arquivo seja carregado da máquina remota
executando o teste. Não é habilitado por padrão e pode ser habilitado em
da seguinte forma:
This feature is only available for Java client binding (Beta onwards). The Remote WebDriver client sends requests to the Selenium Grid server, which passes them to the WebDriver. Tracing should be enabled at the server and client-side to trace the HTTP requests end-to-end. Both ends should have a trace exporter setup pointing to the visualization framework.
By default, tracing is enabled for both client and server.
To set up the visualization framework Jaeger UI and Selenium Grid 4, please refer to Tracing Setup for the desired version.
For client-side setup, follow the steps below.
Add the required dependencies
Installation of external libraries for tracing exporter can be done using Maven.
Add the opentelemetry-exporter-jaeger and grpc-netty dependency in your project pom.xml:
Veja a secção Chrome DevTools para mais informação em como usar Chrome DevTools
2.3.2 - Funcionalidade específica do Edge
Estas capacidades e características são específicas ao navegador Microsoft Edge.
Microsoft Edge foi criado com recurso ao Chromium, cuja versão mais antiga suportada é a v79.
Tal como o Chrome, a versão (maior) do edgedriver deve ser igual à do navegador Edge.
Todas as capacidades e opções encontradas na página Chrome page irão funcionar de igual forma para o Edge.
Opções
Este é um exemplo de como iniciar uma sessão Edge com um conjunto de opções básicas:
O Microsoft Edge pode ser controlado em modo “compatibilidade Internet Explorer”, são usadas
classes do Internet Explorer Driver em conjunção com o Microsoft Edge.
Leia a página Internet Explorer para mais detalhes.
2.3.3 - Funcionalidade específica do Firefox
Estas capacidades e características são específicas ao navegador Mozilla Firefox.
Por omissão, Selenium 4 é compatível com Firefox 78 ou superior. Recomendamos que use sempre a versão mais recente do geckodriver.
Opções
Capacidades comuns a todos os navegadores estão descritas na página Opções.
Capacidades únicas ao Firefox podem ser encontradas na página da Mozilla para firefoxOptions
Este é um exemplo de como iniciar uma sessão Firefox com um conjunto de opções básicas:
Alguns exemplos de uso com capacidades diferentes:
Argumentos
O parametro args é usado para indicar uma lista de opções ao iniciar o navegador.
Opções mais frequentes incluem -headless e "-profile", "/path/to/profile"
O parametro binary é usado contendo o caminho para uma localização específica do navegador.
Como exemplo, pode usar este parametro para indicar ao geckodriver a versão Firefox Nightly ao invés da
versão de produção, quando ambas versões estão presentes no seu computador.
Adicionar uma localização:
Coding Help
Note:
This section could use some updated code examples
const{Builder}=require("selenium-webdriver");constfirefox=require('selenium-webdriver/firefox');constoptions=newfirefox.Options();letprofile='/path to custom profile';options.setProfile(profile);constdriver=newBuilder().forBrowser('firefox').setFirefoxOptions(options).build();
Quando trabalhar em uma extensão não terminada ou não publicada, provavelmente ela não estará assinada.
Desta forma, só pode ser instalada como “temporária”. Isto pode ser feito passando uma arquivo ZIP ou
uma pasta, este é um exemplo com uma pasta:
Estas capacidades e características são específicas ao navegador Microsoft Internet Explorer.
Desde Junho de 2022, o Projecto Selenium deixou de suportar oficialmente o navegador Internet Explorer.
O driver Internet Explorer continua a suportar a execução do Microsoft Edge no modo “IE Compatibility Mode.”
Considerações especiais
O IE Driver é o único driver mantido directamente pelo Projecto Selenium.
Embora existam binários para as versões de 32 e 64 bits, existem algumas
limitações conhecidas
com o driver de 64 bits. Desta forma, recomenda-se a utilização do driver de 32 bits.
Informação adicional sobre como usar o Internet Explorer pode ser encontrada na
página IE Driver Server
Opções
Este é um exemplo de como iniciar o navegador Microsoft Edge em modo compatibilidade Internet Explorer
usando um conjunto de opções básicas:
Se o IE não estiver presente no sistema (ausente por omissão no Windows 11), não necessita
usar os parametros “attachToEdgeChrome” e “withEdgeExecutablePath”, pois o IE Driver
irá encontrar e usar o Edge automaticamente.
Se o IE e o Edge estiverem ambos presentes no sistema, use o parametro “attachToEdgeChrome”,
o IE Driver irá encontrar e usar o Edge automaticamente.
As of Internet Explorer Driver v4.7.0:
No longer need to set Ignore Zoom Level for Edge in IE Mode
Aqui pode ver alguns exemplos de utilização com capacidades diferentes:
fileUploadDialogTimeout
Em alguns ambientes, o Internet Explorer pode expirar ao abrir a
Caixa de Diálogo de upload de arquivo. O IEDriver tem um tempo limite padrão de 1000 ms, mas você
pode aumentar o tempo limite usando o recurso fileUploadDialogTimeout.
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.file_upload_dialog_timeout=2000driver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
Quando definido como true, este recurso limpa o Cache,
Histórico do navegador e cookies para todas as instâncias em execução
do InternetExplorer, incluindo aquelas iniciadas manualmente
ou pelo driver. Por padrão, é definido como false.
Usar este recurso causará queda de desempenho quando
iniciar o navegador, pois o driver irá esperar até que o cache
seja limpo antes de iniciar o navegador IE.
Esse recurso aceita um valor booleano como parâmetro.
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.ensure_clean_session=Truedriver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
O driver do InternetExplorer espera que o nível de zoom do navegador seja de 100%,
caso contrário, o driver lançará uma exceção. Este comportamento padrão
pode ser desativado definindo ignoreZoomSetting como true.
Esse recurso aceita um valor booleano como parâmetro.
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.ignore_zoom_level=Truedriver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
Se deve ignorar a verificação do Modo protegido durante o lançamento
uma nova sessão do IE.
Se não for definido e as configurações do Modo protegido não forem iguais para
todas as zonas, uma exceção será lançada pelo driver.
Se a capacidade for definida como true, os testes podem
tornar-se instáveis, não responderem ou os navegadores podem travar.
No entanto, esta ainda é de longe a segunda melhor escolha,
e a primeira escolha sempre deve ser
definir as configurações do Modo protegido de cada zona manualmente.
Se um usuário estiver usando esta propriedade,
apenas um “melhor esforço” no suporte será dado.
Esse recurso aceita um valor booleano como parâmetro.
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.ignore_protected_mode_settings=Truedriver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.set_capability("silent",True)driver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
O Internet Explorer inclui várias opções de linha de comando
que permitem solucionar problemas e configurar o navegador.
Os seguintes pontos descrevem algumas opções de linha de comando com suporte
-private: Usado para iniciar o IE no modo de navegação privada. Isso funciona para o IE 8 e versões posteriores.
-k: Inicia o Internet Explorer no modo quiosque.
O navegador é aberto em uma janela maximizada que não exibe a barra de endereço, os botões de navegação ou a barra de status.
-extoff: Inicia o IE no modo sem add-on.
Esta opção é usada especificamente para solucionar problemas com complementos do navegador. Funciona no IE 7 e versões posteriores.
Nota: forceCreateProcessApi deve ser habilitado para que os argumentos da linha de comando funcionem.
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.add_argument('-private')options.force_create_process_api=Truedriver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
require'selenium-webdriver'options=Selenium::WebDriver::IE::Options.newoptions.force_create_process_api=trueoptions.add_argument('-k')driver=Selenium::WebDriver.for(:ie,options:options)begin# Navegar para URLdriver.get'https://google.com'puts(driver.capabilities.to_json)ensuredriver.quitend
fromseleniumimportwebdriveroptions=webdriver.IeOptions()options.force_create_process_api=Truedriver=webdriver.Ie(options=options)# Navegar para Urldriver.get("http://www.google.com")driver.quit()
require'selenium-webdriver'options=Selenium::WebDriver::IE::Options.newoptions.force_create_process_api=truedriver=Selenium::WebDriver.for(:ie,options:options)begin# Navegar para Urldriver.get'https://google.com'puts(driver.capabilities.to_json)ensuredriver.quitend
Estas capacidades e características são específicas ao navegador Apple Safari.
Ao invés dos drivers para Chromium e Firefox, o safaridriver faz parte to sistema Operativo.
Para activar a automação no Safari, execute o seguinte comando no terminal:
safaridriver --enable
Opções
Capacidades comuns a todos os navegadores estão descritas na página Opções.
Capacidades únicas ao Safari podem ser encontradas na página da Apple WebDriver para Safari
Este é um exemplo de como iniciar uma sessão Safari com um conjunto de opções básicas::
Geralmente, pode-se dizer que o WebDriver tem uma API de blocante.
Porque é uma biblioteca fora de processo que
instrui ao navegador o que fazer,
e porque a plataforma web tem uma natureza intrinsecamente assíncrona,
O WebDriver não rastreia o estado ativo em tempo real do DOM.
Isso traz alguns desafios que discutiremos aqui.
Por experiência,
a maioria dos problemas intermitentes que surgem do uso de Selenium e WebDriver
estão conectados a condições de corrida que ocorrem entre
o navegador e as instruções do usuário.
Um exemplo pode ser que o usuário instrui o navegador a navegar para uma página,
em seguida, obtém um erro no such element
ao tentar encontrar um elemento.
Considere o seguinte documento:
<!doctype html><metacharset=utf-8><title>Race Condition Example</title><script>varinitialised=false;window.addEventListener("load",function(){varnewElement=document.createElement("p");newElement.textContent="Hello from JavaScript!";document.body.appendChild(newElement);initialised=true;});</script>
As instruções do WebDriver podem parecer inocentes:
driver.get("file:///race_condition.html");WebElementelement=driver.findElement(By.tagName("p"));assertEquals(element.getText(),"Hello from JavaScript!");
driver.navigate("file:///race_condition.html")el=driver.find_element(By.TAG_NAME,"p")assertel.text=="Hello from JavaScript!"
driver.Navigate().GoToUrl("file:///race_condition.html");IWebElementelement=driver.FindElement(By.TagName("p"));assertEquals(element.Text,"Hello from JavaScript!");
require'selenium-webdriver'driver=Selenium::WebDriver.for:firefoxbegin# Navigate to URLdriver.get'file:///race_condition.html'# Get and store Paragraph Textsearch_form=driver.find_element(:css,'p').text"Hello from JavaScript!".eql?search_formensuredriver.quitend
awaitdriver.get('file:///race_condition.html');constelement=driver.findElement(By.css('p'));assert.strictEqual(awaitelement.getText(),'Hello from JavaScript!');
driver.get("file:///race_condition.html")valelement=driver.findElement(By.tagName("p"))assert(element.text=="Hello from JavaScript!")
O problema aqui é que a
estratégia de carregamento de página padrão
usado no WebDriver escuta o document.readyState
para mudar para "complete" antes de retornar da chamada para navigate.
Porque o elemento p é
adicionado após o carregamento do documento concluído,
este script WebDriver pode ser intermitente.
“Pode” ser intermitente porque nenhuma garantia pode ser feita
sobre elementos ou eventos que disparam de forma assíncrona
sem esperar explicitamente - ou bloquear - nesses eventos.
Felizmente, o conjunto normal de instruções disponível na interface
_WebElement _ - tal
como WebElement.click e WebElement.sendKeys — são
garantidamente síncrono,
em que as chamadas de função não retornarão
(ou o retorno de chamada não será acionado em linguagens de estilo de
retorno de chamada) até que o comando seja concluído no navegador.
As APIs avançadas de interação com o usuário,
Keyboard
e Mouse,
são exceções, pois são explicitamente pretendidas como
comandos assíncronos “faça o que eu digo”.
Esperar é fazer a execução de tarefa automatizada
esperar passar um certo tempo antes de continuar com a próxima etapa.
Para superar o problema das condições de corrida
entre o navegador e o script WebDriver,
a maioria dos clientes Selenium vem com um pacote wait.
Ao empregar uma espera,
você está usando o que é comumente referido
como uma espera explícita.
Espera explícita
Esperas explícitas estão disponíveis para clientes Selenium
para linguagens procedurais imperativas.
Eles permitem que seu código interrompa a execução do programa,
ou congelar o tópico,
até que a condição que você passe resolva.
A condição é chamada com uma certa frequência
até que o tempo limite de espera tenha decorrido.
Isso significa que, enquanto a condição retornar um valor falso,
ele continuará tentando e esperando.
Como as esperas explícitas permitem que você espere até que uma condição ocorra,
eles são adequados para sincronizar o estado entre o navegador e seu DOM,
e seu script WebDriver.
Para remediar o nosso conjunto de instruções com erros de antes,
poderíamos empregar um tempo de espera para que a chamada findElement
espere até que o elemento adicionado dinamicamente do script
seja adicionado ao DOM:
WebDriverdriver=newChromeDriver();driver.get("https://google.com/ncr");driver.findElement(By.name("q")).sendKeys("cheese"+Keys.ENTER);// Initialize and wait till element(link) became clickable - timeout in 10 seconds
WebElementfirstResult=newWebDriverWait(driver,Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")));// Print the first result
System.out.println(firstResult.getText());
fromselenium.webdriver.support.waitimportWebDriverWaitdefdocument_initialised(driver):returndriver.execute_script("return initialised")driver.navigate("file:///race_condition.html")WebDriverWait(driver,timeout=10).until(document_initialised)el=driver.find_element(By.TAG_NAME,"p")assertel.text=="Hello from JavaScript!"
require'selenium-webdriver'driver=Selenium::WebDriver.for:firefoxwait=Selenium::WebDriver::Wait.new(:timeout=>10)defdocument_initialised(driver)driver.execute_script('return initialised')endbegindriver.get'file:///race_condition.html'wait.until{document_initialiseddriver}search_form=driver.find_element(:css,'p').text"Hello from JavaScript!".eql?search_formensuredriver.quitend
constdocumentInitialised=()=>driver.executeScript('return initialised');awaitdriver.get('file:///race_condition.html');awaitdriver.wait(()=>documentInitialised(),10000);constelement=driver.findElement(By.css('p'));assert.strictEqual(awaitelement.getText(),'Hello from JavaScript!');
driver.get("https://google.com/ncr")driver.findElement(By.name("q")).sendKeys("cheese"+Keys.ENTER)// Initialize and wait till element(link) became clickable - timeout in 10 seconds
valfirstResult=WebDriverWait(driver,Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.xpath("//a/h3")))// Print the first result
println(firstResult.text)
Passamos a condição como uma referência de função
que o wait executará repetidamente até que seu valor de retorno seja verdadeiro.
Um valor de retorno “verdadeiro” é qualquer coisa avaliada como booleana verdadeira
na linguagem em questão, como string, número, booleano,
um objeto (incluindo um WebElement),
ou uma sequência ou lista preenchida (não vazia).
Isso significa que uma lista vazia é avaliada como falsa.
Quando a condição é verdadeira e a espera de bloqueio é abortada,
o valor de retorno da condição se torna o valor de retorno da espera.
Com este conhecimento,
e como o utilitário de espera ignora erros no such element por padrão,
podemos refatorar nossas instruções para sermos mais concisos:
WebElementfoo=newWebDriverWait(driver,Duration.ofSeconds(3)).until(driver->driver.findElement(By.name("q")));assertEquals(foo.getText(),"Hello from JavaScript!");
fromselenium.webdriver.support.waitimportWebDriverWaitdriver.navigate("file:///race_condition.html")el=WebDriverWait(driver,timeout=3).until(lambdad:d.find_element(By.TAG_NAME,"p"))assertel.text=="Hello from JavaScript!"
using(vardriver=newFirefoxDriver()){varfoo=newWebDriverWait(driver,TimeSpan.FromSeconds(3)).Until(drv=>drv.FindElement(By.Name("q")));Debug.Assert(foo.Text.Equals("Hello from JavaScript!"));}
driver.get'file:///race_condition.html'wait=Selenium::WebDriver::Wait.new(:timeout=>10)ele=wait.until{driver.find_element(css:'p')}foo=ele.textassert_matchfoo,'Hello from JavaScript'
letele=awaitdriver.wait(until.elementLocated(By.css('p')),10000);letfoo=awaitele.getText();assert(foo=="Hello from JavaScript");
driver.get("file:///race_condition.html")valele=WebDriverWait(driver,Duration.ofSeconds(10)).until(ExpectedConditions.presenceOfElementLocated(By.tagName("p")))assert(ele.text=="Hello from JavaScript!")
Nesse exemplo, passamos uma função anônima
(mas também podemos definá-la explicitamente, como fizemos antes,
para que possa ser reutilizado). O primeiro e único argumento que é
passado para nossa condição é sempre uma referência ao nosso objeto
driver, WebDriver. Em um ambiente multi-thread, você deve ter cuidado
para operar na referência do driver passada para a condição
em vez da referência ao driver no escopo externo.
Dado que a espera vai engolir erros no such element
que são gerados quando o elemento não é encontrado,
a condição tentará novamente até que o elemento seja encontrado.
Em seguida, ele receberá o valor de retorno, um WebElement,
e o passará de volta para o nosso script.
Se a condição falhar,
por exemplo um valor de retorno verdadeiro da condição nunca for
alcançado, a espera lançará/gerará um erro/exceção chamado
timeout error.
Opções
A condição de espera pode ser personalizada para atender às suas
necessidades. Às vezes, é desnecessário esperar todo o tempo limite
padrão, já que a penalidade por não atingir uma condição de sucesso pode
ser cara.
A espera permite que você passe um argumento para substituir o tempo
limite:
Já que é uma ocorrência bastante comum
ter que sincronizar o DOM e suas instruções,
a maioria dos clientes também vem com um conjunto de condições esperadas predefinidas.
Como pode ser óbvio pelo nome,
são condições predefinidas para operações de espera frequentes.
As condições disponíveis nas diferentes linguagens variam,
mas esta é uma lista não exaustiva de alguns:
alert is present
element exists
element is visible
title contains
title is
element staleness
visible text
Você pode consultar a documentação da API para cada biblioteca de cliente
para encontrar uma lista exaustiva das condições esperadas:
Há um segundo tipo de espera que é diferente de
espera explícita chamada espera implícita.
Esperando implicitamente, o WebDriver pesquisa o DOM
por um certo período ao tentar encontrar qualquer elemento.
Isso pode ser útil quando certos elementos da página da web
não estão disponíveis imediatamente e precisam de algum tempo para
carregar.
A espera implícita pelo aparecimento de elementos está desativada por
padrão e precisará ser habilitada manualmente por sessão.
Misturar esperas explícitas e esperas implícitas
irá causar consequências não intencionais, ou seja, espera dormir pelo
máximo tempo mesmo se o elemento estiver disponível ou a condição for
verdadeira.
Atenção:
Não misture esperas implícitas e explícitas.
Isso pode causar tempos de espera imprevisíveis.
Por exemplo, definir uma espera implícita de 10 segundos
e uma espera explícita de 15 segundos
pode causar um tempo limite após 20 segundos.
Uma espera implícita é dizer ao WebDriver para pesquisar o DOM
por um certo período de tempo ao tentar encontrar um elemento ou
elementos se não estiverem imediatamente disponíveis.
A configuração padrão é 0, o que significa desativado.
Depois de definida, a espera implícita é definida para a duração da
sessão.
A instância FluentWait define a quantidade máxima de tempo de espera por
uma condição, bem como a frequência com que verificar a condição.
Os usuários podem configurar a espera para ignorar tipos específicos de
exceções enquanto esperam, como NoSuchElementException ao pesquisar um
elemento na página.
// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Wait<WebDriver>wait=newFluentWait<WebDriver>(driver).withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5)).ignoring(NoSuchElementException.class);WebElementfoo=wait.until(driver->{returndriver.findElement(By.id("foo"));});
require'selenium-webdriver'driver=Selenium::WebDriver.for:firefoxexception=Selenium::WebDriver::Error::NoSuchElementErrorbegindriver.get'http://somedomain/url_that_delays_loading'wait=Selenium::WebDriver::Wait.new(timeout:30,interval:5,message:'Timed out after 30 sec',ignore:exception)foo=wait.until{driver.find_element(id:'foo')}ensuredriver.quitend
const{Builder,until}=require('selenium-webdriver');(asyncfunctionexample(){letdriver=awaitnewBuilder().forBrowser('firefox').build();awaitdriver.get('http://somedomain/url_that_delays_loading');// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
letfoo=awaitdriver.wait(until.elementLocated(By.id('foo')),30000,'Timed out after 30 seconds',5000);})();
A maioria do código que é escrito recorrendo às bibliotecas Selenium envolve trabalhar com elementos.
2.5.1 - File Upload
Como subir arquivos com Selenium
A caixa de diálogo para o envio de arquivos pode ser tratada com o Selenium, quando o elemento de entrada é do tipo “file”.
Pode observar um exemplo neste link https://the-internet.herokuapp.com/upload .
Será necessário ter o arquivo a subir disponível para a operação.
Apresentamos alguns exemplos de código para subir os arquivos em diversas linguagens de programação:
importjava.util.concurrent.TimeUnit;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.chrome.ChromeDriver;classfileUploadDoc{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);driver.get("https://the-internet.herokuapp.com/upload");//we want to import selenium-snapshot file.
driver.findElement(By.id("file-upload")).sendKeys("selenium-snapshot.jpg");driver.findElement(By.id("file-submit")).submit();if(driver.getPageSource().contains("File Uploaded!")){System.out.println("file uploaded");}else{System.out.println("file not uploaded");}driver.quit();}}
fromseleniumimportwebdriverdriver.implicitly_wait(10)driver.get("https://the-internet.herokuapp.com/upload");driver.find_element(By.ID,"file-upload").send_keys("selenium-snapshot.jpg")driver.find_element(By.ID,"file-submit").submit()if(driver.page_source.find("File Uploaded!")):print("file upload success")else:print("file upload not successful")driver.quit()
usingSystem;usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceSeleniumDocumentation.SeleniumPRs{classFileUploadExample{staticvoidMain(String[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://the-internet.herokuapp.com/upload");driver.FindElement(By.Id("file-upload")).SendKeys("selenium-snapshot.jpg");driver.FindElement(By.Id("file-submit")).Submit();if(driver.PageSource.Contains("File Uploaded!")){Console.WriteLine("file uploaded");}else{Console.WriteLine("file not uploaded");}driver.Quit();}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromedriver.get("https://the-internet.herokuapp.com/upload")driver.find_element(:id,"file-upload").send_keys("selenium-snapshot.jpg")driver.find_element(:id,"file-submit").submit()ifdriver.page_source().include?"File Uploaded!"puts"file upload success"elseputs"file upload not successful"end
import{Builder,By}from"selenium-webdriver"letdriver=awaitnewBuilder().forBrowser('chrome').build()awaitdriver.get("https://the-internet.herokuapp.com/upload");awaitdriver.findElement(By.id("file-upload")).sendKeys("selenium-snapshot.jpg")awaitdriver.findElement(By.id("file-submit")).submit()driver.getPageSource().then(result=>{if(result.indexOf("File Uploaded!")){console.log("file upload success")}else{console.log("file upload not successful")}})
importorg.openqa.selenium.Byimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()driver.get("https://the-internet.herokuapp.com/upload")driver.findElement(By.id("file-upload")).sendKeys("selenium-snapshot.jpg")driver.findElement(By.id("file-submit")).submit()if(driver.pageSource.contains("File Uploaded!")){println("file uploaded")}else{println("file not uploaded")}}
Esperamos que estes exemplos de código possam ajudar a compreender como subir um arquivo com Selenium.
2.5.2 - Encontrando Elementos Web
Localizando elementos com base nos valores providenciados pelo localizador.
Um dos aspectos mais fundamentais do uso do Selenium é obter referências de elementos para trabalhar.
O Selenium oferece várias estratégias de localizador para identificar exclusivamente um elemento.
Há muitas maneiras de usar os localizadores em cenários complexos. Para os propósitos desta documentação,
vamos considerar este trecho de HTML:
<olid="vegetables"><liclass="potatoes">…
<liclass="onions">…
<liclass="tomatoes"><span>O tomate é um vegetal</span>…
</ol><ulid="fruits"><liclass="bananas">…
<liclass="apples">…
<liclass="tomatoes"><span>O tomate é uma fruta</span>…
</ul>
Primeiro Elemento correspondente
Muitos localizadores irão corresponder a vários elementos na página.
O método de elemento de localização singular retornará uma referência ao
primeiro elemento encontrado dentro de um determinado contexto.
Avaliando o DOM inteiro
Quando o metodo find element é chamado na instância do driver, ele
retorna uma referência ao primeiro elemento no DOM que corresponde ao localizador fornecido.
Esse valor pode ser guardado e usado para ações futuras do elemento. Em nosso exemplo HTML acima, existem
dois elementos que têm um nome de classe de “tomatoes” então este método retornará o elemento na lista “vegetables”.
Ao em vez de tentar encontrar um localizador unico no DOM inteiro, normalmente é útil restringir a busca ao escopo de outro elemento
já localizado. No exemplo acima existem dois elementos com um nome de classe de “tomatoes” e
é um pouco mais desafiador obter a referência para o segundo.
Uma possível solução seria localizar um elemento com um atributo único que seja um ancestral do elemento desejado e não um
ancestral do elemento indesejado, então invoque o find element nesse objeto:
Java e C#
As classes WebDriver, WebElement e ShadowRoot todas implementam o SearchContext interface, que é
considerada uma role-based interface(interface baseada em função). As interfaces baseadas em função permitem determinar se uma determinada
implementação de driver suporta um recurso específico. Essas interfaces são claramente definidas e tentam
aderir a ter apenas um único papel de responsabilidade.
Localizador otimizado
Uma pesquisa aninhada pode não ser a estratégia de localização mais eficaz, pois requer dois
comandos separados a serem emitidos para o navegador.
Existem vários casos de uso para a necessidade de obter referências a todos os elementos que correspondem a um localizador, em vez
do que apenas o primeiro. Os métodos plurais find elements retornam uma coleção de referências de elementos.
Se não houver correspondências, uma lista vazia será retornada. Nesse caso,
referências a todos os itens da lista de frutas e vegetais serão devolvidas em uma coleção.
Muitas vezes você obterá uma coleção de elementos, mas quer trabalhar apenas com um elemento específico, o que significa que você
precisa iterar sobre a coleção e identificar o que você deseja.
fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBydriver=webdriver.Firefox()# Navegar até a URLdriver.get("https://www.example.com")# Obtém todos os elementos disponiveis com o nome da tag 'p'elements=driver.find_elements(By.TAG_NAME,'p')foreinelements:print(e.text)
usingOpenQA.Selenium;usingOpenQA.Selenium.Firefox;usingSystem.Collections.Generic;namespaceFindElementsExample{classFindElementsExample{publicstaticvoidMain(string[]args){IWebDriverdriver=newFirefoxDriver();try{// Navegar até a URLdriver.Navigate().GoToUrl("https://example.com");// Obtém todos os elementos disponiveis com o nome da tag 'p'IList<IWebElement>elements=driver.FindElements(By.TagName("p"));foreach(IWebElementeinelements){System.Console.WriteLine(e.Text);}}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:firefoxbegin# Navegar até a URLdriver.get'https://www.example.com'# Obtém todos os elementos disponiveis com o nome da tag 'p'elements=driver.find_elements(:tag_name,'p')elements.each{|e|putse.text}ensuredriver.quitend
const{Builder,By}=require('selenium-webdriver');(asyncfunctionexample(){letdriver=awaitnewBuilder().forBrowser('firefox').build();try{// Navegar até a URL
awaitdriver.get('https://www.example.com');// Obtém todos os elementos disponiveis com o nome da tag 'p'
letelements=awaitdriver.findElements(By.css('p'));for(leteofelements){console.log(awaite.getText());}}finally{awaitdriver.quit();}})();
importorg.openqa.selenium.Byimportorg.openqa.selenium.firefox.FirefoxDriverfunmain(){valdriver=FirefoxDriver()try{driver.get("https://example.com")// Obtém todos os elementos disponiveis com o nome da tag 'p'
valelements=driver.findElements(By.tagName("p"))for(elementinelements){println("Paragraph text:"+element.text)}}finally{driver.quit()}}
Localizar Elementos em um Elemento
Ele é usado para localizar a lista de WebElements filhos correspondentes dentro do contexto do elemento pai.
Para realizar isso, o WebElement pai é encadeado com o ‘findElements’ para acessar seus elementos filhos.
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importjava.util.List;publicclassfindElementsFromElement{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("https://example.com");// Obtém o elemento com o nome da tag 'div'
WebElementelement=driver.findElement(By.tagName("div"));// Obtém todos os elementos disponiveis com o nome da tag 'p'
List<WebElement>elements=element.findElements(By.tagName("p"));for(WebElemente:elements){System.out.println(e.getText());}}finally{driver.quit();}}}
fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBydriver=webdriver.Chrome()driver.get("https://www.example.com")# Obtém o elemento com o nome da tag 'div'element=driver.find_element(By.TAG_NAME,'div')# Obtém todos os elementos disponíveis com o nome da tag 'p'elements=element.find_elements(By.TAG_NAME,'p')foreinelements:print(e.text)
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingSystem.Collections.Generic;namespaceFindElementsFromElement{classFindElementsFromElement{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{driver.Navigate().GoToUrl("https://example.com");// Obtém o elemento com o nome da tag 'div'IWebElementelement=driver.FindElement(By.TagName("div"));// Obtém todos os elementos disponíveis com o nome da tag 'p'IList<IWebElement>elements=element.FindElements(By.TagName("p"));foreach(IWebElementeinelements){System.Console.WriteLine(e.Text);}}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegin# Navegar até a URLdriver.get'https://www.example.com'# Obtém o elemento com o nome da tag 'div'element=driver.find_element(:tag_name,'div')# Obtém todos os elementos disponíveis com o nome da tag 'p'elements=element.find_elements(:tag_name,'p')elements.each{|e|putse.text}ensuredriver.quitend
const{Builder,By}=require('selenium-webdriver');(asyncfunctionexample(){letdriver=newBuilder().forBrowser('chrome').build();awaitdriver.get('https://www.example.com');// Obtém o elemento com o nome da tag 'div'
letelement=driver.findElement(By.css("div"));// Obtém todos os elementos disponíveis com o nome da tag 'p'
letelements=awaitelement.findElements(By.css("p"));for(leteofelements){console.log(awaite.getText());}})();
importorg.openqa.selenium.Byimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")// Obtém o elemento com o nome da tag 'div'
valelement=driver.findElement(By.tagName("div"))// Obtém todos os elementos disponíveis com o nome da tag 'p'
valelements=element.findElements(By.tagName("p"))for(einelements){println(e.text)}}finally{driver.quit()}}
Obter elemento ativo
Ele é usado para rastrear (ou) encontrar um elemento DOM que tem o foco no contexto de navegação atual.
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;publicclassactiveElementTest{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.google.com");driver.findElement(By.cssSelector("[name='q']")).sendKeys("webElement");// Obter atributo do elemento atualmente ativo
Stringattr=driver.switchTo().activeElement().getAttribute("title");System.out.println(attr);}finally{driver.quit();}}}
fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBydriver=webdriver.Chrome()driver.get("https://www.google.com")driver.find_element(By.CSS_SELECTOR,'[name="q"]').send_keys("webElement")# Obter atributo do elemento atualmente ativoattr=driver.switch_to.active_element.get_attribute("title")print(attr)
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceActiveElement{classActiveElement{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navegar até a URLdriver.Navigate().GoToUrl("https://www.google.com");driver.FindElement(By.CssSelector("[name='q']")).SendKeys("webElement");// Obter atributo do elemento atualmente ativostringattr=driver.SwitchTo().ActiveElement().GetAttribute("title");System.Console.WriteLine(attr);}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.google.com'driver.find_element(css:'[name="q"]').send_keys('webElement')# Obter atributo do elemento atualmente ativoattr=driver.switch_to.active_element.attribute('title')putsattrensuredriver.quitend
const{Builder,By}=require('selenium-webdriver');(asyncfunctionexample(){letdriver=awaitnewBuilder().forBrowser('chrome').build();awaitdriver.get('https://www.google.com');awaitdriver.findElement(By.css('[name="q"]')).sendKeys("webElement");// Obter atributo do elemento atualmente ativo
letattr=awaitdriver.switchTo().activeElement().getAttribute("title");console.log(`${attr}`)})();
importorg.openqa.selenium.Byimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://www.google.com")driver.findElement(By.cssSelector("[name='q']")).sendKeys("webElement")// Obter atributo do elemento atualmente ativo
valattr=driver.switchTo().activeElement().getAttribute("title")print(attr)}finally{driver.quit()}}
2.5.3 - Interacting with web elements
A high-level instruction set for manipulating form controls.
There are only 5 basic commands that can be executed on an element:
These methods are designed to closely emulate a user’s experience, so,
unlike the Actions API, it attempts to perform two things
before attempting the specified action.
If it determines the element is outside the viewport, it
scrolls the element into view, specifically
it will align the bottom of the element with the bottom of the viewport.
It ensures the element is interactable
before taking the action. This could mean that the scrolling was unsuccessful, or that the
element is not otherwise displayed. Determining if an element is displayed on a page was too difficult to
define directly in the webdriver specification,
so Selenium sends an execute command with a JavaScript atom that checks for things that would keep
the element from being displayed. If it determines an element is not in the viewport, not displayed, not
keyboard-interactable, or not
pointer-interactable,
it returns an element not interactable error.
The element send keys command
types the provided keys into an editable element.
Typically, this means an element is an input element of a form with a text type or an element
with a content-editable attribute. If it is not editable,
an invalid element state error is returned.
Here is the list of
possible keystrokes that WebDriver Supports.
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class HelloSelenium {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
try {
// Navigate to Url
driver.get("https://google.com");
// Enter text "q" and perform keyboard action "Enter"
driver.findElement(By.name("q")).sendKeys("q" + Keys.ENTER);
} finally {
driver.quit();
}
}
}
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
# Navigate to url
driver.get("http://www.google.com")
# Enter "webdriver" text and perform "ENTER" keyboard action
driver.find_element(By.NAME, "q").send_keys("webdriver" + Keys.ENTER)
using (var driver = new FirefoxDriver())
{
// Navigate to Url
driver.Navigate().GoToUrl("https://google.com");
// Enter "webdriver" text and perform "ENTER" keyboard action
driver.FindElement(By.Name("q")).SendKeys("webdriver" + Keys.Enter);
}
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
begin
# Navigate to URL
driver.get 'https://google.com'
# Enter "webdriver" text and perform "ENTER" keyboard action
driver.find_element(name: 'q').send_keys 'webdriver', :return
ensure
driver.quit
end
const {Builder, By, Key} = require('selenium-webdriver');
(async function example() {
let driver = await new Builder().forBrowser('firefox').build();
try {
// Navigate to Url
await driver.get('https://www.google.com');
// Enter text "webdriver" and perform keyboard action "Enter"
await driver.findElement(By.name('q')).sendKeys('webdriver', Key.ENTER);
}
finally {
await driver.quit();
}
})();
import org.openqa.selenium.By
import org.openqa.selenium.Keys
import org.openqa.selenium.firefox.FirefoxDriver
fun main() {
val driver = FirefoxDriver()
try {
// Navigate to Url
driver.get("https://google.com")
// Enter text "q" and perform keyboard action "Enter"
driver.findElement(By.name("q")).sendKeys("q" + Keys.ENTER)
} finally {
driver.quit()
}
}
Clear
The element clear command resets the content of an element.
This requires an element to be editable,
and resettable. Typically,
this means an element is an input element of a form with a text type or an element
with acontent-editable attribute. If these conditions are not met,
an invalid element state error is returned.
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;publicclassclear{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{// Navigate to Url
driver.get("https://www.google.com");// Store 'SearchInput' element
WebElementsearchInput=driver.findElement(By.name("q"));searchInput.sendKeys("selenium");// Clears the entered text
searchInput.clear();}finally{driver.quit();}}}
fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBydriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.google.com")# Store 'SearchInput' elementSearchInput=driver.find_element(By.NAME,"q")SearchInput.send_keys("selenium")# Clears the entered textSearchInput.clear()
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingSystem;namespaceSnipetProjectDelete{classProgram{staticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl(@"https://www.google.com");// Store 'SearchInput' elementIWebElementsearchInput=driver.FindElement(By.Name("q"));searchInput.SendKeys("selenium");// Clears the entered textsearchInput.Clear();}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegin# Navigate to URLdriver.get'https://google.com'# store 'search_input' elementsearch_input=driver.find_element(name:'q')search_input.send_keys('selenium')# Clears the entered textsearch_input.clearensuredriver.quitend
importorg.openqa.selenium.Byimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{// Navigate to Url
driver.get("https://www.google.com")// Store 'searchInput' element
valsearchInput=driver.findElement(By.name("q"))searchInput.sendKeys("selenium")// Clears the entered text
searchInput.clear()}finally{driver.quit()}}
Submit
In Selenium 4 this is no longer implemented with a separate endpoint and functions by executing a script. As
such, it is recommended not to use this method and to click the applicable form submission button instead.
2.5.4 - Information about web elements
What you can learn about an element.
There are a number of details you can query about a specific element.
Is Displayed
This method is used to check if the connected Element is
displayed on a webpage. Returns a Boolean value,
True if the connected element is displayed in the current
browsing context else returns false.
This functionality is mentioned in, but not defined by
the w3c specification due to the
impossibility of covering all potential conditions.
As such, Selenium cannot expect drivers to implement
this functionality directly, and now relies on
executing a large JavaScript function directly.
This function makes many approximations about an element’s
nature and relationship in the tree to return a value.
// Navigate to the url
driver.get("https://www.selenium.dev/selenium/web/inputs.html");// Get boolean value for is element display
booleanisEmailVisible=driver.findElement(By.name("email_input")).isDisplayed();
# Navigate to the urldriver.get("https://www.selenium.dev/selenium/web/inputs.html")# Get boolean value for is element displayis_email_visible=driver.find_element(By.NAME,"email_input").is_displayed()
//Navigate to the urldriver.Url="https://www.selenium.dev/selenium/web/inputs.html";//Get boolean value for is element displayBooleanis_email_visible=driver.FindElement(By.Name("email_input")).Displayed;
# Navigate to the urldriver.get("https://www.selenium.dev/selenium/web/inputs.html");#fetch display statusval=driver.find_element(name:'email_input').displayed?
// Navigate to url
awaitdriver.get("https://www.selenium.dev/selenium/web/inputs.html");// Resolves Promise and returns boolean value
letresult=awaitdriver.findElement(By.name("email_input")).isDisplayed();
//navigates to url
driver.get("https://www.selenium.dev/selenium/web/inputs.html")//returns true if element is displayed else returns false
valflag=driver.findElement(By.name("email_input")).isDisplayed()
Coding Help
Note:
This section could use some updated code examples
Este método determina se o elemento referenciado
é Selected ou não. Este método é amplamente utilizado em
caixas de seleção, botões de opção, elementos de entrada e elementos de
opção.
Retorna um valor booleano, true se o elemento referenciado for
selected no contexto de navegação atual, caso contrário, retorna
false.
//navigates to url
driver.get("https://the-internet.herokuapp.com/checkboxes");//returns true if element is checked else returns false
booleanvalue=driver.findElement(By.cssSelector("input[type='checkbox']:first-of-type")).isSelected();
# Navigate to urldriver.get("https://the-internet.herokuapp.com/checkboxes")# Returns true if element is checked else returns falsevalue=driver.find_element(By.CSS_SELECTOR,"input[type='checkbox']:first-of-type").is_selected()
// Navigate to Urldriver.Navigate().GoToUrl("https://the-internet.herokuapp.com/checkboxes");// Returns true if element ins checked else returns falseboolvalue=driver.FindElement(By.CssSelector("input[type='checkbox']:last-of-type")).Selected;
# Navigate to urldriver.get'https://the-internet.herokuapp.com/checkboxes'# Returns true if element is checked else returns falseele=driver.find_element(css:"input[type='checkbox']:last-of-type").selected?
// Navigate to url
awaitdriver.get('https://the-internet.herokuapp.com/checkboxes');// Returns true if element ins checked else returns false
letres=awaitdriver.findElement(By.css("input[type='checkbox']:last-of-type")).isSelected();
//navigates to url
driver.get("https://the-internet.herokuapp.com/checkboxes")//returns true if element is checked else returns false
valattr=driver.findElement(By.cssSelector("input[type='checkbox']:first-of-type")).isSelected()
Coletar TagName do elemento
É usado para buscar o TagName
do elemento referenciado que tem o foco no contexto de navegação atual.
//navigates to url
driver.get("https://www.example.com");//returns TagName of the element
Stringvalue=driver.findElement(By.cssSelector("h1")).getTagName();
# Navigate to urldriver.get("https://www.example.com")# Returns TagName of the elementattr=driver.find_element(By.CSS_SELECTOR,"h1").tag_name
// Navigate to Urldriver.Navigate().GoToUrl("https://www.example.com");// Returns TagName of the elementstringattr=driver.FindElement(By.CssSelector("h1")).TagName;
# Navigate to urldriver.get'https://www.example.com'# Returns TagName of the elementattr=driver.find_element(css:"h1").tag_name
// Navigate to URL
awaitdriver.get('https://www.example.com');// Returns TagName of the element
letvalue=awaitdriver.findElement(By.css('h1')).getTagName();
//navigates to url
driver.get("https://www.example.com")//returns TagName of the element
valattr=driver.findElement(By.cssSelector("h1")).getTagName()
Coletar retângulo do elemento
É usado para buscar as dimensões e coordenadas
do elemento referenciado.
O corpo de dados buscado contém os seguintes detalhes:
Posição do eixo X a partir do canto superior esquerdo do elemento
posição do eixo y a partir do canto superior esquerdo do elemento
// Navigate to url
driver.get("https://www.example.com");// Returns height, width, x and y coordinates referenced element
Rectangleres=driver.findElement(By.cssSelector("h1")).getRect();// Rectangle class provides getX,getY, getWidth, getHeight methods
System.out.println(res.getX());
# Navigate to urldriver.get("https://www.example.com")# Returns height, width, x and y coordinates referenced elementres=driver.find_element(By.CSS_SELECTOR,"h1").rect
// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");varres=driver.FindElement(By.CssSelector("h1"));// Return x and y coordinates referenced elementSystem.Console.WriteLine(res.Location);// Returns height, widthSystem.Console.WriteLine(res.Size);
# Navigate to urldriver.get'https://www.example.com'# Returns height, width, x and y coordinates referenced elementres=driver.find_element(css:"h1").rect
// Navigate to url
awaitdriver.get('https://www.example.com');// Returns height, width, x and y coordinates referenced element
letelement=awaitdriver.findElement(By.css("h1")).getRect();
// Navigate to url
driver.get("https://www.example.com")// Returns height, width, x and y coordinates referenced element
valres=driver.findElement(By.cssSelector("h1")).rect// Rectangle class provides getX,getY, getWidth, getHeight methods
println(res.getX())
Coletar valor CSS do elemento
Recupera o valor da propriedade de estilo computado especificada
de um elemento no contexto de navegação atual.
// Navigate to Url
driver.get("https://www.example.com");// Retrieves the computed style property 'color' of linktext
StringcssValue=driver.findElement(By.linkText("More information...")).getCssValue("color");
# Navigate to Urldriver.get('https://www.example.com')# Retrieves the computed style property 'color' of linktextcssValue=driver.find_element(By.LINK_TEXT,"More information...").value_of_css_property('color')
// Navigate to Urldriver.Navigate().GoToUrl("https://www.example.com");// Retrieves the computed style property 'color' of linktextStringcssValue=driver.FindElement(By.LinkText("More information...")).GetCssValue("color");
# Navigate to Urldriver.get'https://www.example.com'# Retrieves the computed style property 'color' of linktextcssValue=driver.find_element(:link_text,'More information...').css_value('color')
// Navigate to Url
awaitdriver.get('https://www.example.com');// Retrieves the computed style property 'color' of linktext
letcssValue=awaitdriver.findElement(By.linkText("More information...")).getCssValue('color');
// Navigate to Url
driver.get("https://www.example.com")// Retrieves the computed style property 'color' of linktext
valcssValue=driver.findElement(By.linkText("More information...")).getCssValue("color")
Coletar texto do elemento
Recupera o texto renderizado do elemento especificado.
// Navigate to url
driver.get("https://example.com");// Retrieves the text of the element
Stringtext=driver.findElement(By.cssSelector("h1")).getText();
# Navigate to urldriver.get("https://www.example.com")# Retrieves the text of the elementtext=driver.find_element(By.CSS_SELECTOR,"h1").text
// Navigate to urldriver.Url="https://example.com";// Retrieves the text of the elementStringtext=driver.FindElement(By.CssSelector("h1")).Text;
# Navigate to urldriver.get'https://www.example.com'# Retrieves the text of the elementtext=driver.find_element(:css,'h1').text
// Navigate to URL
awaitdriver.get('http://www.example.com');// retrieves the text of the element
lettext=awaitdriver.findElement(By.css('h1')).getText();
// Navigate to URL
driver.get("https://www.example.com")// retrieves the text of the element
valtext=driver.findElement(By.cssSelector("h1")).getText()
Fetching Attributes or Properties
Fetches the run time value associated with a
DOM attribute. It returns the data associated
with the DOM attribute or property of the element.
//Navigate to the url
driver.get("https://www.selenium.dev/selenium/web/inputs.html");//identify the email text box
WebElementemailTxt=driver.findElement(By.name(("email_input")));//fetch the value property associated with the textbox
StringvalueInfo=eleSelLink.getAttribute("value");
# Navigate to the urldriver.get("https://www.selenium.dev/selenium/web/inputs.html")# Identify the email text boxemail_txt=driver.find_element(By.NAME,"email_input")# Fetch the value property associated with the textboxvalue_info=email_txt.get_attribute("value")
//Navigate to the urldriver.Url="https://www.selenium.dev/selenium/web/inputs.html";//identify the email text boxIWebElementemailTxt=driver.FindElement(By.Name(("email_input")));//fetch the value property associated with the textboxStringvalueInfo=eleSelLink.GetAttribute("value");
# Navigate to the urldriver.get("https://www.selenium.dev/selenium/web/inputs.html");#identify the email text boxemail_element=driver.find_element(name:'email_input')#fetch the value property associated with the textboxemailVal=email_element.attribute("value");
// Navigate to the Url
awaitdriver.get("https://www.selenium.dev/selenium/web/inputs.html");// identify the email text box
constemailElement=awaitdriver.findElements(By.xpath('//input[@name="email_input"]'));//fetch the attribute "name" associated with the textbox
constnameAttribute=awaitemailElement.getAttribute("name");
// Navigate to URL
driver.get("https://www.selenium.dev/selenium/web/inputs.html")//fetch the value property associated with the textbox
valattr=driver.findElement(By.name("email_input")).getAttribute("value")
2.5.5 - Localizando elementos
Formas de identificar um ou mais elementos no DOM.
Um localizador é uma forma de identificar elementos numa página. São os argumentos passados aos métodos
Finders .
Visite os nossas directrizes e recomendações para dicas sobre
locators, incluindo quais usar e quando,
e também porque é que deve declarar localizadores separadamente dos finders.
Estratégias de seleção de elemento
Existem oito estratégias diferentes de localização de elementos embutidas no WebDriver:
Localizador
Descrição
class name
Localiza elementos cujo nome de classe contém o valor de pesquisa (nomes de classes compostas não são permitidos)
css selector
Localiza elementos que correspondem a um seletor CSS
id
Localiza elementos cujo atributo de ID corresponde ao valor de pesquisa
name
Localiza elementos cujo atributo NAME corresponde ao valor de pesquisa
link text
Localiza elementos âncora cujo texto visível corresponde ao valor de pesquisa
partial link text
Localiza elementos âncora cujo texto visível contém o valor da pesquisa. Se vários elementos forem correspondentes, apenas o primeiro será selecionado.
tag name
Localiza elementos cujo nome de tag corresponde ao valor de pesquisa
xpath
Localiza elementos que correspondem a uma expressão XPath
Creating Locators
To work on a web element using Selenium, we need to first locate it on the web page.
Selenium provides us above mentioned ways, using which we can locate element on the
page. To understand and create locator we will use the following HTML snippet.
<html><body><style>.information{background-color:white;color:black;padding:10px;}</style><h2>Contact Selenium</h2><formaction="/action_page.php"><inputtype="radio"name="gender"value="m"/>Male <inputtype="radio"name="gender"value="f"/>Female <br><br><labelfor="fname">First name:</label><br><inputclass="information"type="text"id="fname"name="fname"value="Jane"><br><br><labelfor="lname">Last name:</label><br><inputclass="information"type="text"id="lname"name="lname"value="Doe"><br><br><labelfor="newsletter">Newsletter:</label><inputtype="checkbox"name="newsletter"value="1"/><br><br><inputtype="submit"value="Submit"></form><p>To know more about Selenium, visit the official page
<ahref ="www.selenium.dev">Selenium Official Page</a></p></body></html>
class name
The HTML page web element can have attribute class. We can see an example in the
above shown HTML snippet. We can identify these elements using the class name locator
available in Selenium.
CSS is the language used to style HTML pages. We can use css selector locator strategy
to identify the element on the page. If the element has an id, we create the locator
as css = #id. Otherwise the format we follow is css =[attribute=value] .
Let us see an example from above HTML snippet. We will create locator for First Name
textbox, using css.
We can use the ID attribute available with element in a web page to locate it.
Generally the ID property should be unique for a element on the web page.
We will identify the Last Name field using it.
We can use the NAME attribute available with element in a web page to locate it.
Generally the NAME property should be unique for a element on the web page.
We will identify the Newsletter checkbox using it.
If the element we want to locate is a link, we can use the link text locator
to identify it on the web page. The link text is the text displayed of the link.
In the HTML snippet shared, we have a link available, lets see how will we locate it.
WebDriverdriver=newChromeDriver();driver.findElement(By.linkText("Selenium Official Page"));
driver=webdriver.Chrome()driver.find_element(By.LINK_TEXT,"Selenium Official Page")
vardriver=newChromeDriver();driver.FindElement(By.LinkText("Selenium Official Page"));
driver=Selenium::WebDriver.for:chromedriver.find_element(link_text:'Selenium Official Page')
letdriver=awaitnewBuilder().forBrowser('chrome').build();constloc=awaitdriver.findElement(By.linkText('Selenium Official Page'));
valdriver=ChromeDriver()valloc:WebElement=driver.findElement(By.linkText("Selenium Official Page"))
partial link text
If the element we want to locate is a link, we can use the partial link text locator
to identify it on the web page. The link text is the text displayed of the link.
We can pass partial text as value.
In the HTML snippet shared, we have a link available, lets see how will we locate it.
We can use the HTML TAG itself as a locator to identify the web element on the page.
From the above HTML snippet shared, lets identify the link, using its html tag “a”.
A HTML document can be considered as a XML document, and then we can use xpath
which will be the path traversed to reach the element of interest to locate the element.
The XPath could be absolute xpath, which is created from the root of the document.
Example - /html/form/input[1]. This will return the male radio button.
Or the xpath could be relative. Example- //input[@name=‘fname’]. This will return the
first name text box. Let us create locator for female radio button using xpath.
Selenium 4 introduces Relative Locators (previously
called as Friendly Locators). These locators are helpful when it is not easy to construct a locator for
the desired element, but easy to describe spatially where the element is in relation to an element that does have
an easily constructed locator.
How it works
Selenium uses the JavaScript function
getBoundingClientRect()
to determine the size and position of elements on the page, and can use this information to locate neighboring elements.
find the relative elements.
Relative locator methods can take as the argument for the point of origin, either a previously located element reference,
or another locator. In these examples we’ll be using locators only, but you could swap the locator in the final method with
an element object and it will work the same.
Let us consider the below example for understanding the relative locators.
Available relative locators
Above
If the email text field element is not easily identifiable for some reason, but the password text field element is,
we can locate the text field element using the fact that it is an “input” element “above” the password element.
If the password text field element is not easily identifiable for some reason, but the email text field element is,
we can locate the text field element using the fact that it is an “input” element “below” the email element.
If the cancel button is not easily identifiable for some reason, but the submit button element is,
we can locate the cancel button element using the fact that it is a “button” element to the “left of” the submit element.
If the submit button is not easily identifiable for some reason, but the cancel button element is,
we can locate the submit button element using the fact that it is a “button” element “to the right of” the cancel element.
If the relative positioning is not obvious, or it varies based on window size, you can use the near method to
identify an element that is at most 50px away from the provided locator.
One great use case for this is to work with a form element that doesn’t have an easily constructed locator,
but its associated input label element does.
You can also chain locators if needed. Sometimes the element is most easily identified as being both above/below one element and right/left of another.
A primeira coisa que você vai querer fazer depois de iniciar um navegador é
abrir o seu site. Isso pode ser feito em uma única linha, utilize o seguinte comando:
2.6.2 - Alertas, prompts e confirmações JavaScript
WebDriver fornece uma API para trabalhar com os três tipos nativos de
mensagens pop-up oferecidas pelo JavaScript. Esses pop-ups são estilizados pelo
navegador e oferecem personalização limitada.
Alertas
O mais simples deles é referido como um alerta, que mostra um
mensagem personalizada e um único botão que dispensa o alerta, rotulado
na maioria dos navegadores como OK. Ele também pode ser dispensado na maioria dos navegadores
pressionando o botão Fechar, mas isso sempre fará a mesma coisa que
o botão OK. Veja um exemplo de alerta .
O WebDriver pode obter o texto do pop-up e aceitar ou dispensar esses
alertas.
//Click the link to activate the alert
driver.findElement(By.linkText("See an example alert")).click();//Wait for the alert to be displayed and store it in a variable
Alertalert=wait.until(ExpectedConditions.alertIsPresent());//Store the alert text in a variable
Stringtext=alert.getText();//Press the OK button
alert.accept();
# Click the link to activate the alertdriver.find_element(By.LINK_TEXT,"See an example alert").click()# Wait for the alert to be displayed and store it in a variablealert=wait.until(expected_conditions.alert_is_present())# Store the alert text in a variabletext=alert.text# Press the OK buttonalert.accept()
//Click the link to activate the alertdriver.FindElement(By.LinkText("See an example alert")).Click();//Wait for the alert to be displayed and store it in a variableIAlertalert=wait.Until(ExpectedConditions.AlertIsPresent());//Store the alert text in a variablestringtext=alert.Text;//Press the OK buttonalert.Accept();
# Click the link to activate the alertdriver.find_element(:link_text,'See an example alert').click# Store the alert reference in a variablealert=driver.switch_to.alert# Store the alert text in a variablealert_text=alert.text# Press on OK buttonalert.accept
//Click the link to activate the alert
awaitdriver.findElement(By.linkText('See an example alert')).click();// Wait for the alert to be displayed
awaitdriver.wait(until.alertIsPresent());// Store the alert in a variable
letalert=awaitdriver.switchTo().alert();//Store the alert text in a variable
letalertText=awaitalert.getText();//Press the OK button
awaitalert.accept();// Note: To use await, the above code should be inside an async function
//Click the link to activate the alert
driver.findElement(By.linkText("See an example alert")).click()//Wait for the alert to be displayed and store it in a variable
valalert=wait.until(ExpectedConditions.alertIsPresent())//Store the alert text in a variable
valtext=alert.getText()//Press the OK button
alert.accept()
Confirmação
Uma caixa de confirmação é semelhante a um alerta, exceto que o usuário também pode escolher
cancelar a mensagem. Veja
uma amostra de confirmação .
Este exemplo também mostra uma abordagem diferente para armazenar um alerta:
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample confirm")).click();//Wait for the alert to be displayed
wait.until(ExpectedConditions.alertIsPresent());//Store the alert in a variable
Alertalert=driver.switchTo().alert();//Store the alert in a variable for reuse
Stringtext=alert.getText();//Press the Cancel button
alert.dismiss();
# Click the link to activate the alertdriver.find_element(By.LINK_TEXT,"See a sample confirm").click()# Wait for the alert to be displayedwait.until(expected_conditions.alert_is_present())# Store the alert in a variable for reusealert=driver.switch_to.alert# Store the alert text in a variabletext=alert.text# Press the Cancel buttonalert.dismiss()
//Click the link to activate the alertdriver.FindElement(By.LinkText("See a sample confirm")).Click();//Wait for the alert to be displayedwait.Until(ExpectedConditions.AlertIsPresent());//Store the alert in a variableIAlertalert=driver.SwitchTo().Alert();//Store the alert in a variable for reusestringtext=alert.Text;//Press the Cancel buttonalert.Dismiss();
# Click the link to activate the alertdriver.find_element(:link_text,'See a sample confirm').click# Store the alert reference in a variablealert=driver.switch_to.alert# Store the alert text in a variablealert_text=alert.text# Press on Cancel buttonalert.dismiss
//Click the link to activate the alert
awaitdriver.findElement(By.linkText('See a sample confirm')).click();// Wait for the alert to be displayed
awaitdriver.wait(until.alertIsPresent());// Store the alert in a variable
letalert=awaitdriver.switchTo().alert();//Store the alert text in a variable
letalertText=awaitalert.getText();//Press the Cancel button
awaitalert.dismiss();// Note: To use await, the above code should be inside an async function
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample confirm")).click()//Wait for the alert to be displayed
wait.until(ExpectedConditions.alertIsPresent())//Store the alert in a variable
valalert=driver.switchTo().alert()//Store the alert in a variable for reuse
valtext=alert.text//Press the Cancel button
alert.dismiss()
Prompt
Os prompts são semelhantes às caixas de confirmação, exceto que também incluem um texto de
entrada. Semelhante a trabalhar com elementos de formulário, você pode
usar o sendKeys do WebDriver para preencher uma resposta. Isso substituirá
completamente o espaço de texto de exemplo. Pressionar o botão Cancelar não enviará nenhum texto.
Veja um exemplo de prompt .
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample prompt")).click();//Wait for the alert to be displayed and store it in a variable
Alertalert=wait.until(ExpectedConditions.alertIsPresent());//Type your message
alert.sendKeys("Selenium");//Press the OK button
alert.accept();
# Click the link to activate the alertdriver.find_element(By.LINK_TEXT,"See a sample prompt").click()# Wait for the alert to be displayedwait.until(expected_conditions.alert_is_present())# Store the alert in a variable for reusealert=Alert(driver)# Type your messagealert.send_keys("Selenium")# Press the OK buttonalert.accept()
//Click the link to activate the alertdriver.FindElement(By.LinkText("See a sample prompt")).Click();//Wait for the alert to be displayed and store it in a variableIAlertalert=wait.Until(ExpectedConditions.AlertIsPresent());//Type your messagealert.SendKeys("Selenium");//Press the OK buttonalert.Accept();
# Click the link to activate the alertdriver.find_element(:link_text,'See a sample prompt').click# Store the alert reference in a variablealert=driver.switch_to.alert# Type a messagealert.send_keys("selenium")# Press on Ok buttonalert.accept
//Click the link to activate the alert
awaitdriver.findElement(By.linkText('See a sample prompt')).click();// Wait for the alert to be displayed
awaitdriver.wait(until.alertIsPresent());// Store the alert in a variable
letalert=awaitdriver.switchTo().alert();//Type your message
awaitalert.sendKeys("Selenium");//Press the OK button
awaitalert.accept();//Note: To use await, the above code should be inside an async function
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample prompt")).click()//Wait for the alert to be displayed and store it in a variable
valalert=wait.until(ExpectedConditions.alertIsPresent())//Type your message
alert.sendKeys("Selenium")//Press the OK button
alert.accept()
2.6.3 - Trabalhando com cookies
Um cookie é um pequeno pedaço de dado enviado de um site e armazenado no seu computador.
Os cookies são usados principalmente para reconhecer o usuário e carregar as informações armazenadas.
A API WebDriver fornece uma maneira de interagir com cookies com métodos integrados:
Add Cookie
É usado para adicionar um cookie ao contexto de navegação atual.
Add Cookie aceita apenas um conjunto de objetos JSON serializáveis definidos. Aqui
é o link para a lista de valores-chave JSON aceitos.
Em primeiro lugar, você precisa estar no domínio para qual o cookie será
valido. Se você está tentando predefinir cookies antes
de começar a interagir com um site e sua página inicial é grande / demora um pouco para carregar
uma alternativa é encontrar uma página menor no site (normalmente a página 404 é pequena,
por exemplo http://example.com/some404page)
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;publicclassaddCookie{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.example.com");// Adds the cookie into current browser context
driver.manage().addCookie(newCookie("key","value"));}finally{driver.quit();}}}
fromseleniumimportwebdriverdriver=webdriver.Chrome()driver.get("http://www.example.com")# Adds the cookie into current browser contextdriver.add_cookie({"name":"key","value":"value"})
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceAddCookie{classAddCookie{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");// Adds the cookie into current browser contextdriver.Manage().Cookies.AddCookie(newCookie("key","value"));}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'# Adds the cookie into current browser contextdriver.manage.add_cookie(name:"key",value:"value")ensuredriver.quitend
it('Create a cookie',asyncfunction(){awaitdriver.get('https://www.example.com');// set a cookie on the current domain
awaitdriver.manage().addCookie({name:'key',value:'value'});
importorg.openqa.selenium.Cookieimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")// Adds the cookie into current browser context
driver.manage().addCookie(Cookie("key","value"))}finally{driver.quit()}}
Get Named Cookie
Retorna os dados do cookie serializado correspondentes ao nome do cookie entre todos os cookies associados.
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;publicclassgetCookieNamed{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.example.com");driver.manage().addCookie(newCookie("foo","bar"));// Get cookie details with named cookie 'foo'
Cookiecookie1=driver.manage().getCookieNamed("foo");System.out.println(cookie1);}finally{driver.quit();}}}
fromseleniumimportwebdriverdriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")# Adds the cookie into current browser contextdriver.add_cookie({"name":"foo","value":"bar"})# Get cookie details with named cookie 'foo'print(driver.get_cookie("foo"))
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceGetCookieNamed{classGetCookieNamed{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");driver.Manage().Cookies.AddCookie(newCookie("foo","bar"));// Get cookie details with named cookie 'foo'varcookie=driver.Manage().Cookies.GetCookieNamed("foo");System.Console.WriteLine(cookie);}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'driver.manage.add_cookie(name:"foo",value:"bar")# Get cookie details with named cookie 'foo'putsdriver.manage.cookie_named('foo')ensuredriver.quitend
it('Read cookie',asyncfunction(){awaitdriver.get('https://www.example.com');// set a cookie on the current domain
awaitdriver.manage().addCookie({name:'foo',value:'bar'});// Get cookie details with named cookie 'foo'
awaitdriver.manage().getCookie('foo').then(function(cookie){console.log('cookie details => ',cookie);});
importorg.openqa.selenium.Cookieimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")driver.manage().addCookie(Cookie("foo","bar"))// Get cookie details with named cookie 'foo'
valcookie=driver.manage().getCookieNamed("foo")println(cookie)}finally{driver.quit()}}
Get All Cookies
Retorna ‘dados de cookie serializados com sucesso’ para o contexto de navegação atual.
Se o navegador não estiver mais disponível, ele retornará um erro.
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;importjava.util.Set;publicclassgetAllCookies{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.example.com");// Add few cookies
driver.manage().addCookie(newCookie("test1","cookie1"));driver.manage().addCookie(newCookie("test2","cookie2"));// Get All available cookies
Set<Cookie>cookies=driver.manage().getCookies();System.out.println(cookies);}finally{driver.quit();}}}
fromseleniumimportwebdriverdriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")driver.add_cookie({"name":"test1","value":"cookie1"})driver.add_cookie({"name":"test2","value":"cookie2"})# Get all available cookiesprint(driver.get_cookies())
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceGetAllCookies{classGetAllCookies{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");driver.Manage().Cookies.AddCookie(newCookie("test1","cookie1"));driver.Manage().Cookies.AddCookie(newCookie("test2","cookie2"));// Get All available cookiesvarcookies=driver.Manage().Cookies.AllCookies;}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'driver.manage.add_cookie(name:"test1",value:"cookie1")driver.manage.add_cookie(name:"test2",value:"cookie2")# Get all available cookiesputsdriver.manage.all_cookiesensuredriver.quitend
it('Read all cookies',asyncfunction(){awaitdriver.get('https://www.example.com');// Add few cookies
awaitdriver.manage().addCookie({name:'test1',value:'cookie1'});awaitdriver.manage().addCookie({name:'test2',value:'cookie2'});// Get all Available cookies
awaitdriver.manage().getCookies().then(function(cookies){console.log('cookie details => ',cookies);});
importorg.openqa.selenium.Cookieimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")driver.manage().addCookie(Cookie("test1","cookie1"))driver.manage().addCookie(Cookie("test2","cookie2"))// Get All available cookies
valcookies=driver.manage().cookiesprintln(cookies)}finally{driver.quit()}}
Delete Cookie
Exclui os dados do cookie que correspondem ao nome do cookie fornecido.
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;publicclassdeleteCookie{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.example.com");driver.manage().addCookie(newCookie("test1","cookie1"));Cookiecookie1=newCookie("test2","cookie2");driver.manage().addCookie(cookie1);// delete a cookie with name 'test1'
driver.manage().deleteCookieNamed("test1");/*
Selenium Java bindings also provides a way to delete
cookie by passing cookie object of current browsing context
*/driver.manage().deleteCookie(cookie1);}finally{driver.quit();}}}
fromseleniumimportwebdriverdriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")driver.add_cookie({"name":"test1","value":"cookie1"})driver.add_cookie({"name":"test2","value":"cookie2"})# Delete a cookie with name 'test1'driver.delete_cookie("test1")
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceDeleteCookie{classDeleteCookie{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");driver.Manage().Cookies.AddCookie(newCookie("test1","cookie1"));varcookie=newCookie("test2","cookie2");driver.Manage().Cookies.AddCookie(cookie);// delete a cookie with name 'test1' driver.Manage().Cookies.DeleteCookieNamed("test1");// Selenium .net bindings also provides a way to delete// cookie by passing cookie object of current browsing contextdriver.Manage().Cookies.DeleteCookie(cookie);}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'driver.manage.add_cookie(name:"test1",value:"cookie1")driver.manage.add_cookie(name:"test2",value:"cookie2")# delete a cookie with name 'test1'driver.manage.delete_cookie('test1')ensuredriver.quitend
it('Delete a cookie',asyncfunction(){awaitdriver.get('https://www.example.com');// Add few cookies
awaitdriver.manage().addCookie({name:'test1',value:'cookie1'});awaitdriver.manage().addCookie({name:'test2',value:'cookie2'});// Delete a cookie with name 'test1'
awaitdriver.manage().deleteCookie('test1');// Get all Available cookies
awaitdriver.manage().getCookies().then(function(cookies){console.log('cookie details => ',cookies);});
importorg.openqa.selenium.Cookieimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")driver.manage().addCookie(Cookie("test1","cookie1"))valcookie1=Cookie("test2","cookie2")driver.manage().addCookie(cookie1)// delete a cookie with name 'test1'
driver.manage().deleteCookieNamed("test1")// delete cookie by passing cookie object of current browsing context.
driver.manage().deleteCookie(cookie1)}finally{driver.quit()}}
Delete All Cookies
Exclui todos os cookies do contexto de navegação atual.
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;publicclassdeleteAllCookies{publicstaticvoidmain(String[]args){WebDriverdriver=newChromeDriver();try{driver.get("http://www.example.com");driver.manage().addCookie(newCookie("test1","cookie1"));driver.manage().addCookie(newCookie("test2","cookie2"));// deletes all cookies
driver.manage().deleteAllCookies();}finally{driver.quit();}}}
fromseleniumimportwebdriverdriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")driver.add_cookie({"name":"test1","value":"cookie1"})driver.add_cookie({"name":"test2","value":"cookie2"})# Deletes all cookiesdriver.delete_all_cookies()
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;namespaceDeleteAllCookies{classDeleteAllCookies{publicstaticvoidMain(string[]args){IWebDriverdriver=newChromeDriver();try{// Navigate to Urldriver.Navigate().GoToUrl("https://example.com");driver.Manage().Cookies.AddCookie(newCookie("test1","cookie1"));driver.Manage().Cookies.AddCookie(newCookie("test2","cookie2"));// deletes all cookiesdriver.Manage().Cookies.DeleteAllCookies();}finally{driver.Quit();}}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'driver.manage.add_cookie(name:"test1",value:"cookie1")driver.manage.add_cookie(name:"test2",value:"cookie2")# deletes all cookiesdriver.manage.delete_all_cookiesensuredriver.quitend
it('Delete all cookies',asyncfunction(){awaitdriver.get('https://www.example.com');// Add few cookies
awaitdriver.manage().addCookie({name:'test1',value:'cookie1'});awaitdriver.manage().addCookie({name:'test2',value:'cookie2'});// Delete all cookies
awaitdriver.manage().deleteAllCookies();
importorg.openqa.selenium.Cookieimportorg.openqa.selenium.chrome.ChromeDriverfunmain(){valdriver=ChromeDriver()try{driver.get("https://example.com")driver.manage().addCookie(Cookie("test1","cookie1"))driver.manage().addCookie(Cookie("test2","cookie2"))// deletes all cookies
driver.manage().deleteAllCookies()}finally{driver.quit()}}
Same-Site Cookie Attribute
Permite que um usuário instrua os navegadores a controlar se os cookies
são enviados junto com a solicitação iniciada por sites de terceiros.
É usado para evitar ataques CSRF (Cross-Site Request Forgery).
O atributo de cookie Same-Site aceita dois parâmetros como instruções
Strict:
Quando o atributo sameSite é definido como Strict,
o cookie não será enviado junto com
solicitações iniciadas por sites de terceiros.
Lax:
Quando você define um atributo cookie sameSite como Lax,
o cookie será enviado junto com uma solicitação GET
iniciada por um site de terceiros.
Nota: a partir de agora, esse recurso está disponível no Chrome (versão 80+),
Firefox (versão 79+) e funciona com Selenium 4 e versões posteriores.
fromseleniumimportwebdriverdriver=webdriver.Chrome()driver.get("http://www.example.com")# Adds the cookie into current browser context with sameSite 'Strict' (or) 'Lax'driver.add_cookie({"name":"foo","value":"value",'sameSite':'Strict'})driver.add_cookie({"name":"foo1","value":"value",'sameSite':'Lax'})cookie1=driver.get_cookie('foo')cookie2=driver.get_cookie('foo1')print(cookie1)print(cookie2)
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://www.example.com'# Adds the cookie into current browser context with sameSite 'Strict' (or) 'Lax'driver.manage.add_cookie(name:"foo",value:"bar",same_site:"Strict")driver.manage.add_cookie(name:"foo1",value:"bar",same_site:"Lax")putsdriver.manage.cookie_named('foo')putsdriver.manage.cookie_named('foo1')ensuredriver.quitend
it('Create cookies with sameSite',asyncfunction(){awaitdriver.get('https://www.example.com');// set a cookie on the current domain with sameSite 'Strict' (or) 'Lax'
awaitdriver.manage().addCookie({name:'key',value:'value',sameSite:'Strict'});awaitdriver.manage().addCookie({name:'key',value:'value',sameSite:'Lax'});
Frames são um meio obsoleto de construir um layout de site a partir de
vários documentos no mesmo domínio. É improvável que você trabalhe com eles
a menos que você esteja trabalhando com um webapp pré-HTML5. Iframes permitem
a inserção de um documento de um domínio totalmente diferente, e são
ainda comumente usado.
Se você precisa trabalhar com frames ou iframes, o WebDriver permite que você
trabalhe com eles da mesma maneira. Considere um botão dentro de um iframe.
Se inspecionarmos o elemento usando as ferramentas de desenvolvimento do navegador, podemos
ver o seguinte:
# This won't workdriver.find_element(:tag_name,'button').click
// This won't work
awaitdriver.findElement(By.css('button')).click();
//This won't work
driver.findElement(By.tagName("button")).click()
No entanto, se não houver botões fora do iframe, você pode
em vez disso, obter um erro no such element. Isso acontece porque o Selenium é
ciente apenas dos elementos no documento de nível superior. Para interagir com
o botão, precisamos primeiro mudar para o quadro, de forma semelhante
a como alternamos janelas. WebDriver oferece três maneiras de mudar para
um frame.
Usando um WebElement
Alternar usando um WebElement é a opção mais flexível. Você pode
encontrar o quadro usando seu seletor preferido e mudar para ele.
//Store the web element
WebElementiframe=driver.findElement(By.cssSelector("#modal>iframe"));//Switch to the frame
driver.switchTo().frame(iframe);//Now we can click the button
driver.findElement(By.tagName("button")).click();
# Store iframe web elementiframe=driver.find_element(By.CSS_SELECTOR,"#modal > iframe")# switch to selected iframedriver.switch_to.frame(iframe)# Now click on buttondriver.find_element(By.TAG_NAME,'button').click()
//Store the web elementIWebElementiframe=driver.FindElement(By.CssSelector("#modal>iframe"));//Switch to the framedriver.SwitchTo().Frame(iframe);//Now we can click the buttondriver.FindElement(By.TagName("button")).Click();
# Store iframe web elementiframe=driver.find_element(:css,'#modal > iframe')# Switch to the framedriver.switch_to.frameiframe# Now, Click on the buttondriver.find_element(:tag_name,'button').click
// Store the web element
constiframe=driver.findElement(By.css('#modal > iframe'));// Switch to the frame
awaitdriver.switchTo().frame(iframe);// Now we can click the button
awaitdriver.findElement(By.css('button')).click();
//Store the web element
valiframe=driver.findElement(By.cssSelector("#modal>iframe"))//Switch to the frame
driver.switchTo().frame(iframe)//Now we can click the button
driver.findElement(By.tagName("button")).click()
Usando um name ou ID
Se o seu frame ou iframe tiver um atributo id ou name, ele pode ser
usado alternativamente. Se o name ou ID não for exclusivo na página, o
primeiro encontrado será utilizado.
//Using the ID
driver.switchTo().frame("buttonframe");//Or using the name instead
driver.switchTo().frame("myframe");//Now we can click the button
driver.findElement(By.tagName("button")).click();
# Switch frame by iddriver.switch_to.frame('buttonframe')# Now, Click on the buttondriver.find_element(By.TAG_NAME,'button').click()
//Using the IDdriver.SwitchTo().Frame("buttonframe");//Or using the name insteaddriver.SwitchTo().Frame("myframe");//Now we can click the buttondriver.FindElement(By.TagName("button")).Click();
# Switch by IDdriver.switch_to.frame'buttonframe'# Now, Click on the buttondriver.find_element(:tag_name,'button').click
// Using the ID
awaitdriver.switchTo().frame('buttonframe');// Or using the name instead
awaitdriver.switchTo().frame('myframe');// Now we can click the button
awaitdriver.findElement(By.css('button')).click();
//Using the ID
driver.switchTo().frame("buttonframe")//Or using the name instead
driver.switchTo().frame("myframe")//Now we can click the button
driver.findElement(By.tagName("button")).click()
Usando um índice
Também é possível usar o índice do frame, podendo ser
consultado usando window.frames em JavaScript.
// Switches to the second frame
driver.switchTo().frame(1);
# Switch to the second framedriver.switch_to.frame(1)
// Switches to the second framedriver.SwitchTo().Frame(1);
# switching to second iframe based on indexiframe=driver.find_elements(By.TAG_NAME,'iframe')[1]# switch to selected iframedriver.switch_to.frame(iframe)
// Switches to the second frame
awaitdriver.switchTo().frame(1);
// Switches to the second frame
driver.switchTo().frame(1)
Deixando um frame
Para deixar um iframe ou frameset, volte para o conteúdo padrão
como a seguir:
// Return to the top level
driver.switchTo().defaultContent();
# switch back to default contentdriver.switch_to.default_content()
// Return to the top leveldriver.SwitchTo().DefaultContent();
# Return to the top leveldriver.switch_to.default_content
// Return to the top level
awaitdriver.switchTo().defaultContent();
// Return to the top level
driver.switchTo().defaultContent()
2.6.5 - Working with windows and tabs
Janelas e guias
Pegue o idenficador da janela
O WebDriver não faz distinção entre janelas e guias. E se
seu site abre uma nova guia ou janela, o Selenium permitirá que você trabalhe
usando um identificador. Cada janela tem um identificador único que permanece
persistente em uma única sessão. Você pode pegar o identificador atual usando:
Clicar em um link que abre em uma
nova janela
focará a nova janela ou guia na tela, mas o WebDriver não saberá qual
janela que o sistema operacional considera ativa. Para trabalhar com a nova janela
você precisará mudar para ela. Se você tiver apenas duas guias ou janelas abertas,
e você sabe com qual janela você iniciou, pelo processo de eliminação
você pode percorrer as janelas ou guias que o WebDriver pode ver e alternar
para aquela que não é o original.
No entanto, o Selenium 4 fornece uma nova API NewWindow
que cria uma nova guia (ou) nova janela e muda automaticamente para ela.
//Store the ID of the original window
StringoriginalWindow=driver.getWindowHandle();//Check we don't have other windows open already
assertdriver.getWindowHandles().size()==1;//Click the link which opens in a new window
driver.findElement(By.linkText("new window")).click();//Wait for the new window or tab
wait.until(numberOfWindowsToBe(2));//Loop through until we find a new window handle
for(StringwindowHandle:driver.getWindowHandles()){if(!originalWindow.contentEquals(windowHandle)){driver.switchTo().window(windowHandle);break;}}//Wait for the new tab to finish loading content
wait.until(titleIs("Selenium documentation"));
fromseleniumimportwebdriverfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasEC# Start the driverwithwebdriver.Firefox()asdriver:# Open URLdriver.get("https://seleniumhq.github.io")# Setup wait for laterwait=WebDriverWait(driver,10)# Store the ID of the original windoworiginal_window=driver.current_window_handle# Check we don't have other windows open alreadyassertlen(driver.window_handles)==1# Click the link which opens in a new windowdriver.find_element(By.LINK_TEXT,"new window").click()# Wait for the new window or tabwait.until(EC.number_of_windows_to_be(2))# Loop through until we find a new window handleforwindow_handleindriver.window_handles:ifwindow_handle!=original_window:driver.switch_to.window(window_handle)break# Wait for the new tab to finish loading contentwait.until(EC.title_is("SeleniumHQ Browser Automation"))
//Store the ID of the original windowstringoriginalWindow=driver.CurrentWindowHandle;//Check we don't have other windows open alreadyAssert.AreEqual(driver.WindowHandles.Count,1);//Click the link which opens in a new windowdriver.FindElement(By.LinkText("new window")).Click();//Wait for the new window or tabwait.Until(wd=>wd.WindowHandles.Count==2);//Loop through until we find a new window handleforeach(stringwindowindriver.WindowHandles){if(originalWindow!=window){driver.SwitchTo().Window(window);break;}}//Wait for the new tab to finish loading contentwait.Until(wd=>wd.Title=="Selenium documentation");
#Store the ID of the original windoworiginal_window=driver.window_handle#Check we don't have other windows open alreadyassert(driver.window_handles.length==1,'Expected one window')#Click the link which opens in a new windowdriver.find_element(link:'new window').click#Wait for the new window or tabwait.until{driver.window_handles.length==2}#Loop through until we find a new window handledriver.window_handles.eachdo|handle|ifhandle!=original_windowdriver.switch_to.windowhandlebreakendend#Wait for the new tab to finish loading contentwait.until{driver.title=='Selenium documentation'}
//Store the ID of the original window
constoriginalWindow=awaitdriver.getWindowHandle();//Check we don't have other windows open already
assert((awaitdriver.getAllWindowHandles()).length===1);//Click the link which opens in a new window
awaitdriver.findElement(By.linkText('new window')).click();//Wait for the new window or tab
awaitdriver.wait(async()=>(awaitdriver.getAllWindowHandles()).length===2,10000);//Loop through until we find a new window handle
constwindows=awaitdriver.getAllWindowHandles();windows.forEach(asynchandle=>{if(handle!==originalWindow){awaitdriver.switchTo().window(handle);}});//Wait for the new tab to finish loading content
awaitdriver.wait(until.titleIs('Selenium documentation'),10000);
//Store the ID of the original window
valoriginalWindow=driver.getWindowHandle()//Check we don't have other windows open already
assert(driver.getWindowHandles().size()===1)//Click the link which opens in a new window
driver.findElement(By.linkText("new window")).click()//Wait for the new window or tab
wait.until(numberOfWindowsToBe(2))//Loop through until we find a new window handle
for(windowHandleindriver.getWindowHandles()){if(!originalWindow.contentEquals(windowHandle)){driver.switchTo().window(windowHandle)break}}//Wait for the new tab to finish loading content
wait.until(titleIs("Selenium documentation"))
Criar nova janela (ou) nova guia e alternar
Cria uma nova janela (ou) guia e focará a nova janela ou guia na tela.
Você não precisa mudar para trabalhar com a nova janela (ou) guia. Se você tiver mais de duas janelas
(ou) guias abertas diferentes da nova janela, você pode percorrer as janelas ou guias que o WebDriver pode ver
e mudar para aquela que não é a original.
Nota: este recurso funciona com Selenium 4 e versões posteriores.
// Opens a new tab and switches to new tab
driver.switchTo().newWindow(WindowType.TAB);// Opens a new window and switches to new window
driver.switchTo().newWindow(WindowType.WINDOW);
# Opens a new tab and switches to new tabdriver.switch_to.new_window('tab')# Opens a new window and switches to new windowdriver.switch_to.new_window('window')
// Opens a new tab and switches to new tabdriver.SwitchTo().NewWindow(WindowType.Tab)// Opens a new window and switches to new windowdriver.SwitchTo().NewWindow(WindowType.Window)
# Note: The new_window in ruby only opens a new tab (or) Window and will not switch automatically# The user has to switch to new tab (or) new window# Opens a new tab and switches to new tabdriver.manage.new_window(:tab)# Opens a new window and switches to new windowdriver.manage.new_window(:window)
// Opens a new tab and switches to new tab
awaitdriver.switchTo().newWindow('tab');// Opens a new window and switches to new window
awaitdriver.switchTo().newWindow('window');
// Opens a new tab and switches to new tab
driver.switchTo().newWindow(WindowType.TAB)// Opens a new window and switches to new window
driver.switchTo().newWindow(WindowType.WINDOW)
Fechando uma janela ou guia
Quando você fechar uma janela ou guia e que não é a
última janela ou guia aberta em seu navegador, você deve fechá-la e alternar
de volta para a janela que você estava usando anteriormente. Supondo que você seguiu a
amostra de código na seção anterior, você terá o identificador da janela
anterior armazenado em uma variável. Junte isso e você obterá:
//Close the tab or window
driver.close();//Switch back to the old tab or window
driver.switchTo().window(originalWindow);
#Close the tab or windowdriver.close()#Switch back to the old tab or windowdriver.switch_to.window(original_window)
//Close the tab or windowdriver.Close();//Switch back to the old tab or windowdriver.SwitchTo().Window(originalWindow);
#Close the tab or windowdriver.close#Switch back to the old tab or windowdriver.switch_to.windoworiginal_window
//Close the tab or window
awaitdriver.close();//Switch back to the old tab or window
awaitdriver.switchTo().window(originalWindow);
//Close the tab or window
driver.close()//Switch back to the old tab or window
driver.switchTo().window(originalWindow)
Esquecer de voltar para outro gerenciador de janela após fechar uma
janela deixará o WebDriver em execução na página agora fechada e
acionara uma No Such Window Exception. Você deve trocar
de volta para um identificador de janela válido para continuar a execução.
Sair do navegador no final de uma sessão
Quando você terminar a sessão do navegador, você deve chamar a função quit(),
em vez de fechar:
/**
* Example using JUnit
* https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html
*/@AfterAllpublicstaticvoidtearDown(){driver.quit();}
/*
Example using Visual Studio's UnitTesting
https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.aspx
*/[TestCleanup]publicvoidTearDown(){driver.Quit();}
/**
* Example using Mocha
* https://mochajs.org/#hooks
*/after('Tear down',asyncfunction(){awaitdriver.quit();});
/**
* Example using JUnit
* https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html
*/@AfterAllfuntearDown(){driver.quit()}
Se não estiver executando o WebDriver em um contexto de teste, você pode considerar o uso do
try/finally que é oferecido pela maioria das linguagens para que uma exceção
ainda limpe a sessão do WebDriver.
O WebDriver do Python agora suporta o gerenciador de contexto python,
que ao usar a palavra-chave with pode encerrar automaticamente o
driver no fim da execução.
withwebdriver.Firefox()asdriver:# WebDriver code here...# WebDriver will automatically quit after indentation
Gerenciamento de janelas
A resolução da tela pode impactar como seu aplicativo da web é renderizado, então
WebDriver fornece mecanismos para mover e redimensionar a janela do navegador.
//Access each dimension individually
intwidth=driver.manage().window().getSize().getWidth();intheight=driver.manage().window().getSize().getHeight();//Or store the dimensions and query them later
Dimensionsize=driver.manage().window().getSize();intwidth1=size.getWidth();intheight1=size.getHeight();
# Access each dimension individuallywidth=driver.get_window_size().get("width")height=driver.get_window_size().get("height")# Or store the dimensions and query them latersize=driver.get_window_size()width1=size.get("width")height1=size.get("height")
//Access each dimension individuallyintwidth=driver.Manage().Window.Size.Width;intheight=driver.Manage().Window.Size.Height;//Or store the dimensions and query them laterSystem.Drawing.Sizesize=driver.Manage().Window.Size;intwidth1=size.Width;intheight1=size.Height;
# Access each dimension individuallywidth=driver.manage.window.size.widthheight=driver.manage.window.size.height# Or store the dimensions and query them latersize=driver.manage.window.sizewidth1=size.widthheight1=size.height
// Access each dimension individually
const{width,height}=awaitdriver.manage().window().getRect();// Or store the dimensions and query them later
constrect=awaitdriver.manage().window().getRect();constwidth1=rect.width;constheight1=rect.height;
//Access each dimension individually
valwidth=driver.manage().window().size.widthvalheight=driver.manage().window().size.height//Or store the dimensions and query them later
valsize=driver.manage().window().sizevalwidth1=size.widthvalheight1=size.height
// Access each dimension individually
intx=driver.manage().window().getPosition().getX();inty=driver.manage().window().getPosition().getY();// Or store the dimensions and query them later
Pointposition=driver.manage().window().getPosition();intx1=position.getX();inty1=position.getY();
# Access each dimension individuallyx=driver.get_window_position().get('x')y=driver.get_window_position().get('y')# Or store the dimensions and query them laterposition=driver.get_window_position()x1=position.get('x')y1=position.get('y')
//Access each dimension individuallyintx=driver.Manage().Window.Position.X;inty=driver.Manage().Window.Position.Y;//Or store the dimensions and query them laterPointposition=driver.Manage().Window.Position;intx1=position.X;inty1=position.Y;
#Access each dimension individuallyx=driver.manage.window.position.xy=driver.manage.window.position.y# Or store the dimensions and query them laterrect=driver.manage.window.rectx1=rect.xy1=rect.y
// Access each dimension individually
const{x,y}=awaitdriver.manage().window().getRect();// Or store the dimensions and query them later
constrect=awaitdriver.manage().window().getRect();constx1=rect.x;consty1=rect.y;
// Access each dimension individually
valx=driver.manage().window().position.xvaly=driver.manage().window().position.y// Or store the dimensions and query them later
valposition=driver.manage().window().positionvalx1=position.xvaly1=position.y
// Move the window to the top left of the primary monitor
driver.manage().window().setPosition(newPoint(0,0));
# Move the window to the top left of the primary monitordriver.set_window_position(0,0)
// Move the window to the top left of the primary monitordriver.Manage().Window.Position=newPoint(0,0);
driver.manage.window.move_to(0,0)
// Move the window to the top left of the primary monitor
awaitdriver.manage().window().setRect({x:0,y:0});
// Move the window to the top left of the primary monitor
driver.manage().window().position=Point(0,0)
Maximizar janela
Aumenta a janela. Para a maioria dos sistemas operacionais, a janela irá preencher
a tela, sem bloquear os próprios menus do sistema operacional e
barras de ferramentas.
fromseleniumimportwebdriverdriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")# Returns and base64 encoded string into imagedriver.save_screenshot('./image.png')driver.quit()
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.Support.UI;vardriver=newChromeDriver();driver.Navigate().GoToUrl("http://www.example.com");Screenshotscreenshot=(driverasITakesScreenshot).GetScreenshot();screenshot.SaveAsFile("screenshot.png",ScreenshotImageFormat.Png);// Format values are Bmp, Gif, Jpeg, Png, Tiff
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://example.com/'# Takes and Stores the screenshot in specified pathdriver.save_screenshot('./image.png')end
Usado para capturar a imagem de um elemento para o contexto de navegação atual.
O endpoint WebDriver screenshot
retorna a captura de tela codificada no formato Base64.
fromseleniumimportwebdriverfromselenium.webdriver.common.byimportBydriver=webdriver.Chrome()# Navigate to urldriver.get("http://www.example.com")ele=driver.find_element(By.CSS_SELECTOR,'h1')# Returns and base64 encoded string into imageele.screenshot('./image.png')driver.quit()
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.Support.UI;// Webdrivervardriver=newChromeDriver();driver.Navigate().GoToUrl("http://www.example.com");// Fetch element using FindElementvarwebElement=driver.FindElement(By.CssSelector("h1"));// Screenshot for the elementvarelementScreenshot=(webElementasITakesScreenshot).GetScreenshot();elementScreenshot.SaveAsFile("screenshot_of_element.png");
# Works with Selenium4-alpha7 Ruby bindings and aboverequire'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'https://example.com/'ele=driver.find_element(:css,'h1')# Takes and Stores the element screenshot in specified pathele.save_screenshot('./image.jpg')end
const{Builder,By}=require('selenium-webdriver');letfs=require('fs');(asyncfunctionexample(){letdriver=awaitnewBuilder().forBrowser('chrome').build();awaitdriver.get('https://www.example.com');letele=awaitdriver.findElement(By.css("h1"));// Captures the element screenshot
letencodedString=awaitele.takeScreenshot(true);awaitfs.writeFileSync('./image.png',encodedString,'base64');awaitdriver.quit();}())
//Creating the JavascriptExecutor interface object by Type casting
JavascriptExecutorjs=(JavascriptExecutor)driver;//Button Element
WebElementbutton=driver.findElement(By.name("btnLogin"));//Executing JavaScript to click on element
js.executeScript("arguments[0].click();",button);//Get return value from script
Stringtext=(String)js.executeScript("return arguments[0].innerText",button);//Executing JavaScript directly
js.executeScript("console.log('hello world')");
# Stores the header elementheader=driver.find_element(By.CSS_SELECTOR,"h1")# Executing JavaScript to capture innerText of header elementdriver.execute_script('return arguments[0].innerText',header)
//creating Chromedriver instanceIWebDriverdriver=newChromeDriver();//Creating the JavascriptExecutor interface object by Type castingIJavaScriptExecutorjs=(IJavaScriptExecutor)driver;//Button ElementIWebElementbutton=driver.FindElement(By.Name("btnLogin"));//Executing JavaScript to click on elementjs.ExecuteScript("arguments[0].click();",button);//Get return value from scriptStringtext=(String)js.ExecuteScript("return arguments[0].innerText",button);//Executing JavaScript directlyjs.ExecuteScript("console.log('hello world')");
# Stores the header elementheader=driver.find_element(css:'h1')# Get return value from scriptresult=driver.execute_script("return arguments[0].innerText",header)# Executing JavaScript directlydriver.execute_script("alert('hello world')")
// Stores the header element
letheader=awaitdriver.findElement(By.css('h1'));// Executing JavaScript to capture innerText of header element
lettext=awaitdriver.executeScript('return arguments[0].innerText',header);
// Stores the header element
valheader=driver.findElement(By.cssSelector("h1"))// Get return value from script
valresult=driver.executeScript("return arguments[0].innerText",header)// Executing JavaScript directly
driver.executeScript("alert('hello world')")
Imprimir Página
Imprime a página atual dentro do navegador
Nota: isto requer que navegadores Chromium estejam no modo sem cabeçalho
Aplicações web podem habilitar um mecanismo de autenticação baseado em chaves públicas conhecido como Web Authentication para autenticar usuários sem usar uma senha.
Web Authentication define APIs que permitem ao usuário criar uma credencial e registra-la com um autenticador.
Um autenticador pode ser um dispositivo ou um software que guarde as chaves públicas do usuário e as acesse caso seja pedido.
Como o nome sugere, Virtual Authenticator emula esses autenticadores para testes.
Virtual Authenticator Options
Um Autenticador Virtual tem uma série de propriedades.
Essas propriedades são mapeadas como VirtualAuthenticatorOptions nos bindings do Selenium.
A low-level interface for providing virtualized device input actions to the web browser.
In addition to the high-level element interactions,
the Actions API provides granular control over
exactly what designated input devices can do. Selenium provides an interface for 3 kinds of input sources:
a key input for keyboard devices, a pointer input for a mouse, pen or touch devices,
and wheel inputs for scroll wheel devices (introduced in Selenium 4.2).
Selenium allows you to construct individual action commands assigned to specific
inputs and chain them together and call the associated perform method to execute them all at once.
Action Builder
In the move from the legacy JSON Wire Protocol to the new W3C WebDriver Protocol,
the low level building blocks of actions became especially detailed. It is extremely
powerful, but each input device has a number of ways to use it and if you need to
manage more than one device, you are responsible for ensuring proper synchronization between them.
Thankfully, you likely do not need to learn how to use the low level commands directly, since
almost everything you might want to do has been given a convenience method that combines the
lower level commands for you. These are all documented in
keyboard, mouse, pen, and wheel pages.
Pause
Pointer movements and Wheel scrolling allow the user to set a duration for the action, but sometimes you just need
to wait a beat between actions for things to work correctly.
An important thing to note is that the driver remembers the state of all the input
items throughout a session. Even if you create a new instance of an actions class, the depressed keys and
the location of the pointer will be in whatever state a previously performed action left them.
There is a special method to release all currently depressed keys and pointer buttons.
This method is implemented differently in each of the languages because
it does not get executed with the perform method.
A representation of any key input device for interacting with a web page.
There are only 2 actions that can be accomplished with a keyboard:
pressing down on a key, and releasing a pressed key.
In addition to supporting ASCII characters, each keyboard key has
a representation that can be pressed or released in designated sequences.
Keys
In addition to the keys represented by regular unicode,
unicode values have been assigned to other keyboard keys for use with Selenium.
Each language has its own way to reference these keys; the full list can be found
here.
This is a convenience method in the Actions API that combines keyDown and keyUp commands in one action.
Executing this command differs slightly from using the element method, but
primarily this gets used when needing to type multiple characters in the middle of other actions.
Here’s an example of using all of the above methods to conduct a copy / paste action.
Note that the key to use for this operation will be different depending on if it is a Mac OS or not.
This code will end up with the text: SeleniumSelenium!
A representation of any pointer device for interacting with a web page.
There are only 3 actions that can be accomplished with a mouse:
pressing down on a button, releasing a pressed button, and moving the mouse.
Selenium provides convenience methods that combine these actions in the most common ways.
Click and hold
This method combines moving the mouse to the center of an element with pressing the left mouse button.
This is useful for focusing a specific element:
There are a total of 5 defined buttons for a Mouse:
0 — Left Button (the default)
1 — Middle Button (currently unsupported)
2 — Right Button
3 — X1 (Back) Button
4 — X2 (Forward) Button
Context Click
This method combines moving to the center of an element with pressing and releasing the right mouse button (button 2).
This is otherwise known as “right-clicking”:
This method moves the mouse to the in-view center point of the element.
This is otherwise known as “hovering.”
Note that the element must be in the viewport or else the command will error.
These methods first move the mouse to the designated origin and then
by the number of pixels in the provided offset.
Note that the position of the mouse must be in the viewport or else the command will error.
Offset from Element
This method moves the mouse to the in-view center point of the element,
then moves by the provided offset.
This method moves the mouse from its current position by the offset provided by the user.
If the mouse has not previously been moved, the position will be in the upper left
corner of the viewport.
Note that the pointer position does not change when the page is scrolled.
Note that the first argument X specifies to move right when positive, while the second argument
Y specifies to move down when positive. So moveByOffset(30, -10) moves right 30 and up 10 from
the current mouse position.
A Pen is a type of pointer input that has most of the same behavior as a mouse, but can
also have event properties unique to a stylus. Additionally, while a mouse
has 5 buttons, a pen has 3 equivalent button states:
0 — Touch Contact (the default; equivalent to a left click)
2 — Barrel Button (equivalent to a right click)
5 — Eraser Button (currently unsupported by drivers)
This is the most common scenario. Unlike traditional click and send keys methods,
the actions class does not automatically scroll the target element into view,
so this method will need to be used if elements are not already inside the viewport.
This method takes a web element as the sole argument.
Regardless of whether the element is above or below the current viewscreen,
the viewport will be scrolled so the bottom of the element is at the bottom of the screen.
This is the second most common scenario for scrolling. Pass in an delta x and a delta y value for how much to scroll
in the right and down directions. Negative values represent left and up, respectively.
This scenario is effectively a combination of the above two methods.
To execute this use the “Scroll From” method, which takes 3 arguments.
The first represents the origination point, which we designate as the element,
and the second two are the delta x and delta y values.
If the element is out of the viewport,
it will be scrolled to the bottom of the screen, then the page will be scrolled by the provided
delta x and delta y values.
This scenario is used when you need to scroll only a portion of the screen, and it is outside the viewport.
Or is inside the viewport and the portion of the screen that must be scrolled
is a known offset away from a specific element.
This uses the “Scroll From” method again, and in addition to specifying the element,
an offset is specified to indicate the origin point of the scroll. The offset is
calculated from the center of the provided element.
If the element is out of the viewport,
it first will be scrolled to the bottom of the screen, then the origin of the scroll will be determined
by adding the offset to the coordinates of the center of the element, and finally
the page will be scrolled by the provided delta x and delta y values.
Note that if the offset from the center of the element falls outside of the viewport,
it will result in an exception.
Scroll from a offset of origin (element) by given amount
The final scenario is used when you need to scroll only a portion of the screen,
and it is already inside the viewport.
This uses the “Scroll From” method again, but the viewport is designated instead
of an element. An offset is specified from the upper left corner of the
current viewport. After the origin point is determined,
the page will be scrolled by the provided delta x and delta y values.
Note that if the offset from the upper left corner of the viewport falls outside of the screen,
it will result in an exception.
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
Selenium is working with browser vendors to create the
WebDriver BiDirectional Protocol
as a means to provide a stable, cross-browser API that uses the bidirectional
functionality useful for both browser automation generally and testing specifically.
Before now, users seeking this functionality have had to rely on
with all of its frustrations and limitations.
The traditional WebDriver model of strict request/response commands will be supplemented
with the ability to stream events from the user agent to the controlling software via WebSockets,
better matching the evented nature of the browser DOM.
As it is not a good idea to tie your tests to a specific version of any browser, the
Selenium project recommends using WebDriver BiDi wherever possible.
However, until the specification is complete there are many useful things that
CDP (Chrome DevTools Protocol) offers. To help keep your tests independent
and portable, Selenium offers some useful helper classes as well. At the
moment, they use the CDP, but soon it could be done using WebDriver BiDi.
2.8.1 - Chrome DevTools
Apesar do Selenium 4 providenciar acesso direto ao Protocolo Chrome DevTools (CDP), é altamente recomendável que você use o WebDriver Bidi APIs ao invés do acesso direto.
Muitos navegadores fornecem o “DevTools”, um conjunto de ferramentas integradas ao navegador, que
desenvolvedores podem usar para depurar web apps analisar o desempenho de suas páginas. O DevTools do Google Chrome faz o uso de um protocolo chamado Protocolo Chrome DevTools (abreviado como “CDP”).
Como o nome sugere, ele não foi projetado para testes, ou tem uma API estável, portanto, sua funcionalidade depende muito da versão do navegador de internet.
WebDriver Bidi é a próxima geração do protocolo W3C WebDriver e visa fornecer uma API estável
implementado por todos os navegadores, mas ele ainda não está completo. Até que seja, o Selenium fornece acesso ao
CDP para os navegadores que o implementam (como Google Chrome ou Microsoft Edge e
Firefox), permitindo que você aprimore seus testes de maneiras interessantes. Alguns exemplos do que você pode
fazer com ele são dadas abaixo.
Emular Geo Localização
Alguns aplicativos têm recursos e funcionalidades diferentes em diferentes
locations. Automatizar esses tipos de aplicativos é complicado porque é difícil emular
as geolocalizações no navegador usando o Selenium. Mas com a ajuda do Devtools,
podemos facilmente as emular. O trecho do código abaixo demonstra isso.
fromseleniumimportwebdriverfromselenium.webdriver.chrome.serviceimportServicedefgeoLocationTest():driver=webdriver.Chrome()Map_coordinates=dict({"latitude":41.8781,"longitude":-87.6298,"accuracy":100})driver.execute_cdp_cmd("Emulation.setGeolocationOverride",Map_coordinates)driver.get("<your site url>")
usingSystem.Threading.Tasks;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.DevTools;// Replace the version to match the Chrome versionusingOpenQA.Selenium.DevTools.V87.Emulation;namespacedotnet_test{classProgram{publicstaticvoidMain(string[]args){GeoLocation().GetAwaiter().GetResult();}publicstaticasyncTaskGeoLocation(){ChromeDriverdriver=newChromeDriver();DevToolsSessiondevToolsSession=driver.CreateDevToolsSession();vargeoLocationOverrideCommandSettings=newSetGeolocationOverrideCommandSettings();geoLocationOverrideCommandSettings.Latitude=51.507351;geoLocationOverrideCommandSettings.Longitude=-0.127758;geoLocationOverrideCommandSettings.Accuracy=1;awaitdevToolsSession.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V87.DevToolsSessionDomains>().Emulation.SetGeolocationOverride(geoLocationOverrideCommandSettings);driver.Url="<your site url>";}}}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegin# Latitude e longitude de Tóquio, Japãocoordinates={latitude:35.689487,longitude:139.691706,accuracy:100}driver.execute_cdp('Emulation.setGeolocationOverride',coordinates)driver.get'https://www.google.com/search?q=selenium'ensuredriver.quitend
const{By,Key,Browser}=require('selenium-webdriver');const{suite}=require('selenium-webdriver/testing');constassert=require("assert");suite(function(env){describe('Emulate geolocation',function(){letdriver;before(asyncfunction(){driver=awaitenv.builder().build();});after(()=>driver.quit());it('Emulate coordinates of Tokyo',asyncfunction(){constcdpConnection=awaitdriver.createCDPConnection('page');// Latitude and longitude of Tokyo, Japan
constcoordinates={latitude:35.689487,longitude:139.691706,accuracy:100,};awaitcdpConnection.execute("Emulation.setGeolocationOverride",coordinates);awaitdriver.get("https://kawasaki-india.com/dealer-locator/");});});},{browsers:[Browser.CHROME,Browser.FIREFOX]});
fromseleniumimportwebdriver#Replace the version to match the Chrome versionimportselenium.webdriver.common.devtools.v93asdevtoolsasyncdefgeoLocationTest():chrome_options=webdriver.ChromeOptions()driver=webdriver.Remote(command_executor='<grid-url>',options=chrome_options)asyncwithdriver.bidi_connection()assession:cdpSession=session.sessionawaitcdpSession.execute(devtools.emulation.set_geolocation_override(latitude=41.8781,longitude=-87.6298,accuracy=100))driver.get("https://my-location.org/")driver.quit()
usingSystem.Threading.Tasks;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.DevTools;// Replace the version to match the Chrome versionusingOpenQA.Selenium.DevTools.V87.Emulation;namespacedotnet_test{classProgram{publicstaticvoidMain(string[]args){GeoLocation().GetAwaiter().GetResult();}publicstaticasyncTaskGeoLocation(){ChromeOptionschromeOptions=newChromeOptions();RemoteWebDriverdriver=newRemoteWebDriver(newUri("<grid-url>"),chromeOptions);DevToolsSessiondevToolsSession=driver.CreateDevToolsSession();vargeoLocationOverrideCommandSettings=newSetGeolocationOverrideCommandSettings();geoLocationOverrideCommandSettings.Latitude=51.507351;geoLocationOverrideCommandSettings.Longitude=-0.127758;geoLocationOverrideCommandSettings.Accuracy=1;awaitdevToolsSession.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V87.DevToolsSessionDomains>().Emulation.SetGeolocationOverride(geoLocationOverrideCommandSettings);driver.Url="https://my-location.org/";}}}
driver=Selenium::WebDriver.for(:remote,:url=>"<grid-url>",:capabilities=>:chrome)begin# Latitude e longitude de Tóquio, Japãocoordinates={latitude:35.689487,longitude:139.691706,accuracy:100}devToolsSession=driver.devtoolsdevToolsSession.send_cmd('Emulation.setGeolocationOverride',coordinates)driver.get'https://my-location.org/'putsresensuredriver.quitend
constwebdriver=require('selenium-webdriver');constBROWSER_NAME=webdriver.Browser.CHROME;asyncfunctiongetDriver(){returnnewwebdriver.Builder().usingServer('<grid-url>').forBrowser(BROWSER_NAME).build();}asyncfunctionexecuteCDPCommands(){letdriver=awaitgetDriver();awaitdriver.get("<your site url>");constcdpConnection=awaitdriver.createCDPConnection('page');//Latitude and longitude of Tokyo, Japan
constcoordinates={latitude:35.689487,longitude:139.691706,accuracy:100,};awaitcdpConnection.execute("Emulation.setGeolocationOverride",coordinates);awaitdriver.quit();}executeCDPCommands();
importorg.openqa.selenium.WebDriverimportorg.openqa.selenium.chrome.ChromeOptionsimportorg.openqa.selenium.devtools.HasDevTools// Replace the version to match the Chrome version
importorg.openqa.selenium.devtools.v91.emulation.Emulationimportorg.openqa.selenium.remote.Augmenterimportorg.openqa.selenium.remote.RemoteWebDriverimportjava.net.URLimportjava.util.Optionalfunmain(){valchromeOptions=ChromeOptions()vardriver:WebDriver=RemoteWebDriver(URL("<grid-url>"),chromeOptions)driver=Augmenter().augment(driver)valdevTools=(driverasHasDevTools).devToolsdevTools.createSession()devTools.send(Emulation.setGeolocationOverride(Optional.of(52.5043),Optional.of(13.4501),Optional.of(1)))driver["https://my-location.org/"]driver.quit()}
Modo de Dispositivo Override
Usando a integração do Selenium com o CDP, pode-se substituir o modo do dispositivo atual e simular um novo modo. Width(largura), Height(altura), mobile(mobilidade) e deviceScaleFactor são parâmetros obrigatórios. Parâmetros opcionais incluem scale(escala), screenWidth(largura da tela),
screenHeight(altura da tela), positionX, positionY, dontSetVisible(não setar como visível), screenOrientation(orientação da tela), viewport e displayFeature.
ChromeDriverdriver=newChromeDriver();DevToolsdevTools=driver.getDevTools();devTools.createSession();// iPhone 11 Pro dimensions
devTools.send(Emulation.setDeviceMetricsOverride(375,812,50,true,Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty(),Optional.empty()));driver.get("https://selenium.dev/");driver.quit();
fromseleniumimportwebdriverdriver=webdriver.Chrome()//iPhone11Prodimensionsset_device_metrics_override=dict({"width":375,"height":812,"deviceScaleFactor":50,"mobile":True})driver.execute_cdp_cmd('Emulation.setDeviceMetricsOverride',set_device_metrics_override)driver.get("<your site url>")
usingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.DevTools;usingSystem.Threading.Tasks;usingOpenQA.Selenium.DevTools.V91.Emulation;usingDevToolsSessionDomains=OpenQA.Selenium.DevTools.V91.DevToolsSessionDomains;namespaceSelenium4Sample{publicclassExampleDevice{protectedIDevToolsSessionsession;protectedIWebDriverdriver;protectedDevToolsSessionDomainsdevToolsSession;publicasyncTaskDeviceModeTest(){ChromeOptionschromeOptions=newChromeOptions();//Set ChromeDriverdriver=newChromeDriver();//Get DevToolsIDevToolsdevTools=driverasIDevTools;//DevTools Sessionsession=devTools.GetDevToolsSession();vardeviceModeSetting=newSetDeviceMetricsOverrideCommandSettings();deviceModeSetting.Width=600;deviceModeSetting.Height=1000;deviceModeSetting.Mobile=true;deviceModeSetting.DeviceScaleFactor=50;awaitsession.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V91.DevToolsSessionDomains>().Emulation.SetDeviceMetricsOverride(deviceModeSetting);driver.Url="<your site url>";}}}
// File must contain the following using statementsusingOpenQA.Selenium;usingOpenQA.Selenium.Chrome;usingOpenQA.Selenium.DevTools;// We must use a version-specific set of domainsusingOpenQA.Selenium.DevTools.V94.Performance;publicasyncTaskPerformanceMetricsExample(){IWebDriverdriver=newChromeDriver();IDevToolsdevTools=driverasIDevTools;DevToolsSessionsession=devTools.GetDevToolsSession();awaitsession.SendCommand<EnableCommandSettings>(newEnableCommandSettings());varmetricsResponse=awaitsession.SendCommand<GetMetricsCommandSettings,GetMetricsCommandResponse>(newGetMetricsCommandSettings());driver.Navigate().GoToUrl("http://www.google.com");driver.Quit();varmetrics=metricsResponse.Metrics;foreach(Metricmetricinmetrics){Console.WriteLine("{0} = {1}",metric.Name,metric.Value);}}
A seguinte lista de APIs crescerá à medida que o projeto Selenium se prepara
para suportar casos de uso do mundo real. Se houver funcionalidades adicionais que você gostaria de ver, por favor, levante uma solicitação de recurso.
Registrar autenticação básica
Alguns aplicativos fazem o uso da autenticação do navegador para proteger suas páginas. Com o Selenium, você pode automatizar a entrada de credenciais básicas de autenticação sempre que for necessário.
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.devtools.newdriver.register(username:'username',password:'password')driver.get'<your site url>'ensuredriver.quitend
Mutation Observation(Observação de Mutação) é a capacidade de capturar eventos via WebDriver BiDi quando há mutações DOM em um elemento específico no DOM.
ChromeDriverdriver=newChromeDriver();DevToolsdevTools=driver.getDevTools();devTools.createSession();devTools.send(Log.enable());devTools.addListener(Log.entryAdded(),logEntry->{System.out.println("log: "+logEntry.getText());System.out.println("level: "+logEntry.getLevel());});driver.get("http://the-internet.herokuapp.com/broken_images");// Check the terminal output for the browser console messages.
driver.quit();
importtriofromseleniumimportwebdriverfromselenium.webdriver.common.logimportLogasyncdefprintConsoleLogs():chrome_options=webdriver.ChromeOptions()driver=webdriver.Chrome()driver.get("http://www.google.com")asyncwithdriver.bidi_connection()assession:log=Log(driver,session)fromselenium.webdriver.common.bidi.consoleimportConsoleasyncwithlog.add_listener(Console.ALL)asmessages:driver.execute_script("console.log('I love cheese')")print(messages["message"])driver.quit()trio.run(printConsoleLogs)
importorg.openqa.selenium.*;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.devtools.DevTools;publicvoidjsExceptionsExample(){ChromeDriverdriver=newChromeDriver();DevToolsdevTools=driver.getDevTools();devTools.createSession();List<JavascriptException>jsExceptionsList=newArrayList<>();Consumer<JavascriptException>addEntry=jsExceptionsList::add;devTools.getDomains().events().addJavascriptExceptionListener(addEntry);driver.get("<your site url>");WebElementlink2click=driver.findElement(By.linkText("<your link text>"));((JavascriptExecutor)driver).executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);",link2click,"onclick","throw new Error('Hello, world!')");link2click.click();for(JavascriptExceptionjsException:jsExceptionsList){System.out.println("JS exception message: "+jsException.getMessage());System.out.println("JS exception system information: "+jsException.getSystemInformation());jsException.printStackTrace();}}
asyncdefcatchJSException():chrome_options=webdriver.ChromeOptions()driver=webdriver.Chrome()asyncwithdriver.bidi_connection()assession:driver.get("<your site url>")log=Log(driver,session)asyncwithlog.add_js_error_listener()asmessages:# Operation on the website that throws an JS errorprint(messages)driver.quit()
List<string>exceptionMessages=newList<string>();usingIJavaScriptEnginemonitor=newJavaScriptEngine(driver);monitor.JavaScriptExceptionThrown+=(sender,e)=>{exceptionMessages.Add(e.Message);};awaitmonitor.StartEventMonitoring();driver.Navigate.GoToUrl("<your site url>");IWebElementlink2click=driver.FindElement(By.LinkText("<your link text>"));((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].setAttribute(arguments[1], arguments[2]);",link2click,"onclick","throw new Error('Hello, world!')");link2click.Click();foreach(stringmessageinexceptionMessages){Console.WriteLine("JS exception message: {0}",message);}
require'selenium-webdriver'driver=Selenium::WebDriver.for:chromebegindriver.get'<your-site-url>'exceptions=[]driver.on_log_event(:exception)do|event|exceptions.push(event)putsexceptions.lengthend#Ações que causam exceções JSensuredriver.quitend
const{Builder,By}=require('selenium-webdriver');(async()=>{try{letdriver=newBuilder().forBrowser('chrome').build();constcdpConnection=awaitdriver.createCDPConnection('page')awaitdriver.onLogException(cdpConnection,function(event){console.log(event['exceptionDetails']);})awaitdriver.get('https://the-internet.herokuapp.com');constlink=awaitdriver.findElement(By.linkText('Checkboxes'));awaitdriver.executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);",link,"onclick","throw new Error('Hello, world!')");awaitlink.click();awaitdriver.quit();}catch(e){console.log(e);}})()
funkotlinJsErrorListener(){valdriver=ChromeDriver()valdevTools=driver.devToolsdevTools.createSession()vallogJsError={j:JavascriptException->print("Javascript error: '"+j.localizedMessage+"'.")}devTools.domains.events().addJavascriptExceptionListener(logJsError)driver.get("https://www.google.com")vallink2click=driver.findElement(By.name("q"))(driverasJavascriptExecutor).executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);",link2click,"onclick","throw new Error('Hello, world!')")link2click.click()driver.quit()}
Interceptação de Rede
Se você quer capturar eventos de rede que chegam ao navegador e deseja manipulá-los, você pode fazer
com os exemplos a seguir.
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
The following list of APIs will be growing as the WebDriver BiDirectional Protocol grows
and browser vendors implement the same.
Additionally, Selenium will try to support real-world use cases that internally use a combination of W3C BiDi protocol APIs.
If there is additional functionality you’d like to see, please raise a
feature request.
2.8.3.1 - Browsing Context
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
This section contains the APIs related to browsing context commands.
A reference browsing context is a top-level browsing context.
The API allows to pass the reference browsing context, which is used to create a new window. The implementation is operating system specific.
A reference browsing context is a top-level browsing context.
The API allows to pass the reference browsing context, which is used to create a new tab. The implementation is operating system specific.
Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context upto the depth value passed.
Assertions.assertEquals(1,contextInfoList.size());BrowsingContextInfoinfo=contextInfoList.get(0);Assertions.assertNull(info.getChildren());// since depth is 0
Assertions.assertEquals("Error: Not working",logEntry.getText());Assertions.assertEquals("javascript",logEntry.getType());Assertions.assertEquals(LogLevel.ERROR,logEntry.getLevel());}}@TestvoidtestListenToJavascriptErrorLog()
constinspector=awaitLogInspector(driver)awaitinspector.onJavascriptException(function(log){logEntry=log})awaitdriver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')awaitdriver.findElement({id:'jsException'}).click()assert.equal(logEntry.text,'Error: Not working')assert.equal(logEntry.type,'javascript')assert.equal(logEntry.level,'error')
Support classes provide optional higher level features.
The core libraries of Selenium try to be low level and non-opinionated.
The Support classes in each language provide opinionated wrappers for common interactions
that may be used to simplify some behaviors.
2.9.1 - Trabalhando com cores
Ocasionalmente, você desejará validar a cor de algo como parte de seus testes;
o problema é que as definições de cores na web não são constantes.
Não seria bom se houvesse uma maneira fácil de comparar
uma representação HEX de uma cor com uma representação RGB de uma cor,
ou uma representação RGBA de uma cor com uma representação HSLA de uma cor?
Não se preocupe. Existe uma solução: a classe Color!
Em primeiro lugar, você precisará importar a classe:
// This feature is not implemented - Help us by sending a pr to implement this feature
includeSelenium::WebDriver::Support
// This feature is not implemented - Help us by sending a pr to implement this feature
importorg.openqa.selenium.support.Color
Agora você pode começar a criar objetos coloridos.
Cada objeto de cor precisará ser criado a partir de uma representação de string de
sua cor.
As representações de cores com suporte são:
Às vezes, os navegadores retornam um valor de cor “transparent”
se nenhuma cor foi definida em um elemento.
A classe Color também oferece suporte para isso:
Agora você pode consultar com segurança um elemento
para obter sua cor / cor de fundo sabendo que
qualquer resposta será analisada corretamente
e convertido em um objeto Color válido:
Esta classe está disponível apenas no Java Binding
ThreadGuard verifica se um driver é chamado apenas da mesma thread que o criou.
Problemas de threading, especialmente durante a execução de testes em paralelo, podem ter erros misteriosos
e difíceis de diagnosticar. Usar este wrapper evita esta categoria de erros
e gerará uma exceção quando isso acontecer.
O exemplo a seguir simula um conflito de threads:
publicclassDriverClash{//thread main (id 1) criou este driver
privateWebDriverprotectedDriver=ThreadGuard.protect(newChromeDriver());static{System.setProperty("webdriver.chrome.driver","<Set path to your Chromedriver>");}//Thread-1 (id 24) está chamando o mesmo driver causando o conflito
Runnabler1=()->{protectedDriver.get("https://selenium.dev");};Threadthr1=newThread(r1);voidrunThreads(){thr1.start();}publicstaticvoidmain(String[]args){newDriverClash().runThreads();}}
O resultado mostrado abaixo:
Exception in thread "Thread-1" org.openqa.selenium.WebDriverException:
Thread safety error; this instance of WebDriver was constructed
on thread main (id 1)and is being accessed by thread Thread-1 (id 24)
This is not permitted and *will* cause undefined behaviour
Conforme visto no exemplo:
protectedDriver será criado no tópico principal
Usamos Java Runnable para ativar um novo processo e uma nova Thread para executar o processo
Ambas as Threads entrarão em conflito porque a thread principal não tem protectedDriver em sua memória.
ThreadGuard.protect lançará uma exceção.
Nota:
Isso não substitui a necessidade de usar ThreadLocal para gerenciar drivers durante a execução em paralelo.
2.9.3 - Trabalhando com elementos select
Select lists have special behaviors compared to other elements.
The Select object will now give you a series of commands
that allow you to interact with a <select> element.
If you are using Java or .NET make sure that you’ve properly required the support package
in your code. See the full code from GitHub in any of the examples below.
Note that this class only works for HTML elements select and option.
It is possible to design drop-downs with JavaScript overlays using div or li,
and this class will not work for those.
Types
Select methods may behave differently depending on which type of <select> element is being worked with.
Single select
This is the standard drop-down object where one and only one option may be selected.
<selectname="selectomatic"><optionselected="selected"id="non_multi_option"value="one">One</option><optionvalue="two">Two</option><optionvalue="four">Four</option><optionvalue="still learning how to count, apparently">Still learning how to count, apparently</option></select>
Multiple select
This select list allows selecting and deselecting more than one option at a time.
This only applies to <select> elements with the multiple attribute.
First locate a <select> element, then use it to initialize a Select object.
Note that as of Selenium 4.5, you can’t create a Select object if the <select> element is disabled.
Get a list of selected options in the <select> element. For a standard select list
this will only be a list with one element, for a multiple select list it can contain
zero or many elements.
The Select class provides three ways to select an option.
Note that for multiple select type Select lists, you can repeat these methods
for each element you want to select.
It is not always obvious the root cause of errors in Selenium.
The most common Selenium-related error is a result of poor synchronization.
Read about Waiting Strategies. If you aren’t sure if it
is a synchronization strategy you can try temporarily hard coding a large sleep
where you see the issue, and you’ll know if adding an explicit wait can help.
Note that many errors that get reported to the project are actually caused by
issues in the underlying drivers that Selenium sends the commands to. You can rule
out a driver problem by executing the command in multiple browsers.
If you have questions about how to do things, check out the Support options
for ways get assistance.
If you think you’ve found a problem with Selenium code, go ahead and file a
Bug Report
on GitHub.
2.10.1 - Understanding Common Errors
How to get deal with various problems in your Selenium code.
Invalid Selector Exception
CSS and XPath Selectors are sometimes difficult to get correct.
Likely Cause
The CSS or XPath selector you are trying to use has invalid characters or an invalid query.
An element goes stale when it was previously located, but can not be currently accessed.
Elements do not get relocated automatically; the driver creates a reference ID for the element and
has a particular place it expects to find it in the DOM. If it can not find the element
in the current DOM, any action using that element will result in this exception.
Common Causes
This can happen when:
You have refreshed the page, or the DOM of the page has dynamically changed.
You have navigated to a different page.
You have switched to another window or into or out of a frame or iframe.
Common Solutions
The DOM has changed
When the page is refreshed or items on the page have moved around, there is still
an element with the desired locator on the page, it is just no longer accessible
by the element object being used, and the element must be relocated before it can be used again.
This is often done in one of two ways:
Always relocate the element every time you go to use it. The likelihood of
the element going stale in the microseconds between locating and using the element
is small, though possible. The downside is that this is not the most efficient approach,
especially when running on a remote grid.
Wrap the Web Element with another object that stores the locator, and caches the
located Selenium element. When taking actions with this wrapped object, you can
attempt to use the cached object if previously located, and if it is stale, exception
can be caught, the element relocated with the stored locator, and the method re-tried.
This is more efficient, but it can cause problems if the locator you’re using
references a different element (and not the one you want) after the page has changed.
The Context has changed
Element objects are stored for a given context, so if you move to a different context —
like a different window or a different frame or iframe — the element reference will
still be valid, but will be temporarily inaccessible. In this scenario, it won’t
help to relocate the element, because it doesn’t exist in the current context.
To fix this, you need to make sure to switch back to the correct context before using the element.
The Page has changed
This scenario is when you haven’t just changed contexts, you have navigated to another page
and have destroyed the context in which the element was located.
You can’t just relocate it from the current context,
and you can’t switch back to an active context where it is valid. If this is the reason
for your error, you must both navigate back to the correct location and relocate it.
2.10.2 - Logging Selenium commands
Getting information about Selenium execution.
Turning on logging is a valuable way to get extra information that might help you determine
why you might be having a problem.
Java logs are typically created per class. You can work with the default logger to
work with all loggers. To filter out specific classes, see Filtering
Java Logging is not exactly straightforward, and if you are just looking for an easy way
to look at the important Selenium logs,
take a look at the Selenium Logger project
Python logs are typically created per module. You can match all submodules by referencing the top
level module. So to work with all loggers in selenium module, you can do this:
.NET does not currently have a Logging implementation
If you want to see as much debugging as possible in all the classes,
you can turn on debugging globally in Ruby by setting $DEBUG = true.
For more fine-tuned control, Ruby Selenium created its own Logger class to wrap the default Logger class.
This implementation provides some interesting additional features.
Obtain the logger directly from the #loggerclass method on the Selenium::WebDriver module:
Things get complicated when you use PyTest, though. By default, PyTest hides logging unless the test
fails. You need to set 3 things to get PyTest to display logs on passing tests.
To always output logs with PyTest you need to run with additional arguments.
First, -s to prevent PyTest from capturing the console.
Second, -p no:logging, which allows you to override the default PyTest logging settings so logs can
be displayed regardless of errors.
So you need to set these flags in your IDE, or run PyTest on command line like:
pytest -s -p no:logging
Finally, since you turned off logging in the arguments above, you now need to add configuration to
turn it back on:
logging.basicConfig(level=logging.WARN)
.NET does not currently have a Logging implementation
Ruby logger has 5 logger levels: :debug, :info, :warn, :error, :fatal.
As of Selenium v4.9.1, The default is :info.
Things are logged as warnings if they are something the user needs to take action on. This is often used
for deprecations. For various reasons, Selenium project does not follow standard Semantic Versioning practices.
Our policy is to mark things as deprecated for 3 releases and then remove them, so deprecations
may be logged as warnings.
This is the default level where Selenium logs things that users should be aware of but do not need to take actions on.
This might reference a new method or direct users to more information about something
Java logging is managed on a per class level, so
instead of using the root logger (Logger.getLogger("")), set the level you want to use on a per-class
basis:
.NET does not currently have a Logging implementation
Ruby’s logger allows you to opt in (“allow”) or opt out (“ignore”) of log messages based on their IDs.
Everything that Selenium logs includes an ID. You can also turn on or off all deprecation notices by
using :deprecations.
These methods accept one or more symbols or an array of symbols:
Pretende executar testes em paralelo em várias máquinas? Então a Grid é para si.
Selenium Grid permite a execucão de scripts WebDriver em máquinas remotas,
passando os comandos recebidos pelo cliente para a instância remotas do navegador.
O objectivo da Grid é:
Providenciar uma forma fácil de executar testes em paralelo em multiplas máquinas
Permitir testes em versões diferentes de navegadores
Permitir testes em várias plataformas
Está interessado? Enão siga lendo as próximas secções para entender como a Grid funciona
e também como montar a sua.
3.1 - Configurando a sua
Instruções para criar uma Selenium Grid simples
Início rápido
Pré-requisitos
Java 11 ou superior instalado
Navegador(es) instalados
Drivers do(s) navegador(es)
Se usar o Selenium 4.6, o Selenium Manager irá configurar os navegadores Chrome, Firefox e Edge se não forem encontrados no PATH.
Obter o ficheiro Selenium Server Jar a partir da última release
Para aprender mais sobre as diferentes opções de configuração, veja as secções seguintes.
Grid roles
A Grid é composta de seis componentes diferentes, o que permite ser
instalada de várias formas.
Dependendo das necessidades, podemos iniciar cada um dos componentes (Distribuido) ou agrupar no formato
Hub e Node ou ainda numa única máquina (Standalone).
Standalone
Standalone combina todos os componentes num só sitio.
Executar uma Grid em modo Standalone permite uma Grid totalmente funcionar com um único
comando, num único processo. Standalone só funcionará numa única máquina.
Standalone é também a forma mais simples de colocar uma Selenium Grid em funcionamento.
Por omissão, o servidor irá escutar por pedidos RemoteWebDriver em http://localhost:4444.
O servidor irá também detectar os drivers disponíveis no
PATH.
A comunicação entre Hub e Nodes ocorre via HTTP. Para iniciar o processo de registo, o Node envia
uma mensagem para o Hub através do Event Bus
(o Event Bus reside dentro do Hub). Quando o Hub recebe a mensagem, tenta comunicar com o Node
para confirmar a sua existencia.
Para que um Node se consiga registar no Hub, é importante que as portas do Event Bus sejam expostas
na máquina Hub. As portas por omissão são 4442 e 4443 para o Event Bus e 4444 para o Hub.
Se o Hub estiver a usar as portas por omissão, pode usar a flag --hub para registar o Node
Distributor: consulta New Session Queue para novos pedidos de sessão, que entrega ao um Node quando encontra um capacidade
correspondente. Nodes registam-se no Distributor da mesma forma como numa Grid do tipo Hub/Node.
A porta por omissão é 5553. Distributor interage com New Session Queue, Session Map, Event Bus, e Node(s).
Adicione Metadata aos testes, através de GraphQL
ou visualize parcialmente (como se:name) através da Selenium Grid UI.
Metadata pode ser adicionada como uma capacidade com o prefixo se:. Eis um pequeno exemplo em Java.
ChromeOptionschromeOptions=newChromeOptions();chromeOptions.setCapability("browserVersion","100");chromeOptions.setCapability("platformName","Windows");// Mostrando na Grid UI o nome de um teste ao invés de uma session id
chromeOptions.setCapability("se:name","My simple test");// Outros tipos de metadara podem ser visualizados na Grid UI
// ao clicar na informação de sessão ou via GraphQL
chromeOptions.setCapability("se:sampleMetadata","Valor exemplo de Metadata");WebDriverdriver=newRemoteWebDriver(newURL("http://gridUrl:4444"),chromeOptions);driver.get("http://www.google.com");driver.quit();
Questionando a Selenium Grid
Após iniciar a Gris, existem duas formas de saber o seu estado, através da Grid UI ou
por chamada API.
Para simplificar, todos os exemplos apresentados assumem que os componentes estão a ser executados localmente.
Exemplos mais detalhados podem ser encontrados na secção Configurando Componentes.
Por omissão, a Grid irá usar AsyncHttpClient.
AsyncHttpClient é uma biblioteca open-source library criada em cima do Netty. Isto permite a
execução de pedidos e respostas HTTP de forma assíncrona. Esta biblioteca é uma boa escolha
pois além de permitir pedidos assíncronos, também suporta WebSockets.
No entanto, a biblioteca AsyncHttpClient não é mantida activamente desde Junho de 2021. Isto coincide com
o facto de que a partir do Java 11, a JVM tem um cliente nativo que suporta camadas assíncronas
e contém um cliente WebSocket.
Atualmente, o projecto Selenium tem planos de atualizar a versão mínima suportada para Java 11.
No entanto, isto é um esforço considerável. Alinhá-lo com os principais lançamentos e anúncios
acompanhados é crucial para garantir que a experiência do usuário esteja intacta.
Para usar o cliente Java 11, terá que baixar o ficheiro jar selenium-http-jdk-client e usar
a flag --ext para funcionar na Grid.
Este ficheiro pode ser obtido directamente de repo1.maven.org
e depois pode iniciar a Grid com:
Se está a usar a Grid em modo Hub/Node ou Distributed, terá que usar as flags
-Dwebdriver.http.factory=jdk-http-client e --ext em cada um dos componentes.
Dimensionar Grid
A escolha de Grid depende de quais sistemas operacionais e navegadores precisam ser suportados,
quantas sessões paralelas precisam ser executadas, a quantidade de máquinas disponíveis e quão
poderosas (CPU, RAM) essas máquinas são.
A criação de sessões simultaneas depende dos processadores disponíveis para o Distributor.
Por exemplo, se uma máquina tiver 4 CPUs, o Distributor só poderá criar quatro sessões
em simultâneo.
Por omissão, a quantidade máxima de sessões simultâneas que um Node suporta é limitada pelo
número de CPUs disponíveis. Por exemplo, se a máquina Node tiver 8 CPUs, ela poderá executar
até 8 sessões de navegador simultâneas (com exceção do Safari, que é sempre uma).
Além disso, espera-se que cada sessão do navegador use cerca de 1 GB de RAM.
Em geral, é recomendado ter Nodes o mais pequenos possíveis. Em vez de ter
uma máquina com 32CPUs e 32GB de RAM para executar 32 sessões de navegador simultâneas, é melhor
tem 32 pequenos Nodes para isolar melhor os processos. Com isso, se um Node
falhar, será de forma isolada. Docker é uma boa ferramenta para alcançar essa abordagem.
Note que os valores 1CPU/1GB RAM por navegador são uma recomendação e podem não ser os mais indicados
para o seu contexto. Recomenda-se que use estea valores como referência, mas meça o desempenho
continuamente para ajudar a determinar os valores ideais para o seu ambiente.
Os tamanhos da Grid são relativos à quantidade de sessões simultâneas suportadas e à quantidade de
Nodes, não existindo um “tamanho único”. Os tamanhos mencionados abaixo são estimativas aproximadas
que podem variar entre diferentes ambientes. Por exemplo, um Hub/Node com 120 Nodes
pode funcionar bem quando o Hub tiver recursos suficientes. Os valores abaixo não são gravados em pedra,
e comentários são bem-vindos!
Pequena
Standalone e Hub/Node com cinco Nodes ou menos.
Média
Hub/Node entre 6 e 60 Nodes.
Grande
Hub/Node entre 60 e 100 Nodes. Distributed com mais de 100 Nodes.
AVISO
Deve proteger a Selenium Grid de acesso externo, usando regras de firewall apropriadas.
Se falhar em proteger a Grid uma ou mais coisas poderão ocorrer:
Permite acesso aberto à sua infraestrutura da Grid
Permitir acesso de terceiros a aplicativos web e a ficheiros
Permitir execução remota de ficheiros binários por terceiros
Para executar testes em paralelo, com vários tipos e versões de navegador e sistemas operativos
Para reduzir o tempo necessário a executar uma bateria de testes
A Selenium Grid executa baterias de testes em paralelo contra várias máquinas (chamadas Nodes).
Para testes longos, isto poderá poupar minutos, horas e talvez dias.
Isto encurta o tempo de espera para obter resultados dos testes de cada vez que sobre a aplicação
em testes é alterada.
A Grid consegue executar testes (em paralelo) contra multiplos e diferentes navegadores, também
é capaz de executar contra várias instâncias do mesmo navegador. Como exemplo, vamos imaginar
uma Grid com seis Nodes. A primeira máquina tem a versão mais recente do Firefox, a segunda tem
a versão “mais recente -1”, a terceira tem o Chrome mais recente e as restantes máquinas são Mac
Mini, que permitem três testes em paralelo com a versão mais recente to Safari.
O tempo de execução pode ser expresso como uma fórmula simples:
Número de testes * Tempo médio de cada teste / Número de Nodes = Tempo total de execução
15 * 45s / 1 = 11m 15s // Sem Grid
15 * 45s / 5 = 2m 15s // Grid com 5 Nodes
15 * 45s / 15 = 45s // Grid com 15 Nodes
100 * 120s / 15 = 13m 20s // Demoraria mais de 3 horas sem Grid
À medida que a bateria de testes executa, a Grid vai alocando os testes contra estes navegadores
como está definido nos testes.
Uma configuração deste tipo pode acelerar bastante o tempo de execução mesmo no caso de baterias de testes grandes.
A Selenium Grid é uma parte integrante do projecto Selenium e é mantida em paralelo pela mesma equipa de developers
que desenvolvem o resto das funcionalidades base do projecto. Dada a importância da velocidade e desempenho da
execução dos testes, a Grid tem sido considerada desde o início como uma parte crítica e fundamental ao projecto.
3.3 - Componentes
Compreender como usar os componentes da Grid
A Selenium Grid 4 é uma re-escrita completa das versões anteriores. Além dos melhoramentos ao desempenho
e aos cumprimentos dos standards, várias funcionalidades da Grid foram separadas para reflectir uma
nova era de computação e desenvolvimento de software. Criada de raíz para containerização e
escalabilidade cloud, Selenium Grid 4 é uma nova solução para a era moderna.
Componentes Grid
Router
O Router é o ponto de entrada da Grid, recebendo todos os pedidos externos, reenviando para o componente correcto.
Se o Router recebe um novo pedido de sessão, este será enviado para New Session Queue.
Se o pedido recebido pertence a uma sessão existente, o Router irá inquirir o Session Map para obter
o Node ID onde esta sessão está em execução, enviando de seguida o pedido directamente para o Node.
O Router balança a carga na Grid ao enviar o pedido ao componente que está em condições de o receber,
sem sobrecarregar qualquer outro componente que não faz parte do processo.
Distributor
O Distributor tem duas responsabilidades:
Resgistar e manter uma lista de todos os Nodes e as suas capacidades
Um Node regista-se no Distributor enviando um evento de registo Node através do
Event Bus. O Distributor lê o pedido e tenta contactar o Node através de HTTP
para confirmar a sua existência. Se obtiver resposta com sucesso, o Distributor regista
o Node e mantém uma lista de todas as capacidades Nodes através do GridModel.
Processar algum pedido pendente que tenha sido criado na New Session Queue
Quando um novo pedido de sessão é enviado para o Router, ele é reenviado para a New Session Queue,
onde ficará na fila em espera. O Distributor irá processar pedidos pendentes que existam na New Session Queue,
encontrando um Node com as capacidades certas onde a sessão possa ser criada. Após esta nova
sessão ter sido criada, o Distributor guarda na Session Map a relação entre o id da sessão e
o Node onde a sessão está em execução.
Session Map
A Session Map é uma data store que mantém a relação entre o id da sessão e o Node
onde a sessão está em execução. Apoia o Router no processo de envio do pedido para um Node
onde a sessão está em execução. O Router irá pedir ao Session Map qual o Node associado
ao id de sessão.
New Session Queue
A New Session Queue contém todos os pedidos de novas sessões em ordem FIFO. Existem parametros
configuráveis para o timeout de sessão e para o número de tentativas.
O Router adiciona um novo pedido de sessão em New Session Queue e aguarda uma resposta.
A New Session Queue verifica regularmente se algum pedido deu timeout e em caso afirmativo,
rejeita e remove o pedido da queue.
O Distributor verifica regularmente se existe um slot disponível. Em caso afirmativo, o Distributor
obtém um pedido a partir de New Session Queue e tenta criar uma nova sessão.
Assim que existam capacidades pedidas capazes de serem servidas por um dos Node que estejam livres,
o Distributor tenta obter o slot disponível. Caso todos os slots estejam ocupados, o Distributor
envia o pedido de volta para a queue. Se o pedido tiver timeout ao ser readicionado à queue, será rejeitado.
Após um id de sessão ser criado, o Distributor envia a informação se sessão para New Session Queue,
que por sua vez irá enviar para o Router que finalmente entrega ao cliente.
Node
A Grid pode ter múltiplos Nodes. Cada Node gere os slots de disponibilidade para os navegadores existentes
na máquina onde está a executar.
O Node regista-se no Distributor através do Event Bus, sendo que a sua configuração é enviada
como parte da mensagem de registo.
Por omissão, o Node regista automaticamente todos os navegadores que estejam disponíveis no PATH da máquina onde
executa. Cria também um slot de execução por cada CPU para os navegadores Chrome e Firefox. Para Safari,
apenas é criado um slot. Usando uma configuração específica, é também
possível executar sessões em containers Docker.
O Node apenas executa os comandos que recebe, não avalia, faz julgamentos ou controla mais nada que não seja
o fluxo de comandos e respostas. A máquina onde o Node está a executar não necessita de ter o mesmo sistema
operativo do que os restantes componentes. Por exemplo, um Windows Node pode ter a capacidade de oferecer
IE Mode no Edge como opção de navegador, coisa que não é possível em Linux ou Mac. A Grid pode ter múltiplos
Node configurados com Windows, Mac ou Linux.
Event Bus
O Event Bus serve de canal de comunicações entre Nodes, Distributor, New Session Queue,
e Session Map. A Grid usa mensagens para a maioria das comunicações internas. evitando chamadas HTTP.
Quando iniciar a Grid em modo distribuido, deverá iniciar o Event Bus antes dos restantes componentes.
Configurando a sua Grid
Se pretende usar todos estes componentes para criar a sua Grid,
visite a secção “configurando a sua”
para entender como ligar as peças todas.
3.4 - Configurando componentes
Leia aqui como pode configurar cada um dos componentes Grid com base em valores comuns ou específicos para o componente.
3.4.1 - Ajuda de configuração
Obtenha ajuda sobre todas as opções disponíveis para configurar a Grid.
Os comandos de ajuda (help) mostram informação baseada na implementação de código em vigor.
Desta forma, irá obter informação potencialmente mais actual do que esta documentação.
Embora possa não ser a mais detalhada, é sempre a forma mais simples de aprender sobre
as configurações da Grid 4 em qualquer nova versão.
Commando info
O comando info fornece detalhes de documentação sobre os seguintes tópicos:
Configurar Selenium
Segurança
Setup Session Map
Traceamento
Ajuda sobre configuração
Ajuda rápida e resumo pode ser obtida com:
java -jar selenium-server-<version>.jar info config
Segurança
Para obter detalhes em como configurar os servidores Grid para comunicação segura
e para o registo de Nodes:
java -jar selenium-server-<version>.jar info security
Configuração Session Map
Por omissão, a Grid usa um local session map para armazenar informação de sessões.
A Grid permite armazenamento opcional em Redis ou bancos de dados JDBC SQL.
Para obter informação de como usar, use o seguinte comando:
java -jar selenium-server-<version>.jar info sessionmap
Traceamento com OpenTelemetry e Jaeger
Por omissao, traceamento está activo. Para exportar e visualizar através de Jaeger, use o
comando seguinte para instruções de como o efectuar:
java -jar selenium-server-<version>.jar info tracing
Lista de comandos Selenium Grid
Irá mostrar todos os comandos disponíveis e também a descrição de cada um.
Todas os detalhes das opções CLI de cada componente Grid.
Diferentes secções estão disponíveis para configurar uma Grid. Cada secção tem opções que podem ser configuradas
através de opções CLI.
Pode ver abaixo um mapeamento entre o componente e a secção respectiva.
Note que esta documentação pode estar desactualizada se uma opção foi adicionada ou modificada,
mas ainda não ter havido oportunidade de actualizar a documentação.
Caso depare com esta situação, verifique a secção “ajuda de configuração”
e esteja à vontade para nos enviar um pull request com alterações a esta página.
Nome completo da class para uma implementação não padrão do Distributor.
--distributor-port
int
5553
Porta onde o Distributor está à escuta.
--reject-unsupported-caps
boolean
false
Permitir que o Distributor rejeite imediatamente um pedido de sessão se a Grid não suportar a capacidade pedida. Esta configuração é a ideal para Grid que não inicie Nodes a pedido.
--slot-matcher
string
org.openqa.selenium.grid.data.DefaultSlotMatcher
Nome completo da class para uma implementação não padrão do comparador de slots. Isto é usado para determinar se um Node pode suportar uma sessão em particular.
Docker configs which map image name to stereotype capabilities (example `-D selenium/standalone-firefox:latest ‘{“browserName”: “firefox”}’)
--docker-devices
string[]
/dev/kvm:/dev/kvm
Exposes devices to a container. Each device mapping declaration must have at least the path of the device in both host and container separated by a colon like in this example: /device/path/in/host:/device/path/in/container
--docker-host
string
localhost
Host name where the Docker daemon is running
--docker-port
int
2375
Port where the Docker daemon is running
--docker-url
string
http://localhost:2375
URL for connecting to the Docker daemon
--docker-video-image
string
selenium/video:latest
Docker image to be used when video recording is enabled
Events
Opção
Tipo
Valor/Exemplo
Descrição
--bind-bus
boolean
false
Whether the connection string should be bound or connected. When true, the component will be bound to the Event Bus (as in the Event Bus will also be started by the component, typically by the Distributor and the Hub). When false, the component will connect to the Event Bus.
--events-implementation
string
org.openqa.selenium.events.zeromq.ZeroMqEventBus
Full class name of non-default event bus implementation
--publish-events
string
tcp://*:4442
Connection string for publishing events to the event bus
--subscribe-events
string
tcp://*:4443
Connection string for subscribing to events from the event bus
Logging
Opção
Tipo
Valor/Exemplo
Descrição
--http-logs
boolean
false
Enable http logging. Tracing should be enabled to log http logs.
--log-encoding
string
UTF-8
Log encoding
--log
string
Windows path example : '\path\to\file\gridlog.log' or 'C:\path\path\to\file\gridlog.log'
Linux/Unix/MacOS path example : '/path/to/file/gridlog.log'
File to write out logs. Ensure the file path is compatible with the operating system’s file path.
Full classname of non-default Node implementation. This is used to manage a session’s lifecycle.
--grid-url
string
https://grid.example.com
Public URL of the Grid as a whole (typically the address of the Hub or the Router)
--heartbeat-period
int
60
How often, in seconds, will the Node send heartbeat events to the Distributor to inform it that the Node is up.
--max-sessions
int
8
Maximum number of concurrent sessions. Default value is the number of available processors.
--override-max-sessions
boolean
false
The # of available processors is the recommended max sessions value (1 browser session per processor). Setting this flag to true allows the recommended max value to be overwritten. Session stability and reliability might suffer as the host could run out of resources.
--register-cycle
int
10
How often, in seconds, the Node will try to register itself for the first time to the Distributor.
--register-period
int
120
How long, in seconds, will the Node try to register to the Distributor for the first time. After this period is completed, the Node will not attempt to register again.
--session-timeout
int
300
Let X be the session-timeout in seconds. The Node will automatically kill a session that has not had any activity in the last X seconds. This will release the slot for other tests.
--vnc-env-var
string
START_XVFB
Environment variable to check in order to determine if a vnc stream is available or not.
--no-vnc-port
int
7900
If VNC is available, sets the port where the local noVNC stream can be obtained
--drain-after-session-count
int
1
Drain and shutdown the Node after X sessions have been executed. Useful for environments like Kubernetes. A value higher than zero enables this feature.
--hub
string
http://localhost:4444
The address of the Hub in a Hub-and-Node configuration. Can be a hostname or IP address (hostname), in which case the Hub will be assumed to be http://hostname:4444, the --grid-url will be the same --publish-events will be tcp://hostname:4442 and --subscribe-events will be tcp://hostname:4443. If hostname contains a port number, that will be used for --grid-url but the URIs for the event bus will remain the same. Any of these default values may be overridden but setting the correct flags. If the hostname has a protocol (such as https) that will be used too.
--enable-cdp
boolean
true
Enable CDP proxying in Grid. A Grid admin can disable CDP if the network doesnot allow websockets. True by default.
--enable-managed-downloads
boolean
false
This causes the Node to auto manage files downloaded for a given session on the Node.
--selenium-manager
boolean
false
When drivers are not available on the current system, use Selenium Manager. False by default.
Relay
Opção
Tipo
Valor/Exemplo
Descrição
--service-url
string
http://localhost:4723
URL for connecting to the service that supports WebDriver commands like an Appium server or a cloud service.
--service-host
string
localhost
Host name where the service that supports WebDriver commands is running
--service-port
int
4723
Port where the service that supports WebDriver commands is running
--service-status-endpoint
string
/status
Optional, endpoint to query the WebDriver service status, an HTTP 200 response is expected
Configuration for the service where calls will be relayed to. It is recommended to provide this type of configuration through a toml config file to improve readability.
Router
Opção
Tipo
Valor/Exemplo
Descrição
--password
string
myStrongPassword
Password clients must use to connect to the server. Both this and the username need to be set in order to be used.
--username
string
admin
User name clients must use to connect to the server. Both this and the password need to be set in order to be used.
--sub-path
string
my_company/selenium_grid
A sub-path that should be considered for all user facing routes on the Hub/Router/Standalone.
Server
Opção
Tipo
Valor/Exemplo
Descrição
--allow-cors
boolean
true
Whether the Selenium server should allow web browser connections from any host
--host
string
localhost
Server IP or hostname: usually determined automatically.
--bind-host
boolean
true
Whether the server should bind to the host address/name, or only use it to" report its reachable url. Helpful in complex network topologies where the server cannot report itself with the current IP/hostname but rather an external IP or hostname (e.g. inside a Docker container)
--https-certificate
path
/path/to/cert.pem
Server certificate for https. Get more detailed information by running “java -jar selenium-server.jar info security”
--https-private-key
path
/path/to/key.pkcs8
Private key for https. Get more detailed information by running “java -jar selenium-server.jar info security”
--max-threads
int
24
Maximum number of listener threads. Default value is: (available processors) * 3.
--port
int
4444
Port to listen on. There is no default as this parameter is used by different components, for example, Router/Hub/Standalone will use 4444 and Node will use 5555.
SessionQueue
Opção
Tipo
Valor/Exemplo
Descrição
--sessionqueue
uri
http://localhost:1237
Address of the session queue server.
-sessionqueue-host
string
localhost
Host on which the session queue server is listening.
--sessionqueue-port
int
1234
Port on which the session queue server is listening.
--session-request-timeout
int
300
Timeout in seconds. A new incoming session request is added to the queue. Requests sitting in the queue for longer than the configured time will timeout.
--session-retry-interval
int
5
Retry interval in seconds. If all slots are busy, new session request will be retried after the given interval.
Sessions
Opção
Tipo
Valor/Exemplo
Descrição
--sessions
uri
http://localhost:1234
Address of the session map server.
--sessions-host
string
localhost
Host on which the session map server is listening.
--sessions-port
int
1234
Port on which the session map server is listening.
Configuration examples
All the options mentioned above can be used when starting the Grid components. They are a good
way of exploring the Grid options, and trying out values to find a suitable configuration.
We recommend the use of Toml files to configure a Grid.
Configuration files improve readability, and you can also check them in source control.
When needed, you can combine a Toml file configuration with CLI arguments.
Command-line flags
To pass config options as command-line flags, identify the valid options for the component
and follow the template below.
java -jar selenium-server-<version>.jar <component> --<option> value
The Grid infrastructure will try to match a session request with "se:downloadsEnabled" against ONLY those nodes which were started with --enable-managed-downloads true
If a session is matched, then the Node automatically sets the required capabilities to let the browser know, as to where should a file be downloaded.
The Node now allows a user to:
List all the files that were downloaded for a specific session and
Retrieve a specific file from the list of files.
The directory into which files were downloaded for a specific session gets automatically cleaned up when the session ends (or) timesout due to inactivity.
Note: Currently this capability is ONLY supported on:
Edge
Firefox and
Chrome browser
Listing files that can be downloaded for current session:
The endpoint to GET from is /session/<sessionId>/se/files.
The session needs to be active in order for the command to work.
contents - Base64 encoded zipped contents of the file.
The file contents are Base64 encoded and they need to be unzipped.
List files that can be downloaded
The below mentioned curl example can be used to list all the files that were downloaded by the current session in the Node, and which can be retrieved locally.
curl -X GET "http://localhost:4444/session/90c0149a-2e75-424d-857a-e78734943d4c/se/files"
Below is an example in Java that does the following:
Sets the capability to indicate that the test requires automatic managing of downloaded files.
Triggers a file download via a browser.
Lists the files that are available for retrieval from the remote node (These are essentially files that were downloaded in the current session)
Picks one file and downloads the file from the remote node to the local machine.
import staticjava.util.Collections.singletonMap;import staticorg.openqa.selenium.remote.http.Contents.string;importjava.io.File;importjava.lang.reflect.Type;importjava.net.URL;importjava.util.List;importjava.util.Map;importjava.util.concurrent.TimeUnit;importorg.openqa.selenium.By;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.firefox.FirefoxOptions;importorg.openqa.selenium.io.Zip;importorg.openqa.selenium.json.Json;importorg.openqa.selenium.json.TypeToken;importorg.openqa.selenium.remote.RemoteWebDriver;importorg.openqa.selenium.remote.http.Contents;importorg.openqa.selenium.remote.http.HttpClient;importorg.openqa.selenium.remote.http.HttpMethod;importorg.openqa.selenium.remote.http.HttpRequest;importorg.openqa.selenium.remote.http.HttpResponse;publicclassDownloadsSample{publicstaticvoidmain(String[]args)throwsException{// Assuming the Grid is running locally.
URLgridUrl=newURL("http://localhost:4444");RemoteWebDriverdriver=newRemoteWebDriver(gridUrl,firefoxOptions());try{demoFileDownloads(driver,gridUrl);}finally{driver.quit();}}privatestaticvoiddemoFileDownloads(RemoteWebDriverdriver,URLgridUrl)throwsException{// Make sure the following directory exists on your machine
FiledirToCopyTo=newFile("/usr/downloads/file");driver.get("http://the-internet.herokuapp.com/download");WebElementelement=driver.findElement(By.cssSelector(".example a"));element.click();// The download happens in a remote Node, which makes it difficult to know when the file
// has been completely downloaded. For demonstration purposes, this example uses a
// 10-second sleep which should be enough time for a file to be downloaded.
// We strongly recommend to avoid hardcoded sleeps, and ideally, to modify your
// application under test so it offers a way to know when the file has been completely
// downloaded.
TimeUnit.SECONDS.sleep(10);//This is the endpoint which will provide us with list of files to download and also to
//let us download a specific file.
Stringuri=String.format("/session/%s/se/files",driver.getSessionId());StringfileToDownload=null;try(HttpClientclient=HttpClient.Factory.createDefault().createClient(gridUrl)){// To list all files that are were downloaded on the remote node for the current session
// we trigger GET request.
HttpRequestrequest=newHttpRequest(HttpMethod.GET,uri);HttpResponseresponse=client.execute(request);Stringtext=string(response);TyperesponseType=newTypeToken<Map<String,Map<String,List<String>>>>(){}.getType();Map<String,Map<String,List<String>>>map=newJson().toType(text,responseType);Map<String,List<String>>parsedResponse=map.get("value");for(StringeachFile:parsedResponse.get("names")){if(fileToDownload==null){// Let's say there were "n" files downloaded for the current session, we would like
// to retrieve ONLY the first file.
fileToDownload=eachFile;}}}try(HttpClientclient=HttpClient.Factory.createDefault().createClient(gridUrl)){// To retrieve a specific file from one or more files that were downloaded by the current session
// on a remote node, we use a POST request.
HttpRequestrequest=newHttpRequest(HttpMethod.POST,uri);request.setContent(Contents.asJson(singletonMap("name",fileToDownload)));HttpResponseresponse=client.execute(request);Stringtext=string(response);TyperesponseType=newTypeToken<Map<String,Map<String,String>>>(){}.getType();Map<String,Map<String,String>>map=newJson().toType(text,responseType);Map<String,String>parsedResponse=map.get("value");// The returned map would contain 2 keys,
// filename - This represents the name of the file (same as what was provided by the test)
// contents - Base64 encoded String which contains the zipped file.
StringencodedContents=parsedResponse.get("contents");//The file contents would always be a zip file and has to be unzipped.
Zip.unzip(encodedContents,dirToCopyTo);System.out.println("The file which was "+"downloaded in the node is now available in the directory: "+dirToCopyTo.getAbsolutePath());}}privatestaticFirefoxOptionsfirefoxOptions(){FirefoxOptionsoptions=newFirefoxOptions();// This capability tells the Grid, that this test should be routed ONLY to a node that can
// auto manage downloads.
options.setCapability("se:downloadsEnabled",true);// Options specific for Firefox to avoid prompting a dialog for downloads. They might
// change in the future, so please refer to the Firefox documentation for up to date details.
options.addPreference("browser.download.manager.showWhenStarting",false);options.addPreference("browser.helperApps.neverAsk.saveToDisk","images/jpeg, application/pdf, application/octet-stream");options.addPreference("pdfjs.disabled",true);returnoptions;}}
3.4.3 - Toml Options
Grid configuration examples using Toml files.
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
All the options shown in CLI options can be configured through
a TOML file. This page shows configuration examples for the
different Grid components.
Note that this documentation could be outdated if an option was modified or added
but has not been documented yet. In case you bump into this situation, please check
the “Config help” section and feel free to send us a
pull request updating this page.
Overview
Selenium Grid uses TOML format for config files.
The config file consists of sections and each section has options and its respective value(s).
Refer to the TOML documentation for detailed usage guidance. In case of
parsing errors, validate the config using TOML linter.
The general configuration structure has the following pattern:
A Standalone or Node server that is able to run each new session in a Docker container. Disabling
drivers detection, having maximum 2 concurrent sessions. Stereotypes configured need to be mapped
to a Docker image, and the Docker daemon needs to be exposed via http/tcp. In addition, it is
possible to define which device files, accessible on the host, will be available in containers
through the devices property. Refer to the docker documentation
for more information about how docker device mapping works.
[node]detect-drivers=falsemax-sessions=2[docker]configs=["selenium/standalone-chrome:93.0","{\"browserName\": \"chrome\", \"browserVersion\": \"91\"}","selenium/standalone-firefox:92.0","{\"browserName\": \"firefox\", \"browserVersion\": \"92\"}"]#Optionally define all device files that should be mapped to docker containers#devices = [# "/dev/kvm:/dev/kvm"#]url="http://localhost:2375"video-image="selenium/video:latest"
Relaying commands to a service endpoint that supports WebDriver
It is useful to connect an external service that supports WebDriver to Selenium Grid.
An example of such service could be a cloud provider or an Appium server. In this way,
Grid can enable more coverage to platforms and versions not present locally.
The following is an en example of connecting an Appium server to Grid.
[node]detect-drivers=false[relay]# Default Appium/Cloud server endpointurl="http://localhost:4723/wd/hub"status-endpoint="/status"# Stereotypes supported by the service. The initial number is "max-sessions", and will allocate # that many test slots to that particular configurationconfigs=["5","{\"browserName\": \"chrome\", \"platformName\": \"android\", \"appium:platformVersion\": \"11\"}"]
Basic auth enabled
It is possible to protect a Grid with basic auth by configuring the Router/Hub/Standalone with
a username and password. This user/password combination will be needed when loading the Grid UI
or starting a new session.
The Node can be instructed to manage downloads automatically. This will cause the Node to save all files that were downloaded for a particular session into a temp directory, which can later be retrieved from the node.
To turn this capability on, use the below configuration:
A Grid está desenhada como um conjunto de componentes, em que cada tem
o seu papel crucial em manter a Grid. Isto pode parecer um pouco complicado,
mas esperamos que este documento ajude a esclarecer alguma confusão.
Os componentes chave
Os componentes principais da Grid são:
Event Bus
Usado para enviar mensagens que podem ser recebidas de forma assíncrona
entre os outros componentes.
New Session Queue
Mantém uma lista de pedidos de sessão que serão assignadas a um Node
pelo Distributor.
Distributor
Responsável por manter um modelo das localizações da Grid (slots) onde uma
sessão pode ser lançada e também por aceitar novos
pedidos de sessão
e assignar a um slot livre.
Node
Executa uma
sessão WebDriver. Cada sessão é assignada a um slot e cada Node tem
um ou mais slots.
Session Map
Mantém um mapeamento entre um ID de sessão
e o endereço do Node onde a sessão está a ser executada.
Router
Este é o ponto de entrada da Grid. É também a única parte da Grid
que poderá estar exposta à Internet (embora nós não recomendemos).
Este componente reencaminha novos pedidos para New Session Queue ou
para o Node onde a sessão esteja a ser executada
Ao falar da Grid, há alguns conceitos úteis a ter em mente:
Um slot é o sítio onde uma sessão pode ser executada
Cada slot tem um stereotype. Isto é um conjunto mínimo de capacidades
que um pedido de nova sessão terá que corresponder antes que o
Distributor envie esse pedido ao Node que tenha esse slot
O Grid Model é como o Distributor mantém o estado actual da Grid.
Como o nome sugere, este modelo pode perder o sincronismo com a realidade.
Este mecanismo é preferível do que estar a questionar cada Node, e
desta forma, o Distributor rapidamente consegue alocar uma nova sessão a um slot.
Chamadas Síncronas e Assíncronas
Existem duas formas de comunicação dentro da Grid:
Chamadas Síncronas “REST-ish” que usam JSON sobre pedidos HTTP.
Eventos Assíncronos enviados para o Event Bus.
Como é que escolhemos que tipo de mecanismo de comunicação a usar?
Afinal, podiamos ter escolhido usar apenas comunicação baseada em eventos
e tudo iria funcionar sem problemas.
No entanto a resposta correcta é, se a acção em curso é síncrona, por exemplo
a maioria das chamadas WebDriver, ou se perder uma resposta é problemático,
a Grid usa chamadas síncronas. Se quisermos propagar informação que pode ter
várias partes interessadas, ou se perder a mensagem não for crítico,
a Grid usará o event bus.
Um facto interessante a notar é que as chamadas assíncronas estão menos
“presas” aos processos que as executam do que todas as chamadas síncronas.
Sequência de início e dependencias entre componentes
Embora a Grid seja desenhada para permitir que os componentes possam iniciar
em qualquer ordem, conceptualmente é esperado que a ordem de início seja:
O Event Bus e o Session Map iniciam primeiro. Estes componentes não tem qualquer
dependencia, nem mesmo entre eles e como tal, podem iniciar em paralelo.
A Session Queue inicia de seguida
O Distributor inicia. Irá periodicamente procurar novos pedidos de sessão
na Session Queue, embora possa também receber um evento de um pedidos de sessão.
O Router pode ser agora iniciado. Novos pedidos de sessão são direccionados para
a Session Queue, o Distributor tentará encontrar um slot onde a sessão possa ser
executada.
O Node pode ser iniciado, veja mais abaixo os detalhes de como o Node se
regista na Grid. Uma vez que o registo esteja concluído, a Grid estará
pronta a receber pedidos.
Nesta tabela pode ser visualizada a dependencia ente os vários componentes.
Um “✅” indica que a dependência é síncrona.
Event Bus
Distributor
Node
Router
Session Map
Session Queue
Event Bus
X
Distributor
✅
X
✅
✅
Node
✅
X
Router
✅
X
✅
Session Map
X
Session Queue
✅
X
Registo de Node
O processo de registar um Node na Grid é um processo “leve”.
Quando um Node inicia, vai publicar um evento “heart beat” numa
base regular. Este evento contém o estado do Node.
O Distributor escuta os eventos “heart beat” e quando obtém um,
tenta um GET ao endpoint /status do Node. A Grid é
preparada com base nesta informação.
O Distributor irá usar regularmente o endpoint /status para continuar
a obter o estado do Node. Por seu lado, o Node continua a publicar um
evento “heart beat” mesmo depois do registo ter sido concluído com
sucesso.
Isto é feito para que mesmo que um Distributor não tenha um estado
da Grid possa reiniciar e assim obter novamente uma visão do estado
da Grid e assim ficar actualizado.
Objecto Node Status
O Node Status é um blob JSON com os seguintes campos:
Nome
Tipo
Descrição
availability
string
Uma string com up, draining, ou down. A mais importante é draining, que indica que não devem ser enviados novos pedidos de sessão para o Node e assim que a última sessão termine, o Node irá reiniciar ou concluir.
externalUrl
string
Uma URI que os outros componentes da Grid se devem ligar.
lastSessionCreated
integer
Um timestamp da última sessão que foi criada neste Node. O Distributor irá tentar enviar novos pedidos de sessão para o Node que esteja parado há mais tempo.
maxSessionCount
integer
Embora seja possível inferir o número máximo de sessões a partir da lista de slots disponíveis, este número é usado para determinar qual é o máximo de sessões que este Node pode executar em simultâneo antes que se considere que está “cheio”.
nodeId
string
Um identificador UUID para esta instância do Node.
osInfo
object
Um objecto contendo os campos arch, name, e version. Isto é usado pela Grid UI e pelas queries GraphQL.
slots
array
Um array de objectos Slot (descritos na secção seguinte)
version
string
A versão do Node (para Selenium, será igual à versão do Selenium)
É recomendado que todos os campos tenham valores.
O Objecto Slot
O objecto Slot representa um slot dentro de um Node. Um “slot” é onde uma sessão consegue ser executada. É possível que um Node tenha mais do que um Slot capaz de executar ao mesmo tempo.
Por exemplo, um Node pode ser capaz de executar até 10 sessões em simultâneo, mas podem ser uma qualquer combinação de Chrome, Firefox ou Edge e neste caso, o Node irá indicar 10 como o
número máximo de sessões, indicando que podem ser 10 Chrome, 10 Firefox e 10 Edge.
Nome
Tipo
Descrição
id
string
Um identificador UUID para este slot
lastStarted
string
timestamp no formato ISO-8601 contendo a data em que a última sessão iniciou
stereotype
object
Conjunto mínimo de capacidades que fazem match com este slot. O exemplo mínimo será por exemplo {"browserName": "firefox"}
session
object
O objecto Session (descrito na secção seguinte)
O Objecto Session
Representa uma sessão em execução dentro de um Slot
Nome
Tipo
Descrição
capabilities
object
A lista de capacidades fornecidas pela sessão. Irá coincidir com o valor obtido pelo comando nova sessão
startTime
string
timestamp no formato ISO-8601 contendo a data em que a última sessão iniciou
stereotype
object
Conjunto mínimo de capacidades que fazem match com este slot. O exemplo mínimo será por exemplo {"browserName": "firefox"}
uri
string
A URI usada pelo Node para comunicar com a sessão
3.6 - Advanced Features
To get all the details of the advanced features, understand how it works, and how to set up your own, please browse thorough the following sections.
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
3.6.1 - Observability
Page being translated from
English to Portuguese. Do you speak Portuguese? Help us to translate
it by sending us pull requests!
Grid aids in scaling and distributing tests by executing tests on various browser and operating system combinations.
Observability
Observability has three pillars: traces, metrics and logs. Since Selenium Grid 4 is designed to be fully distributed, observability will make it easier to understand and debug the internals.
Distributed tracing
A single request or transaction spans multiple services and components. Tracing tracks the request lifecycle as each service executes the request. It is useful in debugging in an error scenario.
Some key terms used in tracing context are:
Trace
Tracing allows one to trace a request through multiple services, starting from its origin to its final destination. This request’s journey helps in debugging, monitoring the end-to-end flow, and identifying failures. A trace depicts the end-to-end request flow. Each trace has a unique id as its identifier.
Span
Each trace is made up of timed operations called spans. A span has a start and end time and it represents operations done by a service. The granularity of span depends on how it is instrumented. Each span has a unique identifier. All spans within a trace have the same trace id.
Span Attributes
Span attributes are key-value pairs which provide additional information about each span.
Events
Events are timed-stamped logs within a span. They provide additional context to the existing spans. Events also contain key-value pairs as event attributes.
Event logging
Logging is essential to debug an application. Logging is often done in a human-readable format. But for machines to search and analyze the logs, it has to have a well-defined format. Structured logging is a common practice of recording logs consistently in a fixed format. It commonly contains fields like:
Timestamp
Logging level
Logger class
Log message (This is further broken down into fields relevant to the operation where the log was recorded)
Logs and events are closely related. Events encapsulate all the possible information available to do a single unit of work. Logs are essentially subsets of an event. At the crux, both aid in debugging.
Refer following resources for detailed understanding:
Selenium server is instrumented with tracing using OpenTelemetry. Every request to the server is traced from start to end. Each trace consists of a series of spans as a request is executed within the server.
Most spans in the Selenium server consist of two events:
Normal event - records all information about a unit of work and marks successful completion of the work.
Error event - records all information till the error occurs and then records the error information. Marks an exception event.
All spans, events and their respective attributes are part of a trace. Tracing works while running the server in all of the above-mentioned modes.
By default, tracing is enabled in the Selenium server. Selenium server exports the traces via two exporters:
Console - Logs all traces and their included spans at FINE level. By default, Selenium server prints logs at INFO level and above.
The log-level flag can be used to pass a logging level of choice while running the Selenium Grid jar/s.
java -jar selenium-server-4.0.0-<selenium-version>.jar standalone --log-level FINE
Jaeger UI - OpenTelemetry provides the APIs and SDKs to instrument traces in the code. Whereas Jaeger is a tracing backend, that aids in collecting the tracing telemetry data and providing querying, filtering and visualizing features for the data.
Detailed instructions of visualizing traces using Jaeger UI can be obtained by running the command :
java -jar selenium-server-4.0.0-<selenium-version>.jar info tracing
Tracing has to be enabled for event logging as well, even if one does not wish to export traces to visualize them. By default, tracing is enabled. No additional parameters need to be passed to see logs on the console.
All events within a span are logged at FINE level. Error events are logged at WARN level.
All event logs have the following fields :
Field
Field value
Description
Event time
eventId
Timestamp of the event record in epoch nanoseconds.
Trace Id
tracedId
Each trace is uniquely identified by a trace id.
Span Id
spanId
Each span within a trace is uniquely identified by a span id.
Span Kind
spanKind
Span kind is a property of span indicating the type of span. It helps in understanding the nature of the unit of work done by the Span.
Event name
eventName
This maps to the log message.
Event attributes
eventAttributes
This forms the crux of the event logs, based on the operation executed, it has JSON formatted key-value pairs. This also includes a handler class attribute, to show the logger class.
GraphQL é uma linguagem de consulta para APIs e um runtime para atender a essas consultas com seus dados existentes. Ele dá aos usuários o poder de pedir exatamente o que precisam e nada mais.
Enums
Enums representam possíveis conjuntos de valores para um campo.
Por exemplo, o objeto Node possui um campo chamado status. O estado é um enum (especificamente, do tipo Status) porque pode ser UP, DRAINING ou UNAVAILABLE.
Escalares
Escalares são valores primitivos: Int, Float, String, Boolean ou ID.
Ao chamar a API GraphQL, você deve especificar o subcampo aninhado até retornar apenas escalares.
O melhor jeito de consultar GraphQL é utilizando requisições curl. GraphQL permite que você busque apenas os dados que você quer, nada mais, anda menos.
Alguns exemplos de buscas em GraphQL estão abaixo. Você pode montar as queries como quiser.
Buscando o número total de slots (maxSession) e slots usados (sessionCount) na Grid:
O status da Grid fornece o estado atual da grid. Consiste em detalhes sobre cada nó registrado.
Para cada nó, o status inclui informações sobre a disponibilidade, sessões e slots do nó.
cURL GET 'http://localhost:4444/status'
No modo Standalone, o URL da Grid é o endereço do servidor Standalone.
No modo Hub-Node, a URL da Grid é o endereço do servidor Hub.
No modo totalmente distribuído, a URL da Grid é o endereço do servidor do roteador.
A URL padrão para todos os modos acima é http://localhost:4444.
Distribuidor
Remover Nó
Para remover o Nó da Grid, use o comando cURL listado abaixo.
Ele não interrompe nenhuma sessão em andamento em execução nesse nó.
O Node continua rodando como está, a menos que seja explicitamente eliminado.
O Distribuidor não está mais ciente do Nó e, portanto, qualquer solicitação de nova sessão correspondente
não será encaminhado para esse Nó.
No modo Standalone, a URL do distribuidor é o endereço do servidor Standalone.
No modo Hub-Node, a URL do Distribuidor é o endereço do servidor Hub.
O comando de drenagem de nó é para desligamento normal de nó.
A drenagem para o Node após a conclusão de todas as sessões em andamento.
No entanto, ele não aceita novas solicitações de sessão.
No modo Standalone, a URL do distribuidor é o endereço do servidor Standalone.
No modo Hub-Node, a URL do Distribuidor é o endereço do servidor Hub.
cURL --request POST 'http://localhost:4444/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET: <secret> '
No modo totalmente distribuído, a URL é o endereço do servidor Distribuidor.
cURL --request POST 'http://localhost:5553/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET: <secret>'
Se nenhum segredo de registro foi configurado durante a configuração da Grid, use
cURL --request POST 'http://<Distributor-URL>/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET;'
Nó
Os terminais nesta seção são aplicáveis ao modo Hub-Node e ao modo Grid totalmente distribuída, onde o Nó é executado de forma independente.
A URL do Nó padrão é http://localhost:5555 no caso de um Nó.
No caso de vários Nós, use Grid status para obter todos os detalhes do Nó e localizar o endereço do Nó.
Status
O status do Nó é essencialmente uma verificação de integridade do Nó.
O distribuidor executa ping no status do Nó em intervalos regulares e atualiza o modelo de Grid de acordo.
O status inclui informações sobre disponibilidade, sessões e slots.
cURL --request GET 'http://localhost:5555/status'
Drenagem
O Distribuidor passa o comando [drain](# drain-node) para o Nó apropriado identificado pelo ID do Nó.
Para drenar o Nó diretamente, use o comando cuRL listado abaixo.
Ambos as rotas são válidas e produzem o mesmo resultado. Drenar termina as sessões em andamento antes de interromper o Nó.
cURL --request POST 'http://localhost:5555/se/grid/node/drain' --header 'X-REGISTRATION-SECRET: <secret>'
Se nenhum segredo de registro foi configurado durante a configuração da Grid, use
cURL --request POST 'http://<node-URL>/se/grid/node/drain' --header 'X-REGISTRATION-SECRET;'
Checar dono da sessão
Para verificar se uma sessão pertence a um Nó, use o comando cURL listado abaixo.
cURL --request GET 'http://localhost:5555/se/grid/node/owner/<session-id>' --header 'X-REGISTRATION-SECRET: <secret>'
Se nenhum segredo de registro foi configurado durante a configuração da Grid, use
cURL --request GET 'http://<node-URL>/se/grid/node/owner/<session-id>' --header 'X-REGISTRATION-SECRET;'
Ele retornará true se a sessão pertencer ao Nó, caso contrário, retornará false.
Deletar sessão
A exclusão da sessão encerra a sessão do WebDriver, fecha o driver e o remove do mapa de sessões ativas.
Qualquer solicitação usando o id de sessão removido ou reutilizando a instância do driver gerará um erro.
A Fila de Sessão contém as novas solicitações de sessão.
Para limpar a fila, use o comando cURL listado abaixo.
Limpar a fila rejeita todas as solicitações na fila. Para cada solicitação, o servidor retorna uma resposta de erro ao respectivo cliente.
O resultado do comando clear é o número total de solicitações excluídas.
No modo Standalone, a URL Queue é o endereço do servidor Standalone.
No modo Hub-Node, a URL do enfileirador é o endereço do servidor Hub.
Novos pedidos da Fila de Sessão contém os novos pedidos de sessão.
Para obter os pedidos na Fila, utiliza o comando cURL listado abaixo.
É retornado o número total de pedidos na Fila.
No modo Standalone, a URL é a do servidor, em modo Grid, a URL será a do HUB.
cURL --request GET 'http://localhost:4444/se/grid/newsessionqueue/queue'
No modo totalmente distribuido, a URL da Fila é a porta do servidor de Fila.
cURL --request GET 'http://localhost:5559/se/grid/newsessionqueue/queue'
3.6.4 - Customizing a Node
Page being translated from
English to Portugese. Do you speak Portugese? Help us to translate
it by sending us pull requests!
How to customize a Node
There are times when we would like a Node to be customized to our needs.
For e.g., we may like to do some additional setup before a session begins execution and some clean-up after a session runs to completion.
Following steps can be followed for this:
Create a class that extends org.openqa.selenium.grid.node.Node
Add a static method (this will be our factory method) to the newly created class whose signature looks like this:
public static Node create(Config config). Here:
Node is of type org.openqa.selenium.grid.node.Node
Config is of type org.openqa.selenium.grid.config.Config
Within this factory method, include logic for creating your new Class.
To wire in this new customized logic into the hub, start the node and pass in the fully qualified class name of the above class to the argument --node-implementation
Let’s see an example of all this:
Custom Node as an uber jar
Create a sample project using your favourite build tool (Maven|Gradle).
Note: If you are using Maven as a build tool, please prefer using maven-shade-plugin instead of maven-assembly-plugin because maven-assembly plugin seems to have issues with being able to merge multiple Service Provider Interface files (META-INF/services)
Custom Node as a regular jar
Create a sample project using your favourite build tool (Maven|Gradle).
Below is a sample that just prints some messages on to the console whenever there’s an activity of interest (session created, session deleted, a webdriver command executed etc.,) on the Node.
Sample customized node
packageorg.seleniumhq.samples;importjava.net.URI;importjava.util.UUID;importorg.openqa.selenium.Capabilities;importorg.openqa.selenium.NoSuchSessionException;importorg.openqa.selenium.WebDriverException;importorg.openqa.selenium.grid.config.Config;importorg.openqa.selenium.grid.data.CreateSessionRequest;importorg.openqa.selenium.grid.data.CreateSessionResponse;importorg.openqa.selenium.grid.data.NodeId;importorg.openqa.selenium.grid.data.NodeStatus;importorg.openqa.selenium.grid.data.Session;importorg.openqa.selenium.grid.log.LoggingOptions;importorg.openqa.selenium.grid.node.HealthCheck;importorg.openqa.selenium.grid.node.Node;importorg.openqa.selenium.grid.node.local.LocalNodeFactory;importorg.openqa.selenium.grid.security.Secret;importorg.openqa.selenium.grid.security.SecretOptions;importorg.openqa.selenium.grid.server.BaseServerOptions;importorg.openqa.selenium.internal.Either;importorg.openqa.selenium.remote.SessionId;importorg.openqa.selenium.remote.http.HttpRequest;importorg.openqa.selenium.remote.http.HttpResponse;importorg.openqa.selenium.remote.tracing.Tracer;publicclassDecoratedLoggingNodeextendsNode{privateNodenode;protectedDecoratedLoggingNode(Tracertracer,URIuri,SecretregistrationSecret){super(tracer,newNodeId(UUID.randomUUID()),uri,registrationSecret);}publicstaticNodecreate(Configconfig){LoggingOptionsloggingOptions=newLoggingOptions(config);BaseServerOptionsserverOptions=newBaseServerOptions(config);URIuri=serverOptions.getExternalUri();SecretOptionssecretOptions=newSecretOptions(config);// Refer to the foot notes for additional context on this line.
Nodenode=LocalNodeFactory.create(config);DecoratedLoggingNodewrapper=newDecoratedLoggingNode(loggingOptions.getTracer(),uri,secretOptions.getRegistrationSecret());wrapper.node=node;returnwrapper;}@OverridepublicEither<WebDriverException,CreateSessionResponse>newSession(CreateSessionRequestsessionRequest){System.out.println("Before newSession()");try{returnthis.node.newSession(sessionRequest);}finally{System.out.println("After newSession()");}}@OverridepublicHttpResponseexecuteWebDriverCommand(HttpRequestreq){try{System.out.println("Before executeWebDriverCommand(): "+req.getUri());returnnode.executeWebDriverCommand(req);}finally{System.out.println("After executeWebDriverCommand()");}}@OverridepublicSessiongetSession(SessionIdid)throwsNoSuchSessionException{try{System.out.println("Before getSession()");returnnode.getSession(id);}finally{System.out.println("After getSession()");}}@OverridepublicHttpResponseuploadFile(HttpRequestreq,SessionIdid){try{System.out.println("Before uploadFile()");returnnode.uploadFile(req,id);}finally{System.out.println("After uploadFile()");}}@Overridepublicvoidstop(SessionIdid)throwsNoSuchSessionException{try{System.out.println("Before stop()");node.stop(id);}finally{System.out.println("After stop()");}}@OverridepublicbooleanisSessionOwner(SessionIdid){try{System.out.println("Before isSessionOwner()");returnnode.isSessionOwner(id);}finally{System.out.println("After isSessionOwner()");}}@OverridepublicbooleanisSupporting(Capabilitiescapabilities){try{System.out.println("Before isSupporting");returnnode.isSupporting(capabilities);}finally{System.out.println("After isSupporting()");}}@OverridepublicNodeStatusgetStatus(){try{System.out.println("Before getStatus()");returnnode.getStatus();}finally{System.out.println("After getStatus()");}}@OverridepublicHealthCheckgetHealthCheck(){try{System.out.println("Before getHealthCheck()");returnnode.getHealthCheck();}finally{System.out.println("After getHealthCheck()");}}@Overridepublicvoiddrain(){try{System.out.println("Before drain()");node.drain();}finally{System.out.println("After drain()");}}@OverridepublicbooleanisReady(){try{System.out.println("Before isReady()");returnnode.isReady();}finally{System.out.println("After isReady()");}}}
Foot Notes:
In the above example, the line Node node = LocalNodeFactory.create(config); explicitly creates a LocalNode.
There are basically 2 types of user facing implementations of org.openqa.selenium.grid.node.Node available.
These classes are good starting points to learn how to build a custom Node and also to learn the internals of a Node.
org.openqa.selenium.grid.node.local.LocalNode - Used to represent a long running Node and is the default implementation that gets wired in when you start a node.
It can be created by calling LocalNodeFactory.create(config);, where:
LocalNodeFactory belongs to org.openqa.selenium.grid.node.local
Config belongs to org.openqa.selenium.grid.config
org.openqa.selenium.grid.node.k8s.OneShotNode - This is a special reference implementation wherein the Node gracefully shuts itself down after servicing one test session. This class is currently not available as part of any pre-built maven artifact.
You can refer to the source code here to understand its internals.
Selenium Grid allows you to persist information related to currently running sessions into an external data store.
The external data store could be backed by your favourite database (or) Redis Cache system.
Setup
Coursier - As a dependency resolver, so that we can download maven artifacts on the fly and make them available in our classpath
Docker - To manage our PostGreSQL/Redis docker containers.
Database backed Session Map
For the sake of this illustration, we are going to work with PostGreSQL database.
We will spin off a PostGreSQL database as a docker container using a docker compose file.
Steps
You can skip this step if you already have a PostGreSQL database instance available at your disposal.
Create a sql file named init.sql with the below contents:
We can now start our database container by running:
docker-compose up -d
Our database name is selenium_sessions with its username and password set to seluser
If you are working with an already running PostGreSQL DB instance, then you just need to create a database named selenium_sessions and the table sessions_map using the above mentioned SQL statement.
Create a Selenium Grid configuration file named sessions.toml with the below contents:
At this point the current directory should contain the following files:
docker-compose.yml
init.sql
sessions.toml
distributed.sh
You can now spawn the Grid by running distributed.sh shell script and quickly run a test. You will notice that the Grid now stores session information into the PostGreSQL database.
In the line which spawns a SessionMap on a machine:
At this point the current directory should contain the following files:
docker-compose.yml
sessions.toml
distributed.sh
You can now spawn the Grid by running distributed.sh shell script and quickly run a test. You will notice that the Grid now stores session information into the Redis instance. You can perhaps make use of a Redis GUI such as TablePlus to see them (Make sure that you have setup a debug point in your test, because the values will get deleted as soon as the test runs to completion).
In the line which spawns a SessionMap on a machine:
The InternetExplorerDriver is a standalone server which implements WebDriver’s wire protocol.
This driver has been tested with IE 11, and on Windows 10. It might work with older versions
of IE and Windows, but this is not supported.
The driver supports running 32-bit and 64-bit versions of the browser. The choice of how to
determine which “bit-ness” to use in launching the browser depends on which version of the
IEDriverServer.exe is launched. If the 32-bit version of IEDriverServer.exe is launched,
the 32-bit version of IE will be launched. Similarly, if the 64-bit version of
IEDriverServer.exe is launched, the 64-bit version of IE will be launched.
Installing
You do not need to run an installer before using the InternetExplorerDriver, though some
configuration is required. The standalone server executable must be downloaded from
the Downloads page and placed in your
PATH.
Pros
Runs in a real browser and supports JavaScript
Cons
Obviously the InternetExplorerDriver will only work on Windows!
Comparatively slow (though still pretty snappy :)
Command-Line Switches
As a standalone executable, the behavior of the IE driver can be modified through various
command-line arguments. To set the value of these command-line arguments, you should
consult the documentation for the language binding you are using. The command line
switches supported are described in the table below. All -<switch>, –<switch>
and /<switch> are supported.
Switch
Meaning
–port=<portNumber>
Specifies the port on which the HTTP server of the IE driver will listen for commands from language bindings. Defaults to 5555.
–host=<hostAdapterIPAddress>
Specifies the IP address of the host adapter on which the HTTP server of the IE driver will listen for commands from language bindings. Defaults to 127.0.0.1.
–log-level=<logLevel>
Specifies the level at which logging messages are output. Valid values are FATAL, ERROR, WARN, INFO, DEBUG, and TRACE. Defaults to FATAL.
–log-file=<logFile>
Specifies the full path and file name of the log file. Defaults to stdout.
–extract-path=<path>
Specifies the full path to the directory used to extract supporting files used by the server. Defaults to the TEMP directory if not specified.
–silent
Suppresses diagnostic output when the server is started.
Important System Properties
The following system properties (read using System.getProperty() and set using
System.setProperty() in Java code or the “-DpropertyName=value” command line flag)
are used by the InternetExplorerDriver:
Property
What it means
webdriver.ie.driver
The location of the IE driver binary.
webdriver.ie.driver.host
Specifies the IP address of the host adapter on which the IE driver will listen.
webdriver.ie.driver.loglevel
Specifies the level at which logging messages are output. Valid values are FATAL, ERROR, WARN, INFO, DEBUG, and TRACE. Defaults to FATAL.
webdriver.ie.driver.logfile
Specifies the full path and file name of the log file.
webdriver.ie.driver.silent
Suppresses diagnostic output when the IE driver is started.
webdriver.ie.driver.extractpath
Specifies the full path to the directory used to extract supporting files used by the server. Defaults to the TEMP directory if not specified.
Required Configuration
The IEDriverServer executable must be downloaded and placed in your PATH.
On IE 7 or higher on Windows Vista, Windows 7, or Windows 10, you must set the Protected Mode settings for each zone to be the same value. The value can be on or off, as long as it is the same for every zone. To set the Protected Mode settings, choose “Internet Options…” from the Tools menu, and click on the Security tab. For each zone, there will be a check box at the bottom of the tab labeled “Enable Protected Mode”.
Additionally, “Enhanced Protected Mode” must be disabled for IE 10 and higher. This option is found in the Advanced tab of the Internet Options dialog.
The browser zoom level must be set to 100% so that the native mouse events can be set to the correct coordinates.
For Windows 10, you also need to set “Change the size of text, apps, and other items” to 100% in display settings.
For IE 11 only, you will need to set a registry entry on the target computer so that the driver can maintain a connection to the instance of Internet Explorer it creates. For 32-bit Windows installations, the key you must examine in the registry editor is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BFCACHE. For 64-bit Windows installations, the key is HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BFCACHE. Please note that the FEATURE_BFCACHE subkey may or may not be present, and should be created if it is not present. Important: Inside this key, create a DWORD value named iexplore.exe with the value of 0.
Native Events and Internet Explorer
As the InternetExplorerDriver is Windows-only, it attempts to use so-called “native”, or OS-level
events to perform mouse and keyboard operations in the browser. This is in contrast to using
simulated JavaScript events for the same operations. The advantage of using native events is that
it does not rely on the JavaScript sandbox, and it ensures proper JavaScript event propagation
within the browser. However, there are currently some issues with mouse events when the IE
browser window does not have focus, and when attempting to hover over elements.
Browser Focus
The challenge is that IE itself appears to not fully respect the Windows messages we send the
IE browser window (WM\_MOUSEDOWN and WM\_MOUSEUP) if the window doesn’t have the focus.
Specifically, the element being clicked on will receive a focus window around it, but the click
will not be processed by the element. Arguably, we shouldn’t be sending messages at all; rather,
we should be using the SendInput() API, but that API explicitly requires the window to have the
focus. We have two conflicting goals with the WebDriver project.
First, we strive to emulate the user as closely as possible. This means using native events
rather than simulating the events using JavaScript.
Second, we want to not require focus of the browser window being automated. This means that
just forcing the browser window to the foreground is suboptimal.
An additional consideration is the possibility of multiple IE instances running under multiple
WebDriver instances, which means any such “bring the window to the foreground” solution will
have to be wrapped in some sort of synchronizing construct (mutex?) within the IE driver’s
C++ code. Even so, this code will still be subject to race conditions, if, for example, the
user brings another window to the foreground between the driver bringing IE to the foreground
and executing the native event.
The discussion around the requirements of the driver and how to prioritize these two
conflicting goals is ongoing. The current prevailing wisdom is to prioritize the former over
the latter, and document that your machine will be unavailable for other tasks when using
the IE driver. However, that decision is far from finalized, and the code to implement it is
likely to be rather complicated.
Hovering Over Elements
When you attempt to hover over elements, and your physical mouse cursor is within the boundaries
of the IE browser window, the hover will not work. More specifically, the hover will appear
to work for a fraction of a second, and then the element will revert back to its previous
state. The prevailing theory why this occurs is that IE is doing hit-testing of some sort
during its event loop, which causes it to respond to the physical mouse position when the
physical cursor is within the window bounds. The WebDriver development team has been unable
to discover a workaround for this behavior of IE.
Clicking <option> Elements or Submitting Forms and alert()
There are two places where the IE driver does not interact with elements using native events.
This is in clicking <option> elements within a <select> element. Under normal circumstances,
the IE driver calculates where to click based on the position and size of the element, typically
as returned by the JavaScript getBoundingClientRect() method. However, for <option> elements,
getBoundingClientRect() returns a rectangle with zero position and zero size. The IE driver
handles this one scenario by using the click() Automation Atom, which essentially sets
the .selected property of the element and simulates the onChange event in JavaScript.
However, this means that if the onChange event of the <select> element contains JavaScript
code that calls alert(), confirm() or prompt(), calling WebElement’s click() method will
hang until the modal dialog is manually dismissed. There is no known workaround for this behavior
using only WebDriver code.
Similarly, there are some scenarios when submitting an HTML form via WebElement’s submit()
method may have the same effect. This can happen if the driver calls the JavaScript submit()
function on the form, and there is an onSubmit event handler that calls the JavaScript alert(),
confirm(), or prompt() functions.
This restriction is filed as issue 3508 (on Google Code).
Multiple instances of InternetExplorerDriver
With the creation of the IEDriverServer.exe, it should be possible to create and use multiple
simultaneous instances of the InternetExplorerDriver. However, this functionality is largely
untested, and there may be issues with cookies, window focus, and the like. If you attempt to
use multiple instances of the IE driver, and run into such issues, consider using the
RemoteWebDriver and virtual machines.
There are 2 solutions for problem with cookies (and another session items) shared between
multiple instances of InternetExplorer.
The first is to start your InternetExplorer in private mode. After that InternetExplorer will be
started with clean session data and will not save changed session data at quiting. To do so you
need to pass 2 specific capabilities to driver: ie.forceCreateProcessApi with true value
and ie.browserCommandLineSwitches with -private value. Be note that it will work only
for InternetExplorer 8 and newer, and Windows Registry
HKLM_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main path should contain key
TabProcGrowth with 0 value.
The second is to clean session during InternetExplorer starting. For this you need to pass
specific ie.ensureCleanSession capability with true value to driver. This clears the cache
for all running instances of InternetExplorer, including those started manually.
Running IEDriverServer.exe Remotely
The HTTP server started by the IEDriverServer.exe sets an access control list to only accept
connections from the local machine, and disallows incoming connections from remote machines.
At present, this cannot be changed without modifying the source code to the IEDriverServer.exe.
To run the Internet Explorer driver on a remote machine, use the Java standalone remote server
in connection with your language binding’s equivalent of RemoteWebDriver.
Running IEDriverServer.exe Under a Windows Service
Attempting to use IEDriverServer.exe as part of a Windows Service application is expressly
unsupported. Service processes, and processes spawned by them, have much different requirements
than those executing in a regular user context. IEDriverServer.exe is explicitly untested in
that environment, and includes Windows API calls that are documented to be prohibited to be used
in service processes. While it may be possible to get the IE driver to work while running under
a service process, users encountering problems in that environment will need to seek out their
own solutions.
4.1 - Internet Explorer Driver Internals
More detailed information on the IE Driver.
Client Code Into the Driver
We use the W3C WebDriver protocol to communicate with a local instance of an HTTP server. This greatly simplifies the implementation of the language-specific code, and minimzes the number of entry points into the C++ DLL that must be called using a native-code interop technology such as JNA, ctypes, pinvoke or DL.
Memory Management
The IE driver utilizes the Active Template Library (ATL) to take advantage of its implementation of smart pointers to COM objects. This makes reference counting and cleanup of COM objects much easier.
Why Do We Require Protected Mode Settings Changes?
IE 7 on Windows Vista introduced the concept of Protected Mode, which allows for some measure of protection to the underlying Windows OS when browsing. The problem is that when you manipulate an instance of IE via COM, and you navigate to a page that would cause a transition into or out of Protected Mode, IE requires that another browser session be created. This will orphan the COM object of the previous session, not allowing you to control it any longer.
In IE 7, this will usually manifest itself as a new top-level browser window; in IE 8, a new IExplore.exe process will be created, but it will usually (not always!) seamlessly attach it to the existing IE top-level frame window. Any browser automation framework that drives IE externally (as opposed to using a WebBrowser control) will run into these problems.
In order to work around that problem, we dictate that to work with IE, all zones must have the same Protected Mode setting. As long as it’s on for all zones, or off for all zones, we can prevent the transistions to different Protected Mode zones that would invalidate our browser object. It also allows users to continue to run with UAC turned on, and to run securely in the browser if they set Protected Mode “on” for all zones.
In earlier releases of the IE driver, if the user’s Protected Mode settings were not correctly set, we would launch IE, and the process would simply hang until the HTTP request timed out. This was suboptimal, as it gave no indication what needed to be set. Erring on the side of caution, we do not modify the user’s Protected Mode settings. Current versions, however check that the Protected Mode settings are properly set, and will return an error response if they are not.
There are two ways that we could simulate keyboard and mouse input. The first way, which is used in parts of webdriver, is to synthesize events on the DOM. This has a number of drawbacks, since each browser (and version of a browser) has its own unique quirks; to model each of these is a demanding task, and impossible to get completely right (for example, it’s hard to tell what window.selection should be and this is a read-only property on some browsers) The alternative approach is to synthesize keyboard and mouse input at the OS level, ideally without stealing focus from the user (who tends to be doing other things on their computer as long-running webdriver tests run)
The code for doing this is in interactions.cpp The key thing to note here is that we use PostMessages to push window events on to the message queue of the IE instance. Typing, in particular, is interesting: we only send the “keydown” and “keyup” messages. The “keypress” event is created if necessary by IE’s internal event processing. Because the key press event is not always generated (for example, not every character is printable, and if the default event bubbling is cancelled, listeners don’t see the key press event) we send a “probe” event in after the key down. Once we see that this has been processed, we know that the key press event is on the stack of events to be processed, and that it is safe to send the key up event. If this was not done, it is possible for events to fire in the wrong order, which is definitely sub-optimal.
Working On the InternetExplorerDriver
Currently, there are tests that will run for the InternetExplorerDriver in all languages (Java, C#, Python, and Ruby), so you should be able to test your changes to the native code no matter what language you’re comfortable working in from the client side. For working on the C++ code, you’ll need Visual Studio 2010 Professional or higher. Unfortunately, the C++ code of the driver uses ATL to ease the pain of working with COM objects, and ATL is not supplied with Visual C++ 2010 Express Edition. If you’re using Eclipse, the process for making and testing modifications is:
Edit the C++ code in VS.
Build the code to ensure that it compiles
Do a complete rebuild when you are ready to run a test. This will cause the created DLL to be copied to the right place to allow its use in Eclipse
Load Eclipse (or some other IDE, such as Idea)
Edit the SingleTestSuite so that it is usingDriver(IE)
Create a JUnit run configuration that uses the “webdriver-internet-explorer” project. If you don’t do this, the test won’t work at all, and there will be a somewhat cryptic error message on the console.
Once the basic setup is done, you can start working on the code pretty quickly. You can attach to the process you execute your code from using Visual Studio (from the Debug menu, select Attach to Process…).
5 - Selenium IDE
Selenium IDE é uma extensão do navegador que grava e reproduz uma acção do utilizador.
Selenium’s Integrated Development Environment (Selenium IDE)
é uma ferramenta de utilização simples que grava as acções de um utilizador usando comandos Selenium com parametros definidos conforme o contexto de cada elemento.
Esta é uma forma excelente de aprender todo o sintaxe Selenium.
Está disponível para os navegadores Google Chrome, Mozilla Firefox, e Microsoft Edge.
Guias e recomendações ao preparar soluções de testes com o projecto Selenium.
Uma nota sobre “Melhores práticas”: evitamos intencionalmente a frase “Melhores
Práticas” nesta documentação. Nenhuma abordagem funciona para todas as situações.
Preferimos a ideia de “Diretrizes e Recomendações”. Nós encorajamos
que você leia e decida cuidadosamente quais abordagens
funcionarão para você em seu ambiente específico.
O teste funcional é difícil de acertar por muitos motivos.
Como se o estado, a complexidade e as dependências do aplicativo não tornassem o teste suficientemente difícil,
lidar com navegadores (especialmente com incompatibilidades entre navegadores)
torna a escrita de bons testes um desafio.
Selenium fornece ferramentas para facilitar a interação funcional do usuário,
mas não o ajuda a escrever suítes de teste bem arquitetadas.
Neste capítulo, oferecemos conselhos, diretrizes e recomendações
sobre como abordar a automação funcional de páginas da web.
Este capítulo registra os padrões de design de software populares
entre muitos dos usuários do Selenium
que tiveram sucesso ao longo dos anos.
Over time, projects tend to accumulate large numbers of tests. As the total number of tests increases,
it becomes harder to make changes to the codebase — a single “simple”
change may cause numerous tests to fail, even though the application still
works properly. Sometimes these problems are unavoidable, but when they do
occur you want to be up and running again as quickly as possible. The following
design patterns and strategies have been used before with WebDriver to help make
tests easier to write and maintain. They may help you too.
DomainDrivenDesign: Express your tests in the language of the end-user of the app.
PageObjects: A simple abstraction of the UI of your web app.
LoadableComponent: Modeling PageObjects as components.
BotStyleTests: Using a command-based approach to automating tests, rather than the object-based approach that PageObjects encourage
Loadable Component
What Is It?
The LoadableComponent is a base class that aims to make writing PageObjects
less painful. It does this by providing a standard way of ensuring that
pages are loaded and providing hooks to make debugging the failure of a
page to load easier. You can use it to help reduce the amount of boilerplate
code in your tests, which in turn make maintaining your tests less tiresome.
There is currently an implementation in Java that ships as part of Selenium 2,
but the approach used is simple enough to be implemented in any language.
Simple Usage
As an example of a UI that we’d like to model, take a look at
the new issue page. From
the point of view of a test author, this offers the service of being able to
file a new issue. A basic Page Object would look like:
In order to turn this into a LoadableComponent, all we need to do is to set that as the base type:
publicclassEditIssueextendsLoadableComponent<EditIssue>{// rest of class ignored for now
}
This signature looks a little unusual, but it all means is that this class
represents a LoadableComponent that loads the EditIssue page.
By extending this base class, we need to implement two new methods:
@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues/new");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();assertTrue("Not on the issue entry page: "+url,url.endsWith("/new"));}
The load method is used to navigate to the page, whilst the isLoaded method
is used to determine whether we are on the right page. Although the
method looks like it should return a boolean, instead it performs a
series of assertions using JUnit’s Assert class. There can be as few
or as many assertions as you like. By using these assertions it’s
possible to give users of the class clear information that can be
used to debug tests.
With a little rework, our PageObject looks like:
packagecom.example.webdriver;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;import staticjunit.framework.Assert.assertTrue;publicclassEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;// By default the PageFactory will locate elements with the same name or id
// as the field. Since the summary element has a name attribute of "summary"
// we don't need any additional annotations.
privateWebElementsummary;// Same with the submit element, which has the ID "submit"
privateWebElementsubmit;// But we'd prefer a different name in our code than "comment", so we use the
// FindBy annotation to tell the PageFactory how to locate the element.
@FindBy(name="comment")privateWebElementdescription;publicEditIssue(WebDriverdriver){this.driver=driver;// This call sets the WebElement fields.
PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues/new");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();assertTrue("Not on the issue entry page: "+url,url.endsWith("/new"));}publicvoidsetSummary(StringissueSummary){clearAndType(summary,issueSummary);}publicvoidenterDescription(StringissueDescription){clearAndType(description,issueDescription);}publicIssueListsubmit(){submit.click();returnnewIssueList(driver);}privatevoidclearAndType(WebElementfield,Stringtext){field.clear();field.sendKeys(text);}}
That doesn’t seem to have bought us much, right? One thing it has done is
encapsulate the information about how to navigate to the page into the page
itself, meaning that this information’s not scattered through the code base.
It also means that we can do this in our tests:
EditIssuepage=newEditIssue(driver).get();
This call will cause the driver to navigate to the page if that’s necessary.
Nested Components
LoadableComponents start to become more useful when they are used in conjunction
with other LoadableComponents. Using our example, we could view the “edit issue”
page as a component within a project’s website (after all, we access it via a
tab on that site). You also need to be logged in to file an issue. We could
model this as a tree of nested components:
+ ProjectPage
+---+ SecuredPage
+---+ EditIssue
What would this look like in code? For a start, each logical component
would have its own class. The “load” method in each of them would “get”
the parent. The end result, in addition to the EditIssue class above is:
packagecom.example.webdriver;importorg.openqa.selenium.By;importorg.openqa.selenium.NoSuchElementException;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;import staticorg.junit.Assert.fail;publicclassSecuredPageextendsLoadableComponent<SecuredPage>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;privatefinalStringusername;privatefinalStringpassword;publicSecuredPage(WebDriverdriver,LoadableComponent<?>parent,Stringusername,Stringpassword){this.driver=driver;this.parent=parent;this.username=username;this.password=password;}@Overrideprotectedvoidload(){parent.get();StringoriginalUrl=driver.getCurrentUrl();// Sign in
driver.get("https://www.google.com/accounts/ServiceLogin?service=code");driver.findElement(By.name("Email")).sendKeys(username);WebElementpasswordField=driver.findElement(By.name("Passwd"));passwordField.sendKeys(password);passwordField.submit();// Now return to the original URL
driver.get(originalUrl);}@OverrideprotectedvoidisLoaded()throwsError{// If you're signed in, you have the option of picking a different login.
// Let's check for the presence of that.
try{WebElementdiv=driver.findElement(By.id("multilogin-dropdown"));}catch(NoSuchElementExceptione){fail("Cannot locate user name link");}}}
This shows that the components are all “nested” within each other. A call to get() in EditIssue will cause all its dependencies to load too. The example usage:
publicclassFooTest{privateEditIssueeditIssue;@BeforepublicvoidprepareComponents(){WebDriverdriver=newFirefoxDriver();ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","top secret");editIssue=newEditIssue(driver,securedPage);}@TestpublicvoiddemonstrateNestedLoadableComponents(){editIssue.get();editIssue.setSummary("Summary");editIssue.enterDescription("This is an example");}}
If you’re using a library such as Guiceberry in your tests,
the preamble of setting up the PageObjects can be omitted leading to nice, clear, readable tests.
Although PageObjects are a useful way of reducing duplication in your tests, it’s not always a pattern that teams feel comfortable following. An alternative approach is to follow a more “command-like” style of testing.
A “bot” is an action-oriented abstraction over the raw Selenium APIs. This means that if you find that commands aren’t doing the Right Thing for your app, it’s easy to change them. As an example:
publicclassActionBot{privatefinalWebDriverdriver;publicActionBot(WebDriverdriver){this.driver=driver;}publicvoidclick(Bylocator){driver.findElement(locator).click();}publicvoidsubmit(Bylocator){driver.findElement(locator).submit();}/**
* Type something into an input field. WebDriver doesn't normally clear these
* before typing, so this method does that first. It also sends a return key
* to move the focus out of the element.
*/publicvoidtype(Bylocator,Stringtext){WebElementelement=driver.findElement(locator);element.clear();element.sendKeys(text+"\n");}}
Once these abstractions have been built and duplication in your tests identified, it’s possible to layer PageObjects on top of bots.
6.2 - Sobre automação de testes
Primeiro, comece perguntando a si mesmo se você realmente precisa ou não de um navegador.
As probabilidades são de que, em algum ponto, se você estiver trabalhando em um aplicativo da web complexo,
você precisará abrir um navegador e realmente testá-lo.
No entanto, os testes funcionais do usuário final, como os testes Selenium, são caros para executar.
Além disso, eles normalmente exigem infraestrutura substancial
para ser executado de forma eficaz.
É uma boa regra sempre se perguntar se o que você deseja testar
pode ser feito usando abordagens de teste mais leves, como testes de unidade
ou com uma abordagem de nível inferior.
Depois de determinar que está no negócio de teste de navegador da web,
e você tem seu ambiente Selenium pronto para começar a escrever testes,
você geralmente executará alguma combinação de três etapas:
Configurar os dados
Executar um conjunto discreto de ações
Avaliar os resultados
Você deve manter essas etapas o mais curtas possível;
uma ou duas operações devem ser suficientes na maioria das vezes.
A automação do navegador tem a reputação de ser “instável”,
mas, na realidade, é porque os usuários freqüentemente exigem muito dele.
Em capítulos posteriores, retornaremos às técnicas que você pode usar
para mitigar problemas aparentemente intermitentes nos testes,
em particular sobre como superar as condições de corrida
entre o navegador e o WebDriver.
Mantendo seus testes curtos
e usando o navegador da web apenas quando você não tiver absolutamente nenhuma alternativa,
você pode ter muitos testes com instabilidade mínima.
Uma vantagem distinta dos testes do Selenium
é sua capacidade inerente de testar todos os componentes do aplicativo,
de back-end para front-end, da perspectiva do usuário.
Em outras palavras, embora os testes funcionais possam ser caros para executar,
eles também abrangem grandes partes críticas para os negócios de uma só vez.
Requerimentos de teste
Como mencionado antes, os testes do Selenium podem ser caros para serem executados.
Até que ponto depende do navegador em que você está executando os testes,
mas historicamente o comportamento dos navegadores tem variado tanto que muitas vezes
foi uma meta declarada testar cruzado contra vários navegadores.
Selenium permite que você execute as mesmas instruções em vários navegadores
em vários sistemas operacionais,
mas a enumeração de todos os navegadores possíveis,
suas diferentes versões e os muitos sistemas operacionais em que são executados
rapidamente se tornará uma tarefa não trivial.
Vamos começar com um exemplo
Larry escreveu um site que permite aos usuários solicitarem seus
unicórnios personalizados.
O fluxo de trabalho geral (o que chamaremos de “caminho feliz”) é algo
como isso:
Criar uma conta
Configurar o unicórnio
Adicionar ao carrinho de compras
Verificar e pagar
Dar feedback sobre o unicórnio
Seria tentador escrever um grande roteiro do Selenium
para realizar todas essas operações - muitos tentarão.
Resista à tentação!
Isso resultará em um teste que
a) leva muito tempo,
b) estará sujeito a alguns problemas comuns em torno de problemas de tempo de renderização de página, e
c) se falhar,
não lhe dará um método conciso e “superficial” para diagnosticar o que deu errado.
A estratégia preferida para testar este cenário seria
dividi-lo em uma série de testes independentes e rápidos,
cada um dos quais tem uma “razão” de existir.
Vamos fingir que você deseja testar a segunda etapa:
Configure o unicórnio.
Ele executará as seguintes ações:
Criar uma conta
Configurar o unicórnio
Observe que estamos pulando o restante dessas etapas,
vamos testar o resto do fluxo de trabalho em outros casos de teste pequenos e discretos
depois de terminarmos com este.
Para começar, você precisa criar uma conta.
Aqui você tem algumas escolhas a fazer:
Deseja usar uma conta existente?
Você deseja criar uma nova conta?
Existem propriedades especiais de tal usuário que precisam ser
levadas em consideração antes do início da configuração?
Independentemente de como você responde a esta pergunta,
a solução é torná-la parte da etapa de “configurar os dados” do teste.
Se Larry expôs uma API que permite a você (ou qualquer pessoa)
criar e atualizar contas de usuário,
certifique-se de usar isso para responder a esta pergunta.
Se possível, você deseja iniciar o navegador somente depois de ter um usuário “em mãos”,
cujas credenciais você pode usar para fazer login.
Se cada teste para cada fluxo de trabalho começar com a criação de uma conta de usuário,
muitos segundos serão adicionados à execução de cada teste.
Chamar uma API e falar com um banco de dados são operações rápidas,
“sem cabeçalho” que não requerem o processo caro de
abrir um navegador, navegar para as páginas certas,
clicando e aguardando o envio dos formulários, etc.
Idealmente, você pode abordar esta fase de configuração em uma linha de código,
que será executado antes que qualquer navegador seja iniciado:
// Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,
// mas eles não têm informações de pagamento configuradas, nem têm
// privilégios administrativos. No momento em que o usuário é criado, seu endereço
// de e-mail e senha são gerados aleatoriamente - você nem precisa
// conhecê-los.
Useruser=UserFactory.createCommonUser();//Este método está definido em algum outro lugar.
// Faça login como este usuário.
// O login neste site leva você à sua página pessoal "Minha conta", e então
// o objeto AccountPage é retornado pelo método loginAs, permitindo que você
// execute ações da AccountPage.
AccountPageaccountPage=loginAs(user.getEmail(),user.getPassword());
# Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,# mas eles não têm informações de pagamento configuradas, nem têm# privilégios administrativos. No momento em que o usuário é criado, seu endereço# de e-mail e senha são gerados aleatoriamente - você nem precisa# conhecê-los.user=user_factory.create_common_user()#This method is defined elsewhere.# Faça login como este usuário.# O login neste site leva você à sua página pessoal "Minha conta", e então# o objeto AccountPage é retornado pelo método loginAs, permitindo que você# execute ações da AccountPage.account_page=login_as(user.get_email(),user.get_password())
// Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,// mas eles não têm informações de pagamento configuradas, nem têm// privilégios administrativos. No momento em que o usuário é criado, seu endereço// de e-mail e senha são gerados aleatoriamente - você nem precisa// conhecê-los.Useruser=UserFactory.CreateCommonUser();//This method is defined elsewhere.// Faça login como este usuário.// O login neste site leva você à sua página pessoal "Minha conta", e então// o objeto AccountPage é retornado pelo método loginAs, permitindo que você// execute ações da AccountPage.AccountPageaccountPage=LoginAs(user.Email,user.Password);
# Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,# mas eles não têm informações de pagamento configuradas, nem têm# privilégios administrativos. No momento em que o usuário é criado, seu endereço# de e-mail e senha são gerados aleatoriamente - você nem precisa# conhecê-los.user=UserFactory.create_common_user#This method is defined elsewhere.# Faça login como este usuário.# O login neste site leva você à sua página pessoal "Minha conta", e então# o objeto AccountPage é retornado pelo método loginAs, permitindo que você# execute ações da AccountPage.account_page=login_as(user.email,user.password)
// Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,
// mas eles não têm informações de pagamento configuradas, nem têm
// privilégios administrativos. No momento em que o usuário é criado, seu endereço
// de e-mail e senha são gerados aleatoriamente - você nem precisa
// conhecê-los.
varuser=userFactory.createCommonUser();//This method is defined elsewhere.
// Faça login como este usuário.
// O login neste site leva você à sua página pessoal "Minha conta", e então
// o objeto AccountPage é retornado pelo método loginAs, permitindo que você
// execute ações da AccountPage.
varaccountPage=loginAs(user.email,user.password);
// Crie um usuário que tenha permissões somente leitura - eles podem configurar um unicórnio,
// mas eles não têm informações de pagamento configuradas, nem têm
// privilégios administrativos. No momento em que o usuário é criado, seu endereço
// de e-mail e senha são gerados aleatoriamente - você nem precisa
// conhecê-los.
valuser=UserFactory.createCommonUser()//This method is defined elsewhere.
// Faça login como este usuário.
// O login neste site leva você à sua página pessoal "Minha conta", e então
// o objeto AccountPage é retornado pelo método loginAs, permitindo que você
// execute ações da AccountPage.
valaccountPage=loginAs(user.getEmail(),user.getPassword())
Como você pode imaginar, a UserFactory pode ser estendida
para fornecer métodos como createAdminUser () e createUserWithPayment ().
A questão é que essas duas linhas de código não o distraem do objetivo final deste teste:
configurando um unicórnio.
Os detalhes do modelo de objeto de página
será discutido em capítulos posteriores, mas vamos apresentar o conceito aqui:
Seus testes devem ser compostos de ações,
realizadas do ponto de vista do usuário,
dentro do contexto das páginas do site.
Essas páginas são armazenadas como objetos,
que conterão informações específicas sobre como a página da web é composta
e como as ações são realizadas -
muito pouco disso deve preocupar você como testador.
Que tipo de unicórnio você quer?
Você pode querer rosa, mas não necessariamente.
Roxo tem sido bastante popular ultimamente.
Ela precisa de óculos escuros? Tatuagens de estrelas?
Essas escolhas, embora difíceis, são sua principal preocupação como testador -
você precisa garantir que seu centro de atendimento de pedidos
envia o unicórnio certo para a pessoa certa,
e isso começa com essas escolhas.
Observe que em nenhum lugar desse parágrafo falamos sobre botões,
campos, menus suspensos, botões de opção ou formulários da web.
Nem deveriam seus testes!
Você deseja escrever seu código como o usuário tentando resolver seu problema.
Aqui está uma maneira de fazer isso (continuando do exemplo anterior):
// O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.
// Isso armazena apenas os valores; não preenche formulários da web nem interage
// com o navegador de qualquer forma.
Unicornsparkles=newUnicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS);// Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao
// lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"
// nos leva lá.
AddUnicornPageaddUnicornPage=accountPage.addUnicorn();// Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para
// o método createUnicorn(). Este método pegará os atributos do Sparkles,
// preencher o formulário e clicar em enviar.
UnicornConfirmationPageunicornConfirmationPage=addUnicornPage.createUnicorn(sparkles);
# O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.# Isso armazena apenas os valores; não preenche formulários da web nem interage# com o navegador de qualquer forma.sparkles=Unicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)# Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao# lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"# nos leva lá.add_unicorn_page=account_page.add_unicorn()# Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para# o método createUnicorn(). Este método pegará os atributos do Sparkles,# preencher o formulário e clicar em enviar.unicorn_confirmation_page=add_unicorn_page.create_unicorn(sparkles)
// O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.// Isso armazena apenas os valores; não preenche formulários da web nem interage// com o navegador de qualquer forma.Unicornsparkles=newUnicorn("Sparkles",UnicornColors.Purple,UnicornAccessories.Sunglasses,UnicornAdornments.StarTattoos);// Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao// lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"// nos leva lá.AddUnicornPageaddUnicornPage=accountPage.AddUnicorn();// Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para// o método createUnicorn(). Este método pegará os atributos do Sparkles,// preencher o formulário e clicar em enviar.UnicornConfirmationPageunicornConfirmationPage=addUnicornPage.CreateUnicorn(sparkles);
# O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.# Isso armazena apenas os valores; não preenche formulários da web nem interage# com o navegador de qualquer forma.sparkles=Unicorn.new('Sparkles',UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)# Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao# lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"# nos leva lá.add_unicorn_page=account_page.add_unicorn# Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para# o método createUnicorn(). Este método pegará os atributos do Sparkles,# preencher o formulário e clicar em enviar.unicorn_confirmation_page=add_unicorn_page.create_unicorn(sparkles)
// O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.
// Isso armazena apenas os valores; não preenche formulários da web nem interage
// com o navegador de qualquer forma.
varsparkles=newUnicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS);// Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao
// lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"
// nos leva lá.
varaddUnicornPage=accountPage.addUnicorn();// Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para
// o método createUnicorn(). Este método pegará os atributos do Sparkles,
// preencher o formulário e clicar em enviar.
varunicornConfirmationPage=addUnicornPage.createUnicorn(sparkles);
// O Unicórnio é um objeto de nível superior - ele possui atributos, que são definidos aqui.
// Isso armazena apenas os valores; não preenche formulários da web nem interage
// com o navegador de qualquer forma.
valsparkles=Unicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)// Uma vez que já estamos "na" página da conta, temos que usá-la para chegar ao
// lugar real onde você configura os unicórnios. Chamar o método "Add Unicorn"
// nos leva lá.
valaddUnicornPage=accountPage.addUnicorn()// Agora que estamos na AddUnicornPage, passaremos o objeto "sparkles" para
// o método createUnicorn(). Este método pegará os atributos do Sparkles,
// preencher o formulário e clicar em enviar.
unicornConfirmationPage=addUnicornPage.createUnicorn(sparkles)
Agora que você configurou seu unicórnio,
você precisa passar para a etapa 3: certifique-se de que realmente funcionou.
// O método exists() de UnicornConfirmationPage pegará o objeto
// Sparkles - uma especificação dos atributos que você deseja ver e compará-los
// com os campos na página
Assert.assertTrue("Sparkles should have been created, with all attributes intact",unicornConfirmationPage.exists(sparkles));
# O método exists() de UnicornConfirmationPage pegará o objeto# Sparkles - uma especificação dos atributos que você deseja ver e compará-los# com os campos na páginaassertunicorn_confirmation_page.exists(sparkles),"Sparkles should have been created, with all attributes intact"
// O método exists() de UnicornConfirmationPage pegará o objeto// Sparkles - uma especificação dos atributos que você deseja ver e compará-los// com os campos na páginaAssert.True(unicornConfirmationPage.Exists(sparkles),"Sparkles should have been created, with all attributes intact");
# O método exists() de UnicornConfirmationPage pegará o objeto# Sparkles - uma especificação dos atributos que você deseja ver e compará-los# com os campos na páginaexpect(unicorn_confirmation_page.exists?(sparkles)).tobe,'Sparkles should have been created, with all attributes intact'
// O método exists() de UnicornConfirmationPage pegará o objeto
// Sparkles - uma especificação dos atributos que você deseja ver e compará-los
// com os campos na página
assert(unicornConfirmationPage.exists(sparkles),"Sparkles should have been created, with all attributes intact");
// O método exists() de UnicornConfirmationPage pegará o objeto
// Sparkles - uma especificação dos atributos que você deseja ver e compará-los
// com os campos na página
assertTrue("Sparkles should have been created, with all attributes intact",unicornConfirmationPage.exists(sparkles))
Observe que o testador ainda não fez nada além de falar sobre unicórnios neste código–
sem botões, sem localizadores, sem controles do navegador.
Este método de modelagem do aplicativo
permite que você mantenha esses comandos de nível de teste no lugar e imutáveis,
mesmo se Larry decidir na próxima semana que não gosta mais de Ruby-on-Rails
e decidir reimplementar todo o site
em Haskell com um front-end Fortran.
Seus objetos de página exigirão alguma pequena manutenção para
estar conformidade com o redesenho do site,
mas esses testes permanecerão os mesmos.
Pegando esse design básico,
você desejará continuar seus fluxos de trabalho com o menor número possível de etapas voltadas para o navegador.
Seu próximo fluxo de trabalho envolverá adicionar um unicórnio ao carrinho de compras.
Provavelmente, você desejará muitas iterações deste teste para ter certeza de que o carrinho está mantendo o estado adequado:
Existe mais de um unicórnio no carrinho antes de você começar?
Quantos cabem no carrinho de compras?
Se você criar mais de um com o mesmo nome e / ou recursos, ele falhará?
Manterá apenas o existente ou acrescentará outro?
Cada vez que você passa pelo fluxo de trabalho,
você deseja evitar ter que criar uma conta,
fazer login como o usuário e configurar o unicórnio.
Idealmente, você será capaz de criar uma conta
e pré-configurar um unicórnio por meio da API ou banco de dados.
Em seguida, tudo que você precisa fazer é fazer login como o usuário, localizar Sparkles,
e adicioná-lo ao carrinho.
Automatizar ou não automatizar?
A automação é sempre vantajosa? Quando se deve decidir automatizar os casos de teste?
Nem sempre é vantajoso automatizar casos de teste. Tem vezes que
o teste manual pode ser mais apropriado.
Por exemplo, se a interface do aplicativo mudará consideravelmente em um futuro próximo,
então qualquer automação pode precisar ser reescrita de qualquer maneira.
Além disso, às vezes simplesmente não há tempo suficiente para construir automação de testes.
A curto prazo, o teste manual pode ser mais eficaz.
Se um aplicativo tem um prazo muito curto, atualmente não há
automação de teste disponível, e é imperativo que o teste seja feito dentro
nesse período, o teste manual é a melhor solução.
6.3 - Tipos de teste
Teste de aceitação
Este tipo de teste é feito para determinar se um recurso ou sistema
atende às expectativas e requisitos do cliente.
Este tipo de teste geralmente envolve
cooperação ou feedback do cliente, sendo uma atividade de validação que
responde a pergunta:
Estamos construindo o produto certo?.
Para aplicações web, a automação desse teste pode ser feita
diretamente com o Selenium, simulando o comportamento esperado do usuário.
Esta simulação pode ser feita por gravação / reprodução ou por meio dos
diferentes idiomas suportados, conforme explicado nesta documentação.
Observação: o teste de aceitação é um subtipo de teste funcional,
ao qual algumas pessoas também podem se referir.
Teste funcional
Este tipo de teste é feito para determinar se um
recurso ou sistema funciona corretamente sem problemas. Verifica
o sistema em diferentes níveis para garantir que todos os cenários
são cobertos e que o sistema faz o que está
suposto fazer. É uma atividade de verificação que
responde a pergunta:
Estamos construindo o produto corretamente?.
Isso geralmente inclui: os testes funcionam sem erros
(404, exceções …), de forma utilizável (redirecionamentos corretos),
de forma acessível e atendendo às suas especificações
(consulte teste de aceitação acima).
Para aplicativos da web, a automação desse teste pode ser
feito diretamente com o Selenium, simulando os retornos esperados.
Esta simulação pode ser feita por gravação / reprodução ou por meio de
os diferentes idiomas suportados, conforme explicado nesta documentação.
Teste de performance/desempenho
Como o próprio nome indica, testes de desempenho são feitos
para medir o desempenho de um aplicativo.
Existem dois subtipos principais para testes de desempenho:
Teste de carga
O teste de carga é feito para verificar o quão bem o
aplicativo funciona sob diferentes cargas definidas
(geralmente um determinado número de usuários conectados ao mesmo tempo).
Teste de estresse
O teste de estresse é feito para verificar o quão bem
a aplicação funciona sob estresse (ou acima da carga máxima suportada).
Geralmente, os testes de estresse são feitos executando alguns
testes escritos com Selenium simulando diferentes usuários
utilizando uma função específica no aplicativo da web e
recuperando algumas medições significativas.
Isso geralmente é feito por outras ferramentas que recuperam as métricas.
Uma dessas ferramentas é a JMeter.
Para um aplicativo da web, os detalhes a serem medidos incluem
taxa de transferência, latência, perda de dados, tempos de carregamento de componentes individuais …
Nota 1: todos os navegadores têm uma guia de desempenho em seus
seção de ferramentas para desenvolvedores (acessível pressionando F12)
Nota 2: é um subtipo de teste não funcional
já que isso geralmente é medido por sistema e não por função / recurso.
Teste regressivo
Esse teste geralmente é feito após uma alteração, correção ou adição de recurso.
Para garantir que a mudança não quebrou nenhumas das
funcionalidades, alguns testes já executados são executados novamente.
O conjunto de testes re-executados pode ser total ou parcial
e pode incluir vários tipos diferentes, dependendo
da equipe de aplicação e desenvolvimento.
Desenvolvimento orientado a testes (TDD)
Em vez de um tipo de teste per se, o TDD é uma metodologia iterativa de desenvolvimento na qual os testes conduzem o design de um recurso.
Cada ciclo começa criando um conjunto de testes de unidade no qual
o recurso deve eventualmente ser aprovado (eles devem falhar na primeira execução).
Depois disso, ocorre o desenvolvimento para fazer os testes passarem.
Os testes são executados novamente, iniciando outro ciclo
e esse processo continua até que todos os testes sejam aprovados.
Visa acelerar o desenvolvimento de um aplicativo
com base no fato de que os defeitos custam menos quanto mais cedo são encontrados.
Desenvolvimento orientado a comportamento (BDD)
BDD também é uma metodologia de desenvolvimento iterativa
com base no TDD acima, em que o objetivo é envolver
todas as partes no desenvolvimento de um aplicativo.
Cada ciclo começa criando algumas especificações
(que deve falhar). Em seguida, crie a os testes de unidade com falha
(que também devem falhar) e, em seguida, faça o desenvolvimento.
Este ciclo é repetido até que todos os tipos de testes sejam aprovados.
Para fazer isso, uma linguagem de especificação é
usada. Deve ser compreensível por todas as partes e ser
simples, padronizada e explícita.
A maioria das ferramentas usa Gherkin como esse idioma.
O objetivo é ser capaz de detectar ainda mais erros
do que TDD, visando potenciais erros de aceitação
também e tornar a comunicação entre as partes mais fácil.
Um conjunto de ferramentas está atualmente disponível
para escrever as especificações e combiná-las com funções de código,
como Cucumber ou SpecFlow.
Um conjunto de ferramentas é construído em cima do Selenium para tornar este processo
ainda mais rápido, transformando diretamente as especificações BDD em
código executável.
Alguns deles são JBehave, Capybara e Robot Framework.
6.4 - Diretrizes e recomendações
Guias e recomendações ao preparar soluções de testes com o projecto Selenium.
Uma nota sobre “Melhores práticas”: evitamos intencionalmente a frase “Melhores
Práticas” nesta documentação. Nenhuma abordagem funciona para todas as situações.
Preferimos a ideia de “Diretrizes e Recomendações”. Nós encorajamos
que você leia e decida cuidadosamente quais abordagens
funcionarão para você em seu ambiente específico.
O teste funcional é difícil de acertar por muitos motivos.
Como se o estado, a complexidade e as dependências do aplicativo não tornassem o teste suficientemente difícil,
lidar com navegadores (especialmente com incompatibilidades entre navegadores)
torna a escrita de bons testes um desafio.
Selenium fornece ferramentas para facilitar a interação funcional do usuário,
mas não o ajuda a escrever suítes de teste bem arquitetadas.
Neste capítulo, oferecemos conselhos, diretrizes e recomendações
sobre como abordar a automação funcional de páginas da web.
Este capítulo registra os padrões de design de software populares
entre muitos dos usuários do Selenium
que tiveram sucesso ao longo dos anos.
6.4.1 - Modelos de objetos de página
Note: this page has merged contents from multiple sources, including
the Selenium wiki
Overview
Within your web app’s UI, there are areas where your tests interact with.
A Page Object only models these as objects within the test code.
This reduces the amount of duplicated code and means that if the UI changes,
the fix needs only to be applied in one place.
Page Object is a Design Pattern that has become popular in test automation for
enhancing test maintenance and reducing code duplication. A page object is an
object-oriented class that serves as an interface to a page of your AUT. The
tests then use the methods of this page object class whenever they need to
interact with the UI of that page. The benefit is that if the UI changes for
the page, the tests themselves don’t need to change, only the code within the
page object needs to change. Subsequently, all changes to support that new UI
are located in one place.
Advantages
There is a clean separation between the test code and page-specific code, such as
locators (or their use if you’re using a UI Map) and layout.
There is a single repository for the services or operations the page offers
rather than having these services scattered throughout the tests.
In both cases, this allows any modifications required due to UI changes to all
be made in one place. Helpful information on this technique can be found on
numerous blogs as this ‘test design pattern’ is becoming widely used. We
encourage readers who wish to know more to search the internet for blogs
on this subject. Many have written on this design pattern and can provide
helpful tips beyond the scope of this user guide. To get you started,
we’ll illustrate page objects with a simple example.
Examples
First, consider an example, typical of test automation, that does not use a
page object:
/***
* Tests login feature
*/publicclassLogin{publicvoidtestLogin(){// fill login data on sign-in page
driver.findElement(By.name("user_name")).sendKeys("userName");driver.findElement(By.name("password")).sendKeys("my supersecret password");driver.findElement(By.name("sign-in")).click();// verify h1 tag is "Hello userName" after login
driver.findElement(By.tagName("h1")).isDisplayed();assertThat(driver.findElement(By.tagName("h1")).getText(),is("Hello userName"));}}
There are two problems with this approach.
There is no separation between the test method and the AUT’s locators (IDs in
this example); both are intertwined in a single method. If the AUT’s UI changes
its identifiers, layout, or how a login is input and processed, the test itself
must change.
The ID-locators would be spread in multiple tests, in all tests that had to
use this login page.
Applying the page object techniques, this example could be rewritten like this
in the following example of a page object for a Sign-in page.
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;/**
* Page Object encapsulates the Sign-in page.
*/publicclassSignInPage{protectedWebDriverdriver;// <input name="user_name" type="text" value="">
privateByusernameBy=By.name("user_name");// <input name="password" type="password" value="">
privateBypasswordBy=By.name("password");// <input name="sign_in" type="submit" value="SignIn">
privateBysigninBy=By.name("sign_in");publicSignInPage(WebDriverdriver){this.driver=driver;if(!driver.getTitle().equals("Sign In Page")){thrownewIllegalStateException("This is not Sign In Page,"+" current page is: "+driver.getCurrentUrl());}}/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/publicHomePageloginValidUser(StringuserName,Stringpassword){driver.findElement(usernameBy).sendKeys(userName);driver.findElement(passwordBy).sendKeys(password);driver.findElement(signinBy).click();returnnewHomePage(driver);}}
and page object for a Home page could look like this.
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;/**
* Page Object encapsulates the Home Page
*/publicclassHomePage{protectedWebDriverdriver;// <h1>Hello userName</h1>
privateBymessageBy=By.tagName("h1");publicHomePage(WebDriverdriver){this.driver=driver;if(!driver.getTitle().equals("Home Page of logged in user")){thrownewIllegalStateException("This is not Home Page of logged in user,"+" current page is: "+driver.getCurrentUrl());}}/**
* Get message (h1 tag)
*
* @return String message text
*/publicStringgetMessageText(){returndriver.findElement(messageBy).getText();}publicHomePagemanageProfile(){// Page encapsulation to manage profile functionality
returnnewHomePage(driver);}/* More methods offering the services represented by Home Page
of Logged User. These methods in turn might return more Page Objects
for example click on Compose mail button could return ComposeMail class object */}
So now, the login test would use these two page objects as follows.
There is a lot of flexibility in how the page objects may be designed, but
there are a few basic rules for getting the desired maintainability of your
test code.
Assertions in Page Objects
Page objects themselves should never make verifications or assertions. This is
part of your test and should always be within the test’s code, never in an page
object. The page object will contain the representation of the page, and the
services the page provides via methods but no code related to what is being
tested should be within the page object.
There is one, single, verification which can, and should, be within the page
object and that is to verify that the page, and possibly critical elements on
the page, were loaded correctly. This verification should be done while
instantiating the page object. In the examples above, both the SignInPage and
HomePage constructors check that the expected page is available and ready for
requests from the test.
Page Component Objects
A page object does not necessarily need to represent all the parts of a
page itself. The same principles used for page objects can be used to
create “Page Component Objects” that represent discrete chunks of the
page and can be included in page objects. These component objects can
provide references to the elements inside those discrete chunks, and
methods to leverage the functionality provided by them.
For example, a Product page has multiple products.
<!-- Inventory Item --><divclass="inventory_item"><divclass="inventory_item_name">Backpack</div><divclass="pricebar"><divclass="inventory_item_price">$29.99</div><buttonid="add-to-cart-backpack">Add to cart</button></div></div>
The Product page HAS-A list of products. This relationship is called Composition. In simpler terms, something is composed of another thing.
publicabstractclassBasePage{protectedWebDriverdriver;publicBasePage(WebDriverdriver){this.driver=driver;}}// Page Object
publicclassProductsPageextendsBasePage{publicProductsPage(WebDriverdriver){super(driver);// No assertions, throws an exception if the element is not loaded
newWebDriverWait(driver,Duration.ofSeconds(3)).until(d->d.findElement(By.className("header_container")));}// Returning a list of products is a service of the page
publicList<Product>getProducts(){returndriver.findElements(By.className("inventory_item")).stream().map(e->newProduct(e))// Map WebElement to a product component
.toList();}// Return a specific product using a boolean-valued function (predicate)
// This is the behavioral Strategy Pattern from GoF
publicProductgetProduct(Predicate<Product>condition){returngetProducts().stream().filter(condition)// Filter by product name or price
.findFirst().orElseThrow();}}
The Product component object is used inside the Products page object.
publicabstractclassBaseComponent{protectedWebElementroot;publicBaseComponent(WebElementroot){this.root=root;}}// Page Component Object
publicclassProductextendsBaseComponent{// The root element contains the entire component
publicProduct(WebElementroot){super(root);// inventory_item
}publicStringgetName(){// Locating an element begins at the root of the component
returnroot.findElement(By.className("inventory_item_name")).getText();}publicBigDecimalgetPrice(){returnnewBigDecimal(root.findElement(By.className("inventory_item_price")).getText().replace("$","")).setScale(2,RoundingMode.UNNECESSARY);// Sanitation and formatting
}publicvoidaddToCart(){root.findElement(By.id("add-to-cart-backpack")).click();}}
So now, the products test would use the page object and the page component object as follows.
publicclassProductsTest{@TestpublicvoidtestProductInventory(){varproductsPage=newProductsPage(driver);varproducts=productsPage.getProducts();assertEquals(6,products.size());// expected, actual
}@TestpublicvoidtestProductPrices(){varproductsPage=newProductsPage(driver);// Pass a lambda expression (predicate) to filter the list of products
// The predicate or "strategy" is the behavior passed as parameter
varbackpack=productsPage.getProduct(p->p.getName().equals("Backpack"));varbikeLight=productsPage.getProduct(p->p.getName().equals("Bike Light"));assertEquals(newBigDecimal("29.99"),backpack.getPrice());assertEquals(newBigDecimal("9.99"),bikeLight.getPrice());}}
The page and component are represented by their own objects. Both objects only have methods for the services they offer, which matches the real-world application in object-oriented programming.
You can even
nest component objects inside other component objects for more complex
pages. If a page in the AUT has multiple components, or common
components used throughout the site (e.g. a navigation bar), then it
may improve maintainability and reduce code duplication.
Other Design Patterns Used in Testing
There are other design patterns that also may be used in testing. Some use a
Page Factory for instantiating their page objects. Discussing all of these is
beyond the scope of this user guide. Here, we merely want to introduce the
concepts to make the reader aware of some of the things that can be done. As
was mentioned earlier, many have blogged on this topic and we encourage the
reader to search for blogs on these topics.
Implementation Notes
PageObjects can be thought of as facing in two directions simultaneously. Facing toward the developer of a test, they represent the services offered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It’s simplest to think of the methods on a Page Object as offering the “services” that a page offers rather than exposing the details and mechanics of the page. As an example, think of the inbox of any web-based email system. Amongst the services it offers are the ability to compose a new email, choose to read a single email, and list the subject lines of the emails in the inbox. How these are implemented shouldn’t matter to the test.
Because we’re encouraging the developer of a test to try and think about the services they’re interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, methods on the PageObject should return other PageObjects. This means we can effectively model the user’s journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service when it previously didn’t do that), simply changing the appropriate method’s signature will cause the tests to fail to compile. Put another way; we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
One consequence of this approach is that it may be necessary to model (for example) both a successful and unsuccessful login; or a click could have a different result depending on the app’s state. When this happens, it is common to have multiple methods on the PageObject:
public class LoginPage {
public HomePage loginAs(String username, String password) {
// ... clever magic happens here
}
public LoginPage loginAsExpectingError(String username, String password) {
// ... failed login here, maybe because one or both of the username and password are wrong
}
public String getErrorMessage() {
// So we can verify that the correct error is shown
}
}
The code presented above shows an important point: the tests, not the PageObjects, should be responsible for making assertions about the state of a page. For example:
public void testMessagesAreReadOrUnread() {
Inbox inbox = new Inbox(driver);
inbox.assertMessageWithSubjectIsUnread("I like cheese");
inbox.assertMessageWithSubjectIsNotUnread("I'm not fond of tofu");
}
could be re-written as:
public void testMessagesAreReadOrUnread() {
Inbox inbox = new Inbox(driver);
assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu"));
}
Of course, as with every guideline, there are exceptions, and one that is commonly seen with PageObjects is to check that the WebDriver is on the correct page when we instantiate the PageObject. This is done in the example below.
Finally, a PageObject need not represent an entire page. It may represent a section that appears frequently within a site or page, such as site navigation. The essential principle is that there is only one place in your test suite with knowledge of the structure of the HTML of a particular (part of a) page.
Summary
The public methods represent the services that the page offers
Try not to expose the internals of the page
Generally don’t make assertions
Methods return other PageObjects
Need not represent an entire page
Different results for the same action are modelled as different methods
Example
public class LoginPage {
private final WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
// Check that we're on the right page.
if (!"Login".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps logging out first
throw new IllegalStateException("This is not the login page");
}
}
// The login page contains several HTML elements that will be represented as WebElements.
// The locators for these elements should only be defined once.
By usernameLocator = By.id("username");
By passwordLocator = By.id("passwd");
By loginButtonLocator = By.id("login");
// The login page allows the user to type their username into the username field
public LoginPage typeUsername(String username) {
// This is the only place that "knows" how to enter a username
driver.findElement(usernameLocator).sendKeys(username);
// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}
// The login page allows the user to type their password into the password field
public LoginPage typePassword(String password) {
// This is the only place that "knows" how to enter a password
driver.findElement(passwordLocator).sendKeys(password);
// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}
// The login page allows the user to submit the login form
public HomePage submitLogin() {
// This is the only place that submits the login form and expects the destination to be the home page.
// A seperate method should be created for the instance of clicking login whilst expecting a login failure.
driver.findElement(loginButtonLocator).submit();
// Return a new page object representing the destination. Should the login page ever
// go somewhere else (for example, a legal disclaimer) then changing the method signature
// for this method will mean that all tests that rely on this behaviour won't compile.
return new HomePage(driver);
}
// The login page allows the user to submit the login form knowing that an invalid username and / or password were entered
public LoginPage submitLoginExpectingFailure() {
// This is the only place that submits the login form and expects the destination to be the login page due to login failure.
driver.findElement(loginButtonLocator).submit();
// Return a new page object representing the destination. Should the user ever be navigated to the home page after submiting a login with credentials
// expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.
return new LoginPage(driver);
}
// Conceptually, the login page offers the user the service of being able to "log into"
// the application using a user name and password.
public HomePage loginAs(String username, String password) {
// The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
typeUsername(username);
typePassword(password);
return submitLogin();
}
}
Support in WebDriver
There is a PageFactory in the support package that provides support for this pattern and helps to remove some boiler-plate code from your Page Objects at the same time.
6.4.2 - Linguagem específica de domínio (DSL)
Uma linguagem específica de domínio (DSL) é um sistema que fornece ao usuário
um meio expressivo de resolver um problema. Ele permite a um usuário
interagir com o sistema em seus termos - não apenas na linguagem do programador.
Seus usuários, em geral, não se importam com a aparência do seu site. Eles não
preocupam-se com a decoração, animações ou gráficos. Eles
deseja usar seu sistema para empurrar seus novos funcionários através do
processo com dificuldade mínima; eles querem reservar uma viagem para o Alasca;
eles querem configurar e comprar unicórnios com desconto. Seu trabalho como
testador deve chegar o mais perto possível de “capturar” essa mentalidade.
Com isso em mente, começamos a “modelar” o aplicativo que você está
trabalhando, de modo que os scripts de teste (o único proxy de pré-lançamento do usuário) “fala a linguagem” e representa o usuário.
Com Selenium, DSL é geralmente representado por métodos, escritos para fazer
a API simples e legível - eles permitem um relatório entre o
desenvolvedores e as partes interessadas (usuários, proprietários de produtos, negócios
especialistas em inteligência, etc.).
Benefícios
Legível: As partes interessadas da empresa podem entendê-lo.
Gravável: Fácil de escrever, evita duplicações desnecessárias.
Extensível: Funcionalidade pode (razoavelmente) ser adicionada
sem quebrar contratos e funcionalidades existentes.
Manutenção: Deixando os detalhes de implementação fora do teste
casos, você está bem isolado contra alterações no AUT *.
Java
Aqui está um exemplo de um método DSL razoável em Java.
Por questão de brevidade, ele assume que o objeto driver é pré-definido
e está disponível para o método.
/**
* Recebe um username e password, prrenche os campos, e clica em "login".
* @return Uma instância de AccountPage
*/publicAccountPageloginAsUser(Stringusername,Stringpassword){WebElementloginField=driver.findElement(By.id("loginField"));loginField.clear();loginField.sendKeys(username);// Preenche o campo password. O localizador que estamos usando é "By.id", e devemos
// definí-lo em algum outro lugar dentro da Classe.
WebElementpasswordField=driver.findElement(By.id("password"));passwordField.clear();passwordField.sendKeys(password);// Clica o botão de login, que possui o id "submit".
driver.findElement(By.id("submit")).click();// Cria e retorna uma nova instância de AccountPage (via o Selenium
// PageFactory embutido).
returnPageFactory.newInstance(AccountPage.class);}
Este método abstrai completamente os conceitos de campos de entrada,
botões, cliques e até páginas do seu código de teste. Usando este
abordagem, tudo o que o testador precisa fazer é chamar esse método. Isto dá
uma vantagem de manutenção: se os campos de login mudaram, você
teria apenas que alterar esse método - não seus testes.
publicvoidloginTest(){loginAsUser("cbrown","cl0wn3");// Agora que estamos logados, fazemos alguma outra coisa--como usamos uma DSL para suportar
// nossos testadores, é apenas escolher um dos métodos disponíveis.
do.something();do.somethingElse();Assert.assertTrue("Algo deveria ter sido feito!",something.wasDone());// Note que ainda não nos referimos a nenhum botão ou web control nesse
// script...
}
Vale a pena repetir: um de seus principais objetivos deve ser escrever um
API que permite que seus testes resolvam o problema em questão, e NÃO
o problema da IU. A IU é uma preocupação secundária para o seu
usuários - eles não se importam com a interface do usuário, eles apenas querem fazer seu trabalho
feito. Seus scripts de teste devem ser lidos como uma lista de itens sujos que o usuário deseja FAZER e as coisas que deseja SABER. Os testes
não devem se preocupar com COMO a interface do usuário exige que você vá
sobre isso.
*AUT: Application under test
6.4.3 - Gerando estado da aplicação
Selenium não deve ser usado para preparar um caso de teste. Tudo as
ações repetitivas e preparações para um caso de teste devem ser feitas por meio de outros
métodos. Por exemplo, a maioria das IUs da web tem autenticação (por exemplo, um formulário de login). Eliminar o login via navegador da web antes de cada teste irá
melhorar a velocidade e estabilidade do teste. Um método deve ser
criado para obter acesso à AUT* (por exemplo, usando uma API para fazer login e definir um
cookie). Além disso, a criação de métodos para pré-carregar dados para
o teste não deve ser feito usando Selenium. Como dito anteriormente,
APIs existentes devem ser aproveitadas para criar dados para a AUT *.
*AUT: Application under test
6.4.4 - Simulação de serviços externos
Eliminar as dependências de serviços externos melhorará muito
a velocidade e estabilidade de seus testes.
6.4.5 - Relatórios melhorados
O Selenium não foi projetado para relatar sobre o status de casos de teste. Aproveitar
os recursos de relatórios integrados de frameworks de teste unitários é um bom começo.
A maioria dos frameworks de teste unitários podem gerar relatórios formatados em xUnit ou HTML.
Relatórios xUnit são populares para importar resultados para um servidor de integração contínua
(CI) como Jenkins, Travis, Bamboo, etc. Aqui estão alguns links
para obter mais informações sobre resultados de relatórios em vários idiomas.
Embora mencionado em vários lugares, vale a pena mencionar novamente. Garanta que
os testes são isolados uns dos outros.
Não compartilhe dados de teste. Imagine vários testes em que cada um consulta o banco de dados
para pedidos válidos antes de escolher um para executar uma ação. Caso dois testes
peguem a mesma ordem, provavelmente você obterá um comportamento inesperado.
Limpe dados desatualizados no aplicativo que podem ser obtidos por outro
teste, por exemplo registros de pedidos inválidos.
Crie uma nova instância do WebDriver por teste. Isso ajuda a garantir o isolamento do teste
e torna a paralelização mais simples.
6.4.7 - Tips on working with locators
When to use which locators and how best to manage them in your code.
No geral, se os IDs de HTML estiverem disponíveis, únicos e consistentemente
previsíveis, eles são o método preferido para localizar um elemento
uma página. Eles tendem a trabalhar muito rapidamente e dispensar muito processamento
que vem com travessias de DOM complicadas.
Se IDs exclusivos não estiverem disponíveis, um seletor CSS bem escrito é o
método preferido de localização de um elemento. XPath funciona bem como CSS
seletores, mas a sintaxe é complicada e frequentemente difícil de
depurar. Embora os seletores XPath sejam muito flexíveis, eles não são tipicamente testados em performance por fornecedores de navegadores e tendem a ser bastante lentos.
As estratégias de seleção baseadas em linkText e partialLinkText têm
desvantagens porque eles só funcionam em elementos de link. Além disso, eles
chamam seletores querySelectorAll internamente no WebDriver.
O nome da tag pode ser uma maneira perigosa de localizar elementos. tem
frequentemente, vários elementos da mesma tag presentes na página.
Isso é útil principalmente ao chamar o método _findElements(By) _ que
retorna uma coleção de elementos.
A recomendação é manter seus localizadores compactos e
legíveis quanto possível. Pedir ao WebDriver para percorrer a estrutura DOM
é uma operação cara, e quanto mais você pode restringir o escopo de
sua pesquisa, melhor.
6.4.8 - Independência de Testes
Escreva cada teste como sua própria unidade. Escreva os testes de uma forma que não seja
dependente de outros testes para concluir:
Digamos que existe um sistema de gerenciamento de conteúdo com o qual você pode criar
algum conteúdo personalizado que então aparece em seu site como um módulo após
publicação, e pode levar algum tempo para sincronizar entre o CMS e a aplicação.
Uma maneira errada de testar seu módulo é que o conteúdo seja criado e
publicado em um teste e, em seguida, verificar o módulo em outro teste. Este teste
não é viável, pois o conteúdo pode não estar disponível imediatamente para o
outro teste após a publicação.
Em vez disso, você pode criar um conteúdo stub que pode ser ligado e desligado
dentro do teste e use-o para validar o módulo. Contudo,
para a criação de conteúdo, você ainda pode ter um teste separado.
6.4.9 - Considere usar uma API fluente
Martin Fowler cunhou o termo “API Fluent”. Selenium já
implementa algo assim em sua classe FluentWait, que é
pretende ser uma alternativa à classe padrão Wait.
Você pode habilitar o padrão de design de API fluente em seu objeto de página
e, em seguida, consulte a página de pesquisa do Google com um snippet de código como este:
A classe de objeto da página do Google com este comportamento fluente
pode ser assim:
publicabstractclassBasePage{protectedWebDriverdriver;publicBasePage(WebDriverdriver){this.driver=driver;}}publicclassGoogleSearchPageextendsBasePage{publicGoogleSearchPage(WebDriverdriver){super(driver);// Generally do not assert within pages or components.
// Effectively throws an exception if the lambda condition is not met.
newWebDriverWait(driver,Duration.ofSeconds(3)).until(d->d.findElement(By.id("logo")));}publicGoogleSearchPagesetSearchString(Stringsstr){driver.findElement(By.id("gbqfq")).sendKeys(sstr);returnthis;}publicvoidclickSearchButton(){driver.findElement(By.id("gbqfb")).click();}}
6.4.10 - Navegador novo por teste
Comece cada teste a partir de um estado limpo conhecido.
Idealmente, ligue uma nova máquina virtual para cada teste.
Se ligar uma nova máquina virtual não for prático,
pelo menos inicie um novo WebDriver para cada teste.
Most browser drivers like GeckoDriver and ChromeDriver will start with a clean
known state with a new user profile, by default.
WebDriverdriver=newFirefoxDriver();
6.5 - Piores práticas
Temas a evitar quando automatizar navegadores com Selenium.
6.5.1 - Captchas
CAPTCHA, abreviação de Completely Automated Public Turing test
to tell Computers and Humans Apart,
foi projetado explicitamente para impedir a automação, portanto, não tente!
Existem duas estratégias principais para contornar as verificações CAPTCHA:
Desative CAPTCHAs em seu ambiente de teste
Adicione um hook para permitir que os testes ignorem o CAPTCHA
6.5.2 - Downloads de arquivo
Embora seja possível iniciar um download
clicando em um link com um navegador sob o controle do Selenium,
a API não expõe o progresso do download,
tornando-o menos do que ideal para testar arquivos baixados.
Isso ocorre porque o download de arquivos não é considerado um aspecto importante
de emular a interação do usuário com a plataforma da web.
Em vez disso, encontre o link usando Selenium
(e todos os cookies necessários)
e passe este cookie para uma biblioteca de solicitação HTTP como
libcurl.
O driver HtmlUnit pode baixar
anexos acessando-os como fluxos de entrada, implementando o
AttachmentHandler.
O AttachmentHandler pode ser adicionado ao WebClient HtmlUnit.
6.5.3 - Códigos de respostas HTTP
Para algumas configurações de navegador no Selenium RC,
Selenium atuou como um proxy entre o navegador
e o site sendo automatizado.
Isso significa que todo o tráfego do navegador que passou pelo Selenium
poderia ser capturado ou manipulado.
O método captureNetworkTraffic()
pretendia capturar todo o tráfego de rede entre o navegador
e o site sendo automatizado,
incluindo códigos de resposta HTTP.
Selenium WebDriver é uma abordagem completamente diferente
para a automação do navegador,
preferindo agir mais como um usuário.
Isso é representado na maneira como você escreve testes com o WebDriver.
Em testes funcionais automatizados,
verificar o código de status
não é um detalhe particularmente importante da falha de um teste;
as etapas que o precederam são mais importantes.
O navegador sempre representará o código de status HTTP,
imagine, por exemplo, uma página de erro 404 ou 500.
Uma maneira simples de “falhar rapidamente” quando você encontrar uma dessas páginas de erro
é verificar o título da página ou o conteúdo de um ponto confiável
(por exemplo, a tag <h1>) após cada carregamento de página.
Se você estiver usando o modelo de objeto de página,
você pode incluir esta verificação em seu construtor de classe
ou ponto semelhante onde o carregamento da página é esperado.
Ocasionalmente, o código HTTP pode até ser representado
na página de erro do navegador
e você pode usar o WebDriver para ler isso
e melhorar sua saída de depuração.
Verificar se a própria página da web está alinhada
com a prática ideal do WebDriver
de representar a visão do usuário do site.
Se você insiste, uma solução avançada para capturar códigos de status HTTP
é replicar o comportamento do Selenium RC usando um proxy.
A API WebDriver fornece a capacidade de definir um proxy para o navegador,
e há uma série de proxies que irão
permitir que você manipule de forma programática
o conteúdo das solicitações enviadas e recebidas do servidor da web.
Usar um proxy permite que você decida como deseja responder
para códigos de resposta de redirecionamento.
Além disso, nem todo navegador
torna os códigos de resposta disponíveis para WebDriver,
então optar por usar um proxy
permite que você tenha uma solução que funciona para todos os navegadores.
6.5.4 - Login via Gmail, email e Facebook
Por vários motivos, fazer login em sites como Gmail e Facebook
usando do WebDriver não é recomendado.
Além de ser contra os termos de uso desses sites
(onde você corre o risco de ter a conta encerrada),
é lento e não confiável.
A prática ideal é usar as APIs que os provedores de e-mail oferecem,
ou no caso do Facebook, o serviço de ferramentas para desenvolvedores
que expõe uma API para criar contas de teste, amigos e assim por diante.
Embora usar uma API possa parecer um pouco trabalhoso,
você será recompensado em velocidade, confiabilidade e estabilidade.
A API também não deve mudar,
enquanto as páginas da web e os localizadores de HTML mudam frequentemente
e exigem que você atualize sua estrutura de teste.
Login em sites de terceiros usando WebDriver
em qualquer ponto do seu teste aumenta o risco
de seu teste falhar porque torna o teste mais longo.
Uma regra geral é que testes mais longos
são mais frágeis e não confiáveis.
Implementações WebDriver que estão
em conformidade com W3C
também anotam o objeto navigator
com uma propriedade WebDriver
para que os ataques de negação de serviço possam ser mitigados.
6.5.5 - Dependência entre testes
Uma ideia comum e um equívoco sobre o teste automatizado é sobre uma
ordem de testes específica. Seus testes devem ser executados em qualquer ordem,
e não depender da conclusão de outros testes para ter sucesso.
6.5.6 - Teste de performance/desempenho
Teste de desempenho usando Selenium e WebDriver
geralmente não é recomendado.
Não porque é incapaz,
mas porque não é otimizado para o trabalho
e é improvável que você obtenha bons resultados.
Pode parecer ideal para teste de desempenho
no contexto do usuário, mas um conjunto de testes WebDriver
estão sujeitos a muitos pontos de fragilidade externa e interna
que estão além do seu controle;
por exemplo, velocidade de inicialização do navegador,
velocidade dos servidores HTTP,
resposta de servidores de terceiros que hospedam JavaScript ou CSS,
e a penalidade de instrumentação
da própria implementação do WebDriver.
A variação nesses pontos causará variação em seus resultados.
É difícil separar a diferença
entre o desempenho do seu site
e o desempenho de recursos externos,
e também é difícil dizer qual é a penalidade de desempenho
para usar WebDriver no navegador,
especialmente se você estiver injetando scripts.
A outra atração potencial é “economizar tempo” -
execução de testes funcionais e de desempenho ao mesmo tempo.
No entanto, os testes funcionais e de desempenho têm objetivos opostos.
Para testar a funcionalidade, um testador pode precisar ser paciente
e aguarde o carregamento,
mas isso irá turvar os resultados do teste de desempenho e vice-versa.
Para melhorar o desempenho do seu site,
você precisará ser capaz de analisar o desempenho geral
independente das diferenças de ambiente,
identificar práticas de código ruins,
repartição do desempenho de recursos individuais
(ou seja, CSS ou JavaScript),
para saber o que melhorar.
Existem ferramentas de teste de desempenho disponíveis
que podem fazer este trabalho,
que fornecem relatórios e análises,
e podem até fazer sugestões de melhorias.
Pacotes de exemplo (código aberto) a serem usados são: JMeter
6.5.7 - Navegação por links
Usar o WebDriver para navegar por links
não é uma prática recomendada. Não porque não pode ser feito,
mas porque WebDriver definitivamente não é a ferramenta ideal para isso.
O WebDriver precisa de tempo para inicializar,
e pode levar vários segundos, até um minuto
dependendo de como seu teste é escrito,
apenas para chegar à página e atravessar o DOM.
Em vez de usar o WebDriver para isso,
você poderia economizar muito tempo
executando um comando curl,
ou usando uma biblioteca como BeautifulSoup
uma vez que esses métodos não dependem
em criar um navegador e navegar para uma página.
Você está economizando muito tempo por não usar o WebDriver para essa tarefa.
6.5.8 - Autenticação de Dois Fatores (2FA)
A autenticação de dois fatores, conhecida como 2FA, é um mecanismo de autorização
onde a senha de uso único (OTP) é gerada usando aplicativos móveis “Autenticadores”,
como “Google Authenticator”, “Microsoft Authenticator”
etc., ou por SMS, e-mail para autenticação. Automatizar isso perfeitamente
e consistentemente é um grande desafio no Selenium. Existem algumas maneiras
para automatizar este processo. Mas essa será outra camada em cima de nossos
testes Selenium e não protegidos também. Portanto, você pode evitar a automação do 2FA.
Existem algumas opções para contornar as verificações 2FA:
Desative 2FA para determinados usuários no ambiente de teste, para que você possa
usar essas credenciais de usuário na automação.
Desative 2FA em seu ambiente de teste.
Desative 2FA se você fizer o login de determinados IPs. Dessa forma, podemos configurar nosso
teste os IPs da máquina para evitar isso.
7 - Legado
Nesta seção você pode encontrar toda a documentação relacionada aos componentes legados do Selenium. Isso deve ser mantido puramente por razões históricas e não como um incentivo para o uso obsoleto componentes.
Most of the documentation found in this section is still in English.
Please note we are not accepting pull requests to translate this content
as translating documentation of legacy components does not add value to
the community nor the project.
7.1 - Selenium RC (Selenium 1)
The original version of Selenium
Introdução
Selenium RC foi o principal projeto da Selenium por muito tempo, antes da
fusão WebDriver / Selenium trazer o Selenium 2, uma ferramenta mais poderosa.
Vale ressaltar que não há mais suporte para Selenium 1.
Como o Selenium RC funciona
Primeiro, vamos descrever como os componentes do Selenium RC operam e o papel que cada um desempenha na execução
de seus scripts de teste.
Componentes do RC
Os componentes do Selenium RC são:
O servidor Selenium que inicia e mata navegadores, interpreta e executa os comandos em Selenese passados do programa de teste e atua como um proxy HTTP, interceptando e verificando mensagens HTTP passadas entre o navegador e a aplicação sendo testada.
Bibliotecas de cliente que fornecem a interface entre cada linguagem de programação e o Selenium RC Server.
Aqui está um diagrama de arquitetura simplificado:
O diagrama mostra que as bibliotecas cliente se comunicam com o
servidor passando cada comando Selenium para execução. Então o servidor passa o
comando Selenium para o navegador usando comandos Selenium-Core JavaScript. O
navegador, usando seu interpretador JavaScript, executa o comando Selenium. Este
executa a ação em Selenese ou verificação que você especificou em seu script de teste.
Servidor Selenium
O servidor Selenium recebe comandos Selenium do seu programa de teste,
os interpreta e reporta ao seu programa os resultados da
execução desses testes.
O servidor RC agrupa o Selenium Core e o injeta automaticamente
no navegador. Isso ocorre quando seu programa de teste abre o
navegador (usando uma função API de biblioteca cliente).
Selenium-Core é um programa JavaScript, na verdade um conjunto de funções JavaScript que interpretam e executam comandos em Selenese usando o
interpretador de JavaScript embutido do navegador.
O servidor recebe os comandos em Selenese do seu programa de teste
usando solicitações HTTP GET/POST simples. Isso significa que você pode usar qualquer
linguagem de programação que pode enviar solicitações HTTP para automatizar
os testes Selenium no navegador.
Bibliotecas Cliente
As bibliotecas cliente fornecem suporte de programação que permite que você
execute comandos Selenium a partir de um programa de seu próprio projeto. Existe um
biblioteca cliente diferente para cada linguagem compatível. Um cliente Selenium
biblioteca fornece uma interface de programação (API), ou seja, um conjunto de funções,
que executam comandos Selenium de seu próprio programa. Dentro de cada interface,
existe uma função de programação que suporta cada comando em Selenese.
A biblioteca cliente pega um comando em Selenese e o passa para o servidor Selenium
para processar uma ação específica ou teste no aplicativo em teste
(AUT). A biblioteca cliente
também recebe o resultado desse comando e o devolve ao seu programa.
Seu programa pode receber o resultado e armazená-lo em uma variável de programa e
relatá-lo como um sucesso ou fracasso,
ou possivelmente executar uma ação corretiva se for um erro inesperado.
Então, para criar um programa de teste, você simplesmente escreve um programa que executa
um conjunto de comandos Selenium usando uma API de biblioteca cliente. E, opcionalmente, se
você já tem um script de teste em Selenese criado na Selenium-IDE, você pode
gerar o código Selenium RC. A Selenium-IDE pode traduzir (usando seu item de menu
Exportar) seus comandos Selenium em chamadas de função de uma API de driver de cliente.
Consulte o capítulo Selenium-IDE para obter detalhes sobre a exportação de código RC a partir da
Selenium-IDE.
Instalação
A instalação é um nome impróprio para Selenium. Selenium tem um conjunto de bibliotecas disponíveis
na linguagem de programação de sua escolha. Você pode baixá-los na página de downloads.
Depois de escolher uma linguagem para trabalhar, você só precisa:
Instalar o Selenium RC Server.
Configurar um projeto de programação usando um driver cliente específico de linguagem.
Instalando o servidor Selenium
O servidor Selenium RC é simplesmente um arquivo Java jar (selenium-server-standalone-<número da versão>.jar), que não
requer qualquer instalação especial. Basta baixar o arquivo zip e extrair o
servidor no diretório desejado.
Executando o servidor Selenium
Antes de iniciar qualquer teste, você deve iniciar o servidor. Vá para o diretório
onde o servidor Selenium RC está localizado e execute o seguinte a partir da linha de comando.
Isso pode ser simplificado criando
um arquivo executável em lote ou shell (.bat no Windows e .sh no Linux) contendo o comando
acima. Em seguida, faça um atalho para esse executável em seu
desktop e simplesmente clique duas vezes no ícone para iniciar o servidor.
Para o servidor funcionar, você precisa do Java instalado
e a variável de ambiente PATH configurada corretamente para executá-lo a partir do console.
Você pode verificar se o Java está instalado corretamente executando o seguinte
em um console.
java -version
Se você obtiver um número de versão (que precisa ser 1.5 ou posterior), você está pronto para começar a usar o Selenium RC.
Abra a IDE Java desejada (Eclipse, NetBeans, IntelliJ, Netweaver, etc.)
Crie um projeto Java.
Adicione os arquivos selenium-java-.jar ao seu projeto como referências.
Adicione ao classpath do projeto o arquivo selenium-java-.jar.
Na Selenium-IDE, exporte um script para um arquivo Java e inclua-o em seu projeto Java
ou escreva seu teste Selenium em Java usando a API selenium-java-client.
A API é apresentada posteriormente neste capítulo. Você pode usar JUnit ou TestNg
para executar seu teste, ou você pode escrever seu próprio programa main() simples. Esses conceitos são
explicados mais para frente nesta seção.
Execute o servidor Selenium a partir do console.
Execute seu teste na Java IDE ou na linha de comando.
Para obter detalhes sobre a configuração do projeto de teste Java, consulte as seções do Apêndice
Configurando Selenium RC com Eclipse e Configurando Selenium RC com Intellij.
Baixe e instale o NUnit (
Nota: você pode usar o NUnit como seu mecanismo de teste. Se você ainda não está familiarizado com
NUnit, você também pode escrever uma função main() simples para executar seus testes;
no entanto, o NUnit é muito útil como um mecanismo de teste.)
Abra a IDE .Net desejado (Visual Studio, SharpDevelop, MonoDevelop)
Crie uma biblioteca de classes (.dll)
Adicione referências às seguintes DLLs: nmock.dll, nunit.core.dll, nunit.framework.dll, ThoughtWorks.Selenium.Core.dll, ThoughtWorks.Selenium.IntegrationTests.dll
e ThoughtWorks.Selenium.UnitTests.dll
Escreva seu teste Selenium em uma linguagem .Net (C#, VB.Net) ou exporte
um script da Selenium-IDE para um arquivo C# e copie este código para o arquivo de classe
você acabou de criar.
Escreva seu próprio programa main() simples ou você pode incluir NUnit em seu projeto
para executar seu teste. Esses conceitos são explicados posteriormente neste capítulo.
Execute o servidor Selenium a partir do console
Execute seu teste a partir da IDE, da GUI do NUnit ou da linha de comando
Para obter detalhes específicos sobre a configuração do driver cliente .NET com Visual Studio, consulte o apêndice
Configuração do driver cliente .NET.
Usando o driver cliente para Ruby
Se você ainda não tem RubyGems, instale-o do RubyForge.
Execute gem install selenium-client
No topo do seu script de teste, adicione require "selenium / client"
Escreva seu script de teste usando qualquer função de teste Ruby (por exemplo, Test::Unit,
Mini::Test ou RSpec).
Execute o servidor Selenium RC a partir do console.
Execute seu teste da mesma forma que você executaria qualquer outro script Ruby.
Para obter detalhes sobre a configuração do driver do cliente Ruby, consulte a documentação do Selenium-Client
Do Selenese ao Programa
A principal tarefa para usar o Selenium RC é converter seu Selenese em uma linguagem de programação. Nesta seção, fornecemos vários exemplos específicos de linguagens diferentes.
Exemplo de script de teste
Vamos começar com um exemplo de script de teste em Selenese. Imagine gravar
o seguinte teste com Selenium-IDE.
open
/
type
q
selenium rc
clickAndWait
btnG
assertTextPresent
Results * for selenium rc
Observação: este exemplo funcionaria com a página de pesquisa do Google http://www.google.com
Selenese como código
Aqui está o script de teste exportado (via Selenium-IDE) para cada uma das
linguagens de programação. Se você tem pelo menos conhecimento básico de linguagem de programação orientada a objetos (OOP), você vai entender como o Selenium
executa comandos em Selenese lendo um destes
exemplos. Para ver um exemplo em uma linguagem específica, selecione um desses botões.
CSharp
usingSystem;usingSystem.Text;usingSystem.Text.RegularExpressions;usingSystem.Threading;usingNUnit.Framework;usingSelenium;namespaceSeleniumTests{ [TestFixture]publicclassNewTest{privateISeleniumselenium;privateStringBuilderverificationErrors; [SetUp]publicvoidSetupTest(){selenium=newDefaultSelenium("localhost",4444,"*firefox","http://www.google.com/");selenium.Start();verificationErrors=newStringBuilder();} [TearDown]publicvoidTeardownTest(){try{selenium.Stop();}catch(Exception){// Ignore errors if unable to close the browser}Assert.AreEqual("",verificationErrors.ToString());} [Test]publicvoidTheNewTest(){selenium.Open("/");selenium.Type("q","selenium rc");selenium.Click("btnG");selenium.WaitForPageToLoad("30000");Assert.AreEqual("selenium rc - Google Search",selenium.GetTitle());}}}
Java
/** Add JUnit framework to your classpath if not already there
* for this example to work
*/packagecom.example.tests;importcom.thoughtworks.selenium.*;importjava.util.regex.Pattern;publicclassNewTestextendsSeleneseTestCase{publicvoidsetUp()throwsException{setUp("http://www.google.com/","*firefox");}publicvoidtestNew()throwsException{selenium.open("/");selenium.type("q","selenium rc");selenium.click("btnG");selenium.waitForPageToLoad("30000");assertTrue(selenium.isTextPresent("Results * for selenium rc"));}}
Php
<?phprequire_once'PHPUnit/Extensions/SeleniumTestCase.php';classExampleextendsPHPUnit_Extensions_SeleniumTestCase{functionsetUp(){$this->setBrowser("*firefox");$this->setBrowserUrl("http://www.google.com/");}functiontestMyTestCase(){$this->open("/");$this->type("q","selenium rc");$this->click("btnG");$this->waitForPageToLoad("30000");$this->assertTrue($this->isTextPresent("Results * for selenium rc"));}}?>
Python
fromseleniumimportseleniumimportunittest,time,reclassNewTest(unittest.TestCase):defsetUp(self):self.verificationErrors=[]self.selenium=selenium("localhost",4444,"*firefox","http://www.google.com/")self.selenium.start()deftest_new(self):sel=self.seleniumsel.open("/")sel.type("q","selenium rc")sel.click("btnG")sel.wait_for_page_to_load("30000")self.failUnless(sel.is_text_present("Results * for selenium rc"))deftearDown(self):self.selenium.stop()self.assertEqual([],self.verificationErrors)
Ruby
require"selenium/client"require"test/unit"classNewTest<Test::Unit::TestCasedefsetup@verification_errors=[]if$selenium@selenium=$seleniumelse@selenium=Selenium::Client::Driver.new("localhost",4444,"*firefox","http://www.google.com/",60);@selenium.startend@selenium.set_context("test_new")enddefteardown@selenium.stopunless$seleniumassert_equal[],@verification_errorsenddeftest_new@selenium.open"/"@selenium.type"q","selenium rc"@selenium.click"btnG"@selenium.wait_for_page_to_load"30000"assert@selenium.is_text_present("Results * for selenium rc")endend
Na próxima seção, explicaremos como construir um programa de teste usando o código gerado.
Programando seu teste
Agora vamos ilustrar como programar seus próprios testes usando exemplos em cada uma das
linguagens de programação suportadas.
Existem essencialmente duas tarefas:
*Gerar seu script em uma
linguagem de programação a partir da Selenium-IDE, opcionalmente modificando o resultado.
*Escrever um programa principal muito simples que execute o código gerado.
Opcionalmente, você pode adotar uma plataforma de mecanismo de teste como JUnit ou TestNG para Java,
ou NUnit para .NET se você estiver usando uma dessas linguagens.
Aqui, mostramos exemplos específicos de cada linguagem. As APIs específicas do idioma tendem a
diferir de um para o outro, então você encontrará uma explicação separada para cada um.
Java
C#
Python
Ruby
Perl, PHP
Java
Para Java, as pessoas usam JUnit ou TestNG como mecanismo de teste.
Alguns ambientes de desenvolvimento como o Eclipse têm suporte direto para eles via
plug-ins. Isso torna tudo ainda mais fácil. Ensinar JUnit ou TestNG está além do escopo de
este documento, no entanto, os materiais podem ser encontrados online e há publicações
acessíveis. Se você já é uma “loja de Java”, é provável que seus desenvolvedores
já tem alguma experiência com uma dessas estruturas de teste.
Você provavelmente vai querer renomear a classe de teste de “NewTest” para algo
de sua própria escolha. Além disso, você precisará alterar os
parâmetros abertos pelo navegador na declaração:
O código gerado pela Selenium-IDE terá a seguinte aparência. Este exemplo
tem comentários adicionados manualmente para maior clareza.
packagecom.example.tests;// We specify the package of our tests
importcom.thoughtworks.selenium.*;// This is the driver's import. You'll use this for instantiating a
// browser and making it do what you need.
importjava.util.regex.Pattern;// Selenium-IDE add the Pattern module because it's sometimes used for
// regex validations. You can remove the module if it's not used in your
// script.
publicclassNewTestextendsSeleneseTestCase{// We create our Selenium test case
publicvoidsetUp()throwsException{setUp("http://www.google.com/","*firefox");// We instantiate and start the browser
}publicvoidtestNew()throwsException{selenium.open("/");selenium.type("q","selenium rc");selenium.click("btnG");selenium.waitForPageToLoad("30000");assertTrue(selenium.isTextPresent("Results * for selenium rc"));// These are the real test steps
}}
C#
O driver do cliente .NET funciona com o Microsoft.NET.
Pode ser usado com qualquer framework de teste .NET
como o NUnit ou o Visual Studio 2005 Team System.
Selenium-IDE assume que você usará NUnit como sua estrutura de teste.
Você pode ver isso no código gerado abaixo. Inclui a declaração using
para NUnit junto com os atributos NUnit correspondentes que identificam
o papel de cada função-membro da classe de teste.
Você provavelmente terá que renomear a classe de teste de “NewTest” para
algo de sua própria escolha. Além disso, você precisará alterar os
parâmetros abertos pelo navegador na declaração
usingSystem;usingSystem.Text;usingSystem.Text.RegularExpressions;usingSystem.Threading;usingNUnit.Framework;usingSelenium;namespaceSeleniumTests{ [TestFixture]publicclassNewTest{privateISeleniumselenium;privateStringBuilderverificationErrors; [SetUp]publicvoidSetupTest(){selenium=newDefaultSelenium("localhost",4444,"*iehta","http://www.google.com/");selenium.Start();verificationErrors=newStringBuilder();} [TearDown]publicvoidTeardownTest(){try{selenium.Stop();}catch(Exception){// Ignore errors if unable to close the browser}Assert.AreEqual("",verificationErrors.ToString());} [Test]publicvoidTheNewTest(){// Open Google search engine. selenium.Open("http://www.google.com/");// Assert Title of page.Assert.AreEqual("Google",selenium.GetTitle());// Provide search term as "Selenium OpenQA"selenium.Type("q","Selenium OpenQA");// Read the keyed search term and assert it.Assert.AreEqual("Selenium OpenQA",selenium.GetValue("q"));// Click on Search button.selenium.Click("btnG");// Wait for page to load.selenium.WaitForPageToLoad("5000");// Assert that "www.openqa.org" is available in search results.Assert.IsTrue(selenium.IsTextPresent("www.openqa.org"));// Assert that page title is - "Selenium OpenQA - Google Search"Assert.AreEqual("Selenium OpenQA - Google Search",selenium.GetTitle());}}}
Você pode permitir que o NUnit gerencie a execução
de seus testes. Ou, alternativamente, você pode escrever um programa main() simples que
instancia o objeto de teste e executa cada um dos três métodos, SetupTest(),
TheNewTest() e TeardownTest() por sua vez.
Python
Pyunit é a estrutura de teste a ser usada para Python.
A estrutura básica do teste é:
fromseleniumimportselenium# This is the driver's import. You'll use this class for instantiating a# browser and making it do what you need.importunittest,time,re# This are the basic imports added by Selenium-IDE by default.# You can remove the modules if they are not used in your script.classNewTest(unittest.TestCase):# We create our unittest test casedefsetUp(self):self.verificationErrors=[]# This is an empty array where we will store any verification errors# we find in our testsself.selenium=selenium("localhost",4444,"*firefox","http://www.google.com/")self.selenium.start()# We instantiate and start the browserdeftest_new(self):# This is the test code. Here you should put the actions you need# the browser to do during your test.sel=self.selenium# We assign the browser to the variable "sel" (just to save us from # typing "self.selenium" each time we want to call the browser).sel.open("/")sel.type("q","selenium rc")sel.click("btnG")sel.wait_for_page_to_load("30000")self.failUnless(sel.is_text_present("Results * for selenium rc"))# These are the real test stepsdeftearDown(self):self.selenium.stop()# we close the browser (I'd recommend you to comment this line while# you are creating and debugging your tests)self.assertEqual([],self.verificationErrors)# And make the test fail if we found that any verification errors# were found
Ruby
Versões antigas (pré 2.0) da Selenium-IDE geram código Ruby que requer o gem antigo do Selenium. Portanto, é aconselhável atualizar todos os scripts Ruby gerados pela
IDE da seguinte forma:
Na linha 1, altere require "selenium" para require "selenium/client"
Na linha 11, altere Selenium::SeleniumDriver.new para
Selenium::Client::Driver.new
Você provavelmente também deseja alterar o nome da classe para algo mais
informativo do que “Untitled” e alterar o nome do método de teste para
algo diferente de “test_untitled.”
Aqui está um exemplo simples criado pela modificação do código Ruby gerado
pela Selenium IDE, conforme descrito acima.
# load the Selenium-Client gemrequire"selenium/client"# Load Test::Unit, Ruby's default test framework.# If you prefer RSpec, see the examples in the Selenium-Client# documentation.require"test/unit"classUntitled<Test::Unit::TestCase# The setup method is called before each test.defsetup# This array is used to capture errors and display them at the# end of the test run.@verification_errors=[]# Create a new instance of the Selenium-Client driver.@selenium=Selenium::Client::Driver.new\:host=>"localhost",:port=>4444,:browser=>"*chrome",:url=>"http://www.google.com/",:timeout_in_second=>60# Start the browser session@selenium.start# Print a message in the browser-side log and status bar# (optional).@selenium.set_context("test_untitled")end# The teardown method is called after each test.defteardown# Stop the browser session.@selenium.stop# Print the array of error messages, if any.assert_equal[],@verification_errorsend# This is the main body of your test.deftest_untitled# Open the root of the site we specified when we created the# new driver instance, above.@selenium.open"/"# Type 'selenium rc' into the field named 'q'@selenium.type"q","selenium rc"# Click the button named "btnG"@selenium.click"btnG"# Wait for the search results page to load.# Note that we don't need to set a timeout here, because that# was specified when we created the new driver instance, above.@selenium.wait_for_page_to_loadbegin# Test whether the search results contain the expected text.# Notice that the star (*) is a wildcard that matches any# number of characters.assert@selenium.is_text_present("Results * for selenium rc")rescueTest::Unit::AssertionFailedError# If the assertion fails, push it onto the array of errors.@verification_errors<<$!endendend
Perl, PHP
Os membros da equipe de documentação
não usaram Selenium RC com Perl ou PHP. Se você estiver usando Selenium RC com qualquer um desses dois idiomas, entre em contato com a Equipe de Documentação (consulte o capítulo sobre Contribuições).
Gostaríamos muito de incluir alguns exemplos seus e de suas experiências, para oferecer suporte a usuários Perl e PHP.
Aprendendo a API
A API Selenium RC usa convenções de nomenclatura
que, supondo que você entenda Selenese, será em grande parte autoexplicativo.
Aqui, no entanto, explicamos os aspectos mais críticos e
possivelmente menos óbvios.
Cada um desses exemplos abre o navegador e representa esse navegador
atribuindo uma “instância do navegador” a uma variável de programa. Esta variável de programa é então usada para chamar métodos do navegador.
Esses métodos executam os comandos Selenium, ou seja, como open ou type ou verify.
Os parâmetros necessários ao criar a instância do navegador
são:
host
Especifica o endereço IP do computador onde o servidor está localizado. Normalmente, esta é
a mesma máquina em que o cliente está sendo executado, portanto, neste caso, localhost é passado. Em alguns clientes, este é um parâmetro opcional.
port
Especifica o socket TCP/IP onde o servidor está escutando, esperando
para o cliente estabelecer uma conexão. Isso também é opcional em alguns
drivers do cliente.
browser
O navegador no qual você deseja executar os testes. Este é um parâmetro obrigatório.
url
A url base do aplicativo em teste. Isso é exigido por todas as
libs de cliente e é uma informação integral para iniciar a comunicação entre navegador-proxy-aplicação.
Observe que algumas das bibliotecas cliente exigem que o navegador seja iniciado explicitamente chamando
seu método start ().
Executando comandos
Depois de ter o navegador inicializado e atribuído a uma variável (geralmente
chamada “selenium”), você pode fazê-lo executar comandos Selenese chamando os respectivos
métodos a partir da variável do navegador. Por exemplo, para chamar o método type
do objeto selenium:
selenium.type("field-id", "string to type")
Em segundo plano, o navegador realmente realizará uma operação type,
essencialmente idêntico a um usuário digitando uma entrada no navegador,
usando o localizador e a string que você especificou durante a chamada do método.
Reportando resultados
O Selenium RC não tem seu próprio mecanismo para relatar os resultados. Em vez disso,
você pode construir seus relatórios personalizados de acordo com suas necessidades, usando recursos de sua
linguagem de programação escolhida. Isso é ótimo, mas e se você simplesmente quiser algo
rápido que já foi feito para você? Muitas vezes, uma biblioteca existente ou estrutura de teste pode
atender às suas necessidades mais rapidamente do que desenvolver seu próprio código de relatório de teste.
Ferramentas de reporte dos frameworks de teste
Frameworks de teste estão disponíveis para muitas linguagens de programação. Estes, junto com
sua função principal de fornecer um mecanismo de teste flexível para executar seus testes,
incluem o código da biblioteca para relatar os resultados. Por exemplo, Java tem dois
frameworks de teste comumente usados, JUnit e TestNG. .NET também tem seu próprio, NUnit.
Não ensinaremos os frameworks aqui; e que está além do escopo deste
guia de usuário. Vamos simplesmente apresentar os recursos do framework relacionados ao Selenium
junto com algumas técnicas que você pode aplicar. Existem bons livros disponíveis sobre estas
estruturas de teste, juntamente com informações na Internet.
Bibliotecas de relatórios de teste
Também estão disponíveis bibliotecas de terceiros criadas especificamente para reportar
os resultados dos testes na linguagem de programação escolhida. Estes geralmente suportam uma
variedade de formatos, como HTML ou PDF.
Qual a melhor técnica?
A maioria das pessoas novas no uso dos frameworks de teste começarão com os
recursos de relatórios integrados no framework. A partir daí, a maioria examinará todas as bibliotecas disponíveis
pois isso consome menos tempo do que desenvolver a sua própria. Quando você começa a usar o
Selenium, sem dúvida, você vai começar a colocar seus próprios “prints” para
relatar o progresso. Isso pode levá-lo gradualmente a desenvolver seus próprios
relatórios, possivelmente em paralelo ao uso de uma biblioteca ou estrutura de teste. Independentemente,
após a curta curva de aprendizado inicial você desenvolverá naturalmente o que funciona
melhor para sua própria situação.
Exemplos de relatórios de teste
Para ilustrar, iremos direcioná-lo para algumas ferramentas específicas em algumas das outras linguagens
apoiadas pelo Selenium. As listadas aqui são comumente usadas e têm sido usadas
extensivamente (e portanto recomendadas) pelos autores deste guia.
Relatórios de teste em Java
Se os casos de teste Selenium forem desenvolvidos usando JUnit, então o relatório JUnit pode ser usado
para gerar relatórios de teste.
Se os casos de teste Selenium forem desenvolvidos usando TestNG, então nenhuma tarefa externa
é necessária para gerar relatórios de teste. A estrutura TestNG gera um
Relatório HTML que lista os detalhes dos testes.
ReportNG é um plug-in de relatório HTML para a estrutura TestNG.
Destina-se a substituir o relatório HTML padrão do TestNG.
O ReportNG fornece uma visualização simples e codificada por cores dos resultados do teste.
Registrando os comandos Selenese
O Logging Selenium pode ser usado para gerar um relatório de todos os comandos Selenese
em seu teste junto com o sucesso ou fracasso de cada um. Logging Selenium estende
o driver do cliente Java para adicionar esta capacidade de registro do Selenese.
Relatórios de teste em Python
Ao usar o driver de cliente para Python, HTMLTestRunner pode ser usado para
gerar um relatório de teste.
Relatórios de teste em Ruby
Se o framework RSpec for usado para escrever Casos de Teste Selenium em Ruby
então seu relatório HTML pode ser usado para gerar um relatório de teste.
Adicionando algum tempero aos seus testes
Agora veremos toda a razão de usar Selenium RC, adicionando lógica de programação aos seus testes.
É o mesmo que para qualquer programa. O fluxo do programa é controlado por meio de declarações de condição
e iteração. Além disso, você pode relatar informações de progresso usando I/O. Nesta secção
vamos mostrar alguns exemplos de como construções de linguagem de programação podem ser combinadas com
Selenium para resolver problemas de teste comuns.
Você vai descobrir ao fazer a transição dos testes simples da existência de
elementos de página para testes de funcionalidade dinâmica envolvendo várias páginas da web e
dados variáveis que você exigirá lógica de programação para verificar
resultados. Basicamente, a Selenium-IDE não suporta iteração e
declarações de condição padrão. Você pode fazer algumas condições incorporando JavaScript
em parâmetros Selenese, no entanto
iteração é impossível, e a maioria das condições será muito mais fácil em uma
linguagem de programação. Além disso, você pode precisar de tratamento de exceção para
recuperação de erros. Por essas e outras razões, escrevemos esta seção
para ilustrar o uso de técnicas de programação comuns para
dar a você maior ‘poder de verificação’ em seus testes automatizados.
Os exemplos nesta seção são escritos
em C# e Java, embora o código seja simples e possa ser facilmente adaptado às demais
linguagens. Se você tem algum conhecimento básico
de uma linguagem de programação orientada a objetos, você não deve ter dificuldade em entender esta seção.
Iteração
A iteração é uma das coisas mais comuns que as pessoas precisam fazer em seus testes.
Por exemplo, você pode querer executar uma pesquisa várias vezes. Ou, talvez
para verificar os resultados do teste, você precisa processar um “conjunto de resultados” retornado de um banco de dados.
Usando o mesmo exemplo de pesquisa do Google que usamos anteriormente, vamos
verificar os resultados da pesquisa Selenium. Este teste pode usar o Selenese:
open
/
type
q
selenium rc
clickAndWait
btnG
assertTextPresent
Results * for selenium rc
type
q
selenium ide
clickAndWait
btnG
assertTextPresent
Results * for selenium ide
type
q
selenium grid
clickAndWait
btnG
assertTextPresent
Results * for selenium grid
O código foi repetido para executar as mesmas etapas 3 vezes. Mas ter múltiplas
cópias do mesmo código não é uma boa prática de programação porque é mais
trabalhoso para manter. Usando uma linguagem de programação, podemos iterar
sobre os resultados da pesquisa para uma solução mais flexível e sustentável.
In C#
// Collection of String values.String[]arr={"ide","rc","grid"};// Execute loop for each String in array 'arr'.foreach(Stringsinarr){sel.open("/");sel.type("q","selenium "+s);sel.click("btnG");sel.waitForPageToLoad("30000");assertTrue("Expected text: "+s+" is missing on page.",sel.isTextPresent("Results * for selenium "+s));}
Declarações de condição
Para ilustrar o uso de condições em testes, começaremos com um exemplo.
Um problema comum encontrado durante a execução de testes Selenium ocorre quando
o elemento esperado não está disponível na página. Por exemplo, ao executar a
seguinte linha:
selenium.type("q", "selenium " +s);
Se o elemento ‘q’ não estiver na página, então uma exceção é
lançada:
Isso pode fazer com que seu teste seja interrompido. Para alguns testes, é isso que você deseja. Mas
frequentemente isso não é desejável, pois seu script de teste tem muitos outros testes subsequentes para realizar.
Uma abordagem melhor é primeiro validar se o elemento está realmente presente
e então escolher alternativas quando não estiver. Vejamos isso usando Java.
// If element is available on page then perform type operation.
if(selenium.isElementPresent("q")){selenium.type("q","Selenium rc");}else{System.out.printf("Element: "+q+" is not available on page.")}
A vantagem desta abordagem é continuar com a execução do teste, mesmo se alguns elementos de IU não estão disponíveis na página.
Executando JavaScript a partir do seu teste
JavaScript é muito útil para exercitar uma aplicação que não é diretamente suportada
por Selenium. O método getEval da API Selenium pode ser usado para executar JavaScript a partir de
Selenium RC.
Considere um aplicativo com caixas de seleção sem identificadores estáticos.
Neste caso, pode-se avaliar o JavaScript do Selenium RC para obter ids de todas
caixas de seleção e, em seguida, exercitá-las.
publicstaticString[]getAllCheckboxIds(){Stringscript="var inputId = new Array();";// Create array in java script.
script+="var cnt = 0;";// Counter for check box ids.
script+="var inputFields = new Array();";// Create array in java script.
script+="inputFields = window.document.getElementsByTagName('input');";// Collect input elements.
script+="for(var i=0; i<inputFields.length; i++) {";// Loop through the collected elements.
script+="if(inputFields[i].id !=null "+"&& inputFields[i].id !='undefined' "+"&& inputFields[i].getAttribute('type') == 'checkbox') {";// If input field is of type check box and input id is not null.
script+="inputId[cnt]=inputFields[i].id ;"+// Save check box id to inputId array.
"cnt++;"+// increment the counter.
"}"+// end of if.
"}";// end of for.
script+="inputId.toString();";// Convert array in to string.
String[]checkboxIds=selenium.getEval(script).split(",");// Split the string.
returncheckboxIds;}
Você verá uma lista de todas as opções que pode usar com o servidor e uma breve
descrição de cada. As descrições fornecidas nem sempre serão suficientes, então
fornecemos explicações para algumas das opções mais importantes.
Configuração do Proxy
Se o seu aplicação estiver atrás de um proxy HTTP que requer autenticação, você deve
configurar http.proxyHost, http.proxyPort, http.proxyUser e http.proxyPassword
usando o seguinte comando.
Se você estiver usando Selenium 1.0, você provavelmente pode pular esta seção, uma vez que o modo multijanela é
o comportamento padrão. No entanto, antes da versão 1.0, o Selenium executava por padrão o
aplicativo em teste em um subquadro, conforme mostrado aqui.
Alguns aplicativos não funcionavam corretamente em um subquadro e precisavam ser
carregados no quadro superior da janela. A opção de modo multi-janela permitida
a aplicação testada ser executada em uma janela separada, em vez do quadro
padrão onde poderia então ter o quadro superior necessário.
Para versões mais antigas do Selenium você deve especificar o modo multijanela explicitamente
com a seguinte opção:
-multiwindow
A partir do Selenium RC 1.0, se você deseja executar seu teste dentro de um
quadro único (ou seja, usando o padrão para versões anteriores do Selenium)
você pode declarar isso ao servidor Selenium usando a opção
-singlewindow
Especificando o perfil do Firefox
O Firefox não executará duas instâncias simultaneamente, a menos que você especifique um
perfil separado para cada instância. Selenium RC 1.0 e posterior é executado em um perfil separado automaticamente, então se você estiver usando Selenium 1.0, você pode
provavelmente pular esta seção. No entanto, se você estiver usando uma versão mais antiga do
Selenium ou se você precisar usar um perfil específico para seus testes
(como adicionar um certificado https ou ter alguns complementos instalados), você
precisa especificar explicitamente o perfil.
Primeiro, para criar um perfil separado do Firefox, siga este procedimento.
Abra o menu Iniciar do Windows, selecione “Executar”, digite e entre um dos
seguintes:
firefox.exe -profilemanager
firefox.exe -P
Crie o novo perfil usando a caixa de diálogo. Então, quando você executar o Selenium Server,
diga a ele para usar este novo perfil do Firefox com a opção de linha de comando do servidor
-firefoxProfileTemplate e especifique o caminho para o perfil usando seu nome de arquivo
e o caminho do diretório.
-firefoxProfileTemplate "path to the profile"
Aviso: certifique-se de colocar seu perfil em uma nova pasta separada da padrão!!!
A ferramenta gerenciadora de perfil do Firefox irá deletar todos os arquivos em uma pasta se você
excluir um perfil, independentemente de serem arquivos de perfil ou não.
Isso iniciará automaticamente seu pacote HTML, executará todos os testes e salvará um
bom relatório HTML com os resultados.
Nota: ao usar esta opção, o servidor irá iniciar os testes e aguardar um
número especificado de segundos para o teste ser concluído; se o teste não
completar dentro desse período de tempo, o comando sairá com um código de saída diferente de zero
e nenhum arquivo de resultados será gerado.
Esta linha de comando é muito longa, então tome cuidado com o que
você digita. Observe que isso requer que você passe uma suíte de arquivos HTML Selenese, não um único teste. Também esteja ciente de que a opção -htmlSuite é incompatível com -interactive.
Você não pode executar os dois ao mesmo tempo.
Logging do servidor Selenium
logs do lado do servidor
Ao iniciar o servidor Selenium, a opção -log pode ser usada para gravar
informações valiosas de depuração relatadas pelo servidor Selenium em um arquivo de texto.
Este arquivo de log é mais detalhado do que os logs do console padrão (inclui mensagens de registro de nível DEBUG
). O arquivo de log também inclui o nome do registrador e o
número do thread que registrou a mensagem. Por exemplo:
O JavaScript no lado do navegador (Selenium Core) também registra mensagens importantes;
em muitos casos, eles podem ser mais úteis para o usuário final do que os
Logs normais do servidor. Para acessar os registros do lado do navegador, passe o argumento -browserSideLog para o servidor Selenium.
-browserSideLog deve ser combinado com o argumento -log, para registrar
browserSideLogs (bem como todas as outras mensagens de log de nível DEBUG) em um arquivo.
Especificando o caminho para um navegador específico
Você pode especificar para o Selenium RC o caminho para um navegador. Isto
é útil se você possui diferentes versões do mesmo navegador e você deseja usar
uma em específico. Isto também pode ser usado para executar seus testes em um navegador
que não é suportado diretamente pelo Selenium RC. Quando especificar o modo
de execução, use o especificador *custom seguido do caminho completo para o
executável do navegador.
*custom <path to browser>
Arquitetura do Selenium RC
Nota: este tópico tenta explicar a implementação técnica por trás do Selenium RC.
Não é fundamental para um usuário Selenium saber disso, mas
pode ser útil para entender alguns dos problemas que você pode encontrar no
futuro.
Para entender em detalhes como o Selenium RC Server funciona e porque ele usa injeção de proxy
e modos de privilégio elevado você deve primeiro entender the same origin policy.
A política de mesma origem (Same Origin Policy)
A principal restrição que o Selenium enfrenta é a
política de mesma origem. Esta restrição de segurança é aplicada por todos os navegadores
no mercado e seu objetivo é garantir que o conteúdo de um site nunca
esteja acessível por um script de outro site. A política da mesma origem determina que
qualquer código carregado no navegador só pode operar dentro do domínio desse site.
Ele não pode executar funções em outro site. Por exemplo, se o navegador
carrega o código JavaScript quando carrega www.mysite.com, ele não pode executar esse código carregado
em www.mysite2.com - mesmo que seja outro de seus sites. Se isso fosse possível,
um script colocado em qualquer site que você abrir seria capaz de ler informações sobre
sua conta bancária se você tivesse a página da conta
aberto em outra guia. Isso é chamado de XSS (Cross-site Scripting).
Para trabalhar dentro desta política, Selenium-Core (e seus comandos JavaScript que
fazem toda a mágica acontecer) deve ser colocado na mesma origem do aplicativo testado (mesmo URL).
Historicamente, Selenium-Core era limitado por este problema, uma vez que foi implementado em
JavaScript. O Selenium RC não é, entretanto, restringido pela Política da Mesma Origem.
Seu uso do Selenium Server como proxy evita esse problema. Essencialmente, diz ao
navegador que o navegador está funcionando em um único site “falsificado” que o servidor
fornece.
Nota: você pode encontrar informações adicionais sobre este tópico nas páginas da Wikipedia
sobre a política da mesma origem e XSS.
Injeção de Proxy
O primeiro método que o Selenium usou para evitar a Política de Mesma Origem foi a injeção de proxy.
No modo de injeção de proxy, o servidor Selenium atua como um HTTP configurado pelo cliente
proxy1, que fica entre o navegador e o aplicativo em teste 2.
Em seguida, ele mascara a aplicação testada sob uma URL fictícia (incorporação
Selenium-Core e o conjunto de testes e entregando-os como se estivessem chegando
da mesma origem).
Aqui está um diagrama da arquitetura.
Quando um conjunto de testes começa em sua linguagem favorita, acontece o seguinte:
O cliente/driver estabelece uma conexão com o servidor selenium-RC.
O servidor Selenium RC inicia um navegador (ou reutiliza um antigo) com uma URL
que injeta o JavaScript do Selenium-Core na página da web carregada pelo navegador.
O driver do cliente passa um comando Selenese para o servidor.
O servidor interpreta o comando e então aciona a execução correspondente
de JavaScript para executar esse comando no navegador.
Selenium-Core instrui o navegador a agir sobre a primeira instrução, normalmente abrindo uma página da
aplicação testada.
O navegador recebe a solicitação de abertura e pede o conteúdo do site do
servidor Selenium RC (definido como o proxy HTTP para o navegador usar).
O servidor Selenium RC se comunica com o servidor Web solicitando a página e uma vez que
recebe, envia a página para o navegador mascarando a origem para parecer
que a página vem do mesmo servidor que Selenium-Core (isso permite
Selenium-Core para cumprir a Política da Mesma Origem).
O navegador recebe a página da web e a renderiza no quadro/janela reservado
para isso.
Navegadores com privilégio elevado
Este fluxo de trabalho neste método é muito semelhante à injeção de proxy, mas a principal
diferença é que os navegadores são iniciados em um modo especial chamado de Privilégios Aumentados, que permite que os sites façam coisas que normalmente não são permitidas
(como fazer XSS, ou preencher entradas de upload de arquivos e coisas muito úteis para o
Selenium). Ao usar esses modos de navegador, o Selenium Core é capaz de abrir diretamente
a aplicação testada e ler/interagir com seu conteúdo sem ter que passar a aplicação inteira
através do servidor Selenium RC.
Aqui está um diagrama da arquitetura.
Quando um conjunto de testes começa em sua linguagem favorita, acontece o seguinte:
O cliente/driver estabelece uma conexão com o servidor selenium-RC.
O servidor Selenium RC inicia um navegador (ou reutiliza um antigo) com uma URL
que irá carregar o Selenium-Core na página da web.
Selenium-Core obtém a primeira instrução do cliente/driver (através de outra
solicitação HTTP feita ao servidor Selenium RC).
Selenium-Core atua na primeira instrução, normalmente abrindo uma página da aplicação.
O navegador recebe a solicitação de abertura e solicita a página ao servidor da Web.
Assim que o navegador recebe a página da web, a renderiza no quadro / janela reservado
para isso.
Lidando com HTTPS e Popups de segurança
Muitos aplicativos mudam de HTTP para HTTPS quando precisam enviar
informações criptografadas, como senhas ou informações de cartão de crédito. Isto é
comum com muitos dos aplicativos da web de hoje. Selenium RC apoia isso.
Para garantir que o site HTTPS seja genuíno, o navegador precisará de um certificado de segurança.
Caso contrário, quando o navegador acessar a aplicação testada usando HTTPS, ele irá
presumir que o aplicativo não é ‘confiável’. Quando isso ocorre, o navegador
exibe pop-ups de segurança e esses pop-ups não podem ser fechados usando o Selenium RC.
Ao lidar com HTTPS em um teste Selenium RC, você deve usar um modo de execução que suporte isso e controle
o certificado de segurança para você. Você especifica o modo de execução quando seu programa de teste
inicializa o Selenium.
No Selenium RC 1.0 beta 2 e posterior, use *firefox ou *iexplore para o modo de execução.
Em versões anteriores, incluindo Selenium RC 1.0 beta 1, use *chrome ou
*iehta, para o modo de execução. Usando esses modos de execução, você não precisará instalar
quaisquer certificados de segurança especiais; Selenium RC cuidará disso para você.
Na versão 1.0, os modos de execução *firefox ou *iexplore são
recomendados. No entanto, existem modos de execução adicionais de *iexploreproxy e
*firefoxproxy. Eles são fornecidos apenas para compatibilidade com versões anteriores, e
não devem ser usados, a menos que exigido por programas de teste legados. Seu uso vai
apresentar limitações com o manuseio do certificado de segurança e com o funcionamento
de várias janelas se seu aplicativo abrir janelas adicionais do navegador.
Em versões anteriores do Selenium RC, *chrome ou *iehta eram os modos de execução que suportavam
HTTPS suportado e o tratamento de popups de segurança. Estes foram considerados ‘modos experimentais’, embora tenham se tornado bastante estáveis e muitas pessoas os usaram. Se você estiver usando
Selenium 1.0 você não precisa, e não deve usar, esses modos de execução mais antigos.
Certificados de Segurança explicados
Normalmente, seu navegador confiará no aplicativo que você está testando
instalando um certificado de segurança que você já possui. Você pode
verificar isso nas opções do seu navegador ou propriedades da Internet (se você não
conheça o certificado de segurança da sua aplicação, pergunte ao administrador do sistema).
Quando o Selenium carrega seu navegador, ele injeta um código para interceptar
mensagens entre o navegador e o servidor. O navegador agora pensa que algum
software não confiável está tentando se parecer com o seu aplicativo. Ele responde alertando você com mensagens pop-up.
Para contornar isso, Selenium RC, (novamente ao usar um modo de execução que suporta
isso) instalará seu próprio certificado de segurança, temporariamente, em sua
máquina cliente em um local onde o navegador possa acessá-lo. Isso engana
o navegador a pensar que está acessando um site diferente da sua aplicação e suprime efetivamente os pop-ups.
Outro método usado com versões anteriores do Selenium era
instalar o certificado de segurança Cybervillians fornecido com sua instalação do Selenium.
A maioria dos usuários não deve mais precisar fazer isso; se você está
executando o Selenium RC no modo de injeção de proxy, você pode precisar instalar
explicitamente este certificado de segurança.
Suportando navegadores e configurações adicionais
A API Selenium suporta a execução em vários navegadores, além de
Internet Explorer e Mozilla Firefox. Veja o site https://selenium.dev para
navegadores compatíveis. Além disso, quando um navegador não é diretamente compatível,
você ainda pode executar seus testes Selenium em um navegador de sua escolha
usando o modo de execução “*custom” (ou seja, no lugar de *firefox ou *iexplore) quando
seu aplicativo de teste inicia o navegador. Com isso, você passa no caminho para
os navegadores executáveis na chamada de API. Isso também pode ser feito a partir do
servidor em modo interativo.
Executando testes com diferentes configurações de navegador
Normalmente o Selenium RC configura automaticamente o navegador, mas se você iniciar
o navegador usando o modo de execução “*custom”, você pode forçar o Selenium RC
a iniciar o navegador como está, sem usar uma configuração automática.
Por exemplo, você pode iniciar o Firefox com uma configuração personalizada como esta:
Observe que ao iniciar o navegador desta forma, você deve manualmente
configurar o navegador para usar o servidor Selenium como proxy. Normalmente, isso apenas
significa abrir as preferências do navegador e especificar “localhost: 4444” como
um proxy HTTP, mas as instruções para isso podem diferir radicalmente de navegador para
navegador. Consulte a documentação do seu navegador para obter detalhes.
Esteja ciente de que os navegadores Mozilla podem variar em como eles iniciam e param.
Pode ser necessário definir a variável de ambiente MOZ_NO_REMOTE para fazer com que os navegadores Mozilla
se comportem de maneira mais previsível. Os usuários Unix devem evitar iniciar o navegador usando
um script de shell; geralmente é melhor usar o executável binário (por exemplo, firefox-bin) diretamente.
Resolução de problemas comuns
Ao começar a usar o Selenium RC, há alguns problemas potenciais
que são comumente encontrados. Nós os apresentamos junto com suas soluções aqui.
Incapaz de conectar ao servidor
Quando seu programa de teste não pode se conectar ao servidor Selenium, o Selenium lança uma exceção em seu programa de teste.
Ele deve exibir esta mensagem ou outra semelhante:
"Unable to connect to remote server (Inner Exception Message:
No connection could be made because the target machine actively
refused it )"(using .NET and XP Service Pack 2)
Se você vir uma mensagem como esta, certifique-se de iniciar o servidor Selenium. E se
então, há um problema com a conectividade entre a biblioteca cliente Selenium e o servidor Selenium.
Ao começar com Selenium RC, a maioria das pessoas começa executando seu programa de teste
(com uma biblioteca de cliente Selenium) e o servidor Selenium na mesma máquina. Para
fazer isso use “localhost” como parâmetro de conexão.
Recomendamos começar dessa forma, pois reduz a influência de possíveis problemas de rede
que você está começando. Supondo que seu sistema operacional tenha uma rede típica
e configurações TCP/IP, você deve ter pouca dificuldade. Na verdade, muitas pessoas
optam por executar os testes desta forma.
Se, no entanto, você deseja executar o Selenium Server
em uma máquina remota, a conectividade deve ser boa,
supondo que você tenha uma conexão TCP/IP válida entre as duas máquinas.
Se tiver dificuldade para se conectar, você pode usar ferramentas de rede comuns como ping,
telnet, ifconfig (Unix) / ipconfig (Windows), etc para garantir que você tenha uma
conexão de rede. Se não estiver familiarizado com eles, o administrador do sistema pode ajudá-lo.
Incapaz de carregar o navegador
Ok, não é uma mensagem de erro amigável, desculpe, mas se o servidor Selenium não pode carregar o navegador
você provavelmente verá este erro.
(500) Internal Server Error
Isso pode ser causado por
O Firefox (anterior ao Selenium 1.0) não pode iniciar porque o navegador já está aberto e você o fez
não especificar um perfil separado. Consulte a seção sobre perfis do Firefox em Opções do servidor.
O modo de execução que você está usando não corresponde a nenhum navegador em sua máquina. Verifique os parâmetros que você
passou para o Selenium quando seu programa abre o navegador.
Você especificou o caminho para o navegador explicitamente (usando “*custom” - veja acima), mas o caminho é
incorreto. Verifique se o caminho está correto. Verifique também o grupo de usuários para ter certeza de que há
nenhum problema conhecido com seu navegador e os parâmetros “*custom”.
Selenium não consegue achar a aplicação testada
Se o seu programa de teste iniciar o navegador com sucesso, mas o navegador não
exibir o site que você está testando, a causa mais provável é que o seu programa de teste não está usando a URL correta.
Isso pode acontecer facilmente. Quando você usa Selenium-IDE para exportar seu script,
ela insere uma URL fictícia. Você deve alterar manualmente a URL para a correta
para que seu aplicativo seja testado.
O Firefox recusou o desligamento ao preparar um perfil
Isso ocorre com mais frequência quando você executa o programa de teste Selenium RC no Firefox,
mas você já tem uma sessão do navegador Firefox em execução e não especificou
um perfil separado quando você iniciou o servidor Selenium. O erro do
programa de teste tem a seguinte aparência:
Error: java.lang.RuntimeException: Firefox refused shutdown while preparing a profile
Esta é a mensagem de erro completa do servidor:
16:20:03.919 INFO - Preparing Firefox profile...
16:20:27.822 WARN - GET /selenium-server/driver/?cmd=getNewBrowserSession&1=*fir
efox&2=http%3a%2f%2fsage-webapp1.qa.idc.com HTTP/1.1
java.lang.RuntimeException: Firefox refused shutdown while preparing a profile
at org.openqa.selenium.server.browserlaunchers.FirefoxCustomProfileLaunc
her.waitForFullProfileToBeCreated(FirefoxCustomProfileLauncher.java:277) ...
Caused by: org.openqa.selenium.server.browserlaunchers.FirefoxCustomProfileLaunc
her$FileLockRemainedException: Lock file still present! C:\DOCUME~1\jsvec\LOCALS
~1\Temp\customProfileDir203138\parent.lock
Para resolver isso, consulte a seção Especificando um perfil separado do Firefox
Problemas de versionamento
Certifique-se de que sua versão do Selenium é compatível com a versão do seu navegador. Por
exemplo, Selenium RC 0.92 não suporta Firefox 3. Às vezes você pode ter sorte
(eu tive). Mas não se esqueça de verificar quais
versões do navegador são compatíveis com a versão do Selenium que você está usando. Quando em
dúvida, use a versão mais recente do Selenium com a versão mais usada
do seu navegador.
Mensagem de erro: “(Unsupported major.minor version 49.0)” ao inicializar o servidor
Este erro diz que você não está usando uma versão correta do Java.
O Selenium Server requer Java 1.5 ou superior.
Para verificar novamente sua versão java, execute na linha de comando:
java -version
Você deve ver uma mensagem mostrando a versão do Java.
java version "1.5.0_07" Java(TM)2 Runtime Environment, Standard Edition (build 1.5.0_07-b03) Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode)
Se você vir um número de versão inferior, pode ser necessário atualizar o JRE,
ou você pode simplesmente precisar adicioná-lo à sua variável de ambiente PATH.
Erro 404 ao executar o comando getNewBrowserSession
Se você receber um erro 404 ao tentar abrir uma página em
“http://www.google.com/selenium-server/", então deve ser porque o servidor Selenium não foi configurado corretamente como proxy. O diretório “selenium-server”
não existe no google.com; só parece existir quando o proxy é
configurado corretamente. A configuração do proxy depende muito de como o navegador é
lançado com firefox, iexplore, opera ou custom.
iexplore: se o navegador for iniciado usando *iexplore, você pode estar
tendo um problema com as configurações de proxy do Internet Explorer.
O servidor Selenium tenta definir as configurações globais de proxy no painel de controle Opções da Internet.
Você deve se certificar de que elas estão corretamente
configuradas quando o servidor Selenium inicia o navegador. Tente olhar para
seu painel de controle Opções da Internet. Clique na guia “Conexões”
e clique em “Configurações da LAN”.
Se você precisar usar um proxy para acessar o aplicativo que deseja testar,
você precisará iniciar o Selenium Server com “-Dhttp.proxyHost”;
veja Configuração de Proxy para mais detalhes.
Você também pode tentar configurar seu proxy manualmente e, em seguida, iniciar
o navegador com *custom ou com o iniciador de navegador *iehta.
custom: ao usar *custom, você deve configurar o proxy corretamente (manualmente),
caso contrário, você obterá um erro 404. Verifique novamente se você configurou seu proxy corretamente.
Verificar se você configurou o proxy corretamente é configurar intencionalmente o navegador de forma incorreta. Tente configurar o
navegador para usar o nome de host do servidor proxy errado ou a porta errada. Se você tinha
configurado com sucesso as configurações de proxy do navegador incorretamente, então o
navegador não conseguirá se conectar à Internet, o que é uma maneira de
certificar-se de que está ajustando as configurações relevantes.
Para outros navegadores (*firefox, *opera), codificamos automaticamente
o proxy para você e, portanto, não há problemas conhecidos com essa funcionalidade.
Se você estiver encontrando erros 404 e tiver seguido este guia do usuário cuidadosamente
publique seus resultados no grupo de usuários para obter ajuda da comunidade de usuários.
Erro de permissão negada
O motivo mais comum para esse erro é que sua sessão está tentando violar
a política de mesma origem cruzando os limites do domínio (por exemplo, acessa uma página de
http://domínio1 e, em seguida, acessa uma página de http://domínio2) ou troca de protocolos
(passando de http://domainX para https://domainX).
Este erro também pode ocorrer quando o JavaScript tenta encontrar objetos de IU
que ainda não estão disponíveis (antes que a página seja completamente carregada), ou
não estão mais disponíveis (após a página
começar a ser descarregada). Isso é mais comumente encontrado com páginas AJAX
que estão trabalhando com seções de uma página ou subframes que carregam e / ou recarregam
independentemente da página maior.
Este erro pode ser intermitente. Muitas vezes é impossível reproduzir o problema
com um depurador porque o problema decorre de condições de corrida que
não são reproduzíveis quando a sobrecarga do depurador é adicionada ao sistema.
As questões de permissão são abordadas com alguns detalhes no tutorial. Leia a seção
sobre a Política da Mesma Origem, Injeção de Proxy com cuidado.
Gerenciando janelas pop-up do navegador
Existem vários tipos de “Popups” que você pode obter durante um teste Selenium.
Você pode não conseguir fechar esses pop-ups executando comandos do Selenium se
eles são iniciados pelo navegador e não pela aplicação testada. Você pode
precisar saber como gerenciá-los. Cada tipo de pop-up precisa ser tratado de maneira diferente.
Diálogos de autenticação básica de HTTP: esses diálogos solicitam um
nome de usuário / senha para fazer o login no site. Para fazer login em um site que requer
autenticação básica HTTP, use um nome de usuário e senha no URL, como
descrito em RFC 1738, assim: open(“http://myusername:myuserpassword@myexample.com/blah/blah/blah").
Avisos de certificado SSL: Selenium RC tenta automaticamente falsificar certificados SSL
quando está habilitado como proxy; veja mais sobre isso
na seção HTTPS. Se o seu navegador estiver configurado corretamente,
você nunca deve ver avisos de certificado SSL, mas pode ser necessário
configurar seu navegador para confiar em nossa perigosa CA SSL “CyberVillains”.
Novamente, consulte a seção HTTPS para saber como fazer isso.
caixas de diálogo de alerta / confirmação / prompt de JavaScript modais: Selenium tenta ocultar
essas caixas de diálogo de você (substituindo window.alert, window.confirm e
window.prompt) para que não parem a execução da sua página. Se você está
vendo um pop-up de alerta, provavelmente é porque ele disparou durante o processo de carregamento da página,
o que geralmente é muito cedo para protegermos a página. Selenese contém comandos
para afirmar ou verificar pop-ups de alerta e confirmação. Veja as seções sobre estes
tópicos no Capítulo 4.
No Linux, por que minha sessão do navegador Firefox não está fechando?
No Unix / Linux, você deve invocar “firefox-bin” diretamente, então certifique-se de que este
executável está no path. Se estiver executando o Firefox por meio de um
script de shell, quando chegar a hora de encerrar o navegador, o Selenium RC irá encerrar
o script de shell, deixando o navegador em execução. Você pode especificar o caminho
para o firefox-bin diretamente, assim:
Firefox *chrome não funciona com perfil personalizado
Verifique a pasta de perfil do Firefox -> prefs.js -> user_pref (“browser.startup.page”, 0);
Comente esta linha assim: “//user_pref(“browser.startup.page”, 0); " e tente novamente.
Posso carregar um pop-up personalizado enquanto a página pai está carregando (ou seja, antes que a função javascript window.onload() da página principal seja executada)?
Não. O Selenium depende de interceptadores para determinar os nomes das janelas à medida que são carregadas.
Esses interceptores funcionam melhor na captura de novas janelas se as janelas forem carregadas DEPOIS
a função onload(). O Selenium pode não reconhecer as janelas carregadas antes da função onload.
Firefox no Linux
No Unix / Linux, versões do Selenium anteriores a 1.0 precisavam invocar “firefox-bin”
diretamente, então, se você estiver usando uma versão anterior, certifique-se de que o real
executável está no caminho.
Na maioria das distribuições Linux, o verdadeiro firefox-bin está localizado em:
/usr/lib/firefox-x.x.x/
Onde x.x.x é o número da versão que você possui atualmente. Então, para adicionar esse caminho
no path do usuário. você terá que adicionar o seguinte ao seu arquivo .bashrc:
exportPATH="$PATH:/usr/lib/firefox-x.x.x/"
Se necessário, você pode especificar o caminho para o firefox-bin diretamente em seu teste,
assim:
"*firefox /usr/lib/firefox-x.x.x/firefox-bin"
IE e atributos de estilo
Se você estiver executando seus testes no Internet Explorer e não conseguir localizar
elementos usando seu atributo style.
Por exemplo:
//td[@style="background-color:yellow"]
Isso funcionaria perfeitamente no Firefox, Opera ou Safari, mas não com o IE.
O IE interpreta as chaves em @style como maiúsculas. Então, mesmo que o
o código-fonte está em letras minúsculas, você deve usar:
//td[@style="BACKGROUND-COLOR:yellow"]
Isso é um problema se o seu teste se destina a funcionar em vários navegadores, mas
você pode facilmente codificar seu teste para detectar a situação e tentar o localizador alternativo
que só funciona no IE.
Erro encontrado - “Cannot convert object to primitive value” no delsigamento do navegador *googlechrome
Para evitar esse erro, você deve iniciar o navegador com uma opção que desativa as verificações da política de mesma origem:
Erro encontrado no IE - “Couldn’t open app window; is the pop-up blocker enabled?”
Para evitar esse erro, você deve configurar o navegador: desative o bloqueador de pop-ups
e desmarque a opção ‘Ativar modo protegido’ em Ferramentas » Opções » Segurança.
O proxy é uma terceira pessoa no meio que passa a bola entre as duas partes. Ele atua como um “servidor da web” que entrega a aplicação ao navegador. Ser um proxy dá ao Selenium Server a capacidade de “mentir” sobre a URL real da aplicação. ↩︎
O navegador é iniciado com um perfil de configuração que definiu localhost:4444 como o proxy HTTP, é por isso que qualquer solicitação HTTP que o navegador fizer passará pelo servidor Selenium e a resposta passará por ele e não pelo servidor real. ↩︎
7.2 - Selenium 2
Selenium 2 was a rewrite of Selenium 1 that was implemented with WebDriver code.
7.2.1 - Migrando do RC para WebDriver
Como migrar para o Selenium WebDriver
Uma pergunta comum ao adotar o Selenium 2 é qual é a coisa certa a fazer
ao adicionar novos testes a um conjunto existente de testes? Usuários que são novos no
framework podem começar usando as novas APIs WebDriver para escrever seus testes.
Mas e os usuários que já possuem suítes de testes existentes? Este guia é
projetado para demonstrar como migrar seus testes existentes para as novas APIs,
permitindo que todos os novos testes sejam escritos usando os novos recursos oferecidos pelo WebDriver.
O método apresentado aqui descreve uma migração gradativa para as APIs WebDriver sem precisar refazer tudo em um push massivo. Isso significa
que você pode permitir mais tempo para migrar seus testes existentes, que
pode tornar mais fácil para você decidir onde investir seu esforço.
Este guia foi escrito em Java, porque tem o melhor suporte para
fazer a migração. À medida que fornecemos ferramentas melhores para outras linguagens,
este guia deve ser expandido para incluir essas linguagens.
Porque migrar para o WebDriver
Mover um conjunto de testes de uma API para outra requer uma enorme
quantidade de esforço. Por que você e sua equipe considerariam fazer essa mudança?
Aqui estão alguns motivos pelos quais você deve considerar a migração de seus testes Selenium
para usar o WebDriver.
API menor e compacta. A API do WebDriver é mais orientada a objetos do que o
Selenium RC API original. Isso pode facilitar o trabalho.
Melhor emulação das interações do usuário. Sempre que possível, o WebDriver faz
uso de eventos nativos para interagir com uma página da web. Imita melhor a maneira como seus usuários trabalham com seu site e aplicativos. Além do que, o
WebDriver oferece APIs de interações de usuário avançadas que permitem que você
modele interações complexas com seu site.
Suporte de fornecedores de navegadores. Opera, Mozilla e Google são todos participantes ativos
do desenvolvimento do WebDriver, e cada um tem engenheiros trabalhando
para melhorar a estrutura. Frequentemente, isso significa que o suporte para WebDriver
está embutido no próprio navegador: seus testes são executados tão rápidos e estáveis quanto
possível.
Antes de começar
A fim de tornar o processo de migração o mais indolor possível,
certifique-se de que todos os seus testes sejam executados corretamente com a versão mais recente do Selenium.
Isso pode parecer óbvio, mas é melhor que seja dito!
Começando
A primeira etapa ao iniciar a migração é mudar a forma como você obtém
sua instância Selenium. Ao usar Selenium RC, isso é feito assim:
Depois que seus testes forem executados sem erros, a próxima etapa é migrar
o código de teste real para usar as APIs WebDriver. Dependendo de quão bem você
abstrair o seu código, pode ser um processo curto ou longo.
Em ambos os casos, a abordagem é a mesma e pode ser resumida simplesmente:
modifique o código para usar a nova API quando for editá-lo.
Se você precisar extrair a implementação WebDriver subjacente
da instância Selenium, você pode simplesmente fazer um cast para WrapsDriver:
Isso permite que você continue passando a instância Selenium como
normal, mas desembrulhar a instância do WebDriver conforme necessário.
Em algum ponto, sua base de código usará principalmente as APIs mais recentes.
Neste ponto, você pode inverter o relacionamento, usando WebDriver em tudo
e instanciar uma instância do Selenium sob demanda:
Felizmente, você não é a primeira pessoa a passar por essa migração,
então, aqui estão alguns problemas comuns que outras pessoas viram e como resolvê-los.
Clicar e digitar são mais completos
Um padrão comum em um teste de Selenium RC é ver algo como:
Isso se baseia no fato de que o “tipo” simplesmente substitui o conteúdo do
elemento identificado sem também disparar todos os eventos que normalmente
seriam disparados se um usuário interagir com a página. As invocações diretas finais
de “key*” faz com que os manipuladores JS sejam acionados conforme o esperado.
Ao usar o WebDriverBackedSelenium, o resultado do preenchimento do campo do formulário seria “exciting texttt”: não o que você esperaria!
O motivo disso é que o WebDriver emula com mais precisão o comportamento do usuário, e assim terá disparado eventos o tempo todo.
Esse mesmo fato às vezes pode fazer com que o carregamento da página seja disparado antes do que aconteceria em um teste de Selenium 1.
Você pode dizer que isso aconteceu se uma “StaleElementException” é lançada pelo WebDriver.
WaitForPageToLoad retorna muito cedo
Descobrir quando o carregamento de uma página está completo é uma tarefa complicada. Queremos dizer
“quando o evento de carregamento dispara”, “quando todas as solicitações AJAX são concluídas”, “quando
não há tráfego de rede “,” quando document.readyState mudou” ou
outra coisa completamente diferente?
WebDriver tenta simular o comportamento original do Selenium, mas isso não
sempre funciona perfeitamente por vários motivos. O motivo mais comum é que é
difícil dizer a diferença entre um carregamento de página que ainda não começou e um
carregamento da página concluído entre as chamadas de método. Isso às vezes significa que
o controle é devolvido ao seu teste antes que a página termine (ou mesmo comece!)
o carregamento.
A solução para isso é esperar por algo específico. Normalmente, isso pode ser o elemento com o qual deseja interagir a seguir, ou para alguma variável Javascript
a ser definida com um valor específico. Um exemplo seria:
Isso pode parecer complexo, mas é quase todo um código padrão. O único interessante é que a “condição esperada” será avaliada repetidamente
até que o método “apply” retorne algo que não seja “null”
nem Boolean.FALSE.
Claro, adicionar todas essas chamadas de “wait” pode confundir seu código. E se
esse é o caso, e suas necessidades são simples, considere usar as esperas implícitas:
Ao fazer isso, toda vez que um elemento é localizado, se o elemento não estiver presente,
o local é tentado novamente até que esteja presente ou até 30 segundos
passados.
Encontrar por seletores XPath ou CSS nem sempre funciona, mas funciona no Selenium 1
No Selenium 1, era comum para o xpath usar uma biblioteca agrupada em vez de
os recursos do próprio navegador. WebDriver sempre usará
os métodos nativos do navegador, a menos que não haja alternativa. Isso significa que expressões xpath complexas
podem falhar em alguns navegadores.
Os seletores CSS no Selenium 1 foram implementados usando a biblioteca Sizzle. Esta biblioteca
implementa um superconjunto da CSS Selector Spec, e nem sempre é claro onde
você cruzou a linha. Se você estiver usando o WebDriverBackedSelenium e usar um
Localizador Sizzle em vez de um Seletor CSS para encontrar elementos, um aviso
ser registrado no console. Vale a pena procurar por eles,
particularmente se os testes estão falhando por não ser capaz de encontrar os elementos.
Não há nenhum Browserbot
O Selenium RC era baseado no Selenium Core e, portanto, quando você executava
Javascript, você podia acessar bits do Selenium Core para tornar as coisas mais fáceis.
Como o WebDriver não é baseado no Selenium Core, isso não é mais possível.
Como você pode saber se está usando Selenium Core? Simples! Basta olhar para ver
se o seu “getEval” ou chamadas semelhantes usam “selenium” ou “browserbot”
no Javascript avaliado.
Você pode estar usando o browserbot para obter um identificador para a janela atual
ou documento do teste. Felizmente, o WebDriver sempre avalia JS no
contexto da janela atual, então você pode usar “window” ou “document” diretamente.
Como alternativa, você pode usar o browserbot para localizar elementos.
No WebDriver, o idioma para fazer isso é primeiro localizar o elemento,
e então passe isso como um argumento para o Javascript. Portanto:
Observe como a variável “element” passada aparece como o primeiro item
na array de “arguments” padrão do JS.
A execução de Javascript não retorna nada
O JavascriptExecutor do WebDriver envolverá todo o JS e o avaliará como uma expressão anônima. Isso significa que você precisa usar a palavra-chave “return”:
O servidor sempre será executado na máquina com o navegador que você deseja
testar. O servidor pode ser usado a partir da linha de comando ou por meio de configuração de código.
Iniciando o servidor a partir da linha de comando
Depois de fazer o download do selenium-server-standalone-{VERSION}.jar,
coloque-o no computador com o navegador que deseja testar. Então, a partir
do diretório com o jar, execute o seguinte:
O chamador deve encerrar cada sessão adequadamente, chamando
ou Selenium#stop() ou WebDriver#quit.
O selenium-server mantém registros na memória para cada sessão em andamento,
que são apagados quando Selenium#stop() ou WebDriver#quit é chamado. E se
você se esquecer de encerrar essas sessões, seu servidor pode vazar memória. E se
você mantém sessões de duração extremamente longa, você provavelmente precisará
parar / sair de vez em quando (ou aumentar a memória com a opção -Xmx jvm).
Timeouts (a partir da versão 2.21)
O servidor tem dois timeouts diferentes, que podem ser definidos da seguinte forma:
Controla por quanto tempo o navegador pode travar (valor em segundos).
timeout
Controla por quanto tempo o cliente pode ficar fora
antes que a sessão seja recuperada (valor em segundos).
A propriedade do sistema selenium.server.session.timeout
não é mais compatível a partir da versão 2.21.
Observe que o browserTimeout
destina-se a ser um mecanismo de timeout de backup
quando o mecanismo de timeout comum falha,
e deve ser usado principalmente em ambientes de Grid / servidor
para garantir que processos travados / perdidos não permaneçam por muito tempo
poluindo o ambiente de execução.
Configurando o servidor programaticamente
Em teoria, o processo é tão simples quanto mapear o DriverServlet para
uma URL, mas também é possível hospedar a página em um formato leve de
container, como Jetty, configurado inteiramente em código.
Baixe o selenium-server.zip e descompacte.
Coloque os JARs no CLASSPATH.
Crie uma nova classe chamada AppServer.
Aqui, estamos usando Jetty, então você precisará baixar
isso também:
Selenium 3 was the implementation of WebDriver without the Selenium RC Code. It has since been replaced with Selenium 4, which implements the W3C WebDriver specification.
7.3.1 - Grid 3
Selenium Grid 3 supported WebDriver without Selenium RC code. Grid 3 was completely rewritten for the new Grid 4.
Selenium Grid é um servidor proxy inteligente
que permite que os testes Selenium encaminhem comandos para instâncias remotas do navegador da web.
Seu objetivo é fornecer uma maneira fácil de executar testes em paralelo em várias máquinas.
Com Selenium Grid,
um servidor atua como o hub que roteia comandos de teste formatados em JSON
para um ou mais nós registrados.
Os testes entram em contato com o hub para obter acesso a instâncias remotas do navegador.
O hub tem uma lista de servidores registrados aos quais fornece acesso,
e permite o controle dessas instâncias.
Selenium Grid nos permite executar testes em paralelo em várias máquinas,
e gerenciar diferentes versões e configurações do navegador centralmente
(em vez de em cada teste individual).
Selenium Grid não é uma bala de prata.
Ele resolve um subconjunto de problemas comuns de delegação e distribuição,
mas não irá, por exemplo, gerenciar sua infraestrutura,
e pode não atender às suas necessidades específicas.
7.3.2 - Configurando a sua
Quick start guide for setting up Grid 3.
Para usar Selenium Grid,
você precisa manter sua própria infraestrutura para os nós.
Como isso pode ser um esforço pesado e intenso,
muitas organizações usam provedores IaaS
como Amazon EC2 e Google Compute
para fornecer essa infraestrutura.
Outras opções incluem o uso de provedores como Sauce Labs ou Testing Bot
que fornecem uma Selenium Grid como um serviço na nuvem.
Certamente também é possível executar nós em seu próprio hardware.
Este capítulo entrará em detalhes sobre a opção de executar sua própria Grid,
completo com sua própria infraestrutura de nós.
Início
Este exemplo mostrará como iniciar o Selenium 2 Grid Hub,
e registrar um nó WebDriver e um nó legado Selenium 1 RC.
Também mostraremos como chamar a Grid a partir do Java.
O hub e os nós são mostrados aqui em execução na mesma máquina,
mas é claro que você pode copiar o selenium-server-standalone para várias máquinas.
O pacote selenium-server-standalone inclui o hub,
WebDriver e RC legado necessários para executar o Grid,
ant não é mais necessário.
Você pode baixar o selenium-server-standalone.jar de
https://selenium.dev/downloads/.
Passo 1: Inicialize o Hub
O Hub é o ponto central que receberá solicitações de teste
e os distribuirá para os nós certos.
A distribuição é feita com base em recursos,
significando que um teste que requer um conjunto de recursos
só será distribuído para nós que oferecem esse conjunto ou subconjunto de recursos.
Porque os recursos desejados de um teste são apenas o que o nome indica, desired,
o hub não pode garantir que localizará um nó
corresponder totalmente ao conjunto de recursos desejados solicitados.
Abra um prompt de comando
e navegue até o diretório onde você copiou
o arquivo selenium-server-standalone.jar.
Você inicia o hub passando a sinalização -role hub
para o servidor autônomo:
The Hub will listen to port 4444 by default.
You can view the status of the hub by opening a browser window and navigating to
http://localhost:4444/grid/console.
Para alterar a porta padrão,
você pode adicionar a flag opcional -port
com um número inteiro representando a porta a ser ouvida quando você executa o comando.
Além disso, todas as outras opções que você vê no arquivo de configuração JSON (veja abaixo)
são possíveis flags de linha de comando.
Você certamente pode sobreviver apenas com o comando simples mostrado acima,
mas se você precisar de uma configuração mais avançada,
você também pode especificar um arquivo de configuração de formato JSON, por conveniência,
para configurar o hub ao iniciá-lo.
Você pode fazer assim:
Abaixo você verá um exemplo de um arquivo hubConfig.json.
Entraremos em mais detalhes sobre como fornecer arquivos de configuração de nó no Passo 2.
{"_comment":"Configuration for Hub - hubConfig.json","host":ip,"maxSession":5,"port":4444,"cleanupCycle":5000,"timeout":300000,"newSessionWaitTimeout":-1,"servlets":[],"prioritizer":null,"capabilityMatcher":"org.openqa.grid.internal.utils.DefaultCapabilityMatcher","throwOnCapabilityNotPresent":true,"nodePolling":180000,"platform":"WINDOWS"}
Pasos 2: Inicialize os Nós
Independentemente de você querer executar uma Grid com a nova funcionalidade WebDriver,
ou uma Grid com funcionalidade Selenium 1 RC,
ou os dois ao mesmo tempo,
você usa o mesmo arquivo selenium-server-standalone.jar para iniciar os nós:
Se uma porta não for especificada por meio do sinalizador -port,
uma porta livre será escolhida. Você pode executar vários nós em uma máquina
mas se você fizer isso, você precisa estar ciente dos recursos de memória de seus sistemas
e problemas com capturas de tela se seus testes as fizerem.
Configuração de um nó com opções
Como mencionado, para compatibilidade com versões anteriores
as funções “wd” e “rc” ainda são um subconjunto válido da função “node”.
Mas essas funções limitam os tipos de conexões remotas para sua API correspondente,
enquanto “node” permite conexões remotas RC e WebDriver.
Ao passar propriedades JVM (usando o sinalizador -Dantes do argumento -jar)
na linha de comando também,
estas serão coletadas e propagadas para os nós:
-Dwebdriver.chrome.driver=chromedriver.exe
Configuração de um nó com JSON
Você também pode iniciar nós da Grid que estão configurados
com um arquivo de configuração JSON
E aqui está um exemplo do arquivo nodeConfig.json:
{"capabilities":[{"browserName":"firefox","acceptSslCerts":true,"javascriptEnabled":true,"takesScreenshot":false,"firefox_profile":"","browser-version":"27","platform":"WINDOWS","maxInstances":5,"firefox_binary":"","cleanSession":true},{"browserName":"chrome","maxInstances":5,"platform":"WINDOWS","webdriver.chrome.driver":"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"},{"browserName":"internet explorer","maxInstances":1,"platform":"WINDOWS","webdriver.ie.driver":"C:/Program Files (x86)/Internet Explorer/iexplore.exe"}],"configuration":{"_comment":"Configuration for Node","cleanUpCycle":2000,"timeout":30000,"proxy":"org.openqa.grid.selenium.proxy.WebDriverRemoteProxy","port":5555,"host":ip,"register":true,"hubPort":4444,"maxSession":5}}
Uma observação sobre a flag -host
Para hub e nó, se a flag -host não for especificada,
0.0.0.0 será usado por padrão. Isso se ligará a todos as
interfaces IPv4 públicas (sem loopback) da máquina.
Se você tem uma configuração especial de rede ou qualquer
componente que crie interfaces de rede extras,
é aconselhável definir a flag -host com um valor que permite o
hub / nó acessível a partir de uma máquina diferente.
Especificando a porta
A porta TCP / IP padrão usada pelo hub é 4444. Se você precisar alterar a porta
use as configurações mencionadas acima.
Solução de problemas
Usando um arquivo de log
Para solução de problemas avançada, você pode especificar um arquivo de log para registrar mensagens do sistema.
Inicie o hub ou nó Selenium Grid com o argumento -log. Por favor, veja o exemplo abaixo:
Use o seu editor de texto favorito para abrir o arquivo de log (log.txt no exemplo acima) para encontrar
registros de “ERROR” se você tiver problemas.
Usando o argumento -debug
Você também pode usar o argumento -debug para imprimir logs de depuração no console.
Inicie o Selenium Grid Hub ou Node com o argumento -debug. Por favor, veja
o exemplo abaixo:
Docker fornece uma maneira conveniente de
provisionar e escalar a infraestrutura da Selenium Grid em uma unidade conhecida como contêiner.
Os contêineres são unidades padronizadas de software que contêm tudo o que é necessário
para executar o aplicativo desejado, incluindo todas as dependências, de forma confiável e repetível em máquinas diferentes.
O projeto Selenium mantém um conjunto de imagens Docker que você pode baixar
e executar para colocar uma Grid em funcionamento rapidamente. Os nós estão disponíveis para
Firefox e Chrome. Detalhes completos de como provisionar uma grade podem ser encontrados
no repositório Docker Selenium.
Recebe instruções do cliente e as executa remotamente nos nós
Gerencia tópicos
Um Hub é um ponto central para onde todos os seus testes são enviados.
Cada Selenium Grid consiste em exatamente um hub. O hub precisa estar acessível
dos respectivos clientes (ou seja, servidor de CI, máquina do desenvolvedor etc.)
O hub irá conectar um ou mais nós
aos quais os testes serão delegados.
Nós
Onde vivem os navegadores
Registra-se no hub e comunica seus recursos
Recebe solicitações do hub e as executa
Nodes são diferentes instâncias do Selenium
que executarão testes em sistemas de computador individuais.
Pode haver muitos nós em uma grade.
As máquinas que são nós não precisam ser da mesma plataforma
ou ter a mesma seleção de navegador do hub ou de outros nós.
Um nó no Windows pode ter a capacidade de
oferecer o Internet Explorer como uma opção de navegador,
considerando que isso não seria possível no Linux ou Mac.
7.4 - Selenium IDE Legado
Introdução
A Selenium-IDE (Integrated Development Environment) é a ferramenta que você usa para
desenvolver seus casos de teste Selenium. É um plug-in do Firefox fácil de usar e é
geralmente a maneira mais eficiente de desenvolver casos de teste. Ela também contém um
menu de contexto que permite que você primeiro selecione um elemento de UI do navegador
atualmente exibido na página e, em seguida, selecione de uma lista de comandos Selenium com
parâmetros predefinidos de acordo com o contexto do elemento de UI selecionado.
Isso não é apenas uma economia de tempo, mas também uma excelente maneira de aprender a sintaxe do script Selenium.
Este capítulo é sobre a Selenium IDE e como usá-la efetivamente.
Instalando a IDE
Usando o Firefox, primeiro, baixe a IDE da página de downloads do SeleniumHQ.
O Firefox irá protegê-lo contra a instalação de complementos de locais desconhecidos, então
você precisará clicar em “Permitir” para prosseguir com a instalação, conforme mostrado
na imagem a seguir.
Ao fazer download do Firefox, você verá a seguinte janela.
Selecione Instalar Agora. A janela de complementos do Firefox aparece, mostrando primeiro uma barra de progresso,
e quando o download for concluído, exibe o seguinte.
Reinicie o Firefox. Após a reinicialização do Firefox, você encontrará a Selenium-IDE listada no menu Ferramentas do Firefox.
Abrindo a IDE
Para executar a Selenium-IDE, simplesmente selecione-a no menu Ferramentas do Firefox. Ela abrirá
como segue com uma janela de edição de script vazia e um menu para carregar ou
criar novos casos de teste.
Funcionalidades da IDE
Barra de Menu
O menu Arquivo tem opções para Caso de Teste e Suíte de Testes (conjunto de casos de teste).
Usando isso, você pode adicionar um novo caso de teste, abrir um caso de teste, salvar um caso de teste, e
exportar um caso de teste em uma linguagem de sua escolha. Você também pode abrir o
caso de teste mais recente. Todas essas opções também estão disponíveis para a suíte de testes.
O menu Editar permite copiar, colar, excluir, desfazer e selecionar todas as operações para
editar os comandos em seu caso de teste. O menu Opções permite a mudança de
configurações. Você pode definir o valor de tempo limite para certos comandos,
extensões de usuário para o conjunto básico de comandos Selenium e especificar o formato
(linguagem) usado ao salvar seus casos de teste. O menu Ajuda é o padrão
Menu Ajuda do Firefox; há apenas um item neste menu - Documentação do elemento de UI - pertencente ao
Selenium-IDE.
Barra de Ferramentas
A barra de ferramentas contém botões para controlar a execução de seus casos de teste,
incluindo um recurso de etapas para depurar seus casos de teste. O botão mais à direita,
aquele com o ponto vermelho, é o botão de gravação.
Controle de velocidade: controla a velocidade de execução do seu caso de teste.
Executar todos: executa todo a suíte de testes quando uma suíte de testes com vários casos de teste é carregado.
Executar: executa o teste atualmente selecionado. Quando apenas um único teste é carregado
este botão e o botão Executar todos têm o mesmo efeito.
Pausar/Continuar: permite interromper e reiniciar um caso de teste em execução.
Step: permite que você “avance” por um caso de teste, executando um comando de cada vez.
Use para depurar casos de teste.
Modo TestRunner: permite que você execute o caso de teste em um navegador carregado com o
Selenium-Core TestRunner. O TestRunner não é comumente usado agora e é provável
seja descontinuado. Este botão é para avaliar casos de teste para
compatibilidade com versões anteriores com o TestRunner.
A maioria dos usuários provavelmente não precisará desse botão.
Aplicar regras de Rollup: Este recurso avançado permite sequências repetitivas de
comandos do Selenium a serem agrupadas em uma única ação. A documentação detalhada sobre
as regras de rollup podem ser encontradas na documentação do Elemento de UI no menu Ajuda.
Painel de casos de teste
Seu script é exibido no painel de casos de teste. Tem duas guias, uma para
exibir o comando e seus parâmetros em um formato de “tabela” legível.
A outra guia - Código Fonte exibe o caso de teste no formato nativo no qual o
arquivo será armazenado. Por padrão, é HTML, embora possa ser alterado para uma
linguagem de programação como Java ou C#, ou uma linguagem de script como Python.
Consulte o menu Opções para obter detalhes. A visualização do Código Fonte também permite editar o
caso de teste em sua forma bruta, incluindo operações de copiar, recortar e colar.
Os campos de entrada de Comando, Destino e Valor exibem o comando atualmente selecionado
junto com seus parâmetros. Estes são campos de entrada onde você pode modificar
o comando atualmente selecionado. O primeiro parâmetro especificado para um comando
na guia Referência do painel inferior sempre vai para o campo Destino. Se um
segundo parâmetro é especificado pela guia Referência, ele sempre vai no
campo Valor.
Se você começar a digitar no campo Comando,
uma lista suspensa será preenchida
com base nos primeiros caracteres que você digitar;
você pode então selecionar o comando que deseja
no menu suspenso.
Painel de Log / Referência / Elemento de UI / Rollup
O painel inferior é usado para quatro funções diferentes - Log, Referência,
Elemento de UI e Rollup - dependendo da guia selecionada.
Log
Quando você executa seu caso de teste, mensagens de erro e mensagens de informação mostrando
o progresso são exibidas neste painel automaticamente, mesmo se você não
selecionar a guia Log primeiro. Essas mensagens geralmente são úteis para depuração de casos de teste.
Observe o botão Limpar para limpar o registro. Observe também que o botão Informações é um
drop-down permitindo a seleção de diferentes níveis de informação para registrar.
Referência
A guia Referência é a seleção padrão sempre que você entrar ou
modificar comandos e parâmetros Selenium no modo Tabela. No modo Tabela, o
painel de Referência exibirá a documentação do comando atual. Ao inserir
ou modificar comandos, seja do modo Tabela ou Código Fonte, é criticamente
importante garantir que os parâmetros especificados nos campos Destino e Valor
correspondem aos especificados na lista de parâmetros do painel Referência. O
número de parâmetros fornecidos deve corresponder ao número especificado, a ordem
dos parâmetros fornecidos deve corresponder à ordem especificada e os tipos de parâmetros
fornecidos devem corresponder aos tipos especificados.
Se houver uma incompatibilidade em qualquer uma dessas
três áreas, o comando não funcionará corretamente.
Embora a guia Referência seja ótima como uma referência rápida, ainda é
necessário consultar a documentação de referência do Selenium.
Elemento de UI e Rollup
Informações detalhadas sobre esses dois painéis (que abrangem recursos avançados) podem ser
encontradas na documentação do Elemento de UI no menu Ajuda do Selenium-IDE.
Construindo casos de teste
Existem três métodos principais para desenvolver casos de teste. Frequentemente,
um desenvolvedor de testes necessita de todas as três técnicas.
Gravando
Muitos usuários de primeira viagem começam gravando um caso de teste de suas interações
com um site. Quando a Selenium-IDE é aberta pela primeira vez, o botão de gravação é ativado por
padrão. Se você não quiser que a Selenium-IDE comece a gravar automaticamente, você
pode desligar isso indo em Opções > Opções… e desmarcando “Iniciar
gravação imediatamente ao abrir.”
Durante a gravação, a Selenium-IDE irá inserir comandos automaticamente em seu
caso de teste com base em suas ações. Normalmente, isso incluirá:
clicar em um link - comandos click ou clickAndWait
inserir valores - comando type
selecionar opções de uma caixa de listagem suspensa - comando select
clicar em caixas de seleção ou botões de rádio - comando click
Aqui estão algumas “pegadinhas” para ficar atento:
O comando type pode exigir o clique em alguma outra área da página da web para começar a gravar.
Seguir um link geralmente registra um comando de clique. Frequentemente, você precisará mudar
isso para clickAndWait para garantir que seu caso de teste pause até que a nova página seja
completamente carregada. Caso contrário, seu caso de teste continuará executando comandos
antes que a página carregue todos os seus elementos de UI. Isso causará uma falha de teste inesperada.
Adicionando verificações e asserções com o Menu de Contexto
Seus casos de teste também precisarão verificar as propriedades de uma página da web. Isto
requer comandos de asserção e verificação. Não descreveremos os detalhes desses
comandos aqui; que estão no capítulo sobre Comandos do Selenium - “Selenese”. Aqui
vamos simplesmente descrever como adicioná-los ao seu caso de teste.
Com a gravação da Selenium-IDE, vá para o navegador exibindo sua aplicação de teste
e clique com o botão direito em qualquer lugar da página. Você verá um menu de contexto mostrando
comandos verificar e/ou declarar.
Na primeira vez que você usa o Selenium, pode haver apenas um comando Selenium listado.
Ao usar a IDE, no entanto, você encontrará comandos adicionais que serão rapidamente
adicionados a este menu. A Selenium-IDE tentará prever qual comando, junto
com os parâmetros, você precisará para um elemento de interface selecionado na atual
página da web.
Vamos ver como isso funciona. Abra uma página da web de sua escolha e selecione um bloco
de texto na página. Um parágrafo ou título funcionará bem. Agora, clique com o botão direito
no texto selecionado. O menu de contexto deve fornecer um comando verifyTextPresent
e o parâmetro sugerido deve ser o próprio texto.
Além disso, observe a opção Mostrar Todos os Comandos Disponíveis. Isso mostra muitos, muitos
mais comandos, novamente, junto com parâmetros sugeridos, para testar seu
elemento de UI atualmente selecionado.
Experimente mais alguns elementos de UI. Tente clicar com o botão direito em uma imagem ou em um controle de usuário, como
um botão ou uma caixa de seleção. Você pode precisar usar Mostrar Todos os Comandos Disponíveis para ver
opções diferentes de verifyTextPresent. Depois de selecionar essas outras opções,
os mais usados aparecerão no menu de contexto principal. Por exemplo,
selecionar verifyElementPresent para uma imagem deve posteriormente fazer com que esse comando
esteja disponível no menu de contexto principal na próxima vez que você selecionar uma imagem e
clicar com o botão direito.
Novamente, esses comandos serão explicados em detalhes no capítulo sobre comandos Selenium. Por enquanto, fique à vontade para usar a IDE para gravar e selecionar
comandos em um caso de teste e, em seguida, execute-o. Você pode aprender muito sobre os
comandos do Selenium simplesmente experimentando com a IDE.
Editando
Inserir comando
Visualização Tabela
Selecione o ponto em seu caso de teste onde deseja inserir o comando. No painel de caso de teste,
clique com o botão esquerdo na linha onde deseja inserir um
novo comando. Clique com o botão direito e selecione Inserir Comando;
a IDE irá adicionar um espaço em branco imediatamente à frente da linha que você selecionou.
Agora use os campos de edição de texto para inserir seu novo comando e seus parâmetros.
Visualização Código Fonte
Selecione o ponto em seu caso de teste onde deseja inserir o comando. No painel do caso de teste,
clique com o botão esquerdo entre os comandos onde você deseja
insira um novo comando e insira as tags HTML necessárias para criar uma linha de 3 colunas
contendo o Comando, primeiro parâmetro (se for exigido pelo Comando),
e segundo parâmetro (novamente, se for necessário para localizar um elemento) e terceiro
parâmetro (novamente, se for necessário ter um valor). Exemplo:
Comentários podem ser adicionados para tornar seu caso de teste mais legível. Esses comentários são
ignorados quando o caso de teste é executado.
Os comentários também podem ser usados para adicionar espaço em branco vertical (uma ou mais linhas em branco)
em seus testes; apenas crie comentários vazios. Um comando vazio causará um erro
durante a execução; um comentário vazio, não.
Visualização Tabela
Selecione a linha em seu caso de teste onde deseja inserir o comentário.
Clique com o botão direito e selecione Inserir Comentário. Agora use o campo Comando para inserir o
comentário. Seu comentário aparecerá em roxo.
Visualização Código Fonte
Selecione o ponto em seu caso de teste onde deseja inserir o comentário. Adicione um
comentário no estilo HTML, ou seja, <!-- seu comentário aqui -->
Editar um comando ou comentário
Visualização Tabela
Basta selecionar a linha a ser alterada e editá-la usando os campos de comando, destino,
e valor.
Visualização Código Fonte
Uma vez que a visualização do Código Fonte fornece o equivalente a um editor WYSIWYG (What You See Is What You Get), simplesmente modifique a linha que você deseja - comando, parâmetro ou comentário.
Abrindo e salvando um caso de teste
Como a maioria dos programas, existem comandos Salvar e Abrir no menu Arquivo.
No entanto, o Selenium distingue entre casos de teste e suítes de teste. Para salvar
seus testes Selenium-IDE para uso posterior, você pode salvar os casos de teste individualmente
ou salvar a suíte de testes. Se os casos de teste de sua suíte de testes não
foram salvos, você será solicitado a salvá-los antes de salvar a suíte.
Quando você abre um caso de teste ou suíte existente, a Selenium-IDE exibe seu
comandos do Selenium no painel de caso de teste.
Executando casos de teste
A IDE fornece muitas opções para executar seu caso de teste. Você pode executar um caso de teste
inteiro de uma vez, parar e iniciar, executar uma linha de cada vez, executar um único comando
que você está desenvolvendo atualmente e pode fazer uma execução em lote de uma suíte de testes.
A execução de casos de teste é muito flexível na IDE.
Executar um caso de teste
Clique no botão Executar para executar o caso de teste mostrado.
Executar uma suíte de testes
Clique no botão Executar Todos para executar todos os testes dentro da suíte de testes
Parar e Continuar
O botão de Pausa pode ser utilizado para parar o caso de teste no meio da sua execução.
O ícone do botão então muda para indicar que você pode Continuar. Para continuar, clique nele.
Parar no meio
Você pode definir um ponto de interrupção (breakpoint) no caso de teste para que ele pare em um comando específico.
Isto é útil para depurar seu teste. Para definir um ponto de interrupção, selecione um comando, clique com
o botão direito e a partir do Menu de Contexto selecione Alternar ponto de interrupção.
Começar do meio
Você pode preferir que a IDE comece a executar a partir de um comando específico
no meio do caso de teste. Isto também pode ser usado para depuração.
Para definir um ponto de começo, selecione o comando, clique com o botão direito
e a partir do Menu de Contexto selecione Set/Clear Start Point.
Execute um comando isolado
De um duplo-clique em qualquer comando para executá-lo. Isto é útil
quando você está escrevendo um único comando. Permite testar imediatamente
o comando sendo construído, quando não tem certeza se ele está certo.
Você pode dar um duplo-clique para ver se o comando é executado corretamente.
Isto também está disponível no Menu de Contexto.
Usando uma URL base para executar casos de teste em diferentes domínios
O campo URL base na parte superior da janela da Selenium-IDE é muito útil para
permitir que os casos de teste sejam executados em diferentes domínios.
Suponha que um site chamado http://news.portal.com tenha um site beta
interno chamado http://beta.news.portal.com. Quaisquer casos de teste
para esses sites que começam com um comando open devem especificar uma
URL relativa como o argumento para abrir, em vez de uma URL absoluta
(começando com um protocolo como http: ou https:). A Selenium-IDE irá
então criar uma URL absoluta anexando o argumento do comando open no
final do valor da URL base. Por exemplo, o caso de teste
abaixo seria executado em http://news.portal.com/about.html:
Os comandos do Selenium, muitas vezes chamados de Selenese,
são o conjunto de comandos que executam o seu testes.
Uma sequência desses comandos é um script de teste.
Aqui nós explicamos esses comandos em detalhes,
e apresentamos as diversas opções que você tem ao testar a sua
aplicação web usando o Selenium.
Selenium fornece um conjunto rico de comandos para testar totalmente sua
aplicação web quase de qualquer maneira que você possa imaginar.
O conjunto de comandos é frequentemente chamado de Selenese.
Esses comandos criam essencialmente uma linguagem de teste.
Em Selenese, pode-se testar a existência de elementos de UI com base em suas tags HTML,
testar a existência de um conteúdo específico, testar a existência de links quebrados, campos de entrada,
opções de lista de seleção, envio de formulários e dados de tabela, entre outras coisas. Além do mais
os comandos do Selenium suportam testes de tamanho de janela, posição do mouse, alertas,
funcionalidade Ajax, janelas pop-up, tratamento de eventos
e muitas outras características de aplicativos da web.
A Referência de Comandos lista todos os comandos disponíveis.
Um comando diz ao Selenium o que fazer. Os comandos do Selenium vêm em três “sabores”:
Ações, Acessores e Asserções.
Ações são comandos que geralmente manipulam o estado do aplicativo.
Elas fazem coisas como “clicar neste link” e “selecionar essa opção”. Se uma ação
falhar ou tiver um erro, a execução do teste atual é interrompida.
Muitas ações podem ser chamadas com o sufixo “AndWait”, por ex. “ClickAndWait”. Este
sufixo diz ao Selenium que a ação fará com que o navegador faça uma chamada para
o servidor, e que o Selenium deve aguardar o carregamento de uma nova página.
Acessores examinam o estado do aplicativo e armazenam os resultados em
variáveis, por exemplo “StoreTitle”. Eles também são usados para gerar Asserções automaticamente.
Asserções são como Acessores, mas verificam se o estado da
aplicação está em conformidade com o que é esperado. Os exemplos incluem
“certifique-se de que o título da página é X”
e “verifique se esta caixa de seleção está marcada”.
Todas as asserções do Selenium podem ser usadas em 3 modos: “assert”, “verify”
e “wait for”. Por exemplo, você pode usar “assertText”, “verifyText” e “waitForText”.
Quando uma asserção falha, o teste é abortado. Quando uma verificação falha, o teste
continuará a execução, registrando a falha. Isso permite uma única asserção para
certificar-se de que o aplicativo está na página correta, seguido por um monte de
verificações para testar os valores dos campos do formulário, rótulos, etc.
Os comandos “waitFor” aguardam até que alguma condição se torne verdadeira (o que pode ser útil
para testar aplicativos Ajax). Eles terão sucesso imediatamente se a condição
já é verdadeira. No entanto, eles falharão e interromperão o teste se a condição
não se tornar verdadeira dentro da configuração de timeout atual (veja o setTimeout
ação abaixo).
Sintaxe do Script
Os comandos do Selenium são simples, consistem no comando e em dois parâmetros.
Por exemplo:
verifyText
//div//a[2]
Login
Os parâmetros nem sempre são necessários, depende do comando. Em alguns
casos ambos são necessários, em outros um parâmetro é necessário, e ainda em
outros, o comando pode não ter nenhum parâmetro. Aqui estão mais alguns
exemplos:
goBackAndWait
verifyTextPresent
Welcome to My Home Page
type
id=phone
(555) 666-7066
type
id=address1
${myVariableAddress}
A referência de comandos descreve os requisitos de parâmetro para cada comando.
Os parâmetros variam, mas normalmente são:
um localizador para identificar um elemento de UI em uma página.
um padrão de texto para verificar ou fazer uma asserção do conteúdo esperado da página
um padrão de texto ou uma variável Selenium para inserir texto em um campo de entrada ou
para selecionar uma opção de uma lista de opções.
Localizadores, padrões de texto, variáveis Selenium e os próprios comandos são
descritos em bastante detalhe na seção sobre Comandos do Selenium.
Os scripts do Selenium que serão executados a partir da Selenium-IDE serão
armazenados em um arquivo de texto HTML. Isso consiste em uma tabela HTML com três colunas.
A primeira coluna identifica o comando Selenium, a segunda é um alvo e a última
coluna contém um valor. A segunda e terceira colunas podem não exigir valores
dependendo do comando Selenium escolhido, mas elas devem estar presentes.
Cada linha da tabela representa um novo comando Selenium. Aqui está um exemplo de um teste que
abre uma página, faz um asserção no título da página e, em seguida, verifica algum conteúdo na página:
Renderizado como uma tabela em um navegador, seria assim:
open
/download/
assertTitle
Downloads
verifyText
//h2
Downloads
A sintaxe HTML Selenese pode ser usada para escrever e executar testes sem exigir
conhecimento de uma linguagem de programação. Com um conhecimento básico de Selenese e
Selenium-IDE você pode produzir e executar casos de teste rapidamente.
Suítes de Teste
Uma suíte de testes é uma coleção de testes. Frequentemente, você executará todos os testes em uma
suite de teste como um trabalho em lote contínuo.
Ao usar a Selenium-IDE, as suítes de testes também podem ser definidas usando um arquivo HTML simples.
A sintaxe novamente é simples. Uma tabela HTML define uma lista de testes onde
cada linha define o caminho do sistema de arquivos para cada teste. Um exemplo diz tudo.
<html><head><title>Test Suite Function Tests - Priority 1</title></head><body><table><tr><td><b>Suite Of Tests</b></td></tr><tr><td><ahref="./Login.html">Login</a></td></tr><tr><td><ahref="./SearchValues.html">Test Searching for Values</a></td></tr><tr><td><ahref="./SaveValues.html">Test Save</a></td></tr></table></body></html>
Um arquivo semelhante a este permitiria executar todos os testes de uma vez, um após o
outro, a partir da Selenium-IDE.
As suítes de testes também podem ser mantidas ao usar o Selenium-RC. Isso é feito via
programação de várias maneiras. Normalmente Junit é usado para
manter um conjunto de testes se estiver usando Selenium-RC com Java. Além disso, se
C# é a linguagem escolhida, o Nunit pode ser utilizado. Se estiver usando uma linguagem interpretada
como Python com Selenium-RC, então alguma programação simples seria
envolvida na configuração de uma suíte. Uma vez que o motivo de usar
Selenium-RC é se aproveitar da lógica de programação para o seu teste, geralmente
não é um problema.
Comandos Selenium usados com frequencia
Para concluir nossa introdução ao Selenium, mostraremos alguns
comandos típicos. Estes são provavelmente os comandos mais comumente usados para construir
testes.
open
abre uma página usando a URL.
click/clickAndWait
realiza um clique e opcionalmente aguarda o carregamento de uma nova página.
verifyTitle/assertTitle
verifica se o título da página é o esperado.
verifyTextPresent
verifica se o texto esperado está em algum lugar da página.
verifyElementPresent
verifica se o elemento de UI esperado, definido pela tag HTML, está em algum lugar da página.
verifyText
verficia se o texto esperado e a tag HTML correspondente estão presentes na página.
verifyTable
verifica se o conteúdo da tabela é o esperado.
waitForPageToLoad
pausa a execução até que a nova página carregue. Chamado automaticamente quando
clickAndWait é utilizado.
waitForElementPresent
pausa a execução até que um elemento HTML, definido por sua tag HTML, esteja
presenta na página.
Verificando elementos da página
Verificar os elementos de UI em uma página da web é provavelmente o recurso mais comum dos seus
testes automatizados. Selenese permite várias maneiras de verificar os elementos de UI.
É importante que você entenda esses métodos diferentes porque eles
definem o que você está realmente testando.
Por exemplo, você vai testar se…
um elemento está presente em algum lugar da página?
um texto específico está em algum lugar da página?
um texto específico está em um local específico na página?
Por exemplo, se você estiver testando um título de texto, o texto
e sua posição na parte superior da página provavelmente são relevantes para o seu teste.
Se, no entanto, você está testando a existência de uma imagem na página inicial,
e os web designers frequentemente alteram o arquivo de imagem específico
junto com sua posição na página,
então você só quer testar se uma imagem (em oposição à um arquivo de imagem específico)
existe em algum lugar.
Asserção ou Verificação?
Escolher entre “assert” e “verify” se resume à conveniência e gerenciamento
de falhas. Não vale a pena verificar se o primeiro parágrafo da
página é correto se o seu teste já falhou ao verificar se o
navegador está exibindo a página esperada. Se você não estiver na página correta,
você provavelmente vai querer abortar seu caso de teste para poder investigar a
causa e corrigir o(s) problema(s) imediatamente. Por outro lado, você pode querer verificar
muitos atributos de uma página sem abortar o caso de teste na primeira falha
pois isso permitirá que você analise todas as falhas na página e tome a
ação apropriada. Efetivamente, um “assert” irá falhar no teste e abortar o
caso de teste atual, enquanto um “verify” irá falhar no teste e continuar a executar
o caso de teste.
O melhor uso desse recurso é agrupar logicamente seus comandos de teste e
iniciar cada grupo com um “assert” seguido por um ou mais comandos de “verify”.
Segue um exemplo:
Command
Target
Value
open
/download/
assertTitle
Downloads
verifyText
//h2
Downloads
assertTable
1.2.1
Selenium IDE
verifyTable
1.2.2
June 3, 2008
verifyTable
1.2.3
1.0 beta 2
O exemplo acima primeiro abre uma página e, em seguida, faz uma asserção para saber se a página correta
é carregada comparando o título com o valor esperado. Só se passar,
o seguinte comando será executado e verificará se o texto está presente na
localização esperada. O caso de teste, então, faz uma asserção para saber se a primeira coluna na segunda
linha da primeira tabela contém o valor esperado, e somente se este for aprovado
as células restantes nessa linha serão “verificadas”.
verifyTextPresent
O comando verifyTextPresent é usado para verificar se existe um texto específico em algum lugar
na página. Leva um único argumento - o texto a ser verificado. Por
exemplo:
Command
Target
Value
verifyTextPresent
Marketing Analysis
Isso faria com que o Selenium procurasse e verificasse que a string de texto
“Marketing Analysis” aparece em algum lugar na página que está sendo testada. Use
verifyTextPresent quando você está interessado apenas no próprio texto estar presente
na página. Não use isso quando você também precisa testar onde o texto está
na página.
verifyElementPresent
Use este comando quando precisar testar a presença de um elemento de UI específico,
em vez de seu conteúdo. Esta verificação não verifica o texto, apenas a
tag HTML. Um uso comum é verificar a presença de uma imagem.
Command
Target
Value
verifyElementPresent
//div/p/img
Este comando verifica se uma imagem, especificada pela existência de uma tag HTML <img>,
está presente na página e aparece após uma tag <div> e uma tag <p>.
O primeiro (e único) parâmetro é um localizador para informar o
comando Selenese de como encontrar o elemento.
Os localizadores são explicados na próxima seção.
verifyElementPresent pode ser usado para verificar a existência de qualquer tag HTML dentro
da página. Você pode verificar a existência de links, parágrafos, divisões <div>,
etc. Aqui estão mais alguns exemplos.
Command
Target
Value
verifyElementPresent
//div/p
verifyElementPresent
//div/a
verifyElementPresent
id=Login
verifyElementPresent
link=Go to Marketing Research
verifyElementPresent
//a[2]
verifyElementPresent
//head/title
Esses exemplos ilustram a variedade de maneiras pelas quais um elemento de UI pode ser testado. Novamente,
os localizadores são explicados na próxima seção.
verifyText
Use verifyText quando o texto e seu elemento de UI devem ser testados. verifyText
deve usar um localizador. Se você escolher um localizador XPath ou DOM, você pode verificar se um
texto específico aparece em um local específico na página em relação a outro componente na página.
Command
Target
Value
verifyText
//table/tr/td/div/p
This is my text and it occurs right after the div inside the table.
Localizando elementos
Para muitos comandos do Selenium, um alvo é necessário. Este alvo identifica um
elemento no conteúdo do aplicativo da web, e consiste na estratégia de localização seguida pela localização no formato locatorType = location.
O tipo de localizador pode ser omitido em muitos casos. Os vários tipos de localizadores são
explicados abaixo com exemplos para cada um.
Localizando pelo Identificador
Este é provavelmente o método mais comum de localização de elementos e é o
padrão quando nenhum tipo de localizador reconhecido é usado. Com esta estratégia,
o primeiro elemento com o valor do atributo id correspondente ao local será usado. E se
nenhum elemento tem um atributo id correspondente, então o primeiro elemento com um
atributo name correspondente ao local será usado.
Por exemplo, o código fonte da sua página pode ter atributos id e name
do seguinte modo:
As seguintes estratégias de localização retornariam os elementos do HTML acima indicado pelo número da linha:
identifier=loginForm (3)
identifier=password (5)
identifier=continue (6)
continue (6)
Como o tipo de localizador identifier é o padrão, o identifier =
nos primeiros três exemplos acima não é necessário.
Localizando pelo id
Este tipo de localizador é mais limitado do que o tipo Localizador por Identificador, mas
também mais explícito. Use isto quando você souber o atributo id de um elemento.
O tipo Localizador de Nome irá localizar o primeiro elemento com um atributo name correspondente.
Se vários elementos tiverem o mesmo valor para um atributo name, então
você pode usar filtros para refinar ainda mais sua estratégia de localização.
O tipo de filtro padrão é value (correspondendo ao atributo value).
Nota: Ao contrário de alguns tipos de localizadores XPath e DOM, os três
tipos de localizadores acima permitem que o Selenium teste um elemento de UI independente
de sua localização em
a página. Portanto, se a estrutura e a organização da página forem alteradas, o teste
ainda vai passar. Você pode ou não querer também testar se a página
tem mudanças de estrutura. No caso em que os web designers frequentemente alteram a
página, mas sua funcionalidade deve ser testada por regressão, testando via id e
atributos de nome, ou realmente através de qualquer propriedade HTML, torna-se muito importante.
Localizando pelo XPath
XPath é a linguagem usada para localizar nós em um documento XML. Como o HTML pode
ser uma implementação de XML (XHTML), os usuários do Selenium podem aproveitar esta poderosa
linguagem para encontrar elementos em seus aplicativos da web. XPath vai além (bem como apoia)
os métodos simples de localização por atributos id ou name
e abre todos os tipos de novas possibilidades, como localizar a
terceira caixa de seleção na página.
Uma das principais razões para usar XPath é quando você não tem um id adequado
ou atributo de nome para o elemento que você deseja localizar. Você pode usar XPath para
localizar o elemento em termos absolutos (não recomendado) ou em relação a um
elemento que possui um atributo id ou name. Localizadores XPath também podem ser
usados para especificar elementos por meio de atributos diferentes de id e name.
Os XPaths absolutos contêm a localização de todos os elementos da raiz (html) e
como resultado, é provável que falhe com apenas o menor ajuste na
aplicação. Ao encontrar um elemento próximo com um atributo id ou name (de preferência
um elemento pai), você pode localizar seu elemento de destino com base no relacionamento.
É muito menos provável que isso mude e pode tornar seus testes mais robustos.
Uma vez que apenas os localizadores xpath começam com “//”, não é necessário incluir
o rótulo xpath= ao especificar um localizador XPath.
Existem também alguns complementos do Firefox muito úteis que podem ajudar a
descobrir o XPath de um elemento:
XPath Checker - Pode
ser usado para testar os resultados do XPath.
Firebug - Sugestões de XPath
é apenas um dos muitos recursos poderosos deste complemento muito útil.
Localizando hyperlinks pelo texto do link
Este é um método simples de localizar um hiperlink em sua página da web usando o
texto do link. Se dois links com o mesmo texto estiverem presentes, então a primeira
correspondência será usada.
<html><body><p>Are you sure you want to do this?</p><ahref="continue.html">Continue</a><ahref="cancel.html">Cancel</a></body><html>
link=Continue (4)
link=Cancel (5)
Localizando pelo DOM
O Document Object Model representa um documento HTML e pode ser acessado
usando JavaScript. Esta estratégia de localização usa um JavaScript que representa
um elemento na página, que pode ser simplesmente a localização do elemento usando a
notação hierárquica.
Uma vez que apenas os localizadores dom começam com “document”, não é necessário incluir
o rótulo dom= ao especificar um localizador DOM.
Você pode usar o próprio Selenium, bem como outros sites e extensões para explorar
o DOM do seu aplicativo da web. Uma boa referência é a W3Schools.
Localizando pelo CSS
CSS (Cascading Style Sheets) é uma linguagem para descrever a renderização de HTML
e documentos XML. CSS usa seletores para vincular propriedades de estilo a elementos
no documento. Esses seletores podem ser usados pelo Selenium como outra estratégia de localização.
Para obter mais informações sobre seletores CSS, o melhor lugar para ir é a
publicação do W3C. Você encontrará todas as
referências lá.
Localizadores implícitos
Você pode optar por omitir o tipo de localizador nas seguintes situações:
Localizadores sem uma estratégia de localização explicitamente definida utilizará a estratégia de localização padrão. Veja Localizando pelo Identificador.
Localizadores começando com “//” usarão a estratégia de localização XPath.
Veja Localizando pelo XPath.
Os localizadores que começam com “document” usarão a estratégia do localização DOM.
Veja Localizando pelo DOM
Padrões de texto
Como os localizadores, padrões são um tipo de parâmetro frequentemente exigido pelos comandos Selenese. Exemplos de comandos que exigem padrões são verifyTextPresent,
verifyTitle, verifyAlert, assertConfirmation, verifyText, e
verifyPrompt. E como foi mencionado acima, os localizadores de link podem utilizar
um padrão. Os padrões permitem que você descreva, por meio do uso de caracteres especiais,
qual texto é esperado em vez de precisar especificar esse texto exatamente.
Existem três tipos de padrões: globbing, expressões regulares e exato.
Padrão de Globbing
A maioria das pessoas está familiarizada com o uso de globbing em
expansão de nome de arquivo em uma linha de comando DOS ou Unix / Linux como ls * .c.
Neste caso, globbing é usado para exibir todos os arquivos no diretório atual
que terminam com uma extensão .c. Globbing é bastante limitado.
Apenas dois caracteres especiais são suportados na implementação do Selenium:
* que é traduzido como “corresponder a qualquer coisa”, ou seja, nada, um único caractere ou muitos caracteres.
[ ] (classe de caracteres) que é traduzido como “corresponder a qualquer caractere dentro dos colchetes.”
Um travessão (hífen) pode ser usado como uma abreviação para especificar um intervalo de caracteres
(que são contíguos no conjunto ASCII).
Alguns exemplos tornarão clara a funcionalidade de uma classe de caracteres:
[aeiou] corresponde a qualquer vogal minúscula
[0-9] corresponde a qualquer dígito
[a-zA-Z0-9] corresponde a qualquer caractere alfanumérico
Na maioria dos outros contextos, globbing inclui um terceiro caractere especial, o ?.
No entanto, os padrões de globbing do Selenium suportam apenas o asterisco e a classe de caracteres.
Para especificar um parâmetro de padrão globbing para um comando Selenese, você pode
prefixar o padrão com um rótulo glob:. No entanto, já que o padrão globbing é o padrão,
você também pode omitir o rótulo e especificar apenas o padrão em si.
Abaixo está um exemplo de dois comandos que usam padrões globbing. O
texto real do link na página que está sendo testada
foi “Film/Television Department”; usando um padrão
em vez do texto exato, o comando click funcionará mesmo se o
o texto do link for alterado para “Film & Television Department” ou “Film and Television
Department”. O asterisco do padrão glob corresponderá a “qualquer coisa ou nada”
entre a palavra “Film” e a palavra “Television”.
Command
Target
Value
click
link=glob:Film*Television Department
verifyTitle
glob:*Film*Television*
O título real da página acessada clicando no link era “De Anza Film And
Television Department - Menu”. Usando um padrão em vez do texto exato,
o verifyTitle vai passar enquanto as duas palavras “Film” e “Television” aparecerem
(nessa ordem) em qualquer lugar no título da página. Por exemplo, se
o proprietário da página encurtar
o título apenas para “Film & Television Department”, o teste ainda seria aprovado.
Usar um padrão para um link e um teste simples de que o link funcionou (como
o verifyTitle acima faz) pode reduzir bastante a manutenção de tais
casos de teste.
Padrão de Expressões Regulares
Os padrões de expressão regular são os mais poderosos dos três tipos
de padrões que o Selenese suporta. Expressões regulares
também são suportados pela maioria das linguagens de programação de alto nível, muitos editores de texto
e uma série de ferramentas, incluindo utilitários grep, sed e awk da linha de comando Linux / Unix. Em Selenese,
padrões de expressão regular permitem que um usuário execute muitas tarefas que iriam
ser muito difíceis de outra forma. Por exemplo, suponha que seu teste precise garantir que uma determinada célula da tabela contivesse nada além de um número.
regexp:[0-9]+ é um padrão simples que corresponderá a um número decimal de qualquer comprimento.
Enquanto os padrões de Globbing do Selenese suportam apenas o *
e [ ] (classe de caracteres), os padrões de expressão regular Selenese oferecem a mesma
ampla gama de caracteres especiais que existem em JavaScript. Abaixo
está um subconjunto desses caracteres especiais:
PATTERN
MATCH
.
qualquer caractere isolado
[ ]
classe de caracteres: qualquer caractere definido dentros dos colchetes
*
quantificação: 0 ou mais do caractere anterior (ou grupo)
+
quantificação: 1 ou mais do caractere anterior (ou grupo)
?
quantificação: 0 ou 1 do caractere anterior (ou grupo)
{1,5}
quantificação: 1 até 5 repetições do caractere anterior (ou grupo)
|
alternação: o caractere/grupo na esquerda OU o caractere/grupo na direita
( )
agrupamento: normalmente usado com alternação e/ou quantificação
Os padrões de expressão regular em Selenese precisam ser prefixados com regexp: ou regexpi:.
O primeiro é sensível a maiúsculas e minúsculas;
o último não faz distinção entre maiúsculas e minúsculas.
Alguns exemplos ajudarão a esclarecer como os padrões de expressão regular podem
ser usados com comandos Selenese. O primeiro usa o que é provavelmente
o padrão de expressão regular mais comumente usado - .* (“ponto estrela”). Esta
sequência de dois caracteres pode ser traduzida como “0 ou mais ocorrências de
qualquer caractere” ou, mais simplesmente, “qualquer coisa ou nada.” É o
equivalente do padrão globbing de um caractere * (um único asterisco).
Command
Target
Value
click
link=glob:Film*Television Department
verifyTitle
regexp:.*Film.*Television.*
O exemplo acima é funcionalmente equivalente ao exemplo anterior
que usou padrões de globbing para este mesmo teste. As únicas diferenças
são o prefixo (regexp: em vez de glob:) e o padrão “qualquer coisa
ou nada” (.* em vez de apenas *).
O exemplo mais complexo abaixo testa que a página de clima do Yahoo!
para Anchorage, Alasca, contém informações sobre o horário do nascer do sol:
Vamos examinar a expressão regular acima em partes:
Sunrise: *
A string Sunrise: seguida por 0 ou mais espaços
[0-9]{1,2}
1 ou 2 dígitos (para a hora do dia)
:
O caractere : (sem caracteres especiais envolvidos)
[0-9]{2}
2 dígitos (para os minutos) seguidos de um espaço
[ap]m
“a” ou “p” seguido por “m” (am ou pm)
Padrão Exato
O tipo de padrão exato do Selenium é de utilidade marginal.
Ele não usa nenhum caractere especial. Então, se você precisasse procurar
um caractere de asterisco real (que é especial para globbing e
padrões de expressão regular), o padrão exato seria uma maneira
fazer isso. Por exemplo, se você quiser selecionar um item rotulado
“Real*” em uma lista suspensa, o código a seguir pode funcionar ou não.
O asterisco no padrão glob:Real* irá corresponder a qualquer coisa ou a nada.
Portanto, se houvesse uma opção de seleção anterior rotulada “Números reais”,
ser a opção selecionada em vez da opção “Real*”.
Command
Target
Value
select
//select
glob:Real *
A fim de garantir que o item “Real*” seja selecionado, o prefixo exact: pode ser usado para criar um padrão exato conforme mostrado abaixo:
Command
Target
Value
select
//select
exact:Real *
Mas o mesmo efeito pode ser alcançado escapando o asterisco em um
padrão de expressão regular:
Command
Target
Value
select
//select
regexp:Real \*
É bastante improvável que a maioria dos testadores precise procurar
um asterisco ou um conjunto de colchetes com caracteres dentro deles (a
classe de caracteres para padrões globbing). Assim, os padrões de globbing e
os padrões de expressão regular são suficientes para a grande maioria de nós.
Os comandos “AndWait”
A diferença entre um comando e sua alternativa AndWait é que o comando
regular (por exemplo, click) fará a ação e
continuará com o seguinte comando o mais rápido possível,
enquanto a alternativa AndWait (por exemplo, clickAndWait)
diz ao Selenium para esperar que a página
carregue após a ação ter sido realizada.
A alternativa AndWait é sempre usada quando a ação faz com que o navegador
navegue para outra página ou recarregue a atual.
Esteja ciente, se você usar um comando AndWait para uma ação que
não aciona uma navegação/atualização, seu teste falhará. Isto acontece
porque o Selenium alcançará o timeout de AndWait sem ver nenhuma
navegação ou atualização sendo feita, fazendo com que o Selenium lance uma exceção de timeout.
Os comandos waitFor em aplicações Ajax
Em aplicações web orientadas a AJAX, os dados são recuperados do servidor sem
atualização da página. Usar os comandos AndWait não funcionará porque a página não é
realmente atualizada. Pausar a execução do teste por um determinado período de tempo
também não é uma boa abordagem, pois o elemento da web pode aparecer mais tarde ou antes do
período estipulado dependendo da capacidade de resposta do sistema, carga ou outros
fatores descontrolados do momento, levando a falhas de teste. A melhor abordagem
seria esperar pelo elemento necessário em um período dinâmico e então continuar
a execução assim que o elemento for encontrado.
Isso é feito usando comandos waitFor, como waitForElementPresent ou
waitForVisible, que espera dinamicamente, verificando a condição desejada
a cada segundo e continuando para o próximo comando no script assim que a
condição for atendida.
Sequências de avaliação e controle de fluxo
Quando um script é executado, ele simplesmente é executado em sequência, um comando após o outro.
Selenese, por si só, não suporta declarações de condição (if-else, etc.) ou
iteração (for, while, etc.). Muitos testes úteis podem ser realizados sem fluxo
de controle. No entanto, para um teste funcional de conteúdo dinâmico, possivelmente envolvendo
múltiplas páginas, a lógica de programação é frequentemente necessária.
Quando o controle de fluxo é necessário, existem três opções:
a) Execute o script usando Selenium-RC e uma biblioteca cliente, como Java ou
PHP para utilizar os recursos de controle de fluxo da linguagem de programação.
b) Execute um pequeno fragmento de JavaScript de dentro do script usando o comando storeEval.
c) Instale a extensão goto_sel_ide.js.
A maioria dos testadores exportará o script de teste para um arquivo de linguagem de programação que usa a
API Selenium-RC (consulte o capítulo Selenium-IDE). No entanto, algumas organizações preferem executar seus scripts a partir do Selenium-IDE sempre que possível (por exemplo, quando eles têm
muitas pessoas de nível júnior executando testes para eles, ou quando as habilidades de programação estão
em falta). Se este for o seu caso, considere um snippet de JavaScript ou a extensão goto_sel_ide.js.
Comandos de armazenamento e variáveis Selenium
Você pode usar variáveis Selenium para armazenar constantes no
início de um script. Além disso, quando combinado com um design de teste baseado em dados
(discutido em uma seção posterior), as variáveis Selenium podem ser usadas para armazenar valores
passados para o seu programa de teste da linha de comando, de outro programa ou de
um arquivo.
O comando store é o mais básico dos muitos comandos de armazenamento e pode ser usado
para simplesmente armazenar um valor constante em uma variável Selenium. Leva dois
parâmetros, o valor do texto a ser armazenado e uma variável Selenium. Use as
convenções de nomenclatura de variável padrão de apenas caracteres alfanuméricos quando
escolher um nome para sua variável.
Posteriormente em seu script, você desejará usar o valor armazenado de sua
variável. Para acessar o valor de uma variável, coloque a variável em
colchetes ({}) e preceda-a com um cifrão como a seguir.
Command
Target
Value
verifyText
//div/p
\${userName}
Um uso comum de variáveis é armazenar a entrada para um campo input.
Command
Target
Value
type
id=login
\${userName}
Variáveis Selenium podem ser usadas no primeiro ou segundo parâmetro e
são interpretadas pelo Selenium antes de quaisquer outras operações realizadas pelo
comando. Uma variável Selenium também pode ser usada em uma expressão de localização.
Existe um comando de armazenamento equivalente para cada comando de verificação e asserção. Aqui
são alguns comandos de armazenamento mais comumente usados.
storeElementPresent
Isso corresponde a verifyElementPresent. Ele simplesmente armazena um valor booleano - “true”
ou “false” - dependendo se o elemento de UI for encontrado.
storeText
StoreText corresponde a verifyText. Ele usa um localizador para identificar um texto específico
na página. O texto, se encontrado, é armazenado na variável. StoreText pode ser
usado para extrair texto da página que está sendo testada.
storeEval
Este comando leva um script como seu
primeiro parâmetro. A incorporação de JavaScript no Selenese é abordada na próxima seção.
StoreEval permite que o teste armazene o resultado da execução do script em uma variável.
JavaScript e parâmetros Selenese
JavaScript pode ser usado com dois tipos de parâmetros Selenese: script
e não-script (geralmente expressões). Na maioria dos casos, você deseja acessar
e/ou manipular uma variável de caso de teste dentro do snippet JavaScript usado como
um parâmetro Selenese. Todas as variáveis criadas em seu caso de teste são armazenadas em
um array associativo JavaScript. Uma matriz associativa tem índices de string
em vez de índices numéricos sequenciais. A matriz associativa contendo
as variáveis do seu caso de teste é chamada storedVars. Sempre que você quiser
acessar ou manipular uma variável em um snippet de JavaScript, você deve consultá-la como storedVars[‘yourVariableName’].
Usando JavaScript com parâmetros de script
Vários comandos Selenese especificam um parâmetro script incluindo
assertEval, verifyEval, storeEval e waitForEval.
Esses parâmetros não requerem sintaxe especial.
Um usuário da Selenium-IDE simplesmente colocaria um snippet de código JavaScript
no campo apropriado, normalmente o campo Target (porque
um parâmetro script é normalmente o primeiro ou único parâmetro).
O exemplo abaixo ilustra como um snippet de JavaScript
pode ser usado para realizar um cálculo numérico simples:
Command
Target
Value
store
10
hits
storeXpathCount
//blockquote
blockquotes
storeEval
storedVars[‘hits’].storedVars[‘blockquotes’]
paragraphs
Este próximo exemplo ilustra como um snippet de JavaScript pode incluir chamadas para
métodos, neste caso, os métodos toUpperCase e toLowerCasedo objeto JavaScript String.
Command
Target
Value
store
Edith Wharton
name
storeEval
storedVars[’name’].toUpperCase()
uc
storeEval
storedVars[’name’].toUpperCase()
lc
Usando JavaScript com parâmetros não-script
JavaScript também pode ser usado para ajudar a gerar valores para parâmetros, mesmo
quando o parâmetro não é especificado para ser do tipo script.
No entanto, neste caso, uma sintaxe especial é necessária - o parâmetro inteiro
deve ser prefixado por javascript{ com um } final, que envolve o snippet JavaScript,
como em javascript{*yourCodeHere*}.
Abaixo está um exemplo em que o segundo parâmetro do comando type
value - é gerado através do código JavaScript usando esta sintaxe especial:
Selenese tem um comando simples que permite imprimir texto para a saída do seu teste.
Isso é útil para fornecer notas de progresso informativas em seu
teste que são exibidas no console durante a execução. Essas notas também podem ser
usadas para fornecer contexto em seus relatórios de resultados de teste, o que pode ser útil
para descobrir onde existe um defeito em uma página, caso seu teste encontre um
problema. Finalmente, declarações echo podem ser usadas para imprimir o conteúdo de
variáveis Selenium.
Command
Target
Value
echo
Testing page footer now.
echo
Username is \${userName}
Alertas, Popups e Múltiplas Janelas
Suponha que você esteja testando uma página semelhante a esta.
<!DOCTYPE HTML><html><head><scripttype="text/javascript">functionoutput(resultText){document.getElementById('output').childNodes[0].nodeValue=resultText;}functionshow_confirm(){varconfirmation=confirm("Chose an option.");if(confirmation==true){output("Confirmed.");}else{output("Rejected!");}}functionshow_alert(){alert("I'm blocking!");output("Alert is gone.");}functionshow_prompt(){varresponse=prompt("What's the best web QA tool?","Selenium");output(response);}functionopen_window(windowName){window.open("newWindow.html",windowName);}</script></head><body><inputtype="button"id="btnConfirm"onclick="show_confirm()"value="Show confirm box"/><inputtype="button"id="btnAlert"onclick="show_alert()"value="Show alert"/><inputtype="button"id="btnPrompt"onclick="show_prompt()"value="Show prompt"/><ahref="newWindow.html"id="lnkNewWindow"target="_blank">New Window Link</a><inputtype="button"id="btnNewNamelessWindow"onclick="open_window()"value="Open Nameless Window"/><inputtype="button"id="btnNewNamedWindow"onclick="open_window('Mike')"value="Open Named Window"/><br/><spanid="output"></span></body></html>
O usuário deve responder às caixas de alerta / confirmação, bem como mover o foco para as novas
janelas pop-up abertas. Felizmente, o Selenium pode cobrir pop-ups de JavaScript.
Mas antes de começarmos a abordar alertas / confirmações / solicitações em detalhes individuais, é
útil compreender a semelhança entre eles. Alertas, caixas de confirmação
e todos os prompts têm variações do seguinte
Command
Description
assertFoo(pattern)
gera erro se o padrão não corresponder ao texto do pop-up
assertFooPresent
gera erro se o pop-up estiver presente
assertFooNotPresent
gera um erro se algum pop-up não estiver presente
storeFoo(variable)
armazena o texto do pop-up em uma variável
storeFooPresent(variable)
armazena o texto do pop-up em uma variável e retorna verdadeiro ou falso
Ao executar no Selenium, pop-ups de JavaScript não aparecerão. Isto é porque
as chamadas de função são realmente substituídas em tempo de execução pelo próprio JavaScript do Selenium.
No entanto, só porque você não pode ver o pop-up, não significa que você não
tem que lidar com isso. Para lidar com um pop-up, você deve chamar sua função assertFoo(padrão).
Se você falhar em fazer a asserção da presença de um pop-up, seu próximo comando será
bloqueado e você obterá um erro semelhante ao seguinte [error] Error: There was an unexpected Confirmation! [Chose an option.]
Alertas
Vamos começar com alertas porque eles são os pop-ups mais simples de lidar. Para começar,
abra o exemplo de HTML acima em um navegador e clique no botão “Show alert”. Você vai
observar que, depois de fechar o alerta, o texto “Alert is gone.” é exibido na
página. Agora execute as mesmas etapas com a gravação da Selenium IDE e verifique que
o texto é adicionado após fechar o alerta. Seu teste será parecido com
este:
Command
Target
Value
open
/
click
btnAlert
assertAlert
I’m blocking!
verifyTextPresent
Alert is gone.
Você pode estar pensando: “Isso é estranho, nunca tentei fazer uma asserção nesse alerta.” Mas isso é a
Selenium-IDE manipulando e fechando o alerta para você. Se você remover essa etapa e repetir
o teste você obterá o seguinte erro [error] Error: There was an unexpected Alert! [I'm blocking!]. Você deve incluir uma asserção do alerta para reconhecer
sua presença.
Se você apenas deseja verificar que um alerta está presente, mas não sabe ou não se importa
o texto que ele contém, você pode usar assertAlertPresent. Isso retornará verdadeiro ou falso,
sendo que falso faz o teste parar.
Confirmações
As confirmações se comportam da mesma forma que os alertas, com assertConfirmation e
assertConfirmationPresent oferecendo as mesmas características de suas contrapartes de alerta.
No entanto, por padrão, o Selenium selecionará OK quando uma confirmação for exibida. Tente gravar
clicando no botão “Show confirm box” na página de amostra, mas clique no botão “Cancel”
no pop-up e, em seguida, confirme o texto de saída. Seu teste pode ser semelhante a este:
Command
Target
Value
open
/
click
btnConfirm
chooseCancelOnNextConfirmation
assertConfirmation
Choose an option.
verifyTextPresent
Rejected
A função chooseCancelOnNextConfirmation diz ao Selenium que todas as seguintes
confirmações devem retornar falso. Ela pode ser redefinido chamando chooseOkOnNextConfirmation.
Você vai notar que não pode repetir este teste, porque o Selenium reclama que há
uma confirmação não tratada. Isso ocorre porque a ordem dos registros de eventos do Selenium-IDE
faz com que o clique e chooseCancelOnNextConfirmation sejam colocados na ordem errada (faz sentido
se você pensar sobre isso, o Selenium não pode saber que você está cancelando antes de abrir uma confirmação).
Simplesmente troque esses dois comandos e seu teste funcionará bem.
Prompts
Os prompts se comportam da mesma forma que os alertas, com assertPrompt e assertPromptPresent
oferecendo as mesmas características que suas contrapartes de alerta. Por padrão, o Selenium irá esperar
você inserir dados quando o prompt for exibido. Tente gravar clicando no botão “Show prompt”
na página de amostra e digite “Selenium” no prompt. Seu teste pode ser semelhante a este:
Command
Target
Value
open
/
answerOnNextPrompt
Selenium!
click
id=btnPrompt
assertPrompt
What’s the best web QA tool?
verifyTextPresent
Selenium!
Se você escolher “Cancel” no prompt, poderá observar que answerOnNextPrompt simplesmente mostrará um
alvo em branco. Selenium trata o cancelamento e uma entrada em branco no prompt basicamente como a mesma coisa.
Depuração
Depurar significa encontrar e corrigir erros em seu caso de teste. Isso é normal
e parte do desenvolvimento.
Não vamos ensinar depuração aqui, pois a maioria dos novos usuários do Selenium já terá
alguma experiência básica com depuração. Se isso for novo para você, recomendamos
que você pergunte a um dos desenvolvedores em sua organização.
Pontos de interrupção e pontos de começo
O Sel-IDE suporta a configuração de pontos de interrupção e a capacidade de iniciar e
interromper a execução de um caso de teste, de qualquer ponto dele. Ou seja, você
pode executar até um comando específico no meio do caso de teste e inspecionar como
o caso de teste se comporta nesse ponto. Para fazer isso, defina um ponto de interrupção no
comando imediatamente antes daquele a ser examinado.
Para definir um ponto de interrupção, selecione um comando, clique com o botão direito e no menu de contexto
selecione Alternar ponto de interrupção (Toggle Breakpoint, em inglês).
Em seguida, clique no botão Executar para executar seu caso de teste
do início ao ponto de interrupção.
Às vezes também é útil executar um caso de teste de algum lugar no meio para
o final ou até um ponto de interrupção após o ponto de partida.
Por exemplo, suponha que seu caso de teste primeiro faz login no site e depois
executa uma série de testes e você está tentando depurar um desses testes.
No entanto, você só precisa fazer o login uma vez, mas precisa continuar executando novamente o seu
teste conforme você o desenvolve. Você pode fazer o login uma vez e, em seguida, executar seu caso de teste
de um ponto de início colocado após a parte de login do seu caso de teste. Isso vai
evitar que você tenha que fazer logout manualmente sempre que executar novamente.
Para definir um ponto de partida, selecione um comando, clique com o botão direito e do contexto
no menu selecione Definir / Limpar Ponto Inicial (Set/Clear Start Point, em inglês).
Em seguida, clique no botão Executar para executar o
caso de teste começando naquele ponto inicial.
Avançando por etapas em um caso de teste
Para executar um caso de teste, um comando de cada vez (“percorrê-lo”), siga estes
passos:
Inicie o caso de teste em executando com o botão Executar na barra de ferramentas.
Pare imediatamente o caso de teste em execução com o botão Pausar.
Selecione repetidamente o botão Etapa.
Botão Localizar
O botão Localizar é usado para ver qual elemento da interface do usuário atualmente exibido
página da web (no navegador) é usado no comando Selenium atualmente selecionado.
Isso é útil ao construir um localizador para o primeiro parâmetro de um comando (consulte a
seção sobre: ref:locators <locators-section> no capítulo Comandos do Selenium).
Ele pode ser usado com qualquer comando que identifica um elemento de UI em uma página da web,
ou seja, click, clickAndWait, type e certos comandos assert e verify,
entre outros.
Na visualização de Tabela, selecione qualquer comando que tenha um parâmetro localizador.
Clique no botão Localizar.
Agora olhe na página da web: deve haver um retângulo verde brilhante
envolvendo o elemento especificado pelo parâmetro localizador.
Código Fonte da página para depuração
Muitas vezes, ao depurar um caso de teste, você simplesmente deve olhar para o código fonte da página (o
HTML da página da web que você está tentando testar) para determinar um problema. O Firefox
torna isso mais fácil. Simplesmente clique com o botão direito na página da web e selecione ‘Exibir-> Código-fonte da página.
O HTML é aberto em uma janela separada. Use seu recurso de pesquisa (Editar => Encontrar)
para procurar uma palavra-chave para encontrar o HTML do elemento de UI que você está tentando
testar.
Como alternativa, selecione apenas a parte da página da web para a qual deseja
ver o código fonte. Em seguida, clique com o botão direito na página da web e
selecione Exibir Código Fonte da Seleção. Neste caso, a janela HTML separada conterá apenas uma pequena
quantidade de código fonte, com destaque na parte que representa a sua
seleção.
Assistência de localizador
Sempre que a Selenium-IDE registra um argumento do tipo localizador, ela armazena
informações adicionais que permitem ao usuário visualizar outros possíveis
argumentos do tipo localizador que podem ser usados em seu lugar. Este recurso pode ser
muito útil para aprender mais sobre localizadores e muitas vezes é necessário para ajudar
a construir um tipo de localizador diferente do tipo que foi registrado.
Esta assistência do localizador é apresentada na janela Selenium-IDE
como um menu suspenso acessível na extremidade direita do campo Destino (Target, em inglês)
(somente quando o campo Destino contém um argumento do tipo localizador registrado).
Abaixo está uma captura de tela mostrando o conteúdo desse menu suspenso para um comando.
Observe que a primeira coluna do menu suspenso fornece localizadores alternativos,
enquanto a segunda coluna indica o tipo de cada alternativa.
Programando uma suíte de testes
Uma suíte de testes é uma coleção de casos de teste que é exibida no
painel mais à esquerda na IDE.
O painel da suíte de testes pode ser aberto ou fechado manualmente selecionando um pequeno ponto
no meio da borda direita do painel (que é a borda esquerda da
janela inteira da Selenium-IDE se o painel estiver fechado).
O painel da suíte de testes será aberto automaticamente quando uma suíte de testes existente
é aberta ou quando o usuário seleciona o item Novo Caso de Teste (New Test Case, em inglês) no
menu Arquivo. Neste último caso, o novo caso de teste aparecerá imediatamente
abaixo do caso de teste anterior.
A Selenium-IDE também suporta o carregamento de casos de teste pré-existentes usando Arquivo
-> Adicionar Caso de Teste. Isso permite que você adicione casos de teste existentes a
um novo conjunto de testes.
Um arquivo de suíte de testes é um arquivo HTML que contém uma tabela de uma coluna. Cada
célula de cada linha na seção
contém um link para um caso de teste.
O exemplo abaixo é de um conjunto de testes contendo quatro casos de teste:
<html><head><metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"><title>Sample Selenium Test Suite</title></head><body><tablecellpadding="1"cellspacing="1"border="1"><thead><tr><td>Test Cases for De Anza A-Z Directory Links</td></tr></thead><tbody><tr><td><ahref="./a.html">A Links</a></td></tr><tr><td><ahref="./b.html">B Links</a></td></tr><tr><td><ahref="./c.html">C Links</a></td></tr><tr><td><ahref="./d.html">D Links</a></td></tr></tbody></table></body></html>
Observação: os arquivos do caso de teste não devem ser colocados no mesmo local do arquivo do conjunto de testes
que os invoca. E em sistemas Mac OS e Linux, esse é realmente o
caso. No entanto, no momento em que este livro foi escrito, um bug impedia os usuários do Windows
de ser capaz de colocar os casos de teste em outro lugar que não com o conjunto de testes
que os invoca.
Extensões de usuário
As extensões de usuário são arquivos JavaScript que permitem criar as suas próprias
personalizações e recursos para adicionar funcionalidade adicional. Frequentemente, isso está
na forma de comandos personalizados, embora esta extensibilidade não se limite a
comandos adicionais.
Existem várias extensões úteis criadas por usuários.
IMPORTANTE: ESTA SEÇÃO ESTÁ DESATUALIZADA - REVISAREMOS EM BREVE.
Talvez a mais popular de todas as extensões da Selenium-IDE
é aquela que fornece controle de fluxo na forma de loops while e
condicionais primitivas. Esta extensão é a goto_sel_ide.js_. Para um exemplo
de como usar a funcionalidade fornecida por esta extensão, veja a
página criada pelo autor.
Para instalar esta extensão, coloque o nome do caminho da extensão em seu
computador no campo Selenium Core extensions da Selenium-IDE
Opções => Opções => Geral.
Depois de selecionar o botão OK, você deve fechar e reabrir a Selenium-IDE
para que o arquivo de extensões seja lido. Qualquer mudança que você fizer em uma
extensão também exigirá que você feche e reabra a Selenium-IDE.
Informações sobre como escrever suas próprias extensões podem ser encontradas perto da
parte inferior do documento Selenium Reference.
Às vezes, pode ser muito útil depurar passo a passo a Selenium IDE e sua
Extensão do usuário. O único depurador que parece capaz de depurar
as extensões baseadas em XUL / Chrome é o Venkman, que é suportada no Firefox até a versão 32 (incluída).
A depuração passo a passo foi verificada para funcionar com Firefox 32 e Selenium IDE 2.9.0.
Formato
Formato, no menu Opções, permite que você selecione uma linguagem para salvar
e exibir o caso de teste. O padrão é HTML.
Se você for usar Selenium-RC para executar seus casos de teste, este recurso é usado
para traduzir seu caso de teste em uma linguagem de programação. Selecione a
linguagem, por exemplo Java ou PHP, que você usará com Selenium-RC para o desenvolvimento
dos seus programas de teste. Em seguida, simplesmente salve o caso de teste usando Arquivo => Exportar Caso de Teste Como.
Seu caso de teste será traduzido para uma série de funções na linguagem que você
escolher. Essencialmente, o código do programa que suporta o seu teste é gerado para você
por Selenium-IDE.
Além disso, observe que se o código gerado não atender às suas necessidades, você pode alterar
editando um arquivo de configuração que define o processo de geração.
Cada linguagem com suporte possui definições de configuração que podem ser editadas. Isto
está em Opções => Opções => Formatos.
Executando testes da Selenium-IDE em diferentes navegadores
Embora o Selenium-IDE só possa executar testes no Firefox, os testes
desenvolvidos com Selenium-IDE podem ser executados em outros navegadores, usando uma
interface de linha de comando simples que invoca o servidor Selenium-RC. Este tópico
é abordado na seção: ref: Executar testes Selenese <html-suite> no capítulo
Selenium-RC. A opção de linha de comando -htmlSuite é o recurso específico de interesse.
Solução de problemas
Abaixo está uma lista de pares de imagem / explicação que descrevem
fontes de problemas com Selenium-IDE:
Table view is not available with this format.
Esta mensagem pode ser exibida ocasionalmente na guia Tabela quando a Selenium IDE é
lançada. A solução alternativa é fechar e reabrir a Selenium IDE. Veja
a issue 1008.
Para maiores informações. Se você é capaz de reproduzir isso de forma confiável, por favor
forneça detalhes para que possamos trabalhar em uma correção.
error loading test case: no command found
Você usou File => Open para tentar abrir um arquivo de suíte de testes. Use File => Open
Test Suite em vez disso.
Uma solicitação de aprimoramento foi levantada para melhorar esta mensagem de erro. Veja
a issue 1010.
Este tipo de erro pode indicar um problema de tempo, ou seja, o elemento
especificado por um localizador em seu comando não foi totalmente carregado quando o comando
foi executado. Tente colocar um pause 5000 antes do comando para determinar
se o problema está realmente relacionado ao tempo. Em caso afirmativo, investigue usando um
comando waitFor* ou *AndWait apropriado antes do comando com falha.
Sempre que sua tentativa de usar a substituição de variável falha, como é o
caso para o comando open acima, isso indica
que você não criou realmente a variável cujo valor você está
tentando acessar. Isto é
às vezes devido a colocar a variável no campo Valor quando
deve estar no campo Destino ou vice-versa. No exemplo acima,
os dois parâmetros para o comando store foram erroneamente
colocados na ordem inversa do que é necessário.
Para qualquer comando Selenese, o primeiro parâmetro obrigatório deve ir
no campo Destino e o segundo parâmetro obrigatório (se houver)
deve ir no campo Valor.
error loading test case: [Exception… “Component returned failure code:
0x80520012 (NS_ERROR_FILE_NOT_FOUND) [nsIFileInputStream.init]” nresult:
“0x80520012 (NS_ERROR_FILE_NOT_FOUND)” location: “JS frame ::
chrome://selenium-ide/content/file-utils.js :: anonymous :: line 48” data: no]
Um dos casos de teste em seu conjunto de testes não pode ser encontrado. Certifique-se de que
o caso de teste está realmente localizado onde o conjunto de testes indica que ele está localizado. Além disso,
certifique-se de que seus arquivos de caso de teste tenham a extensão .html em
seus nomes de arquivo e no arquivo de suíte de testes onde são referenciados.
Uma solicitação de aprimoramento foi levantada para melhorar esta mensagem de erro. Veja
a issue 1011.
O conteúdo do seu arquivo de extensão não foi lido pela Selenium-IDE.
Certifique-se de ter especificado o nome do caminho adequado para o arquivo de extensões via
Options => Options => General no campo Selenium Core extensions.
Além disso, a Selenium-IDE deve ser reiniciada após qualquer alteração em um
arquivo de extensões ou no conteúdo do campo Selenium Core extensions.
7.4.1 - HTML runner
Execute HTML Selenium IDE exports from command line
Selenium HTML-runner permite que você execute suítes de teste da
linha de comando. Suítes de teste são exportações de HTML do Selenium IDE ou
ferramentas compatíveis.
Informação comum
Combinação de lançamentos de geckodriver / firefox /
selenium-html-runner são importantes. Pode haver um software
matriz de compatibilidade em algum lugar.
selenium-html-runner executa apenas suítes de teste (não casos de teste -
por exemplo, uma exportação do Monitis Transaction Monitor). Certifique-se de cumprir isso.
Para usuários Linux sem DISPLAY - você precisa iniciar o html-runner
com display virtual (procure por xvfb)
[user@localhost ~]$ cat testsuite.html
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><htmlxmlns="http://www.w3.org/1999/xhtml"xml:lang="en"lang="en"><head><metacontent="text/html; charset=UTF-8"http-equiv="content-type"/><title>Test Suite</title></head><body><tableid="suiteTable"cellpadding="1"cellspacing="1"border="1"class="selenium"><tbody><tr><td><b>Test Suite</b></td></tr><tr><td><ahref="YOUR-TEST-SCENARIO.html">YOUR-TEST-SCENARIO</a></td></tr></tbody></table></body></html>
Como rodar o selenium-html-runner headless
Agora, a parte mais importante, um exemplo de como executar o
selenium-html-runner! Sua experiência pode variar dependendo das combinações
de software - versões geckodriver / FF / html-runner.
[user@localhost ~]$ xvfb-run java -Dwebdriver.gecko.driver=/home/mmasek/geckodriver.0.18.0 -jar selenium-html-runner-3.7.1.jar -htmlSuite "*firefox""https://YOUR-BASE-URL""$(pwd)/testsuite.html""results.html"; grep result: -A1 results.html/firefox.results.html
Multi-window mode is longer used as an option and will be ignored.
1510061109691 geckodriver INFO geckodriver 0.18.0
1510061109708 geckodriver INFO Listening on 127.0.0.1:2885
1510061110162 geckodriver::marionette INFO Starting browser /usr/bin/firefox with args ["-marionette"]1510061111084 Marionette INFO Listening on port 432291510061111187 Marionette WARN TLS certificate errors will be ignored for this session
Nov 07, 2017 1:25:12 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
2017-11-07 13:25:12.714:INFO::main: Logging initialized @3915ms to org.seleniumhq.jetty9.util.log.StdErrLog
2017-11-07 13:25:12.804:INFO:osjs.Server:main: jetty-9.4.z-SNAPSHOT
2017-11-07 13:25:12.822:INFO:osjsh.ContextHandler:main: Started o.s.j.s.h.ContextHandler@87a85e1{/tests,null,AVAILABLE}2017-11-07 13:25:12.843:INFO:osjs.AbstractConnector:main: Started ServerConnector@52102734{HTTP/1.1,[http/1.1]}{0.0.0.0:31892}2017-11-07 13:25:12.843:INFO:osjs.Server:main: Started @4045ms
Nov 07, 2017 1:25:13 PM org.openqa.selenium.server.htmlrunner.CoreTestCase run
INFO: |open | /auth_mellon.php ||Nov 07, 2017 1:25:14 PM org.openqa.selenium.server.htmlrunner.CoreTestCase run
INFO: |waitForPageToLoad |3000||.
.
.etc
<td>result:</td>
<td>PASS</td>
8 - Sobre esta documentação
Essa documentação, como o próprio código, são mantidos 100% por voluntários
dentro da comunidade Selenium.
Muitos têm usado desde o seu início,
mas muitos mais o usam há pouco tempo,
e dedicaram seu tempo para ajudar a melhorar a experiência de integração
para novos usuários.
Se houver algum problema com a documentação, queremos saber!
A melhor maneira de comunicar um problema é visitar
https://github.com/seleniumhq/seleniumhq.github.io/issues
e pesquise se o problema já foi ou não arquivado.
Se não, fique à vontade para abrir um!
Muitos membros da comunidade frequentam
o canal Libera #selenium em Libera.chat.
Sinta-se à vontade para entrar e fazer perguntas
e se você receber ajuda que você acha que poderia ser útil nessa documentação,
certifique-se de adicionar sua contribuição!
Podemos atualizar essa documentação,
mas é muito mais fácil para todos quando recebemos contribuições
de fora dos committers normais.
8.1 - Direitos autorais e atribuições
Copyright, contributions and all attributions for the different projects under the Selenium umbrella.
A Documentação do Selenium
Todo esforço foi feito para tornar esta documentação a mais completa e precisa possível,
mas nenhuma garantia ou adequação está implícita. As informações fornecidas são
“no estado em que se encontram”. Os autores e a editora não terão qualquer responsabilidade
para com qualquer pessoa ou entidade com relação a quaisquer perdas ou danos decorrentes
das informações contidas neste livro. Nenhuma responsabilidade de patente é assumida com
relação ao uso das informações aqui contidas.
Todo o código e documentação proveniente do projeto Selenium
está licenciado sob a licença Apache 2.0,
com a Software Freedom Conservancy
como detentor dos direitos autorais.
A licença está incluída aqui por conveniência,
mas você também pode encontrá-la no
Site da Apache Foundation:
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
8.2 - Contribuindo com o Site e Documentação do Selenium
Informações em como melhorar a documentação e exemplos de código para Selenium.
Selenium é um grande projeto de software, seu site e documentação são fundamentais
para entender como as coisas funcionam e aprender maneiras eficazes de explorar
seu potencial.
Este projeto contém o site e a documentação do Selenium. Isto é
um esforço contínuo (não direcionado a nenhuma versão específica) para fornecer
informações atualizadas sobre como usar o Selenium de forma eficaz, como se
envolver e como contribuir para o Selenium.
As contribuições para o site e documentação seguem o processo descrito na seção abaixo sobre contribuições.
O projeto Selenium recebe contribuições de todos. Há um
várias maneiras de ajudar:
Reportar um problema
Ao relatar um novo problema ou comentar sobre problemas existentes, por favor
certifique-se de que as discussões estão relacionadas a questões técnicas concretas sobre o
software Selenium, seu site e/ou documentação.
Todos os componentes do Selenium mudam bastante rápido ao longo do tempo, então este
pode fazer com que a documentação fique desatualizada. Se você observar que este é
o caso, como mencionado, não hesite em criar um problema para isso.
Também pode ser possível que você saiba como atualizar a
documentação, então, envie-nos um Pull Request com a
alteração.
Se você não tem certeza se o que encontrou é um problema ou não,
pergunte através dos canais de comunicação descritos em
https://selenium.dev/support.
Contribuições
O projeto Selenium dá as boas-vindas a novos contribuidores. Indivíduos fazendo
contribuições significativas e valiosas ao longo do tempo são transformados em Committers
e recebem acesso de commit ao projeto.
Este guia irá guiá-lo através do processo de contribuição.
Passo 1: Fork
Faça um fork do projeto no Github
e faça checkout na sua cópia localmente.
% git clone git@github.com:seleniumhq/seleniumhq.github.io.git
% cd seleniumhq.github.io
Dependências: Hugo
Usamos Hugo e Docsy theme
para criar e gerar o website. Você vai necessitar de usar a versão “extended”
Sass/SCSS do binário Hugo. Recomendamos a versão 0.101.0 ou superior.
Por favor siga as instruções do Docsy Install Hugo
Passo 2: Branch
Crie uma branch e comece a hackear:
% git checkout -b my-feature-branch
Praticamos o desenvolvimento baseado em HEAD, o que significa que todas as mudanças são aplicadas
diretamente no topo do dev.
Passo 3: Faça mudanças
O repositório contém o website e a documentação. Antes de começar a alterar coisas, por favor
veja o resto dos passos para preparar as dependências e sub-módulos (veja os comandos abaixo).
Para fazer alterações ao website, trabalha na pasta website_and_docs. Para ver uma previsão
do aspecto do website, execute hugo server a partir da raíz do projecto.
% git submodule update --init --recursive
% cd website_and_docs
% hugo server
See Style Guide for more information on our conventions for contribution
Passo 4: Commit
Primeiro, certifique-se de que o git saiba seu nome e endereço de e-mail:
Escrever boas mensagens de commit é importante. Uma mensagem de confirmação
deve descrever o que mudou, por que e conter referência de problemas corrigidos (se
houver). Siga estas diretrizes ao escrever um:
A primeira linha deve ter cerca de 50 caracteres ou menos e conter uma
breve da descrição da mudança.
Mantenha a segunda linha em branco.
Quebra todas as outras linhas em 72 colunas.
Incluir Fixes # N, onde N é o número do problema que o commit corrige
se houver.
Uma boa mensagem de confirmação pode ter a seguinte aparência:
explain commit normatively in one line
Body of commit message is a few lines of text, explaining things
in more detail, possibly giving some background about the issue
being fixed, etc.
The body of the commit message can be several paragraphs, and
please do proper word-wrap and keep columns shorter than about
72 characters or so. That way `git log` will show things
nicely even when it is indented.
Fixes #141
A primeira linha deve ser significativa, pois é o que as pessoas veem quando
executam git shortlog ou git log --oneline.
Passo 5: Rebase
Use git rebase (não git merge) para sincronizar seu trabalho de tempos em tempos.
% git fetch origin
% git rebase origin/trunk
Passo 6: Teste
Lembre-se sempre de executar o servidor local,
com isso, você pode ter certeza de que suas alterações não prejudicaram nada.
Os Pull Requests geralmente são revisados em alguns dias. Se houver
comentários a abordar, aplique suas alterações em novos commits (de preferência
fixups) e envie para a mesma
branch.
Passo 8: Integração
Quando a revisão do código for concluída, um committer integrará seu PR no branch de tronco do repositório. Porque gostamos de manter um
histórico linear no trunk, nós normalmente iremos dar Squash & Rebase no histórico da sua branch.
Comunicação
Todos os detalhes sobre como se comunicar com os colaboradores do projeto
e a comunidade em geral podem ser encontrados em https://selenium.dev/support
8.3 - Style guide for Selenium documentation
Conventions for contributions to the Selenium documentation and code examples
Read our contributing documentation for complete instructions on
how to add content to this documentation.
Alerts
Alerts have been added to direct potential contributors to where specific help is needed.
When code examples are needed, this code has been added to the site:
{{<alert-code/>}}
Which gets displayed like this:
Coding Help
Note:
This section could use some updated code examples
Our documentation uses Title Capitalization for linkTitle which should be short
and Sentence capitalization for title which can be longer and more descriptive.
For example, a linkTitle of Special Heading might have a title of
The importance of a special heading in documentation
Line length
When editing the documentation’s source,
which is written in plain HTML,
limit your line lengths to around 100 characters.
Some of us take this one step further
and use what is called
semantic linefeeds,
which is a technique whereby the HTML source lines,
which are not read by the public,
are split at ‘natural breaks’ in the prose.
In other words, sentences are split
at natural breaks between clauses.
Instead of fussing with the lines of each paragraph
so that they all end near the right margin,
linefeeds can be added anywhere
that there is a break between ideas.
This can make diffs very easy to read
when collaborating through git,
but it is not something we enforce contributors to use.
Translations
Selenium now has official translators for each of the supported languages.
If you add a code example to the important_documentation.en.md file,
also add it to important_documentation.ja.md, important_documentation.pt-br.md,
important_documentation.zh-cn.md.
If you make text changes in the English version, just make a Pull Request.
The new process is for issues to be created and tagged as needs translation based on
changes made in a given PR.
Code examples
All references to code should be language independent,
and the code itself should be placed inside code tabs.
To generate the above tabs, this is what you need to write.
Note that the tabpane includes langEqualsHeader=true.
This auto-formats the code in each tab to match the header name,
but more importantly it ensures that all tabs on the page with a language
are set to the same thing, so we always want to include it.
To ensure that all code is kept up to date, our goal is to write the code in the repo where it
can be executed when Selenium versions are updated to ensure that everything is correct.
This code can be automatically displayed in the documentation using the gh-codeblock shortcode.
The shortcode automatically generates its own html, so if any tab is using this shortcode,
set text=true in the tabpane/tab to prevent the auto-formatting, and add code=true in any
tab that still needs to get formatted with code.
Either way, set langEqualsHeader=true to keep the language tabs synchronized throughout the page.
Note that the gh-codeblock line can not be indented at all.
One great thing about using gh-codeblock is that it adds a link to the full example.
This means you don’t have to include any additional context code, just the line(s) that
are needed, and the user can navigate to the repo to see how to use it.
If you want your example to include something other than code (default) or html (from gh-codeblock),
you need to first set text=true,
then change the Hugo syntax for the tabto use % instead of < and > with curly braces:
This is preferred to writing code comments because those will not be translated.
Only include the code that is needed for the documentation, and avoid over-explaining.
Finally, remember not to indent plain text or it will rendered as a codeblock.
Selenium Level Sponsors
Support the Selenium Project
Want to support the Selenium project? Learn more or view the full list of sponsors.