Skip to content

Latest commit

 

History

History
284 lines (206 loc) · 14.4 KB

interacting-with-elements.md

File metadata and controls

284 lines (206 loc) · 14.4 KB

Interagindo com Elementos

O que você vai aprender

- Como o Cypress calcula visibilidade
- Como o Cypress garante que os elementos sejam acionáveis
- Como o Cypress lida com elementos de animação
- Como você pode ignorar essas verificações e forçar eventos

Acionabilidade

Alguns comandos no Cypress são para interagir com o DOM, como:

Esses comandos simulam um usuário interagindo com sua aplicação. Por debaixo dos panos, o Cypress dispara os eventos que um navegador dispararia, fazendo com que as associações de evento de sua aplicação sejam disparadas.

Antes de emitir qualquer um dos comandos, verificamos o estado atual do DOM e executamos algumas ações para garantir que o elemento DOM esteja “pronto” para receber a ação.

O Cypress esperará que o elemento passe em todas essas verificações durante o defaultCommandTimeout (descrito em detalhes no guia de conceito principal Default Assertions).

Verificações e Ações Realizadas

Sempre que o Cypress não pode interagir com um elemento, ele pode falhar em qualquer uma das etapas acima. Normalmente, você receberá um erro explicando por que o elemento não foi considerado acionável.

Visibilidade

Cypress verifica muitas coisas para determinar a visibilidade de um elemento. Os cálculos a seguir levam em consideração as traduções e transformações CSS.

Um elemento é considerado oculto se

  • O width ou height é 0.
  • A propriedade CSS (ou ancestrais) é visibility: hidden.
  • A propriedade CSS (ou ancestrais) é display: none.
  • A propriedade CSS é position: fixed e está fora da tela ou encoberta.
  • Qualquer um de seus ancestrais esconde transbordamento*
    • E esse ancestral tem um width ou height de 0
    • E um elemento entre esse ancestral e o elemento é position: absolute
  • Qualquer um de seus ancestrais esconde transbordamento*
    • E esse ancestral ou um ancestral entre ele e esse ancestral é seu pai deslocado
    • E está posicionado fora dos limites do ancestral
  • Qualquer um de seus ancestrais esconde transbordamento*
    • E o elemento é position: relative
    • E está posicionado fora dos limites do ancestral

* Esconde transbordamento significa que ele tem overflow: hidden, overflow-x: hidden, overflow-y: hidden, overflow: scroll, or overflow: auto

Opacidade

Os elementos onde a propriedade CSS (ou ancestrais) tem opacity: 0 são considerados ocultos ao declarar a visibilidade do elemento diretamente. No entanto, os elementos onde a propriedade CSS (ou ancestrais) tem opacity: 0 são considerados acionáveis ​​e quaisquer comandos usados ​​para interagir com o elemento oculto realizarão a ação.

Inabilidade

O Cypress verifica se a propriedade disabled de um elemento é true.

Desconectado

Quando muitos aplicativos renderizam o DOM, na verdade eles removem o elemento DOM e inserem um novo elemento DOM em seu lugar com os atributos recém-alterados.

O Cypress verifica se um elemento que você está fazendo asserções está separado do DOM. Isso verifica se o elemento ainda está dentro document da aplicação em teste.

Somente Leitura

O Cypress verifica se a propriedade readonly de um elemento é definida durante .type().

Animações

O Cypress irá automaticamente determinar se um elemento está sendo animado e esperará até que ele pare.

Para calcular se um elemento está animado, pegamos uma amostra das últimas posições em que ele estava e calculamos a inclinação do elemento. Você deve se lembrar disso da álgebra da 8ª série. 😉

Para calcular se um elemento está animado, verificamos as posições atual e anterior do próprio elemento. Se a distância exceder o animationDistanceThreshold, então consideramos o elemento como uma animação.

Ao chegar a esse valor, fizemos alguns experimentos para encontrar uma velocidade que “parece” muito rápida para um usuário interagir. Você sempre pode aumentar ou diminuir esse limite.

Você também pode desligar nossas verificações de animações com a opção de configuração waitForAnimations.

Cobertura

Também garantimos que o elemento com o qual estamos tentando interagir não seja coberto por um elemento pai.

Por exemplo, um elemento pode passar por todas as verificações anteriores, mas uma caixa de diálogo gigante pode estar cobrindo toda a tela, tornando a interação com o elemento impossível para qualquer usuário real.

Ao verificar se o elemento está coberto, sempre verificamos suas coordenadas centrais.

Se um elemento filho o estiver cobrindo, tudo bem. Na verdade, emitiremos automaticamente os eventos que dispararmos para o elemento filho.

Imagine que você tem um botão:

<button>
  <i class="fa fa-check">
  <span>Submit</span>
</button>

Muitas vezes, o elemento <i> ou <span> está cobrindo a coordenada exata com a qual estamos tentando interagir. Nesses casos, o evento dispara no elemento filho. Nós até anotamos isso para você no Log de Comandos.

Rolagem

Antes de interagir com um elemento, sempre o rolaremos para a visualização (incluindo qualquer um de seus contêineres pais). Mesmo se o elemento estivesse visível sem rolagem, executamos o algoritmo de rolagem para reproduzir o mesmo comportamento toda vez que o comando for executado.

