Skip to content

Latest commit

 

History

History
741 lines (536 loc) · 27.8 KB

writing-and-organizing-tests.md

File metadata and controls

741 lines (536 loc) · 27.8 KB

Escrevendo e Organizando Testes

O que você vai aprender

- Como organizar seus arquivos de teste e suporte.
- Quais idiomas são suportados em seus arquivos de teste.
- Como o Cypress lida com testes de unidade versus testes de integração.
- Como agrupar seus testes.

Melhores Práticas

Recentemente demos uma palestra de “Melhores práticas” na conferência AssertJS (Fevereiro de 2018). Este vídeo demonstra como dividir seu aplicativo e organizar seus testes.

Vídeo do Brian Mann na AssertJS(2018)

Estrutura da Pasta

Depois de adicionar um novo projeto, o Cypress criará automaticamente uma estrutura de pastas sugerida. Por padrão, ele criará:

/cypress
  /fixtures
    - example.json

  /integration
    /examples
      - actions.spec.js
      - aliasing.spec.js
      - assertions.spec.js
      - connectors.spec.js
      - cookies.spec.js
      - cypress_api.spec.js
      - files.spec.js
      - local_storage.spec.js
      - location.spec.js
      - misc.spec.js
      - navigation.spec.js
      - network_requests.spec.js
      - querying.spec.js
      - spies_stubs_clocks.spec.js
      - traversal.spec.js
      - utilities.spec.js
      - viewport.spec.js
      - waiting.spec.js
      - window.spec.js

  /plugins
    - index.js

  /support
    - commands.js
    - index.js

Configurando a Estrutura da Pasta

Enquanto o Cypress permite que você configure onde seus testes, fixtures e arquivos de suporte estão localizados, se você estiver iniciando seu primeiro projeto, recomendamos que você use a estrutura acima.

Você pode modificar a configuração da pasta em seu arquivo de configuração. Veja a configuração para mais detalhes.

Quais arquivos devo adicionar ao meu arquivo '.gitignore'?

O Cypress criará um screenshotsFolder e um videosFolder para armazenar as capturas de tela e vídeos feitos durante o teste de seu aplicativo. Muitos usuários optarão por adicionar essas pastas a seus arquivos .gitignore. Além disso, se você estiver armazenando variáveis ​​de ambiente confidenciais em seu arquivo de configuração (cypress.json por padrão) ou cypress.env.json, elas também devem ser ignoradas ao fazer check-in no Git.

Arquivos de teste

Os arquivos de teste estão localizados em cypress/integration por padrão, mas podem ser configurados em outro diretório. Os arquivos de teste podem ser escritos como:

  • .js
  • .jsx
  • .coffee
  • .cjsx

O Cypress também oferece suporte ES2015 pronto para uso. Você pode usar ES2015 modules ou CommonJS modules. Isto significa que pode utilizar import ou require, ambos pacotes NPM e módulos relativos locais.

Receita de exemplo

Confira nossa receita usando os módulos ES2015 e CommonJS.

Para ver um exemplo de cada comando usado no Cypress, abra a pasta example dentro da sua pasta cypress/integration.

Para começar a escrever testes para seu aplicativo, crie um novo arquivo como app_spec.js em sua pasta cypress/integration. Atualize sua lista de testes no Cypress Test Runner e seu novo arquivo deve ter aparecido na lista.

Arquivos Fixture

Fixtures são usadas como partes externas de dados estáticos que podem ser usadas por seus testes. Os arquivos de fixtures estão localizados em cypress/fixtures por padrão, mas podem ser configurados em outro diretório.

Você normalmente os usaria com o comando cy.fixture() e com mais frequência quando estiver fazendo o stub de Solicitações de Rede.

Arquivos de ativos

Existem algumas pastas que podem ser geradas após a execução de um teste, contendo ativos que foram gerados durante a execução do teste.

Você pode considerar adicionar essas pastas ao seu arquivo .gitignore para ignorar a verificação desses arquivos no Git.

Download de arquivos

Todos os arquivos baixados durante o teste do recurso de download de arquivo de um aplicativo serão armazenados em downloadsFolder que é definido como padrão cypress/downloads.

/cypress
  /downloads
    - records.csv

Arquivos de captura de tela

Se as capturas de tela foram tiradas por meio do comando cy.screenshot() ou automaticamente quando um teste falha, as capturas de tela são armazenadas em screenshotsFolder qual é definido como cypress/screenshots por padrão.

