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.
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
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 umvideosFolder
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) oucypress.env.json
, elas também devem ser ignoradas ao fazer check-in no Git.
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.
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.
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.
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
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
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
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.
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!!!!!!')
})
Nota: Este exemplo pressupõe que você já esteja familiarizado com os ganchos Mocha.
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
ebeforeEach
de maneiras que você pode não antecipar. Leia 'Cuidado ao executar todas as especificações juntas' para exemplos.
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
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.
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 --
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 ganchosafterEach()
, consulte nossospensamentos sobre o anti-padrão de limpeza do estado com
after()ou
afterEach()`.
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
oucontext
para isolamento. Leia 'Tenha cuidado ao executar todas as especificações juntas'.
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')
})
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.
describe(name, config, fn)
context(name, config, fn)
it(name, config, fn)
specify(name, config, fn)
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 atualdefaultCommandTimeout
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
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
})
})
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('/')
// ...
})
})
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'
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)
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”.
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.
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
oucontext
para isolamento. Leia 'Tenha cuidado ao executar todas as especificações juntas'.
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”.
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.
- 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.
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.
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 usandocypress 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.