Usando PageObjects, Page Factory e WebDriverWait no Selenium WebDriver usando Java

Eu tenho usado o Selenium WebDriver para implementar testes funcionais em alguns projetos com os quais trabalhei. Eu estou tentando usar o padrão de design de object de página com Page Factory para fatorar meus localizadores. Também criei um object estático WaitTool (singleton) que implementa várias técnicas de espera com parâmetros de tempo limite opcionais.

Meu problema atual é que eu gostaria de usar meus methods de espera antes do PageFactory tentar inicializar os WebElements. A razão pela qual eu gostaria de esperar é porque o PageFactory pode tentar inicializar os elementos da página antes que eles estejam disponíveis na página.

Aqui está uma amostra do PageObject:

public class SignInPage extends PageBase { @FindBy(id = "username") @CacheLookup private WebElement usernameField; @FindBy(id = "password") @CacheLookup private WebElement passwordField; @FindBy(name = "submit") @CacheLookup private WebElement signInButton; public SignInPage(WebDriver driver) { super(driver); WaitTool.waitForPageToLoad(driver, this); // I'd like initialisation to occur here } public MainPage signInWithValidCredentials(String username, String password){ return signIn(username, password, MainPage.class); } private T signIn(String username, String password, Class expectedPage) { usernameField.type(username); passwordField.type(password); signInButton.click(); return PageFactory.initElements(driver, expectedPage); } } 

Aqui está um exemplo de TestObject:

 public class SignInTest extends TestBase { @Test public void SignInWithValidCredentialsTest() { SignInPage signInPage = PageFactory.initElements(driver, SignInPage.class); MainPage mainPage = signInPage.signInWithValidCredentials("sbrown", "sbrown"); assertThat(mainPage.getTitle(), is(equalTo(driver.getTitle()))); } } 

Eu costumo colocar minha lógica no object de página, tanto quanto possível (incluindo esperas), pois torna os casos de teste muito mais legível.

Os WebElements em um PageFactroy são realmente proxies para WebElements. Isso significa que toda vez que você acessar um WebElement, ele executará uma pesquisa para localizar o elemento na página.

Isso tem algumas vantagens:

  • Quando o PageFactory é inicializado, os proxies são configurados, mas os WebElements não são encontrados naquele ponto (assim você não obterá um NoSuchElementException)
  • Toda vez que você usar um WebElement, ele irá encontrá-lo novamente, então você não deve usar o StaleElementException.

Você está usando a anotação @CacheLookup, que está perdendo o segundo benefício, pois ele encontrará o elemento uma vez e, em seguida, manterá uma referência a ele. Agora, é muito mais provável que você veja StaleElementExceptions.

Dito isto, você ainda mantém o benefício principal de que o Selenium não irá para a página e realmente encontrará o elemento até que você o use pela primeira vez.

Então, em resumo, tudo que você precisa fazer é mover

 PageFactory.initElements(driver, this); 

Em seu construtor e tudo vai funcionar bem.