/cypress
  /screenshots
    /app_spec.js
      - Navigates to main menu (failures).png

Para saber mais sobre as capturas de tela e as configurações disponíveis, consulte Capturas de tela e vídeos

Arquivos de vídeo

Todos os vídeos gravados da execução são armazenados em videosFolder, que é definido como cypress/videos por padrão.

/cypress
  /videos
    - app_spec.js.mp4

Para saber mais sobre os vídeos e as configurações disponíveis, consulte Capturas de tela e vídeos

Arquivos de plug-in

Por padrão, o Cypress incluirá automaticamente o arquivo de plug-ins cypress/plugins/index.js antes de cada arquivo de especificação executado. Fazemos isso puramente como um mecanismo de conveniência para que você não precise importar esse arquivo em cada um dos seus arquivos de especificação.

O arquivo de plug-ins importado inicial pode ser configurado para outro arquivo.

Leia mais sobre como usar plug-ins para estender o comportamento do Cypress.

Arquivo de suporte

Por padrão, o Cypress incluirá automaticamente o arquivo de suporte cypress/support/index.js. Este arquivo é executado antes de cada arquivo de especificação. Fazemos isso puramente como um mecanismo de conveniência para que você não precise importar esse arquivo em cada um dos seus arquivos de especificação.

Lembre-se de que, ao clicar em “Run all specs” após o comando cypress open, o código no arquivo de suporte é executado uma vez antes de todos os arquivos de especificação, em vez de uma vez antes de cada arquivo de especificação. Consulte Execução para obter mais detalhes.

O arquivo de suporte importado inicial pode ser configurado para outro arquivo ou desligado completamente usando a configuração de supportFile.

O arquivo de suporte é um ótimo lugar para colocar comportamento reutilizável, como comandos personalizados ou substituições globais que você deseja aplicar e disponibilizar para todos os seus arquivos de especificação.

A partir do seu arquivo de suporte você pode executar os comandos import ou require de outros arquivos para manter as coisas organizadas.

Nós preenchemos automaticamente um arquivo de suporte de exemplo, que tem vários exemplos comentados.

Você pode definir comportamentos em um before ou beforeEach em qualquer um dos arquivos cypress/support:

beforeEach(() => {
  cy.log('I run before every test in every spec file!!!!!!')
})

Ganchos globais para testes

Nota: Este exemplo pressupõe que você já esteja familiarizado com os ganchos Mocha.

Execução

O Cypress executa o arquivo de suporte antes do arquivo de especificação. Por exemplo, quando você clica em um arquivo de teste denominado spec-a.js via cypress open, o Test Runner executa os arquivos na seguinte ordem:

<!-- bundled support file -->
<script src="support/index.js"></script>
<!-- bundled spec file -->
<script src="integration/spec-a.js"></script>

O mesmo acontece ao usar o comando cypress run: uma nova janela do navegador é aberta para cada par de arquivos de suporte e especificações.

Mas quando você clica no botão “Run all specs” depois do comando cypress open, o Test Runner empacota e concatena todas as especificações juntas, basicamente executando scripts como mostrado abaixo. Isso significa que o código no arquivo de suporte é executado uma vez antes de todos os arquivos de especificação, em vez de uma vez antes de cada arquivo de especificação.

<!-- bundled support file -->
<script src="support/index.js"></script>
<!-- bundled first spec file, second spec file, etc -->
<script src="integration/spec-a.js"></script>
<script src="integration/spec-b.js"></script>
...
<script src="integration/spec-n.js"></script>

Ter um único arquivo de suporte ao executar todas as especificações juntas pode executar os ganchos before e beforeEach de maneiras que você pode não antecipar. Leia 'Cuidado ao executar todas as especificações juntas' para exemplos.

Solução de problemas

Se o Cypress não encontrar os arquivos de especificação por algum motivo, você pode solucionar o problema de sua lógica abrindo ou executando o Cypress com os logs de depuração habilitados:

$ DEBUG=cypress:server:specs npx cypress open
# or
DEBUG=cypress:server:specs npx cypress run

Escrevendo testes

O Cypress é construído em cima de Mocha e Chai. Apoiamos os estilos de asserção de Chai BDD e de TDD. Os testes que você escreve no Cypress irão, em sua maioria, seguir esse estilo.

