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).

Antes

DesiredCapabilities caps = DesiredCapabilities.firefox();
caps.setCapability("platform", "Windows 10");
caps.setCapability("version", "92");
caps.setCapability("build", myTestBuild);
caps.setCapability("name", myTestName);
WebDriver driver = new RemoteWebDriver(new URL(cloudUrl), caps);
caps = {};
caps['browserName'] = 'Firefox';
caps['platform'] = 'Windows 10';
caps['version'] = '92';
caps['build'] = myTestBuild;
caps['name'] = myTestName;
DesiredCapabilities caps = new DesiredCapabilities();
caps.SetCapability("browserName", "firefox");
caps.SetCapability("platform", "Windows 10");
caps.SetCapability("version", "92");
caps.SetCapability("build", myTestBuild);
caps.SetCapability("name", myTestName);
var driver = new RemoteWebDriver(new Uri(CloudURL), caps);
caps = Selenium::WebDriver::Remote::Capabilities.firefox
caps[:platform] = 'Windows 10'
caps[:version] = '92'
caps[:build] = my_test_build
caps[:name] = my_test_name
driver = Selenium::WebDriver.for :remote, url: cloud_url, desired_capabilities: caps
caps = {}
caps['browserName'] = 'firefox'
caps['platform'] = 'Windows 10'
caps['version'] = '92'
caps['build'] = my_test_build
caps['name'] = my_test_name
driver = webdriver.Remote(cloud_url, desired_capabilities=caps)

Depois

FirefoxOptions browserOptions = new FirefoxOptions();
browserOptions.setPlatformName("Windows 10");
browserOptions.setBrowserVersion("92");
Map<String, Object> cloudOptions = new HashMap<>();
cloudOptions.put("build", myTestBuild);
cloudOptions.put("name", myTestName);
browserOptions.setCapability("cloud:options", cloudOptions);
WebDriver driver = new RemoteWebDriver(new URL(cloudUrl), browserOptions);
capabilities = {
  browserName: 'firefox',
  browserVersion: '92',
  platformName: 'Windows 10',
  'cloud:options': {
     build: myTestBuild,
     name: myTestName,
  }
}
var browserOptions = new FirefoxOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "92";
var cloudOptions = new Dictionary<string, object>();
cloudOptions.Add("build", myTestBuild);
cloudOptions.Add("name", myTestName);
browserOptions.AddAdditionalOption("cloud:options", cloudOptions);
var driver = new RemoteWebDriver(new Uri(CloudURL), browserOptions);
options = Selenium::WebDriver::Options.firefox
options.browser_version = 'latest'
options.platform_name = 'Windows 10'
cloud_options = {}
cloud_options[:build] = my_test_build
cloud_options[:name] = my_test_name
options.add_option('cloud:options', cloud_options)
driver = Selenium::WebDriver.for :remote, url: cloud_url, capabilities: options
from selenium.webdriver.firefox.options import Options as FirefoxOptions
options = FirefoxOptions()
options.browser_version = '92'
options.platform_name = 'Windows 10'
cloud_options = {}
cloud_options['build'] = my_test_build
cloud_options['name'] = my_test_name
options.set_capability('cloud:options', cloud_options)
driver = webdriver.Remote(cloud_url, options=options)

Utilitário para encontrar elemento (s) no Java

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.

Encontrando um único elemento com findElement*

Antes

driver.findElementByClassName("className");
driver.findElementByCssSelector(".className");
driver.findElementById("elementId");
driver.findElementByLinkText("linkText");
driver.findElementByName("elementName");
driver.findElementByPartialLinkText("partialText");
driver.findElementByTagName("elementTagName");
driver.findElementByXPath("xPath");
Depois

driver.findElement(By.className("className"));
driver.findElement(By.cssSelector(".className"));
driver.findElement(By.id("elementId"));
driver.findElement(By.linkText("linkText"));
driver.findElement(By.name("elementName"));
driver.findElement(By.partialLinkText("partialText"));
driver.findElement(By.tagName("elementTagName"));
driver.findElement(By.xpath("xPath"));

Encontrando multiplos elementos com findElements*

Antes

driver.findElementsByClassName("className");
driver.findElementsByCssSelector(".className");
driver.findElementsById("elementId");
driver.findElementsByLinkText("linkText");
driver.findElementsByName("elementName");
driver.findElementsByPartialLinkText("partialText");
driver.findElementsByTagName("elementTagName");
driver.findElementsByXPath("xPath");
Depois

driver.findElements(By.className("className"));
driver.findElements(By.cssSelector(".className"));
driver.findElements(By.id("elementId"));
driver.findElements(By.linkText("linkText"));
driver.findElements(By.name("elementName"));
driver.findElements(By.partialLinkText("partialText"));
driver.findElements(By.tagName("elementTagName"));
driver.findElements(By.xpath("xPath"));

Atualizando as dependências

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:

PM> Install-Package Selenium.WebDriver -Version 4.4.0

Python

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:

{
  "name": "selenium-tests",
  "version": "1.0.0",
  "dependencies": {
    "selenium-webdriver": "^4.4.0"
  }
}

Possíveis erros e mensagens de descontinuação

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).

Antes

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().timeouts().setScriptTimeout(2, TimeUnit.MINUTES);
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
Depois

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(2));
driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(10));
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).

Antes

new WebDriverWait(driver, 3)
.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
  .withTimeout(30, TimeUnit.SECONDS)
  .pollingEvery(5, TimeUnit.SECONDS)
  .ignoring(NoSuchElementException.class);
Depois

new WebDriverWait(driver, Duration.ofSeconds(3))
  .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

  Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
  .withTimeout(Duration.ofSeconds(30))
  .pollingEvery(Duration.ofSeconds(5))
  .ignoring(NoSuchElementException.class);

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.

Antes

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformVersion", "Windows 10");
FirefoxOptions options = new FirefoxOptions();
options.setHeadless(true);
options.merge(capabilities);

//Como resultado, o objeto `options` estava sendo modificado.
Depois

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformVersion", "Windows 10");
FirefoxOptions options = new FirefoxOptions();
options.setHeadless(true);
options = options.merge(capabilities);

// 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.

FirefoxOptions options = new FirefoxOptions();
options.setLegacy(true);

BrowserType

A interface BrowserType existe há um bom tempo, más ela está ficando obsoleta a favor da nova interface Browser.

Antes

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("browserVersion", "92");
capabilities.setCapability("browserName", BrowserType.FIREFOX);
Depois

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("browserVersion", "92");
capabilities.setCapability("browserName", Browser.FIREFOX);

C#

AddAdditionalCapability está descontinuada

Em vez dela, AddAdditionalOption é recomendada. Aqui está um exemplo mostrando isso:

Antes

var browserOptions = new ChromeOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "latest";
var cloudOptions = new Dictionary<string, object>();
browserOptions.AddAdditionalCapability("cloud:options", cloudOptions, true);
Depois

var browserOptions = new ChromeOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "latest";
var cloudOptions = new Dictionary<string, object>();
browserOptions.AddAdditionalOption("cloud:options", cloudOptions);

Python

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.)

Antes

from selenium import webdriver
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(
    executable_path=CHROMEDRIVER_PATH, 
    options=options
)
Depois

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
options = webdriver.ChromeOptions()
service = ChromeService(executable_path=CHROMEDRIVER_PATH)
driver = webdriver.Chrome(service=service, options=options)

Resumo

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.

Este tópico foi originalmente postado no site https://saucelabs.com/resources/articles/how-to-upgrade-to-selenium-4