Como testamos o arrastar e soltar no HTML5

De uma forma ou de outra, todos se deparavam com situações em que algo incomum acontecia em um ambiente banal. Um caso semelhante aconteceu conosco ao testar um novo aplicativo em um ambiente cem vezes testado. Uma surpresa para nós foi o uso de alguns recursos HTML5 no front-end, ou melhor, a incapacidade de automatizar o teste das operações de arrastar e soltar usando as ferramentas padrão do Selenium WebDriver. Queremos conversar sobre essa experiência.



Imagine um projeto tecnologicamente muito semelhante ao anterior (em nossa opinião, teve um pequeno efeito negativo em termos de compreensão e análise correta do problema que apareceu), mas a versão do Angular entre projetos mudou de 1.x para 5.x e a biblioteca Selenide para auto-testes de interface do usuário foi adicionada .

O aplicativo da Web desenvolvido tinha uma página com um certo conjunto de entidades que podiam ser movidas entre si. Imagine nossa surpresa quando uma tentativa de executar um autoteste de verificação das funções de arrastar e soltar usando as ferramentas Selenide não teve êxito. Parece que o que poderia ter dado errado? No projeto anterior, em um ambiente de teste semelhante, tudo funcionou perfeitamente.

Primeiro, verificamos a função arrastar e soltar das funções Selenide e Selenium no navegador atual usando um exemplo de outro aplicativo da web. Tudo funciona. Versões atualizadas, você nunca sabe ...
Decidimos verificar se arrastamos para lá. E fazer a escolha errada dos elementos ao usar Angular é muito fácil. Sentamos com um desenvolvedor front-end e descobrimos que os elementos de arrastar e soltar foram selecionados corretamente.

Em geral, o ambiente de teste está funcionando, os métodos de teste estão escritos corretamente, o recurso de arrastar e soltar "manualmente" funciona, mas o autoteste não funciona. E não há razões para isso à primeira vista.

Por fim, atendemos ao fato do problema e fomos procurar uma solução na Internet. Qual foi a nossa surpresa quando encontramos a edição aberta do Chrome WebDriver # 3604 a partir de 03/04/2016 . Basta pensar que, desde a primavera de 2016, há oficialmente um problema de arrastar e soltar quebrado no Chrome WebDriver, sem mencionar outros navegadores. Não, certamente funciona, mas não ao usar HTML5. E, como ocorreu no processo de análise do problema, nosso aplicativo usou a implementação de arrastar e soltar usando HTML5.

Quais são as implementações de arrastar e soltar para testar em HTML5? Na Internet, foram encontradas duas soluções:

  • Use a biblioteca Java awt.Robot (ou algum clicker de terceiros);
  • Use javascript.

Provavelmente, ganhamos um pouco de dinheiro ou estamos enterrados no problema, mas imediatamente farei uma reserva de que a primeira solução escolhida não nos convinha :)

O que se pode dizer sobre a implementação no Robot:

  • Interceptamos o mouse, simulando ações completas do usuário;
  • Usamos Selenium para determinar as coordenadas dos elementos;
  • Como os elementos Selenium são usados, você não precisa alterar os localizadores. Estamos tentando no projeto usar o xpath;
  • Está escrito em Java, a sintaxe é intuitiva, boa documentação.

Mas algo sobre a implementação do JavaScript veio à mente:

  • Tudo acontece no JavaScript dentro do navegador (as ações estão ocultas dos olhos do testador e essas ações interferem no código);
  • Das bibliotecas js para testar arrastar e soltar na Internet, uma foi encontrada, cuja fonte não era tão fácil de encontrar;
  • A biblioteca encontrada precisará ser finalizada com um arquivo para atender às suas necessidades, uma vez que implementa apenas arrastar e soltar limpo. E nós, por exemplo, precisamos arrastar -> mover -> segurar -> soltar;
  • A biblioteca é implementada como um complemento do jQuery e, portanto, será necessário entender a estrutura do jQuery;
  • Teremos que converter localizadores para css (o jquery não funciona com o xpath);
  • É impossível usar a busca por elementos Selenium, você precisará colar os localizadores com “canetas”.

À primeira vista, a primeira solução era muito mais conveniente e foi testada.

//Setup robot Robot robot = new Robot(); robot.setAutoDelay(50); //Fullscreen page so selenium coordinates work robot.keyPress(KeyEvent.VK_F11); Thread.sleep(2000); //Get size of elements Dimension fromSize = dragFrom.getSize(); Dimension toSize = dragTo.getSize(); //Get centre distance int xCentreFrom = fromSize.width / 2; int yCentreFrom = fromSize.height / 2; int xCentreTo = toSize.width / 2; int yCentreTo = toSize.height / 2; //Get x and y of WebElement to drag to Point toLocation = dragTo.getLocation(); Point fromLocation = dragFrom.getLocation(); //Make Mouse coordinate centre of element toLocation.x += xOffset + xCentreTo; toLocation.y += yCentreTo; fromLocation.x += xCentreFrom; fromLocation.y += yCentreFrom; //Move mouse to drag from location robot.mouseMove(fromLocation.x, fromLocation.y); //Click and drag robot.mousePress(InputEvent.BUTTON1_MASK); //Move to final position robot.mouseMove(toLocation.x, toLocation.y); //Drop robot.mouseRelease(InputEvent.BUTTON1_MASK); 