Se você está familiarizado com a escrita de testes em JavaScript, escrever testes em Cypress será muito fácil.

Estrutura de Teste

A interface de teste, emprestado do mocha fornece comandos describe(), context(), it() e specify().

context() é idêntico a describe() e specify() é idêntico a it(), portanto, escolha a terminologia que funciona melhor para você.

// -- Start: Our Application Code --
function add (a, b) {
  return a + b
}

function subtract (a, b) {
  return a - b
}

function divide (a, b) {
  return a / b
}

function multiply (a, b) {
  return a * b
}
// -- End: Our Application Code --

// -- Start: Our Cypress Tests --
describe('Unit test our math functions', () => {
  context('math', () => {
    it('can add numbers', () => {
      expect(add(1, 2)).to.eq(3)
    })

    it('can subtract numbers', () => {
      expect(subtract(5, 12)).to.eq(-7)
    })

    specify('can divide numbers', () => {
      expect(divide(27, 9)).to.eq(3)
    })

    specify('can multiply numbers', () => {
      expect(multiply(5, 4)).to.eq(20)
    })
  })
})
// -- End: Our Cypress Tests --

Ganchos

O Cypress também fornece ganchos (emprestados do Mocha).

Eles são úteis para definir as condições que você deseja executar antes de um conjunto de testes ou antes de cada teste. Eles também são úteis para limpar as condições após um conjunto de testes ou após cada teste.

beforeEach(() => {
  // root-level hook
  // runs before every test
})

describe('Hooks', () => {
  before(() => {
    // runs once before all tests in the block
  })

  beforeEach(() => {
    // runs before each test in the block
  })

  afterEach(() => {
    // runs after each test in the block
  })

  after(() => {
    // runs once after all tests in the block
  })
})

A ordem de execução do gancho e do teste é a seguinte:

  • Todos os ganchos before() funcionam (uma vez)

  • Qualquer gancho beforeEach() é executado

  • Testes executados

  • Qualquer gancho afterEach() é executado

  • Todos os ganchos after() funcionam (uma vez)

