GithubHelp home page GithubHelp logo

mathsena / cypessblogangular Goto Github PK

View Code? Open in Web Editor NEW
0.0 1.0 0.0 703 KB

Neste projeto você terá o desafio de construir um teste E2E com Cypress para um Blog em Angular.

JavaScript 51.87% TypeScript 34.99% HTML 13.01% CSS 0.12%

cypessblogangular's Introduction

Testes E2E com Cypress

Programação

  • Motivação
  • Cypress?
  • Trade-offs
  • Pré-Requisitos
  • O que vamos testar
  • Instalação
  • Removendo o Protactor
  • Cypress Test Runner
  • Primeiro Teste
  • Como Rodar
  • Configuração
  • Roteiro de Testes
  • Support Commands
  • Fixture
  • Relatórios e Integrações
  • Plugins
  • Incluir Outra Spec
  • Falso Negativo
  • DevOps
  • Paralelismo
  • Analytics Dashboard

Motivação

     Agilidade (- tempo)
     Qualidade (- bugs)
     Economia de horas (- custo)


Por que não somente Testes Unitários?

     O teste E2E simula a navegação pelo usuário, validando não só a interface frontend como integração com o backend.
     Teste unitário valida a qualidade do Código. E2E valida a aplicação.


Cypress?

     JavaScritpt: Baixa curva de aprendizado, custo com treinamento reduzido.
     Performance: Paralelismo, Stress Test, Load Test.
     Recorder: Cypress Recorder (Chrome), Katalon Recorder.
     Produtividade: Auto-reload, Spies, Stubs e Mocks.
     Licença: OpenSource (Mit).
     End-to-end tests, Integration tests, Unit tests.

     Diferente do Selenium ou Appium, que injetam comandos exernos, o Cypress roda no mesmo contexto JS do App, com acesso instantâneo a todas as interações e eventos.

Trade-offs

     Cypress não é uma ferramenta de automação geral.
     Os comandos do Cypress sempre são executados dentro de um navegador.
     Nunca haverá suporte para várias guias do navegador.
     Você não pode usar o Cypress para controlar dois navegadores no mesmo teste.


Pré-Requisitos

     Git
     Node


O que vamos testar

     Projeto para teste: Angular Real World Example App

git clone https://github.com/gothinkster/angular-realworld-example-app
cd angular-realworld-example-app
npm install
npm run start
http://localhost:4200/

     Aqui temos um aplicativo Angular contendo exemplos "reais" (CRUD, autenticação, etc) de acordo com a especificação para exemplos RealWord.
     Vamos adicionar o Cypress!


Instalação

     Abra outro terminal. Na pasta/angular-realworld-example-app/ execute:

npm install cypress --save-dev
npx cypress -v
     Caso tenha problemas com Proxy ou Firewall, baixe o binário e configure a variável de ambiente antes de instalar:

set CYPRESS_INSTALL_BINARY=C:\cypress.zip
npm install cypress --save-dev --verbose


Removendo o Protactor

     Remova o pacote:

npm uninstall protactor --save-dev
     Exclua a pasta /e2e/
     Do package.json, remova a linha: "e2e": "ng e2e"


Cypress Test Runner

npx cypress open
     O comando "cypress open", além de abrir o Cypress Test Runner, cria a pasta inicial /cypress/ e o arquivo de configuração /cypress.json
     E já vem com /examples/ dos principais comandos Cypress.


Primeiro Teste

     cypress/integrations/exemplo.spec.js

describe('Primeiro Teste', () => {
  it('Exemplos Cypress', () => {
    cy.visit('https://example.cypress.io')
    expect(true).to.equal(true)
  })
})

     describe and it come from Mocha
     expect comes from Chai


Como Rodar

     Para executar todos os testes da pasta /cypress/integration/:

npx cypress run
     Para executar somente um roteiro:
npx cypress run --spec "cypress/integration/examples/example.spec.js"
     Para abrir a interface do Cypress Test Runner:
npx cypress open


Configuração

     cypress.json

{
  "baseUrl": "http://localhost:4200",
  "pageLoadTimeout": 30000,
  "defaultCommandTimeOut": 30000,
  "viewportHeight": 800,
  "viewportWidth": 500,
  "retries": 3
}


Roteiro de Testes

  1. Cadastro
  2. Login
  3. Perfil
  4. Feeds
  5. Paginação
  6. Post
  7. Tags
  8. Comentários
  9. Seguir
  10. Logout