Em geral, a solução está funcionando ... No entanto, no processo de seu desenvolvimento, suas áreas problemáticas ficaram claras.

  • O movimento do mouse ou a minimização do navegador durante a execução dos testes levam a interferências no decorrer dos testes e sua queda;
  • Não é possível executar testes em paralelo usando JUnit / TestNG. A menos que paralelize através de tarefas separadas no IC.
  • Não foi possível controlar o mouse na máquina remota através do Selenium Grid / Selenoid;
  • No caso de uma falha no navegador, o Robot pode facilmente clicar / arrastar algo na área de trabalho ou em outro aplicativo aberto.

No final, no entanto, a implementação do JavaScript ...

Gostaria de dizer imediatamente que conseguimos resolver o problema do uso de localizadores xpath usando o plugin jQuery jquery.xpath.js.

E a biblioteca drag_and_drop_helper.js (fonte aqui ) tornou-se a principal ferramenta para js controlar as operações de arrastar e soltar. Não faz sentido classificar o trabalho dela, mas como trabalhamos nele um pouco mais tarde.

Agora diretamente na implementação nos testes. Na Selenide, tudo é simples. Antes de usar o recurso de arrastar e soltar, você precisa carregar as bibliotecas JS usadas:

 StringBuilder sb = new StringBuilder(); sb.append(readFile("jquery-3.3.1.min.js")); sb.append(readFile("jquery.xpath.min.js")); sb.append(readFile("drag_and_drop_helper.js")); executeJavaScript(sb.toString()); 

Naturalmente, o jQuery precisa ser carregado se ainda não estiver no aplicativo.

Na versão original da biblioteca, basta escrever o seguinte:

 executeJavaScript("$('" + source + "') .simulateDragDrop({ dropTarget: '" + target + "'});"); 

source e target são localizadores de CSS de elementos de arrastar e soltar.

Como mencionado acima, geralmente usamos xpath-localators no projeto, portanto, após um pouco de aprimoramento, a biblioteca começou a aceitá-los:

 executeJavaScript("$(document).xpath('" + source + "').simulateDragDrop({ dropTarget: '" + target + "'});"); 

Agora, na verdade, sobre a biblioteca drag_and_drop_helper.js. Há partes no bloco de código simulateEvent que são responsáveis ​​por determinados eventos do mouse. Não faz sentido listar os possíveis eventos de operações de arrastar e soltar no HTML5; essas informações são fáceis de encontrar.

Para o teste, precisamos implementar uma função que mova o elemento e segure o mouse no elemento de destino. E isso, como na biblioteca de origem, não é fornecido.

Por analogia, adicionamos o evento dragenter à biblioteca (entre o dragstart e o drop).

 /*Simulating dragenter*/ type = 'dragenter'; var dragenterEvent = this.createEvent(type, {}); dragenterEvent.dataTransfer = event.dataTransfer; this.dispatchEvent($(options.dropTarget)[0], type, dragenterEvent); 

No entanto, isso não é suficiente. Afinal, o evento de espera será concluído instantaneamente. Colocar uma pausa fixa entre os eventos dragEnter e drop não parecia a opção mais conveniente. Afinal, inicialmente não se sabe quanto tempo o aplicativo precisa para processar um evento, o número e o tempo das verificações nos testes são desconhecidos. O atraso entre esses eventos deve ser pelo menos gerenciável. Em vez disso, decidimos dividir o teste de arrastar e soltar em estágios e não emular o conjunto completo de eventos do mouse, ou seja, adicionar a capacidade de gerenciar a lista de eventos envolvidos por meio do parâmetro

E tudo parece estar bem, novas falhas não apareceram e algumas das antigas não são mais essas e, mais importante, as tarefas atribuídas estão sendo realizadas. Parece que tudo está perfeito. No entanto, as ferramentas de desenvolvimento modernas colocam o processamento longe de dois eventos e usam vários parâmetros do elemento movido. Suponha que tenhamos essa solução ao executar o arrastar e soltar que causa erros no dragStartListener. Mas como não quebra nada, não começamos a mudar mais nada. No entanto, em alguma outra aplicação, você provavelmente terá que terminar este momento.

Queremos resumir o acima. Surpreendentemente, um fato! O HTML5 foi lançado em 2013, os navegadores já o suportam há vários anos, os aplicativos foram desenvolvidos para ele, mas o webDriver, infelizmente, ainda não pode usar seus recursos. E o teste das operações de arrastar e soltar deve ser implementado com ferramentas de terceiros, complicar a arquitetura e fazer todo tipo de truque. Sim, existem essas ferramentas e “dançar com um pandeiro” apenas nos fortalece, mas ainda quero ter uma solução de trabalho pronta para uso.

Em nossa experiência, podemos dizer que tais problemas não são tão comuns hoje em dia, embora o recurso arrastar e soltar seja usado em qualquer lugar. Provavelmente, o problema é a escolha das tecnologias de desenvolvimento de aplicativos da web. No entanto, a porcentagem de aplicativos que usam HTML5 está crescendo constantemente, as estruturas estão sendo desenvolvidas e seria ótimo se os desenvolvedores de navegadores e drivers para eles também não ficasse para trás.

PS E, finalmente, uma pequena letra. Gostaria de aconselhar a todos, se possível, a não levar em consideração a banalidade da situação ou a proximidade do ambiente de teste a algum tipo de padrão ao analisar problemas. Isso pode levar a conclusões incorretas ou perda de tempo.

Source: https://habr.com/ru/post/pt437200/


All Articles