Antes de escrever after() ou chamar ganchos afterEach(), consulte nossos pensamentos sobre o anti-padrão de limpeza do estado com after()ouafterEach()`.

Desconfie de ganchos no nível de raiz, pois eles podem ser executados em uma ordem surpreendente ao clicar no botão “Run all specs”. Em vez disso, coloque-os dentro de suítes describe ou context para isolamento. Leia 'Tenha cuidado ao executar todas as especificações juntas'.

Excluindo e Incluindo Testes

Para executar um conjunto ou teste especificado, anexe .only à função. Todas as suítes aninhadas também serão executadas. Isso nos dá a capacidade de executar um teste por vez e é a maneira recomendada de escrever um conjunto de testes.

// -- Start: Our Application Code --
function fizzbuzz (num) {
  if (num % 3 === 0 && num % 5 === 0) {
    return 'fizzbuzz'
  }

  if (num % 3 === 0) {
    return 'fizz'
  }

  if (num % 5 === 0) {
    return 'buzz'
  }
}
// -- End: Our Application Code --

// -- Start: Our Cypress Tests --
describe('Unit Test FizzBuzz', () => {
  function numsExpectedToEq (arr, expected) {
    // loop through the array of nums and make
    // sure they equal what is expected
    arr.forEach((num) => {
      expect(fizzbuzz(num)).to.eq(expected)
    })
  }

  it.only('returns "fizz" when number is multiple of 3', () => {
    numsExpectedToEq([9, 12, 18], 'fizz')
  })

  it('returns "buzz" when number is multiple of 5', () => {
    numsExpectedToEq([10, 20, 25], 'buzz')
  })

  it('returns "fizzbuzz" when number is multiple of both 3 and 5', () => {
    numsExpectedToEq([15, 30, 60], 'fizzbuzz')
  })
})

Para pular um conjunto ou teste especificado, anexe .skip() à função. Todas as suítes aninhadas também serão ignoradas.

it.skip('returns "fizz" when number is multiple of 3', () => {
  numsExpectedToEq([9, 12, 18], 'fizz')
})

Configuração de Teste

Para aplicar um valor específico de configuração Cypress a um conjunto ou teste, passe um objeto de configuração para a função de teste ou suíte como o segundo argumento.

Essa configuração entrará em vigor durante o conjunto ou testes em que foram definidos e, em seguida, retornará aos valores padrão anteriores depois que o conjunto ou os testes forem concluídos.

Sintaxe

describe(name, config, fn)
context(name, config, fn)
it(name, config, fn)
specify(name, config, fn)

Valores de configuração permitidos

Observação: alguns valores de configuração são somente leitura e não podem ser alterados por meio da configuração de teste. Os seguintes valores de configuração podem ser alterados por meio de configuração de teste:

  • animationDistanceThreshold
  • baseUrl
  • browser nota: filtra se os testes ou um conjunto de testes são executados, dependendo do navegador atual
  • defaultCommandTimeout
  • execTimeout
  • env nota: as variáveis ​​de ambiente fornecidas serão mescladas com as variáveis ​​de ambiente atuais.
  • includeShadowDom
  • requestTimeout
  • responseTimeout
  • retries
  • scrollBehavior
  • viewportHeight
  • viewportWidth
  • waitForAnimations

Configuração de suíte

Se você deseja definior um conjunto de testes a ser executado ou excluído, passando um navegador específico, você pode sobrescrever as configurações do browser dentro das configurações do conjunto de testes. A opção browser aceita os mesmos argumentos de Cypress.isBrowser().

O seguinte conjunto de testes será ignorado se os testes forem executados em navegadores Chrome.

describe('When NOT in Chrome', { browser: '!chrome' }, () => {
  it('Shows warning', () => {
    cy.get('.browser-warning')
      .should('contain', 'For optimal viewing, use Chrome browser')
  })

  it('Links to browser compatibility doc', () => {
    cy.get('a.browser-compat')
      .should('have.attr', 'href')
      .and('include', 'browser-compatibility')
  })
})

O seguinte conjunto de testes só será executado no navegador Firefox. Ele sobrescreverá a resolução da janela de visualização em um dos testes e mesclará todas as variáveis ​​de ambiente atuais com as fornecidas.

describe('When in Firefox', {
  browser: 'firefox',
  viewportWidth: 1024,
  viewportHeight: 700,
  env: {
    DEMO: true,
    API: 'http://localhost:9000'
  }
}, () => {
  it('Sets the expected viewport and API url', () => {
    expect(cy.config('viewportWidth')).to.equal(1024)
    expect(cy.config('viewportHeight')).to.equal(700)
    expect(cy.env('API')).to.equal('http://localhost:9000')
  })

  it('Uses the closest API environment variable', {
    env: {
      API: 'http://localhost:3003'
    }
  }, () => {
    expect(cy.env('API')).to.equal('http://localhost:3003')
    // other environment variables remain unchanged
    expect(cy.env('DEMO')).to.be.true
  })
})

Configuração de teste único

Você pode configurar o número de tentativas de repetição durante cypress run ou cypress open. Consulte Testar novas tentativas para obter mais informações.

it('should redirect unauthenticated user to sign-in page', {
    retries: {
      runMode: 3,
      openMode: 2
    }
  } () => {
    cy.visit('/')
    // ...
  })
})

Gerar testes dinamicamente

Você pode gerar testes dinamicamente usando JavaScript.

describe('if your app uses jQuery', () => {
  ['mouseover', 'mouseout', 'mouseenter', 'mouseleave'].forEach((event) => {
    it('triggers event: ' + event, () => {
      // if your app uses jQuery, then we can trigger a jQuery
      // event that causes the event callback to fire
      cy
        .get('#with-jquery').invoke('trigger', event)
        .get('#messages').should('contain', 'the event ' + event + 'was fired')
    })
  })
})

O código acima produzirá um pacote com 4 testes:

> if your app uses jQuery
  > triggers event: 'mouseover'
  > triggers event: 'mouseout'
  > triggers event: 'mouseenter'
  > triggers event: 'mouseleave'

Estilos de Asserção

O Cypress suporta asserções simples de estilo BDD (expect/ should) e TDD (assert). Leia mais sobre asserções simples.

it('can add numbers', () => {
  expect(add(1, 2)).to.eq(3)
})

it('can subtract numbers', () => {
  assert.equal(subtract(5, 12), -7, 'these numbers are equal')
})

O comando .should() e seu alias .and() também podem ser usados ​​para encadear mais facilmente as asserções dos comandos do Cypress. Leia mais sobre asserções.

cy.wrap(add(1, 2)).should('equal', 3)

Executando testes

Execute um único arquivo de especificação

Sugerimos executar arquivos de teste individualmente clicando no nome do arquivo de especificação para garantir o melhor desempenho. Por exemplo, o aplicação Cypress RealWorld tem vários arquivos de teste, mas abaixo executamos um único arquivo de teste “new-transaction.spec.ts”.

Executando uma única especificação

Execute todas as especificações

Você pode executar todos os arquivos de especificações juntos clicando no botão “Run all specs”. Este modo é equivalente a concatenar todos os arquivos de especificações juntos em uma única parte do código de teste.

Executando todas as especificações

Desconfie de ganchos no nível de raiz, pois eles podem ser executados em uma ordem surpreendente ao clicar no botão “Run all specs”. Em vez disso, coloque-os dentro de suítes describe ou context para isolamento. Leia 'Tenha cuidado ao executar todas as especificações juntas'.

Executar especificações filtradas

Você também pode executar um subconjunto de todas as especificações inserindo um filtro de pesquisa de texto. Apenas as especificações com caminhos de arquivo relativos contendo o filtro de pesquisa permanecerão e serão executadas como se estivessem concatenando todos os arquivos de especificações ao clicar no botão “Run N specs”.

  • O filtro de pesquisa não diferencia maiúsculas de minúsculas; o filtro “ui” corresponderá aos arquivos “UI-spec.js” e “admin-ui-spec.js”.

  • O filtro de pesquisa é aplicado a todo o caminho do arquivo de especificação relativo, portanto, você pode usar nomes de pasta para limitar as especificações; o filtro “ui” irá corresponder aos arquivos “admin-ui.spec.js” e “ui / admin.spec.js”.

Execução de especificações que correspondem ao filtro de pesquisa

Monitorando testes

Ao executar testes por meio do comando cypress open, O Cypress observa o sistema de arquivos para mudanças em seus arquivos de especificação. Logo após adicionar ou atualizar um teste, o Cypress o recarregará e executará todos os testes naquele arquivo de especificação.

Isso torna a experiência de desenvolvimento produtiva porque você pode adicionar e editar testes enquanto implementa um recurso e a interface de usuário do Cypress sempre refletirá os resultados de suas edições mais recentes.

Lembre-se de usar .only para limitar quais testes são executados: isso pode ser especialmente útil quando você tem muitos testes em um único arquivo de especificação que está constantemente editando; considere também dividir seus testes em arquivos menores, cada um lidando com comportamento logicamente relacionado.

O que é monitorado?

Arquivos

Pastas

  • Diretório de integração (cypress/integration/ por padrão)
  • Diretório de suporte (cypress/support/ por padrão)
  • Diretório de plugins (cypress/plugins/ por padrão)

A pasta, os arquivos dentro da pasta e todas as pastas filhas e seus arquivos (recursivamente) são monitorados.

Esses caminhos de pasta referem-se aos caminhos de pasta padrão. Se você configurou o Cypress para usar caminhos de pasta diferentes, então as pastas específicas para sua configuração serão monitoradas.

O que não é monitorado?

Todo o resto; isso inclui, mas não se limita a:

  • Seu código de aplicativo
  • node_modules
  • cypress/fixtures/

Se você está desenvolvendo usando uma stack de aplicativos da web moderna baseada em JS, então provavelmente você tem suporte para alguma forma de substituição de módulo quente que é responsável por observar o código do seu aplicativo - HTML, CSS, JS, etc. - e recarregar de forma transparente o seu aplicação em resposta às mudanças.

Configuração

Defina a propriedade de configuração watchForFileChanges para false com o objetivo de desativar a observação de arquivos.

Nada é observado durante cypress run.

A propriedade watchForFileChanges só tem efeito ao executar o Cypress usando cypress open.

O componente responsável pelo comportamento de observação de arquivos no Cypress é o webpack-preprocessor. Este é o observador de arquivos padrão fornecido com o Cypress.

Se você precisar de mais controle do comportamento de observação de arquivos, pode configurar este pré-processador explicitamente: ele expõe opções que permitem configurar o comportamento, como o que é assistido e o atraso antes de emitir um evento de “atualização” após uma alteração.

O Cypress também fornece outros pré-processadores de monitoramento de arquivos; você terá que configurá-los explicitamente se quiser usá-los.

Voltar para o topo