Cypress Recorder

     Extensão para o Chrome capaz de gravar um roteiro base.
     Recomendado para capturar os seletores no DOM.

describe('Conduit Cadastro', () => {
    const usuario = 'usuario' + (new Date()).getTime()
    const senha = 'senha' + (new Date()).getTime()

    it('Novo Usuário', () => {
        cy.visit('/register')
        cy.get('[formcontrolname=username]').type(usuario)
        cy.get('[formcontrolname=email]').type(usuario+'@email.com')
        cy.get('[formcontrolname=password]').type(senha)
        cy.get('.btn').click()
        cy.contains('.nav-item:nth-child(4) > .nav-link', usuario)
            .should('be.visible')
    })
})
npx cypress run --spec "cypress/integration/register.spec.js"


Support Comands

     cypress/support/index.js

Cypress.Commands.add('login', (username, password) => {
  cy.visit('/login')
  cy.url().should('include', '/login')
  cy.get('[formcontrolname=email]').type(username)
  cy.get('[formcontrolname=password]').type(password)
  cy.get('.btn').click()
})

Login

     cypress/integration/login.spec.js

describe('Conduit Login', () => {
    it('Login sucesso', () => {
        cy.login('[email protected]', 'testecypress')
        cy.get('.nav-item:nth-child(4) > nav-link').click()
        cy.get('.btn:nth-child(5)').click()
        cy.url().should('contain', '/settings')
    })

    it('Dados Inválidos', () => {
        cy.login('[email protected]', 'senhaerrada')
        cy.get('.error-messages > li')
            .should('contain', 'email or password is invalid')
    })
})

Perfil

     cypress/integration/perfil.spec.js

describe('Profile', () => {
    it('Editar Perfil', () => {
        cy.login('[email protected]', 'testecypress')
        cy.contains('testecypress').click()
        cy.contains('Edit Profile Settings').click()
        cy.get('[formcontrolname="image"]').clear()
        cy.get('[formcontrolname="image"]')
            .type('https://thispersondoesnotexist.com/image')
        cy.get('[formcontrolname="password"]').type('testecypress')
        cy.contains('Update Settings').click()
    })
})

Feeds

     cypress/integration/feed.spec.js

describe('Conduit Feed', () => {

    it('Ver Feeds', () => {
        cy.login('[email protected]', 'testecypress')
        cy.get('.nav-pills > .nav-item:nth-child(1) > .nav-link').click();
        cy.get('.nav-pills > .nav-item:nth-child(2) > .nav-link').click()
        cy.get('app-article-preview:nth-child(1) .btn').click()
    })
    
})

Pagination

     cypress/integration/pagination.spec.js

describe('Paginação', () => {
    it('Paginar', () => {
        cy.visit('/')
        cy.get('.page-item.active > a').contains('1')
        cy.get('.page-item:nth-child(2) > .page-link').click()
        cy.get('.page-item.active > a').contains('2')
        cy.get('.page-item:nth-child(3) > .page-link').click()
        cy.get('.page-item.active > a').contains('3')
    })
})

Post

     cypress/integration/post.spec.js

describe('Post', () => {

    beforeEach(() => {
        cy.login('[email protected]', 'testecypress')
    })

    it('Novo', () => {
        const tit = 'Cypress E2E'
        cy.contains('New Article').click()
        cy.location('pathname').should('equal', '/editor')
        cy.get('[formcontrolname=title]').type(tit)
        cy.get('[formcontrolname=description]').type('Ponta a Ponta')
        cy.get('[formcontrolname=body]').type('Agilidade, Qualidade')
        cy.contains('Publish Article').click()
        cy.get('h1').contains(tit)
    })

    it('Editar', () => {
        cy.contains('testecypress').click()
        cy.location('pathname').should('contains', '/profile')
        cy.get('.article-preview').get('h1').first().click()
        cy.contains('Edit Article').click()
        cy.get('[formcontrolname=body]').clear()
        cy.get('[formcontrolname=body]').type('Economia')
        cy.contains('Publish Article').click()
        cy.contains('Economia')
    })

})

Tags

     cypress/integration/tags.spec.js

describe('Tags', () => {
    it('Adicionar', () => {
        cy.login('[email protected]', 'testecypress')
        cy.contains('testecypress').click()
        cy.location('pathname').should('contains', '/profile')
        cy.get('.article-preview').get('h1').first().click()
        cy.contains('Edit Article').click()
        cy.get('[placeholder="Enter tags"]').type('dungeons{enter}');
        cy.get('[placeholder="Enter tags"]').type('dragons{enter}');
        cy.contains('Publish Article').click();
        cy.get('.tag-list').contains('dragons');
    })
})