Essa lógica de rolagem se aplica apenas aos comandos acionáveis ​​acima. Não rolamos os elementos para a visualização ao usar comandos DOM, como cy.get() ou .find().

Por padrão, o algoritmo de rolagem funciona rolando o ponto superior mais à esquerda do elemento no qual emitimos o comando para o ponto de rolagem superior e mais à esquerda de seu contêiner rolável.

Depois de rolar o elemento, se determinarmos que ele ainda está sendo encoberto, continuaremos a rolar e “empurrar” a página até que ela se torne visível. Isso acontece frequentemente quando você tem position: fixed ou position: sticky elementos de navegação que são fixados para o topo da página.

Nosso algoritmo deve sempre ser capaz de rolar até que o elemento não seja coberto.

Para alterar a posição na janela de visualização para onde rolamos um elemento, você pode usar a opção de configuração scrollBehavior. Isso pode ser útil se o elemento for coberto quando alinhado ao topo da janela de visualização ou se você apenas preferir que o elemento seja centralizado durante a rolagem dos comandos de ação. Os valores aceitos são 'center', 'top', 'bottom', 'nearest', e false, com false a rolagem é desativada completamente.

Coordenadas

Depois de verificarmos se o elemento é acionável, o Cypress disparará todos os eventos apropriados e as ações padrão correspondentes. Normalmente, as coordenadas desses eventos são disparadas no centro do elemento, mas a maioria dos comandos permite que você altere a posição para a qual são disparadas.

cy.get('button').click({ position: 'topLeft' })

As coordenadas nas quais disparamos o evento geralmente estarão disponíveis ao clicar no comando no Log de Comandos.

coords

Além disso, exibiremos um “hitbox” vermelho - que é um ponto que indica as coordenadas do evento.

cypress hitbox

Depurando

Pode ser difícil depurar problemas quando os elementos não são considerados acionáveis ​​pelo Cypress.

Embora você deva ver uma bela mensagem de erro, nada se compara a inspecionar visualmente e cutucar o DOM você mesmo para entender o motivo.

Ao usar o Log de comandos para passar o mouse sobre um comando, você notará que sempre rolaremos o elemento ao qual o comando foi aplicado para exibição. Observe que isso NÃO está usando os mesmos algoritmos que descrevemos acima.

Na verdade, só rolamos elementos para exibição quando comandos acionáveis ​​estão sendo executados usando os algoritmos acima. Nós não rolamos elementos com os comandos DOM regulares como cy.get() ou .find().

O motivo pelo qual rolamos um elemento para exibição ao passar o mouse sobre um comando executado é para ajudá-lo a ver quais elementos foram encontrados por aquele comando correspondente. É um recurso puramente visual e não reflete necessariamente a aparência de sua página quando o comando foi executado.

Em outras palavras, você não pode obter uma representação visual correta do que Cypress “viu” ao olhar para um estado anterior.

A única maneira de você “ver” e depurar porque Cypress pensou que um elemento não estava visível é usar uma instrução debugger.

Recomendamos colocar debugger ou usar o comando .debug() diretamente ANTES da ação.

Garantir de que suas Ferramentas de Desenvolvedor estejam abertas e você possa chegar bem perto de “ver” os cálculos que o Cypress está realizando.

Você também pode vincular a eventos que o Cypress dispara enquanto trabalha com seu elemento. Usar um depurador com esses eventos lhe dará uma visão baixo nível de como o Cypress funciona.

// break on a debugger before the action command
cy.get('button').debug().click()

Forçando

Embora as verificações acima sejam muito úteis para encontrar situações que impediriam seus usuários de interagir com os elementos - às vezes, eles podem atrapalhar!

Às vezes, não vale a pena tentar “agir como um usuário” para que um robô execute as etapas exatas que um usuário faria para interagir com um elemento.

Imagine que você tenha uma estrutura de navegação aninhada onde o usuário deve passar o mouse e mover o mouse em um padrão muito específico para alcançar o link desejado.

Vale a pena tentar replicar durante o teste?

Talvez não! Para esses cenários, oferecemos uma saída de emergência para contornar todas as verificações acima e forçar a ocorrência de eventos!

Você pode passar { force: true } para a maioria dos comandos de ação.

// force the click and all subsequent events
// to fire even if this element isn't considered 'actionable'
cy.get('button').click({ force: true })

Qual é a diferença? Quando você força um evento a acontecer, nós iremos:

  • Continuar a realizar todas as ações padrão
  • Acionar o evento à força no elemento

NÃO iremos:

  • Rolar o elemento para a view
  • Garantir de que está visível
  • Garantir de que não está desativado
  • Garantir de que não está desanexado
  • Garantir de que não seja somente leitura
  • Garantir de que não está animando
  • Garantir de que não está coberto
  • Dispare o evento em um descendente

Em resumo, { force: true } pula as verificações e sempre dispara o evento no elemento desejado.

forçar .select() opções desabilitadas Passar { force: true } para .select() não substituirá as verificações de ação para selecionar uma <option> desabilitada ou uma opção dentro de um <optgroup> desabilitado. Veja este problema para mais detalhes.

Voltar para o topo