Comentários

     cypress/integration/comentarios.spec.js

describe('Comentarios', () => {
    it('Escrever', () => {
        cy.login('[email protected]', 'testecypress')
        cy.contains('Global Feed').click()
        cy.get('.preview-link').first().click()
        cy.get('.form-control').type('Sensacional!')
        cy.get('.btn-primary').click()
        cy.contains('Sensacional!')
    })
})

Seguir

     cypress/integration/seguir.spec.js

describe('Seguir', () => {
    it('Seguir Usuário', () => {
        const usuario = 'usuario'+(new Date()).getTime();
        const senha = 'senha'+(new Date()).getTime();
        cy.visit('/register', { timeout: 10000 })
        cy.get('[formcontrolname=username]').type(usuario)
        cy.get('[formcontrolname=email]').type(usuario+'@email.com')
        cy.get('[formcontrolname=password]').type(senha)
        cy.get('.btn').click()
        cy.wait(10000)
        cy.visit('/profile/testecypress')
        cy.contains('Folow').click()
    })
})

Logout

     cypress/integration/logout.spec.js

describe('Logout', () => {
    it('Logout via Perfil', () => {
        cy.login('[email protected]', 'testecypress')
        cy.contains('Settings').click()
        cy.url().should('include', '/settings')
        cy.get('.btn-outline-danger').click()
    })
})

Fixture: Data-Driven Tests

     cypress/support/index.js

Cypress.Commands.add('loadUsers', () => {
  cy.fixture('users')
    .as('users')
})

     cypress/integration/test.spec.js

// this.users.default.username
// this.users.default.pass
// this.users.client.username
// this.users.client.pass

     cypress/fixtures/users.json

{
  "default":{
    "user": "basic-user",
    "pass": "testpass"
  },
  "client":{
    "user": "premium-user",
    "pass": "testpass"
  }
}

     Plugins

     Funcionalidades extendidas


Relatórios e Integrações

     Reports json, html e xml

  • mocha
  • mochawesome
  • mochawesome-merge
  • mochawesome-report-generator
  • cypress-multi-reporters
  • cypress-slack-reporter
  • cypress-sonarqube-reporter

Falso Negativo

     Rede, microserviços e dependências podem falhar
     Um teste E2E pode falhar por conta de outros recursos além do controle da sua aplicação:

  • Uma API pode falhar
  • Insdisponibilidade de Rede ou Firewall
  • Indisponibilidade de recursos como CPU e memória
  • Deploys paralelos

Como Identificar?

     Verifique se os as apis e serviços estão rodando:

it('Backend Health Checks', () => {
  
  cy.request('https://login/healthcheck').then((response) => {
    expect(response.status).to.eq(200)
  })
  
  cy.request('https://database/healtcheck')
    .then((response) => {
    expect(response.status).to.eq(200)
  })  

})

DevOps

Environments:

  • CYPRESS_BASE_URL
  • CYPRESS_VIDEO_COMPRESSION
  • CYPRSS_REPORTER
  • CYPRESS_INSTALL_BINARY
  • CYPRESS_RECORD_KEY
# cypress/Dockerfile

# Imagem base
FROM cypress/base:14.0.0

# Copia os arquivos para a imagem
COPY ./

# Opcional - Pega o binário local
#ENV CYPRESS_INSTALL_BINARY=/cypress.zip

RUN npm install --verbose
RUN $(npm bin)/cypress verify

# Inicialização do container
CMD $(npm bin)/cypress run
# prompt / terminal

docker build -t cypress:0.0.1
docker run cypress:0.0.1

Paralelismo

cypress run --parallel --record

Cypress Dashboard

cypress run --record --key=abc123

+ exemplos

1 - Cypress Kitchen Sink

git clone
https://github.com/cypress-io/cypress-example-kitchensink.git

cd cypress-example-kitchensink
npm install
npm start
npm run cy:open

2 - Cypress Real Word App

git clone
https://github.com/cypress-io/cypress-realworld-app.git

cd cypress-realworld-app
npm install
npm dev
npm run cypress:open

     Cheatsheet Mocha
     Cheatsheet Chai
     Cheatsheet Cypress

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.