├── .gitignore ├── LICENSE ├── README.md ├── lessons ├── 0.md ├── 01.md ├── 02.md ├── 03.md ├── 04.md ├── 05.md ├── 06.md ├── 07.md ├── 08.md ├── 09.md ├── 10.md ├── 11.md ├── 12.md ├── 13.md ├── 14.md ├── 15.md ├── 16.md ├── 17.md ├── 18.md ├── 19.md ├── 20.md ├── 21.md ├── _course-structure_.md ├── _pre-requisites_.md ├── _the-app_.md ├── assets │ └── cypress-simulator.png └── congratulations.md ├── package.json └── src ├── index.html ├── script.js └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | cypress.env.json 4 | cypress/downloads/ 5 | cypress/screenshots/ 6 | cypress/videos/ 7 | 8 | node_modules/ 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Walmyr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # _Cypress Simulator_ 2 | 3 | 👋 Seja bem-vindo(a)! 4 | 5 | É muito bom tê-lo(a) aqui. Tenho certeza que você vai amar esse curso. ❤️ 6 | 7 | ## O que você vai aprender? 8 | 9 | - Como planejar quais testes devem ser implementados e em que orderm 10 | - Como garantir testes estáveis 11 | - Como lidar com esperas aleatórias 12 | - Como lidar com _captcha_ 13 | - Como lidar com _banners_ de consentimento de _cookies_ 🍪 14 | - Como criar diferentes comandos customizados 15 | - Como otimizar testes com a criação e restauração da sessão do usuário 16 | - Como criar testes de acessibilidade automatizados 17 | - Como utilizar _feature flags_ em testes automatizados 18 | - Como configurar uma esteira de integração contínua onde os testes sejam executados em paralelo 19 | - Como configurar _test retries_ 20 | - Como gerar artefatos para ajudar na depuração de falhas na integração contínua 21 | 22 | ## Vamos começar? 23 | 24 | Vá para a seção [estrutura do curso](./lessons/_course-structure_.md). 25 | 26 | ___ 27 | 28 | Este é um curso da [**Escola Talking About Testing**](https://talking-about-testing.vercel.app/). 29 | -------------------------------------------------------------------------------- /lessons/0.md: -------------------------------------------------------------------------------- 1 | # Fork e clone do projeto 🐑 2 | 3 | 1. Abra o navegador e visite a URL https://github.com/wlsf82/curso-cypress-simulator. 4 | 2. Faça um [fork]((https://docs.github.com/pt/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)) do projeto. 5 | 6 | > 👨‍🏫 É importante que você trabalhe em seu fork, para que ao final do curso, você possa executar os testes em um _workflow_ de integração contínua. 7 | 8 | 3. Em seu fork, clique no botão **Code**, escolha a opção _clone via SSH_ e copie o link de clone do projeto. 9 | 10 | > Para obter detalhes sobre como criar e configurar uma chave SSH no GitHub, leia a [documentação oficial](https://docs.github.com/pt/authentication/connecting-to-github-with-ssh/about-ssh). 11 | 12 | 4. Em seu terminal de linha de comando (em uma pasta onde você armazena seus projetos de software), execute o comando `git clone [cole-o-link-copiado-aqui]`. 13 | 14 | > 👨‍🏫 Para garantir que você está clonando seu fork corretamente, verifique seu nome de usuário do GitHub na URL de clone do projeto. Deve ser semelhante a `git@github.com:[seu-nome-de-usuário-aqui]/curso-cypress-simulator.git`. 15 | 16 | 5. Após clonar o projeto, acesse o diretório recém-clonado (`cd curso-cypress-simulator/`). 17 | 18 | > **Obs.:** Dentro do diretório `curso-cypress-simulator/`, você deve ter os subdiretórios `.git/` (diretório oculto), `lessons/` e `src/`, e os arquivos `.gitignore` (arquivo oculto), `LICENSE`, `package.json` e `README.md`. 19 | > 20 | > Dentro do diretório `src/`, você deverá ver os arquivos `index.html`, `script.js` e `style.css`. Este é o código fonte da aplicação em teste. 21 | 22 | ## Instalação e inicialização do [Cypress](https://cypress.io) 🌲 23 | 24 | 1. Na raiz do projeto, execute o comando `npm install cypress@13.17.0 --save-dev` (ou `npm i cypress@13.17.0 -D` para a versão curta). 25 | 2. Execute o comando `npx cypress open` para abrir o Cypress pela primeira vez e deixe-o guiá-lo na criação de uma suite de testes de ponta a ponta (E2E). 26 | 3. Por fim, com a _Cypress App_ aberta, crie um arquivo chamado `cypress-simulator.cy.js` e feche a _Cypress App_. 27 | 28 | > **Obs. 2:** Quando iniciado pela primeira vez, o Cypress cria automaticamente o arquivo `cypress.config.js` e o diretório `cypress/`, com os subdiretórios `e2e/`, `fixtures/` e `support/`, com seus respectivos arquivos. 29 | > 30 | > 👨‍🏫 É importante instalar a exata versão do Cypress descrita acima (`13.17.0`) visto que apesar de no momento da escrita desta aula a versão `14.0.0` do Cypress já estar disponível, ela é incompatível com a versão `1.5.0` da biblioteca `cypress-axe`, que será utilizada para os testes de acessibilidade. 31 | > 32 | > 👨‍🏫 Para usar o Cypress versão 14, é necessário aguardar o _merge_ do seguinte [_pull request_](https://github.com/component-driven/cypress-axe/pull/180), e então, o lançamento de uma nova versão do `cypress-axe`, compatível com a versão 14 do Cypress. 33 | 34 | ## Configuração extra 35 | 36 | 1. Atualize o arquivo `cypress.config.js` da seguinte maneira. 37 | 38 | ```js 39 | const { defineConfig } = require("cypress") 40 | 41 | module.exports = defineConfig({ 42 | viewportHeight: 1024, 43 | viewportWidth: 1700, 44 | e2e: { 45 | fixturesFolder: false, 46 | }, 47 | }) 48 | 49 | ``` 50 | 51 | > 👨‍🏫 Com a configuração acima, estamos "dizendo" ao Cypress que substituiremos as [dimensões de altura e largura padrão do Cypress](https://docs.cypress.io/api/commands/viewport#Defaults), além de não usarmos a pasta `cypress/fixtures/`. 52 | 53 | 2. Delete a pasta `cypress/fixtures/` visto que a mesma não será usada. 54 | 3. Pronto! 55 | 56 | ___ 57 | 58 | Parabéns! vamos para a [lição 1](./01.md) para organizar os testes que iremos implementar ao longo do curso. 59 | -------------------------------------------------------------------------------- /lessons/01.md: -------------------------------------------------------------------------------- 1 | # Planejamento de testes 2 | 3 | Ao iniciar um projeto de testes automatizados (ou evoluir um projeto existente), gosto de começar me fazendo as seguintes perguntas: 4 | 5 | 1. "Qual a funcionalidade principal da aplicação, àquela que se não funcionar, não atende às necessidades dos/as usuários/as?" 6 | 2. "Quais casos de teste serão implementados?" 7 | 3. "Quais testes são mais importantes e devem ser priorizados?" 8 | 4. "Quais testes podem ficar para depois?" 9 | 5. "Que tipos de testes serão escritos? _End-to-end_? _A11y_?" 10 | 11 | Ao responder estas perguntas, tenho _insights_ valiosos para dar início ao que chamo de **processo criativo na escrita de testes automatizados**. 12 | 13 | Depois, começo um processo exploratório da aplicação (ou funcionalidade) que será testada. 14 | 15 | Neste momento, além de descobrir como a aplicação se comporta atualmente, descubro também casos alternativos, os quais, às vezes, podem ser esquecidos durante o desenvolvimento da aplicação. 16 | 17 | Então, sem mais delongas, abro o editor de código e começo a escrever um "esqueleto" 💀 da suíte de testes. Só as descrições dos casos de teste, sem detalhes de implementação. 18 | 19 | ## Conteúdo sugerido 📚 20 | 21 | - [Estruturando a suíte de testes e seus respectivos casos de teste com Cypress](https://talkingabouttesting.com/2024/08/26/estruturando-a-suite-de-testes-e-seus-respectivos-casos-de-teste-com-cypress/) 22 | 23 | ## Exercício 🎯 24 | 25 | Com base no processo (e no conteúdo) sugeridos acima, crie um "esqueleto" dos testes que você considera essenciais para garantir que a aplicação _Cypress Simulator_ funciona conforme o esperado, dando assim confiança ao time de que, se todos os testes estiverem verdes, a mesma pode ser entregue em produção para o uso. 26 | 27 | ## Mostre ao mundo o que você aprendeu 🌎 28 | 29 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 30 | 31 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde aprendi um processo de planejamento de testes automatizados prático, o qual me ajuda a priorizar os testes mais importantes e ter algo concreto para trabalhar. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 32 | > 33 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 34 | 35 | ___ 36 | 37 | Parabéns! 🎉 Vamos para a [lição 2](./02.md) para preencher as lacunas e começar a implementar os testes que planejamos. 38 | -------------------------------------------------------------------------------- /lessons/02.md: -------------------------------------------------------------------------------- 1 | # Implementando o caso de teste mais importante 2 | 3 | Em vez de uma competição de quem pensa ou escreve mais casos de teste, é importante pensar bem e implementar antes de mais nada o caso de teste mais importante, àquele essencial, o qual, se não estiver passando, não atende às necessidades primárias dos/as usuários/as do software. 4 | 5 | Na aplicação _Cypress Simulator_, tal caso de teste é o caso em que após autenticado/a no sistema, o/a usuário/a consegue executar a simulação de um comando do Cypress com sucesso. 6 | 7 | No entanto, para testar o cenário de sucesso, o/a usuário/a deve primeiro efetuar login. Ou seja, o cenário de sucesso possui uma pré-condição, a qual deve ser atendida antes da implementação do teste propriamente dito. 8 | 9 | Além disso, por questões de segurança um ["Captcha"](https://pt.wikipedia.org/wiki/CAPTCHA) deve ser resolvido após o login, porém, Captchas são feitos para que não possam ser resolvidos por "robôs". 🤖 10 | 11 | E agora? 12 | 13 | Uma alternativa sugerida quando lidando com Captchas em testes automatizados é o uso de uma _feature flag_ que desliga o Captcha durante a execução dos testes automatizados. No entanto, tal mecanismo precisa ser implementado, ou seja, o time que desenvolveu a aplicação deve ter pensado na "testabilidade" da mesma. 14 | 15 | Para sua "sorte", a aplicação _Cypress Simulator_ possui tal mecanismo. Basta passar a _feature flag_ `skipCaptcha=true` como parâmetro da URL e pula-se tal etapa. 16 | 17 | ## Exercício 1 🎯 18 | 19 | Visto que o login é uma pré-condição para o teste, não parte do teste propriamente dito, é melhor isolá-lo com o [_hook_](https://docs.cypress.io/app/core-concepts/writing-and-organizing-tests#Hooks) `beforeEach`, o qual é executado antes de cada bloco `it` (cada caso de teste). 20 | 21 | Portanto, dentro da função de _callback_ do _hook_ `beforeEach`, implemente os passos necessários para a realização do login, pulando a etapa do Captcha com o uso da _feature flag_ citada acima. 22 | 23 | > 👨‍🏫 Tal etapa será valiosa, pois muitos dos outros testes que escreveremos necessitarão do/a usuário/a já autenticado/a, e ao definir tais passos no `beforeEach`, não precisaremos mais se preocupar com isso. 24 | 25 | ## Exercício 2 🎯 26 | 27 | Após o login, o/a usuário/a já pode interagir com a aplicação, no entanto, ainda há algo que por vezes pode atrapalhar nos testes. 28 | 29 | O _banner_ de consentimento de _cookies_. 30 | 31 | E se tal _banner_ ficar na frente de algum elemento com o qual o teste precisa interagir, como uma área de texto ou um botão? 32 | 33 | Seria melhor fechar tal _banner_, não? 34 | 35 | Mas ter que clicar em _Accept_ ou _Decline_ antes de cada teste seria um passo a mais, um passo que adicionaria algum tempo a mais na execução dos testes, por mais que mínimo. 36 | 37 | E se pudéssemos pular essa etapa também? 38 | 39 | Ao clicar em _Accept_ ou _Decline_, uma _key_ chamada `cookieConsent` é adicionada ao _local storage_ com um dos seguintes valores: `accepted` ou `declined`. 40 | 41 | A parte boa é que o comando [`cy.visit`](https://docs.cypress.io/api/commands/visit) do Cypress pode receber além da URL da aplicação como primeiro parâmetro, um objeto de _options_, como segundo parâmetro, e tal objeto, pode conter a opção `onBeforeLoad`, para a qual pode ser passada [uma função de _callback_ que é chamada antes da página carregar](https://docs.cypress.io/api/commands/visit#Provide-an-onBeforeLoad-callback-function). 42 | 43 | Tal função de _callback_ recebe como argumento um objeto que representa a janela do navegador (`window`), e a partir de tal objeto, é possível acessar e definir um item no `localStorage` (veja um exemplo abaixo). 44 | 45 | > 🙊 46 | 47 | ```js 48 | cy.visit("./src/index.html?skipCaptcha=true", { 49 | onBeforeLoad(win) { 50 | win.localStorage.setItem("cookieConsent", "accepted") 51 | } 52 | }) 53 | 54 | ``` 55 | 56 | O _snippet_ de código acima define que os _cookies_ já foram aceitos antes da página carregar, e quando a mesma carrega, o _banner_ não aparece mais. 57 | 58 | Seu exercício é aplicar tal mudança de modo que o _banner_ não seja exibido após o login. 59 | 60 | ## Exercício 3 🎯 61 | 62 | Por fim, implemente o teste que executa uma simulação bem sucedida de um comando do Cypress, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as. 63 | 64 | Ao implementar tal teste, tenha em mente que, ao digitar um comando válido do Cypress e pressionar o botão _Run_, a aplicação _Cypress Simulator_ "simula" uma chamada à um servidor, o qual pode demorar tempos distintos para responder ao _frontend_. 65 | 66 | Por padrão, [comandos de _query_](https://docs.cypress.io/api/table-of-contents#Queries) do Cypress, como [`cy.get`](https://docs.cypress.io/api/commands/get) e [`cy.contains`](https://docs.cypress.io/api/commands/contains), esperam por até 4 segundos antes de falhar, através de um mecanismo chamado [_Retry-ability_](https://docs.cypress.io/app/core-concepts/retry-ability). 67 | 68 | Mas e se esse um servidor demora mais do que 4 segundos para responder? 69 | 70 | Uma alternativa para lidar com tal situação é alterar o _timeout_ padrão de um comando de _query_, como `cy.get` ou `cy.contains`, para um tempo maior. Algo assim: `cy.get("#outputArea", { timeout: 6000 })`. 71 | 72 | Agora sim, vai lá e implementa o teste. 73 | 74 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it successfully simulates a Cypress command (e.g., cy.log('Yay!'))`. 75 | 76 | ### Conteúdo sugerido 77 | 78 | - [Vamos conversar sobre os timeouts do Cypress](https://youtube.com/live/pb4gCXRt_4Y?feature=share) 79 | 80 | ## Mostre ao mundo o que você aprendeu 🌎 81 | 82 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 83 | 84 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing e acabei de implementar o primeiro teste, o qual garante que a funcionalidade principal do aplicação atende às necessidades de seus/suas usuários/as. Além disso, aprendi como utilizar _feature flags_ para pular a etapa de Captcha e também como definir um item direto no _local storage_ para evitar o aparecimento do _banner_ de consentimento de _cookies_. Por fim aprendi como controlar o _timeout_ do Cypress em seus comandos de _query_ para tornar os testes mais robustos. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 85 | > 86 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 87 | 88 | ___ 89 | 90 | Parabéns! 🎉 Vamos para a [lição 3](./03.md) para dar continuidade com os próximos testes. 91 | -------------------------------------------------------------------------------- /lessons/03.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Comando inválido do Cypress 2 | 3 | Outro cenário importante é àquele em que o/a usuário/a tenta simular um comando que não existe no "universo" Cypress. 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo um erro ao tentar executar um comando inválido. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows an error when entering and running an invalid Cypress command (e.g., cy.run())`. 10 | 11 | ## Mostre ao mundo o que você aprendeu 🌎 12 | 13 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 14 | 15 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde estou criando uma suíte de teste para os cenários mais importantes da aplicação, e além de cenários de sucesso, também estou testando cenários de erro. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 16 | > 17 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 18 | 19 | ___ 20 | 21 | Parabéns! 🎉 Vamos para a [lição 4](./04.md) para dar continuidade com os próximos testes. 22 | -------------------------------------------------------------------------------- /lessons/04.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Comando do Cypress não implementado 2 | 3 | Outro cenário importante é àquele em que o/a usuário/a tenta simular um comando do Cypress o qual sua implementação ainda está pendente. 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo um _warning_ ao tentar executar um comando o qual sua simulação ainda não foi implementada. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows a warning when entering and running a not-implemented Cypress command (e.g., cy.contains('Login'))`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 5](./05.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/05.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Comando do Cypress faltando parênteses 2 | 3 | Outro cenário importante é àquele em que o/a usuário/a tenta simular um comando do Cypress, porém, esquece de abrir e fechar os parênteses. 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo um erro ao tentar executar um comando do Cypress sem abrir e fechar os parênteses. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows an error when entering and running a valid Cypress command without parentheses (e.g., cy.visit)`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 6](./06.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/06.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Comando de ajuda 2 | 3 | Outro cenário importante é àquele em que o/a usuário/a executa o comando "especial" de ajuda (_help_). 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo o texto apropriado quando o comando de ajuda é executado. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it asks for help and gets common Cypress commands and examples with a link to the docs`. 10 | 11 | ## Mostre ao mundo o que você aprendeu 🌎 12 | 13 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 14 | 15 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde aprendi como testar um link que abre em outra aba do navegador, sem nem mesmo precisar clicar em tal link. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 16 | > 17 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 18 | 19 | ___ 20 | 21 | Parabéns! 🎉 Vamos para a [lição 7](./07.md) para dar continuidade com os próximos testes. 22 | -------------------------------------------------------------------------------- /lessons/07.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Maximiza e minimiza o resultado de uma simulação 2 | 3 | O último cenário importante é àquele em que o/a usuário/a maximiza e minimiza o resultado de uma simulação. 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo o ícone de minimizar quando no modo maximizado e o ícone de maximizar quando no modo minimizado. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it maximizes and minimizes a simulation result`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 8](./08.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/08.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Efetua _logout_ com sucesso 2 | 3 | Agora que os casos de testes mais importantes foram implementados, que tal partir para outros casos, não essenciais, porém necessários? 4 | 5 | Um deles, por exemplo, é o _logout_ do sistema. 6 | 7 | ## Exercício 🎯 8 | 9 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo o botão de _login_ após o _logout_ bem sucedido. 10 | 11 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it logs out successfully`. 12 | 13 | ___ 14 | 15 | Parabéns! 🎉 Vamos para a [lição 9](./09.md) para dar continuidade com os próximos testes. 16 | -------------------------------------------------------------------------------- /lessons/09.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Exibe e esconde o botão de _logout_ 2 | 3 | Já que implementamos o caso de testes para o _logout_ com sucesso, que tal testar também que o botão de _logout_ é exibido ao abrir o menu "sanduíche" e escondido ao fechá-lo? 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, exibindo e escondendo o botão de _logout_ ao abrir e fechar o menu "sanduíche". 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows and hides the logout button`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 10](./10.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/10.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Estado transitório da simulação de um comando do Cypress 2 | 3 | Outra cenário que talvez seja importante de verificar é o estado transitório da simulação de um comando do Cypress. 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, onde o botão Run muda para "Running...", fica desabilitado, e além disso, o texto "Running... Please wait." é exibido na área de _output_ da simulação, antes do resultado final ser exibido. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows the running state before showing the final result`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 11](./11.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/11.md: -------------------------------------------------------------------------------- 1 | # Casos de teste: _Banner_ de consentimento de _cookies_ 2 | 3 | Apesar de estarmos pulando o _banner_ de consentimento de _cookies_ na maioria dos testes, seria interessante testar que tal _banner_ se comporta conforme o esperado. 4 | 5 | Ou seja, deve haver um cenário para o caso em que o usuário aceita os _cookies_ e outro para quando os rejeita. 6 | 7 | ## Exercício 1 🎯 8 | 9 | Implemente o teste que aceita os _cookies_, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, onde ao ao clicar no botão _Accept_, uma chave chamada `cookieConsent` é definida no _local storage_ com o valor `accepted`. 10 | 11 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it consents on the cookies usage`. 12 | 13 | ## Exercício 2 🎯 14 | 15 | Implemente o teste que rejeita os _cookies_, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, onde ao ao clicar no botão _Decline_, uma chave chamada `cookieConsent` é definida no _local storage_ com o valor `declined`. 16 | 17 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it declines on the cookies usage`. 18 | 19 | ___ 20 | 21 | Parabéns! 🎉 Vamos para a [lição 12](./12.md) para dar continuidade com os próximos testes. 22 | -------------------------------------------------------------------------------- /lessons/12.md: -------------------------------------------------------------------------------- 1 | # Casos de teste: Captcha 2 | 3 | E o Captcha? Apesar de estarmos pulando o Captcha na maioria dos testes, seria interessante testar ao menos os seguintes cenários: 4 | 5 | - Que o botão _Verify_ inicia desabilitado e quando digita-se uma resposta, passa a estar habilitado 6 | - Que quando uma resposta errada é forncida, a mensagem "Incorrect answer, please try again." é exibida, o campo da resposta é limpo, e o botão _Verify_ volta ao modo desabilitado 7 | 8 | ## Exercício 1 🎯 9 | 10 | Implemente o primeiro teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, com as seguintes verificações: 11 | 12 | - O botão inicia desabilitado 13 | - O botão é habilitado ao digitar uma resposta qualquer 14 | - O botão volta ao estado desabilitado ao limpar a resposta 15 | 16 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it disables the captcha verify button when no answer is provided or it's cleared`. 17 | 18 | ## Exercício 2 🎯 19 | 20 | Implemente o segundo teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, com as seguintes verificações: 21 | 22 | - A mensagem de erro é exibida 23 | - O campo da resposta é limpo para que a nova resposta seja digitada 24 | - O botão volta ao estado desabilitado 25 | 26 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it shows an error on a wrong captcha answer and goes back to its initial state`. 27 | 28 | ___ 29 | 30 | Parabéns! 🎉 Vamos para a [lição 13](./13.md) para dar continuidade com os próximos testes. 31 | -------------------------------------------------------------------------------- /lessons/13.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: Estados do botão _Run_ 2 | 3 | E que tal testar também o estado habilitado e desabilitado do botão _Run_? 4 | 5 | ## Exercício 🎯 6 | 7 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, onde o botão _Run_ inicia desabilitado, é habilitado ao digitar um comando do Cypress e volta ao estado desabilitado ao limpar o comando digitado antes da execução da simulação. 8 | 9 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it checks the run button disabled and enabled states`. 10 | 11 | ___ 12 | 13 | Parabéns! 🎉 Vamos para a [lição 14](./14.md) para dar continuidade com os próximos testes. 14 | -------------------------------------------------------------------------------- /lessons/14.md: -------------------------------------------------------------------------------- 1 | # Casos de teste: _Resets_ após o _logout_ e novo _login_ 2 | 3 | Há três outros cenários que também podem ser interessantes de testar, todos relacionados ao _logout_ e um novo _login_. São eles: 4 | 5 | - Que o campo de digitação de um comando do Cypress é limpo após um _logout_ seguido de um novo _login_ 6 | - Que o botão _Run_ é desabilitado após a digitação de um comando do Cypress, o _logout_ e um novo _login_ 7 | - Que o campo de _output_ da simulação de um comando do Cypress é limpo após a execução de um comando do Cypress, o _logout_ e um novo _login_ 8 | 9 | ## Exercício 1 🎯 10 | 11 | Implemente o primeiro teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, garantindo que mesmo que o usuário tenha digitado um comando para execução sem o executá-lo, ao fazer o _logout_ seguido de um novo _login_, o campo é limpo 12 | 13 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it clears the code input when logging off then logging in again`. 14 | 15 | ## Exercício 2 🎯 16 | 17 | Implemente o segundo teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, garantindo que mesmo que o usuário tenha digitado um comando para execução sem o executá-lo, ao fazer o _logout_ seguido de um novo _login_, o botão _Run_ volta no estado desabilitado. 18 | 19 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it disables the run button when logging off then logging in again`. 20 | 21 | ## Exercício 3 🎯 22 | 23 | Implemente o terceiro teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, garantindo que mesmo que o usuário tenha executado a simulação de um comando, ao fazer o _logout_ seguido de um novo _login_, o _output_ da execução é limpo. 24 | 25 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it clears the code output when logging off then logging in again`. 26 | 27 | ___ 28 | 29 | Parabéns! 🎉 Vamos para a [lição 15](./15.md) para dar continuidade com os próximos testes. 30 | -------------------------------------------------------------------------------- /lessons/15.md: -------------------------------------------------------------------------------- 1 | # Caso de teste: _Banner_ de consentimento de _cookies_ não aparece na página de _login_ 2 | 3 | Você já percebeu que o _banner_ de consentimento de _cookies_ não aparece na página de _login_? 4 | 5 | Que tal testar isso também? 6 | 7 | ## Exercício 🎯 8 | 9 | Implemente o teste descrito acima, garantindo que tal funcionalidade atende às expectativas dos/as usuários/as, onde ao acessar a página de _login_, o banner de consentimento de _cookies_ não é exibido. 10 | 11 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it doesn't show the cookie consent banner on the login page`. 12 | > 13 | > 🧑‍🏫 Lembre-se que para esse teste, o item `cookieConsent` não pode estar definido no _local storage_. 14 | > 15 | > 🧑‍🏫 Ah, recomendo a leitura dos conteúdos sugeridos. 16 | 17 | ## Conteúdos sugeridos 📚 18 | 19 | - [`cy.clearAllLocalStorage`](https://docs.cypress.io/api/commands/clearalllocalstorage) 20 | - [`cy.reload`](https://docs.cypress.io/api/commands/reload) 21 | 22 | ## Mostre ao mundo o que você aprendeu 🌎 23 | 24 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 25 | 26 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde aprendi como limpar todos os items do _local storage_ (para testar lógicas como _banner_ de consentimento de _cookies_ 🍪), além de aprender sobre o comando `cy.reaload()` (para testar o recarregamento de uma página web). #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 27 | > 28 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 29 | 30 | ___ 31 | 32 | Parabéns! 🎉 Vamos para a [lição 16](./16.md) para implementar alguns testes de acessibilidade. 33 | -------------------------------------------------------------------------------- /lessons/16.md: -------------------------------------------------------------------------------- 1 | # Testes de acessibilidade com Cypress 2 | 3 | A acessibilidade, frequentemente abreviada como _a11y_ (pelo fato da palavra _accessibility_ ter onze caracteres entre o 'a' e o 'y'), é uma faceta essencial do desenvolvimento de software que visa garantir que produtos e serviços sejam utilizáveis por pessoas com uma variedade de deficiências. Isso inclui deficiências visuais, auditivas, físicas, de fala, cognitivas e neurológicas. 4 | 5 | A acessibilidade é importante não apenas do ponto de vista ético e de inclusão, mas também comercial, pois amplia o público-alvo e cumpre com as regulamentações legais como a Lei Brasileira de Inclusão da Pessoa com Deficiência, a _ADA_ (_Americans with Disabilities Act_) e a _WCAG_ (_Web Content Accessibility Guidelines_). 6 | 7 | No mundo dos testes automatizados web com Cypress, é possível criar testes de acessibilidade, unindo duas ferramentas. São elas: 8 | 9 | - [`axe-core`](https://www.npmjs.com/package/axe-core): Uma biblioteca de teste de acessibilidade que pode ser integrada a várias ferramentas de testes automatizados, incluindo o Cypress. 10 | - [`cypress-axe`](https://www.npmjs.com/package/cypress-axe): Este plugin do Cypress permite incorporar testes de acessibilidade automaticamente em seus testes _end-to-end_ usando a biblioteca `axe-core`. 11 | 12 | ## O que é verificado em testes automatizados de acessibilidade? 13 | 14 | Em testes de acessiblidade automatizados, é possível identificar diferentes problemas de acessiblidade, tais como: 15 | 16 | - Contraste entre cor de fundo e cor da fonte 17 | - Uso de elementos semânticos 18 | - Ordem de cabeçalhos (`h1`, `h2`, ..., `h6`) 19 | - Etc. 20 | 21 | > 👨‍🏫 Vale lembrar que testes automatizados de acessiblidade são limitados ao que é possível encontrar de forma automática, mas isso não descarta outros tipos de testes, tais como testes em par com pessoas com deficiência, testes com leitores de tela, etc. 22 | 23 | ## Passo-a-passo para configurar o plugin `cypress-axe` 24 | 25 | Para iniciar testes automatizados com Cypress e o plugin `cypress-axe`, basta seguir os seguintes passos: 26 | 27 | 1. Instale ambas as bibliotecas `axe-core` e `cypress-axe` como dependências de desenvolvimento (levando em consideração que o `cypress` já esteja instalado), nas versões 4.10.2 e 1.5.0, respectivamente. Assim: `npm i axe-core@4.10.2 cypress-axe@1.5.0 -D` 28 | 2. Importe a biblioteca `cypress-axe` dentro do arquivo `cypress/support/e2e.js`. Assim: `import 'cypress-axe'` 29 | 3. Injete o _Axe_ logo após a visita à URL da aplicação em teste. Assim: `cy.injectAxe()` 30 | 4. Por fim, execute as verificações de acessibilidade em diferentes momentos, enquanto o Cypress roda, utilizando o comando `cy.checkA11y()`. 31 | 32 | ## Exercício 1 🎯 33 | 34 | 1. Primeiro de tudo, siga os passos acima para configurar o plugin `cypress-axe` 35 | 2. Na pasta `cypress/e2e/`, crie um arquivo chamado `a11y.cy.js` 36 | 3. Crie a estrutura básica para a suíte de testes de acessiblidade. Algo assim: 37 | 38 | ```js 39 | describe("Cypress Simulator - A11y Checks", () => { 40 | beforeEach(() => { 41 | cy.visit("./src/index.html?skipCaptcha=true", { 42 | onBeforeLoad(win) { 43 | win.localStorage.setItem("cookieConsent", "accepted") 44 | } 45 | }) 46 | cy.contains("button", "Login").click() 47 | cy.injectAxe() 48 | }) 49 | 50 | it("test case 1", () => {}) 51 | 52 | it("test case 2", () => {}) 53 | 54 | // ... 55 | 56 | it("test case n", () => {}) 57 | }) 58 | 59 | ``` 60 | 61 | 4. Mova os seguintes testes do arquivo `cypress/e2e/cypress-simulator.cy.js` para o arquivo `cypress/e2e/a11y.cy.js`: 62 | 63 | - `it successfully simulates a Cypress command (e.g., cy.log('Yay!'))` 64 | - `it shows an error when entering and running an invalid Cypress command (e.g., cy.run())` 65 | - `it shows a warning when entering and running a not-implemented Cypress command (e.g., cy.contains('Login'))` 66 | - `it asks for help and gets common Cypress commands and examples with a link to the docs` 67 | - `it maximizes and minimizes a simulation result` 68 | - `it logs out successfully` 69 | - `it shows and hides the logout button` 70 | - `it shows the running state before showing the final result` 71 | - `it consents on the cookies usage` ou `it declines on the cookies usage` 72 | - `it disables the captcha verify button when no answer is provided or it's cleared` 73 | - `it shows an error on a wrong captcha answer and goes back to its initial state` 74 | 75 | > 👨‍🏫 A idéia aqui é pegar diferentes estados da aplicação onde pode-se encontrar algum dos problemas de acessibilidade citados anterioremente. 76 | 77 | 5. Siga para o exercício 2 78 | 79 | ## Exercício 2 🎯 80 | 81 | Para cada um dos testes listados abaixo, implemente uma verificação de acessibilidade. 82 | 83 | - `it maximizes and minimizes a simulation result` 84 | - `it logs out successfully` 85 | - `it shows and hides the logout button` 86 | - `it shows the running state before showing the final result` 87 | - `it consents on the cookies usage` ou `it declines on the cookies usage` 88 | 89 | > 👨‍🏫 Pense bem nos diferentes estados da aplicação para que tal verificação seja adicionada no momento correto, como após alguma verificação de resultado esperado intermediária ou final. 90 | > 91 | > 💥 Ao executar a primeira verificação de acessibilidade, você deve perceber um erro (`html-has-lang`). 92 | 93 | Abra o console do navegador, investigue e corrija a falha, e siga adiante somente quando as verificações de acessibilidade estiverem passando. 🕵️ 94 | 95 | ## Exercício 3 🎯 96 | 97 | Junte ambos casos de teste do captcha em um úncio caso de teste, e adicione duas verificações de acessibilidade: uma antes e outra depois da exibição da mensagem de erro. 98 | 99 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it finds no a11y issues on all captcha view states (button enabled/disabled and error)`. 100 | > 101 | > 🙊 Quando o votão _Verify_ não estiver habilitado não precisa de verificação de acessibilidade. Quer saber por quê? Continue lendo. 102 | > 103 | > 👨‍🏫 "Componentes de Interface do Usuário que não estão disponíveis para interação do usuário (por exemplo, um controle desabilitado em HTML) não são necessários para atender aos requisitos de contraste." 104 | > 105 | > Fonte: https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html 106 | 107 | ## Exercício 4 🎯 108 | 109 | Ao executar o teste do exercício anterior, você deve perceber um problema de acessibilidade com relação ao contraste entre a cor de fundo e a cor da fonte da mensagem de erro. 110 | 111 | 1. Abra o arquivo `src/style.css` e procure por 'captcha' 112 | 2. Proponha uma solução para resolver tal problema. 113 | 114 | > 🙊 Altere a cor da fonte (`color`) da mensagem de erro do captcha para `#AB1A0D`. 115 | 116 | ## Exercício 5 🎯 117 | 118 | Para cada um dos testes listados abaixo, implemente uma verificação de acessibilidade, logo após suas verificações de resultado esperado. 119 | 120 | - `it successfully simulates a Cypress command (e.g., cy.log('Yay!'))` 121 | - `it shows an error when entering and running an invalid Cypress command (e.g., cy.run())` 122 | - `it shows a warning when entering and running a not-implemented Cypress command (e.g., cy.contains('Login'))` 123 | - `it asks for help and gets common Cypress commands and examples with a link to the docs` 124 | 125 | > 👨‍🏫 Para experimentar e obter mais experência com o uso do plugin `cypress-axe`, passe um seletor CSS ao comando `cy.checkA11y()`, para verificar que não há problemas de acessibilidade somente na área do resultado da execução de uma simulação de um comando do Cypress, não na página toda. 126 | > 127 | > Não sabe do que estou falando? Leia sobre o [contexto da verificação de acessibilidade direto da documentação oficial do plugin](https://www.npmjs.com/package/cypress-axe#context-optional). 128 | 129 | ## Conteúdos sugeridos 📚 130 | 131 | - [_Playlist_ com conteúdos sobre acessibilidade no Canal TAT no YouTube](https://www.youtube.com/playlist?list=PL-eblSNRj0QH_HJ4lxiWVS9TazxCsA1Ba) 132 | - [Guia WCAG](https://guia-wcag.com/) 133 | - [Livro: Acessibilidade na Web - Boas práticas para construir sites e aplicações acessíveis](https://www.casadocodigo.com.br/products/livro-acessibilidade), do autor [Reinaldo Ferraz](https://reinaldoferraz.com.br/) 134 | - [Podcast Foco Acessivel](https://open.spotify.com/show/4D6HigcXDCdNuCXxrkStWL), por Wagner Beethoven 135 | - [_Newsletter_ do Bruno Pulis](https://brunopulis.com/newsletter/) 136 | 137 | ## Mostre ao mundo o que você aprendeu 🌎 138 | 139 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 140 | 141 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde aprendi como criar testes de acessibilidade automatizados com as bibliotecas `axe-core` e `cypress-axe`. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 142 | > 143 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 144 | 145 | ___ 146 | 147 | Parabéns! 🎉 Vamos para a [lição 17](./17.md) para criar alguns comandos customizados, tanto para o login, quanto para rodar um comando no _Cypress Simulator_. Dessa forma, evitaremos código duplicado ao longo dos testes. 148 | -------------------------------------------------------------------------------- /lessons/17.md: -------------------------------------------------------------------------------- 1 | # Comandos customizados 2 | 3 | No mundo de testes automatizados com Cypress, podemos fazer uso de [comandos customizados]((https://docs.cypress.io/api/cypress-api/custom-commands)) para evitar duplicação de código. 4 | 5 | É possível perceber código duplicado tanto para a lógica do login, quanto para rodar um comando no _Cypress Simulator_. 6 | 7 | Portanto, que tal criarmos comandos customizados para abstratir tais lógicas, remover um monte de código duplicado e ainda deixar o código mais "limpo". 🫧 8 | 9 | A propósito, deixei uma lista de conteúdos sugeridos pra te ajudar, logo após a lista de exercícios. 10 | 11 | ## Conhecendo o comando `cy.session` 12 | 13 | O processo de login da aplicação _Cypress Playground_ é bastante simples, visto que é uma aplicação criada simplesmente para fins de ensino, no entanto, em cenários reais, o processo de login normalmente envolve também o preenchimento de um formulário (com usuário e senha), e cada passo a mais que um teste precisa executar, é mais tempo que o teste leva para rodar. 14 | 15 | No entanto, o Cypress sendo a ferramenta fantástica que é, dispõe de um comando chamado [`cy.session`](https://docs.cypress.io/api/commands/session), o qual, dentre outras coisas, permite a otimização do prcesso de login, onde pode-se autenticar o usuário uma única vez, guardar a sessão de tal usuário no navegador, e quando necessário, restaurar tal sessão sem a necessidade de re-executar os passos do login. 16 | 17 | O comando `cy.session` também permite que a sessão seja compatilhada entre arquivos de teste (`*.cy.js`), com o uso da propriedade `cacheAcrossSpecs`. 18 | 19 | **Fonte:** [_Caching session data across specs_](https://docs.cypress.io/api/commands/session#Caching-session-data-across-specs) 20 | 21 | Por fim, além do comando `cy.session` permitir restaurar uma sessão préviamente criada e compartilhá-la entre _specs_, tal comando também permite validar se a sessão ainda é válida, e caso a sessão tenha sido invalidada (por um processo de logout, por exemplo), possa re-criar a sessão, de forma a fornecer resultados determinísticos durante a execução dos testes. 22 | 23 | > 👨‍🏫 Vale comentar que ao utilizar a funcionalidade `cy.session`, após a criação, restauração, ou re-criação da mesma, o Cypress visita uma página em branco, e portanto, é necessário um novo `cy.vist()` para a URL que deseja-se acessar. 24 | > 25 | > **Fonte:** [_Why are all my Cypress commands failing after calling cy.session()?_](https://docs.cypress.io/api/commands/session#Why-are-all-my-Cypress-commands-failing-after-calling-cysession) 26 | 27 | A propósito, o Canal TAT no YouTube tem uma _playlist_ com vídeos sobre esta funcionalidade e deixei o link na lista de conteúdos sugeridos. 28 | 29 | ## Exercício 1 🎯 - Comando de login que salva a sessão, valida e re-cria caso necessário 30 | 31 | 1. Atualize o arquivo `cypress/support/commands.js` pelo seguinte: 32 | 33 | > 🙊 34 | 35 | ```js 36 | Cypress.Commands.add("login", () => { 37 | const setup = () => { 38 | cy.visit("./src/index.html?skipCaptcha=true") 39 | cy.contains("button", "Login").click() 40 | } 41 | 42 | const validate = () => { 43 | cy.visit("./src/index.html") 44 | cy.contains("button", "Login", { timeout: 1000 }) 45 | .should("not.be.visible") 46 | } 47 | 48 | const options = { 49 | cacheAcrossSpecs: true, 50 | validate 51 | } 52 | 53 | cy.session( 54 | "sessionId", 55 | setup, 56 | options 57 | ) 58 | }) 59 | 60 | ``` 61 | 62 | 2. Atualize os arquivos `cypress/e2e/a11y.cy.js` e `cypress/e2e/cypress-simulator.cy.js` para que façam uso do comando `cy.login()` 63 | 3. Após o login, lembre-se de visitar a URL adequada, dependendo se quer ou não pular o captcha. 64 | 65 | ## Exercício 2 🎯 - Comando `cy.run` 66 | 67 | Crie um comando customizado chamado `cy.run`, o qual recebe como argumento um comando (como uma _string_). Tal comando deve abstrair a lógica de digitar a _string_ recebida como argumento no campo de área de texto (`textarea`), além do clique no botão _Run_. 68 | 69 | > 🙊 70 | 71 | ```js 72 | Cypress.Commands.add('run', cmd => { 73 | cy.get("textarea[placeholder='Write your Cypress code here...']") 74 | .type(cmd) 75 | cy.contains("button", "Run").click() 76 | }) 77 | 78 | ``` 79 | 80 | ## Conteúdos sugeridos 📚 81 | 82 | - [Como criar comandos customizados com Cypress](https://talkingabouttesting.com/2021/02/10/como-criar-comandos-customizados-com-cypress/) 83 | - [Cypress Page Object vs GUI Custom Commands](https://youtu.be/1OkfwHUJ-fk) 84 | - [_Playlist_ cy.session do Canal TAT no YouTube](https://www.youtube.com/playlist?list=PL-eblSNRj0QF1RA4fd9FrDVov_uyYfCAL) 85 | - [Autentique testes mais rápido com o comando cy.session](https://talkingabouttesting.com/2021/08/07/autentique-testes-mais-rapido-com-o-comando-cy-session/) 86 | 87 | ## Mostre ao mundo o que você aprendeu 🌎 88 | 89 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 90 | 91 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, no qual aprendi como criar comandos customizados com Cypress e como criar testes otimizados com uso da funcionalidade cy.session (compartilhando a sessão entre _specs_ e validando e re-criando a sessão quando a mesma é invalidada). #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress 92 | > 93 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 94 | 95 | ___ 96 | 97 | Parabéns! 🎉 Vamos para a [lição 18](./18.md) para implementar uma esteira de integração contínua que executa sempre que mudanças forem enviadas ao GitHub. 98 | -------------------------------------------------------------------------------- /lessons/18.md: -------------------------------------------------------------------------------- 1 | # Integração Contínua 2 | 3 | A integração contínua é uma prática de desenvolvimento de software onde membros de uma equipe integram seu código frequentemente, geralmente cada um fazendo ao menos uma integração diária, o que leva a múltiplas integrações por dia. 4 | 5 | Cada integração é automaticamente verificada por meio de um _build_ (construção do software) e testes automatizados, detectando problemas de integração. 6 | 7 | No ecosistema do GitHub, é possível utilizar o serviço [GitHub Actions](https://github.com/features/actions), o qual permite a criação de um _workflow_ de integração contínua. 8 | 9 | ## Conteúdos sugeridos 📚 10 | 11 | - [Documentação oficial do Cypress sobre GitHub Action](https://docs.cypress.io/guides/continuous-integration/github-actions#Cypress-GitHub-Action) 12 | - [Documentação da imagem cypress-io/github-action no GitHub](https://github.com/cypress-io/github-action#readme) 13 | 14 | ## Exercício 1 🎯 - CI sem paralelização 15 | 16 | 1. Na raiz do projeto, crie um diretório oculto chamado `.github/` e dentro dele, crie um subdiretório chamado `workflows/`. 17 | 18 | > 👨‍🏫 Você deve ter a seguinte estrutura `.github/workflows/` 19 | 20 | 2. Dentro do diretório `.github/workflows/`, crie um arquivo chamado `ci.yml`, com o seguinte conteúdo: 21 | 22 | ```yml 23 | name: End-to-end tests 24 | on: push 25 | jobs: 26 | cypress-run: 27 | runs-on: ubuntu-22.04 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | - name: Cypress run 32 | uses: cypress-io/github-action@v6 33 | 34 | ``` 35 | 36 | **Referência:** https://github.com/cypress-io/github-action#end-to-end-testing 37 | 38 | > 👨‍🏫 O nome do arquivo pode ser qualquer nome aleatório. Eu escolhi `ci` porque significa integração contínua (em inglês - _continuous integration_). 39 | 40 | 3. Com o `git`, adicione todas suas alterações à área de _staging_ (`git add .`). 41 | 4. Faça um commit com a mensagem `Configure the ci workflow` (`git commit -m "Configure the ci workflow"`.) 42 | 5. Envie suas alterações locais para seu fork remoto no GitHub (`git push origin main`.) 43 | 6. Acesse o GitHub e veja suas alterações disparando o _workflow_ (e se tudo der certo, veja seus testes passando). 44 | 45 | ## Exercício 2 🎯 - CI com paralelização 46 | 47 | ### Conteúdos sugeridos específicos do plugin `cypress-split` 📚 48 | 49 | - [Documentação oficial do plugin `cypress-split` no npm](https://www.npmjs.com/package/cypress-split) 50 | - [Aprenda como rodar testes em paralelo na integração contínua usando o plugin cypress-split](https://youtu.be/h4ogzgoHUTg) 51 | 52 | 1. Instale o plugin `cypress-split` como uma dependeência de desenvolvimento: `npm i cypress-split@1.24.7 -D` 53 | 2. Importe o `cypress-split` no arquivo de configurações do Cypress (`cypress.config.js`) e o configure, conforme desmontrado abaixo: 54 | 55 | ```js 56 | const { defineConfig } = require("cypress") 57 | 58 | const cypressSplit = require("cypress-split") 59 | 60 | module.exports = defineConfig({ 61 | viewportHeight: 1024, 62 | viewportWidth: 1700, 63 | e2e: { 64 | fixturesFolder: false, 65 | setupNodeEvents(on, config) { 66 | cypressSplit(on, config) 67 | return config 68 | } 69 | }, 70 | }) 71 | 72 | ``` 73 | 74 | 3. Atualize o arquivo `.github/workflows/ci.yml` conforme abaixo": 75 | 76 | ```yml 77 | name: End-to-end tests 78 | on: push 79 | jobs: 80 | tests: 81 | runs-on: ubuntu-22.04 82 | strategy: 83 | fail-fast: false 84 | matrix: 85 | containers: [1, 2] 86 | steps: 87 | - name: Checkout 88 | uses: actions/checkout@v4 89 | - name: Run Cypress tests in parallel 🧪 90 | uses: cypress-io/github-action@v6 91 | env: 92 | SPLIT: ${{ strategy.job-total }} 93 | SPLIT_INDEX: ${{ strategy.job-index }} 94 | 95 | ``` 96 | 97 | 4. Com o `git`, adicione todas suas alterações à área de _staging_ (`git add .`). 98 | 5. Faça um commit com a mensagem `Configure cypress-split` (`git commit -m "Configure cypress-split"`.) 99 | 6. Envie suas alterações locais para seu fork remoto no GitHub (`git push origin main`.) 100 | 7. Acesse o GitHub e veja suas alterações disparando o _workflow_ (e se tudo der certo, veja seus testes passando), onde dessa vez, ambos os arquivos da pasta `cypress/e2e/` serão executados em paralelo, otimizando o _feedback loop_. 101 | 102 | ## Exercício 3 🎯 - Artefatos 103 | 104 | 1. Atualize o arquivo `.github/workflows/ci.yml` conforme abaixo": 105 | 106 | ```yml 107 | name: End-to-end tests 108 | on: push 109 | jobs: 110 | tests: 111 | runs-on: ubuntu-22.04 112 | strategy: 113 | fail-fast: false 114 | matrix: 115 | containers: [1, 2] 116 | steps: 117 | - name: Checkout 118 | uses: actions/checkout@v4 119 | - name: Run Cypress tests in parallel 🧪 120 | uses: cypress-io/github-action@v6 121 | env: 122 | SPLIT: ${{ strategy.job-total }} 123 | SPLIT_INDEX: ${{ strategy.job-index }} 124 | - name: Save screenshots in case of failures 125 | uses: actions/upload-artifact@v4 126 | if: failure() 127 | with: 128 | name: cypress-screenshots 129 | path: cypress/screenshots 130 | if-no-files-found: ignore 131 | 132 | ``` 133 | 134 | 2. Acesse o arquivo `src/script.js` e quebre algo de propósito 135 | 3. Adicione todas suas mudanças (`git add .`) 136 | 4. Faça um _commit_ com a mensagem `Configure CI artifacts and break the app` (`git commit -m "Configure CI artifacts and break the app"`) 137 | 5. Envie suas mudanças locais para seu fork remoto no GitHub (`git push origin main`) 138 | 6. Vá até o GitHub e veja suas mudanças disparando o _workflow_ e um (ou mais) teste(s) falhando 139 | 7. Após a execução do _workflow_, baixe a _screenshot_ gerada como artefato para analisar a falha. 140 | 141 | ## Exercício 4 🎯 - Correção da falha 142 | 143 | Corrija a alteração do exercício anterior, rode os comandos `git` necessários, vá até o GitHub e veja sua mudança disparando o _workflow_ novamente (e se tudo der certo, veja todos os testes passando de novo). 144 | 145 | ## Exercício 5 🎯 - _test retries_ 146 | 147 | 1. Atualize o arquivo de configurações do Cypress (`cypress.config.js`) conforme abaixo: 148 | 149 | ```js 150 | const { defineConfig } = require("cypress") 151 | 152 | const cypressSplit = require("cypress-split") 153 | 154 | module.exports = defineConfig({ 155 | viewportHeight: 1024, 156 | viewportWidth: 1700, 157 | e2e: { 158 | fixturesFolder: false, 159 | retries: { 160 | runMode: 2, 161 | openMode: 0, 162 | }, 163 | setupNodeEvents(on, config) { 164 | cypressSplit(on, config) 165 | return config 166 | } 167 | }, 168 | }) 169 | 170 | ``` 171 | 172 | 2. Para provar que os `retries` funcionam, altere o teste que simula a execução de um comando do Cypress com sucesso para que esteja dentro do seguinte comando: 173 | 174 | ```js 175 | Cypress._.times(100, () => { 176 | 177 | }) 178 | 179 | ``` 180 | 181 | 3. Adicione todas suas mudanças (`git add .`) 182 | 4. Faça um _commit_ com a mensagem `Run the same test a hundred times` (`git commit -m "Run the same test a hundred times"`) 183 | 5. Envie suas mudanças locais para seu fork remoto no GitHub (`git push origin main`) 184 | 6. Vá até o GitHub e veja suas mudanças disparando o _workflow_ e tal teste sendo executado cem vezes, e caso ele venha a falhar, será re-tentado, evitando quebrar o _pipeline_. 185 | 186 | ## Conteúdos sugeridos da TAT 📚 187 | 188 | - [_Playlist_ de Integração Contínua no Canal TAT no YouTube](https://www.youtube.com/playlist?list=PL-eblSNRj0QHgzdWNkGks9_JdhV9iAwFr) 189 | - [Categoria Integração Contínua no blog Talking About Testing](https://talkingabouttesting.com/category/integracao-continua/) 190 | - [Como rodar um teste várias vezes com Cypress para provar que ele é estável](https://talkingabouttesting.com/2021/02/06/como-rodar-um-teste-varias-vezes-com-cypress-para-provar-que-ele-e-estavel/) 191 | 192 | ## Mostre ao mundo o que você aprendeu 🌎 193 | 194 | Para mostrar à sua rede profissional o que você aprendeu nesta aula, publique o seguinte no LinkedIn. 195 | 196 | > Estou fazendo o curso "_Cypress Simulator_" da escola online Talking About Testing, onde aprendi como configurar uma esteira de integração contínua para garantir que mudanças que quebram a aplicação são identificadas automaticamente por uma suíte de testes, como configurar _test retries_ para evitar resultados falsos negativos, como rodar tais testes em paralelo para otimizar o _feedback loop_, e por fim, como gerar artefatos de testes, tais como _screenthos_, para ajudar na depuração de problemas. #TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress #GitHubActions 197 | > 198 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 199 | 200 | ___ 201 | 202 | Parabéns! 🎉 Vamos para a [lição 19](./19.md) para criarmos um último teste, de maneira a aumentar a cobertura de testes da aplicação _Cypress Simulator_. 203 | -------------------------------------------------------------------------------- /lessons/19.md: -------------------------------------------------------------------------------- 1 | # Aumentando a cobertura da aplicação _Cypress Simulator_ 2 | 3 | Ao trabalhar no último exercício da aula anterior, você deve ter percebido um cenário novo, no qual, às vezes, a simulação de um comando do Cypress não funciona e gera "um erro na Matrix". 4 | 5 | > 👨‍🏫 Caso não tenha percebido, coloque um `.only` no teste que simula a execução de um comando do Cypress com sucesso e execute-o localmente utilizando a Cypress App. 6 | 7 | No entanto, isso é só a simulação de um erro, criada exatamente para te ensinar sobre a fucionalidade de _test retries_. 8 | 9 | A idéia foi simular o que ocorreria quando, por exemplo, uma API da qual o _frontend_ depende esteja "fora do ar". 10 | 11 | Implementei tal simulação de erro de forma que ela ocorra somente em um por cento dos casos, por isso que no exercício anterior executamos o mesmo teste cem vezes. 12 | 13 | E quando eu criei tal simulação, também a criei de forma que seja possível alterar esse percentual, com o uso da _feature flag_ `chancesOfError`. 14 | 15 | - Se `chancesOfError=0`, o erro nunca vai ocorrer 16 | - Se `chancesOfError=1`, o erro vai ocorrer em 100% dos casos 17 | - Se `chancesOfError=0.5`, o erro vai ocorrer em 50% dos casos 18 | - E assim por diante. 19 | 20 | ## Exercício 1 🎯 - `chancesOfError=0` 21 | 22 | Teu exercício é: 23 | 24 | - Remover o teste que simula a execução de um comando do Cypress com sucesso de dentro do `Cypress._.times()` 25 | - Alterar sua pre-condição (o `cy.visit` que vem logo após o login) para que tal erro nunca ocorra 26 | - Para isso, use a _feature flag_ `chancesOfError=0` 27 | 28 | > 👨‍🏫 Lembre-se de versionar as mudanças com o git e enviá-las ao GitHub. 29 | > 30 | > 👨‍🏫 Caso necessário, adicione a _feature flag_ `chancesOfError=0`em algum outro teste o qual possa falhar pelo "erro na Matrix". 31 | 32 | ## Exercício 2 🎯 - `chancesOfError=1` 33 | 34 | Agora, implemente o teste que exibe um erro sempre que a simulação de um comando do Cypress seja executada. 35 | 36 | > 🧑‍🏫 Aqui vai uma sugestão de descrição para o caso de teste: `it errors out with a glitch in the Matrix`. 37 | > 38 | > 🧑‍🏫 Este teste pode ser implementado no arquivo `cypress/e2e/cypress-simulator.cy.js`. 39 | > 40 | > 🙊 Lembre-se que para garantir que o erro sempre vai ocorrer, deve-se usar a _feature flag_ `chancesOfError` igual a `1`. 41 | > 42 | > 👨‍🏫 Lembre-se de versionar as mudanças com o git e enviá-las ao GitHub. 43 | 44 | ___ 45 | 46 | Parabéns! 🎉 Vamos para a [lição 20](./20.md) para eu te apresentar algumas outras iniciativas da Talking About Testing. 47 | -------------------------------------------------------------------------------- /lessons/20.md: -------------------------------------------------------------------------------- 1 | # Serviços da Talking About Testing 2 | 3 | Agora que você chegou até aqui, queria te convidar pra conhecer alguns outros serviços da TAT, os quais te levarão mais longe em sua jornada como profissional da área de engenharia de software. 4 | 5 | ## [Assinatura Talking About Testing](https://talkingabouttesting.com/assinatura-talking-about-testing/) 6 | 7 | Transforme sua carreira com a Assinatura Talking About Testing, uma experiência prática e exclusiva para profissionais de qualidade e engenharia de software. 🚀 8 | 9 | A Assinatura Talking About Testing é um serviço exclusivo, limitado a 100 participantes, criado para profissionais que desejam aprofundar seus conhecimentos em qualidade e engenharia de software. 10 | 11 | Aqui, você terá acesso a conteúdos práticos e atualizados, uma comunidade colaborativa e mentoria ao-vivo com o Walmyr. 12 | 13 | ## [Test Design Masterclass](https://talkingabouttesting.com/test-design-masterclass/) 14 | 15 | Aumente sua senioridade e evolua em sua carreira. 🚀 16 | 17 | A Test Design Masterclass da Talking About Testing é uma mentoria em grupo focada no ensino de design de testes automatizados e é destinada para profissionais que querem atingir novos patamares de senioridade para evoluírem em suas carreiras. 18 | 19 | A mentoria consiste em quatro encontros, com aproximadamente duas horas de duração cada, sendo um encontro por final de semana, contabilizando um mês. 20 | 21 | Durante o programa, o instrutor (Walmyr) abordará design de software com foco em automação de testes, com base na metodologia do livro _A philosophy of Software Design_, do autor John Ousterhout (professor do curso de ciência da computação na universidade de Stanford, nos Estados Unidos da América). 22 | 23 | ## [Mentoria Individual](https://talkingabouttesting.com/servicos/mentoria-coaching/) 24 | 25 | Precisa de ajuda para se desenvolver profissionalmente? 26 | 27 | Com o serviço de mentoria individual, mentor e mentorado(a) se reúnem quinzenalmente (de forma virtual) por um período de 1 a 3 meses. 28 | 29 | Através dessas reuniões, lhe ajudo no desenvolvimento profissional relacionado a área de engenharia software (incluindo questões relacionadas a DevOps, qualidade, testes automatizados, etc.) com base em seus objetivos. 30 | 31 | ___ 32 | 33 | Vamos para a [lição 21](./21.md). Vou te apresentar alguns conteúdos que mantenho, específicos sobre Cypress. 34 | -------------------------------------------------------------------------------- /lessons/21.md: -------------------------------------------------------------------------------- 1 | # Conteúdos de Cypress da Talking About Testing 📚 2 | 3 | Pra te ajudar nas tuas aventuras com Cypress, tenho criado conteúdos dos mais diversos tipos, desde [_blog posts_](https://talkingabouttesting.com) em formato de tutoriais, _lives_ no [YouTube](https://youtube.com/@talkingabouttesting), vídeos "mão-na-massa" e entrevistas com profissionais sobre o uso da ferramenta. 4 | 5 | Deixo aqui cada um deles, como fonte de estudo auxiliar ao curso. 6 | 7 | ## Pitadas de Cypress 8 | 9 | Na [categoria Cypress no blog Talking About Testing](https://talkingabouttesting.com/category/cypress/), você vai encontrar conteúdos no formato de tutoriais sobre como resolver os mais diversos problemas utilizando Cypress. 10 | 11 | ## `cy.handsOn()` 12 | 13 | A _playlist_ [`cy.handsOn()`](https://www.youtube.com/playlist?list=PL-eblSNRj0QHIRCg9hYUYzSY87EyWo4k_) é parecida com as "pitadas de Cypress" do blog, porém, em vez de texto, são tutoriais em formato de vídeo. 14 | 15 | ## `cy.chat()` 16 | 17 | Na _playlist_ [`cy.chat()`](https://www.youtube.com/playlist?list=PL-eblSNRj0QH95Kx6iMR_Fwk5WsCM89Ha), entrevisto profissionais que usam Cypress, onde estas (e estes) compartilham suas experiências sobre o uso da ferramenta. 18 | 19 | > 👨‍🏫 Nesta _playlist_, você encontrará conteúdos em português e em inlgês, inclusive, entrevistas com outras(os) [embaixadoras(es) do Cypress.io](https://www.cypress.io/ambassadors/). 20 | 21 | ## Explorando a Cypress _Real-World App_ (_RWA_) 22 | 23 | Quando comecei a fazer _lives_ no YouTube, [quatro delas](https://youtube.com/playlist?list=PL-eblSNRj0QGU6gO4Yhb27ZwaCASG-lQl) foram: explorando os testes _end-to-end_; testes de API; testes de unidade; e a integração contínua da [Cypress RWA](https://github.com/cypress-io/cypress-realworld-app). 24 | 25 | ## Explorando os exemplos do Cypress 26 | 27 | Além disso, fiz uma _playlist_ de [seis episódios](https://youtube.com/playlist?list=PL-eblSNRj0QFFRzKi2GP0U-I5xFlUHW5E), exploranado diversos exemplos criados pelo time do Cypress. 28 | 29 | ## _API Testing_ 30 | 31 | [Nesta _playlist_](https://www.youtube.com/playlist?list=PL-eblSNRj0QGkMqsqxUvy7VI4VfXEUp-G), você vai encontrar vídeos "mão-na-massa" dos mais diversos no que diz respeito a testes de API com Cypress. 32 | 33 | ## `cy.session` 34 | 35 | [Nesta _playlist_](https://www.youtube.com/playlist?list=PL-eblSNRj0QF1RA4fd9FrDVov_uyYfCAL), você vai encontrar conteúdos "mão-na-massa" sobre o uso da funcionalidade [`cy.session()`](https://docs.cypress.io/api/commands/session) do Cypress. 36 | 37 | ## `cy.origin` 38 | 39 | [Nesta _playlist_](https://youtube.com/playlist?list=PL-eblSNRj0QGTdVBmyETrANxfWdDWo5LV), você vai encontrar conteúdos "mão-na-massa" sobre o uso da funcionalidade [`cy.origin()`](https://docs.cypress.io/api/commands/origin) do Cypress. 40 | 41 | ___ 42 | 43 | > Além disso, o [Canal TAT](https://www.youtube.com/@TalkingAboutTesting/playlists) também possui _playlists_ de [Integração Contínua](https://www.youtube.com/playlist?list=PL-eblSNRj0QHgzdWNkGks9_JdhV9iAwFr), [JavaScript para QAs](https://www.youtube.com/playlist?list=PL-eblSNRj0QH36XrwvGfhh14GjpG-ViS2), [Seletores CSS para QAs](https://www.youtube.com/playlist?list=PL-eblSNRj0QHGg3iE2HAtOkzIyNH9DSjL), [_a11y_](https://www.youtube.com/playlist?list=PL-eblSNRj0QH_HJ4lxiWVS9TazxCsA1Ba), [_flaky tests_](https://www.youtube.com/playlist?list=PL-eblSNRj0QEbv8BKEpjLREshG0fg3VKr), [Carreira em Qualidade de Software](https://www.youtube.com/playlist?list=PL-eblSNRj0QEFTDuBqAgIN1H6vRViVLRL), [Contribuindo com projetos _open-source_](https://www.youtube.com/playlist?list=PL-eblSNRj0QEWVVNZJRfJX_H_m-Bd0IXY), [_English Content_](https://www.youtube.com/playlist?list=PL-eblSNRj0QFCgBuHFSSJUeEYDm6wwvHI) e muito mais. 44 | 45 | ___ 46 | 47 | Uau! Você merece uma medalha por ter chego até aqui. 🥇 48 | 49 | Vá para a [próxima aula](./congratulations.md) para recapitularmos tudo que você aprendeu. 50 | -------------------------------------------------------------------------------- /lessons/_course-structure_.md: -------------------------------------------------------------------------------- 1 | # Estrutura do curso 📜 2 | 3 | Abaixo você encontrará tudo o que precisa saber para aproveitar 💯% do conteúdo do curso. 4 | 5 | ## Conceito e exemplos 👨‍🏫 6 | 7 | No início de cada lição, descrevo o conceito a ser abordado. 8 | 9 | > 👨‍🏫 Por exemplo: lidando com _banners_ de consentimento de _cookies_. 10 | 11 | Nesta seção, trago situações comuns encontradas no mundo da automação de testes web e apresento funcionalidades do Cypress que resolvem determinados casos de uso. 12 | 13 | > 👨‍🏫 No caso acima, por exemplo, eu mencionaria o uso da opção [`onBeforeLoad`](https://docs.cypress.io/api/commands/visit#Provide-an-onBeforeLoad-callback-function) do comando `cy.visit`, com exemplos de seu uso. 14 | 15 | ## Conteúdos sugeridos 📚 e links para a documentação 🔗 16 | 17 | Em muitas lições há sugestões de conteúdos e links para a documentação oficial ao seu alcance. 18 | 19 | ## Dicas do instrutor 👨‍🏫 (e _spoilers_ 🙊) 20 | 21 | Em alguns exercícios, você verá o emoji do instrutor, ou do macaco com a boca fechada. 22 | 23 | Quando for o emoji do instrutor (👨‍🏫), é apenas um lembrete. 24 | 25 | Já quando for o emoji do macaco (🙊), tem algum _spoiler_ para te ajudar. 26 | 27 | ## Exercícios 🎯 28 | 29 | Acredito que a prática leva à perfeição. 30 | 31 | Por isso, ao final de cada aula, há exercícios para você colocar em prática os novos conhecimentos aprendidos. 32 | 33 | > 👨‍🏫 Minha dica é: Pratique o seu ofício. 34 | 35 | ___ 36 | 37 | Agora que você conhece a estrutura do curso, vá para a seção de [pré-requisitos](./_pre-requisites_.md). 38 | -------------------------------------------------------------------------------- /lessons/_pre-requisites_.md: -------------------------------------------------------------------------------- 1 | # Pré-requisitos 📋 2 | 3 | Para a realização do curso, há sistemas que precisam estar instalados e conhecimentos prévios necessários, os quais são listados abaixo. 4 | 5 | ## Sistemas 6 | 7 | Antes de começar, certifique-se de que os seguintes sistemas estejam instalados em seu computador. 8 | 9 | - [git](https://git-scm.com/) (`2.42.1` no momento da escrita deste documento) 10 | - [Node.js](https://nodejs.org/en/) (`22.12.0` no momento da escrita deste documento) 11 | - npm (`11.0.0` no momento da escrita deste documento) 12 | - [Visual Studio Code](https://code.visualstudio.com/) (`v1.96.2` no momento da escrita deste documento) **ou alguma outra IDE de sua preferência** 13 | 14 | > 👨‍🏫 Recomendo usar as mesmas versões, ou versões mais recentes - de suporte de longo prazo (LTS) - dos sistemas listados acima. 15 | > 16 | > 👨‍🏫 Ao instalar o Node.js, o npm é instalado junto. 🎉 17 | > 18 | > 👨‍🏫 Para verificar as versões do git, Node.js e npm instaladas em seu computador, execute o comando `git --version && node --version && npm --version` em seu terminal de linha de comando. 19 | > 20 | > 👨‍🏫 Deixei links para os instaladores na lista de requisitos acima, caso você ainda não os tenha instalados. 21 | 22 | ## Conhecimentos 23 | 24 | Para que você tire o melhor proveito do curso, é necessário que você possua ao menos conhecimentos básicos de: 25 | 26 | - [JavaScript](https://www.youtube.com/playlist?list=PL-eblSNRj0QH36XrwvGfhh14GjpG-ViS2) 27 | - [Seletores CSS](https://www.youtube.com/playlist?list=PL-eblSNRj0QHGg3iE2HAtOkzIyNH9DSjL) 28 | - [Linha de comando](https://github.com/wlsf82/linha-de-comando-basico/) e [git](https://youtube.com/live/xmTU2jqLuAc?feature=share) 29 | 30 | > 👨‍🏫 Deixei links acima para playlists sobre JS e seletores CSS no [Canal TAT no YouTube](https://youtube.com/@talkingabouttesting), além de um repositório no GitHub com o básico de linha de comando e um vídeo sobre os comandos de git que mais utilizo. 31 | 32 | Por fim, você precisará possuir uma conta no [GitHub](https://github.com). 33 | 34 | ___ 35 | 36 | Legal, os pré-requisitos estão prontos. ☑️ 37 | 38 | Clique [aqui](./_the-app_.md) que eu vou te apresentar a aplicação em teste. 39 | -------------------------------------------------------------------------------- /lessons/_the-app_.md: -------------------------------------------------------------------------------- 1 | # Conhecendo a aplicação em teste 💻 2 | 3 | Antes de começarmos a configurar o Cypress e escrever scripts de teste automatizados, deixe-me apresentar a aplicação que testaremos ao longo deste curso. 4 | 5 | A aplicação se chama [_Cypress Simulator_](https://cypress-simulator.s3.eu-central-1.amazonaws.com/index.html) e foi desenvolvida utilizando HTML, CSS e JavaScript. 6 | 7 | ## O que é a aplicação _Cypress Simulator_? 8 | 9 | A _Cypress Simulator_ é uma aplicação web interativa que permite experimentar e aprender comandos do Cypress em tempo real. Ela fornece um ambiente seguro para a prática de comandos do Cypress sem a necessidade de configurar e instalar o Cypress. 10 | 11 | ## Requisitos funcionais 12 | 13 | ### Autenticação 14 | 15 | - O/a usuário/a deve efetuar _login_ para acessar o simulador 16 | - A sessão de login persiste por 30 dias, a menos que o usuário efetue _logout_ 17 | - O/a usuário/a podem efetuar _logout_ pelo menu sanduíche no cabeçalho 18 | - Nenhuma senha é necessária para esta aplicação de demonstração 19 | - Verificação de CAPTCHA necessária durante o _login_ por questões de segurança 20 | - O/a usuário/a deve resolver um problema matemático simples 21 | - Várias tentativas são permitidas se a resposta for incorreta 22 | 23 | ### Consentimento de _cookies_ 🍪 24 | 25 | - _Banner_ de consentimento de _cookies_ exibido para novos/as usuários/as 26 | - O/a usuário/a deve aceitar ou recusar os _cookies_ explicitamente 27 | - O _banner_ inclui: 28 | - Uma explicação clara do uso de _cookies_ 29 | - Botões de Aceitar e Recusar 30 | - A preferência do usuário é lembrada para futuras visitas 31 | 32 | ### Interface gráfica do usuário (_GUI_) 33 | 34 | - Cabeçalho 35 | - Exibe o título da aplicação: "_Cypress Simulator_" 36 | - Exibe um parágrafo com o texto: "_Explore and experiment with Cypress commands in real-time!_" 37 | - Inclui um menu sanduíche para navegação 38 | - Mostra a opção de logout ao abrir o menu sanduíche 39 | - Conteúdo principal 40 | - Exibe comandos úteis do Cypress com suas devidas descrições 41 | - Fornece uma área de entrada de código para escrever comandos do Cypress 42 | - Mostra a saída da execução dos comandos em uma seção dedicada 43 | - Permite que a seção de saída seja maximizada e minimizada 44 | - Entrada e saída 45 | - Suporte a comandos comuns do Cypress, tais como: `cy.visit`, `cy.get`, `cy.contains`, `cy.request`, `cy.exec`, `cy.log`, etc. 46 | - Fornece feedback imediato sobre a execução dos comandos 47 | - Mostra mensagens de sucesso, erro e _warning_ com base na validade do comando 48 | - Inclui um comando de ajuda para exibir exemplos de uso 49 | - Rodapé 50 | - Exibe o crédito "_Powered by Talking About Testing_" 51 | - Fornece os seguintes links da Talking About Testing: 52 | - Blog 53 | - YouTube 54 | - Podcast 55 | - Udemy 56 | - Todos os links abrem em uma nova aba do navegador 57 | 58 | ### Imagem da _GUI_ 59 | 60 | Abaixo está um exemplo de como a aplicação se parece em um _viewport desktop_. 61 | 62 | ![cypress-simulator](./assets/cypress-simulator.png) 63 | 64 | ## Resumo 65 | 66 | A aplicação _Cypress Simulator_ é uma ferramenta de aprendizado que ajuda a praticar os comandos de teste do Cypress sem nenhuma configuração. Pense nela como uma aplicação onde você pode: 67 | 68 | - Experimentar os comandos do Cypress com segurança 69 | - Obter feedback imediato sobre o que funciona e o que não funciona 70 | - Aprender com exemplos e documentação de ajuda 71 | - Praticar sem medo de quebrar nada 72 | 73 | A ferramenta foi projetada para ser: 74 | 75 | - Fácil de usar (basta fazer login e começar a digitar os comandos) 76 | - Educacional (inclui exemplos e ajuda) 77 | - Acessível (funciona em qualquer navegador moderno) 78 | - Conveniente (lembra que você está conectado por 30 dias) 79 | - Segura (inclui verificação de CAPTCHA) 80 | - Focada na privacidade (é necessário consentimento explícito de _cookies_) 81 | 82 | Nenhum conhecimento técnico é necessário para começar a usar o simulador, tornando-o perfeito para iniciantes que estão aprendendo testes com Cypress. 83 | 84 | ## Teu desafio 🎯 85 | 86 | Durante o curso, te desafio a testar **TODAS** as funcionalidades da aplicação _Cypress Simulator_. 87 | 88 | Espero que você esteja tão ansioso/a para começar, quanto estou para guiá-lo/a ao longo do caminho! 🧑‍🏫 89 | 90 | Vá para a [lição 0](./0.md) para configurar o projeto de testes. 91 | -------------------------------------------------------------------------------- /lessons/assets/cypress-simulator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlsf82/curso-cypress-simulator/4a6b57d361179bc814ff2df6ee62fe9b50c46855/lessons/assets/cypress-simulator.png -------------------------------------------------------------------------------- /lessons/congratulations.md: -------------------------------------------------------------------------------- 1 | # Parabéns, você concluiu o curso Cypress Simulator 2 | 3 | 🥳 🎉 4 | 5 | Que jornada, hein? 6 | 7 | Espero que você tenha gostado do curso tanto quanto gostei de te ensinar. 8 | 9 | Neste mesmo [repositório](https://github.com/wlsf82/curso-cypress-simulator/tree/main), você irá encontrar [soluções para todos os exercícios](https://github.com/wlsf82/curso-cypress-simulator/commits/final-solution/), caso você queira consultar. 10 | 11 | A propósito, não esqueça de deixar uma estrela no [repositório no GitHub](https://github.com/wlsf82/curso-cypress-simulator). ⭐ 12 | 13 | Vamos recapitular o que você aprendeu? 14 | 15 | No curso **Cypress Simulator**, você aprendeu: 16 | 17 | - Como planejar quais testes devem ser implementados e em que orderm ✔️ 18 | - Como garantir testes estáveis ✔️ 19 | - Como lidar com esperas aleatórias ✔️ 20 | - Como lidar com _captcha_ ✔️ 21 | - Como lidar com _banners_ de consentimento de _cookies_ 🍪 ✔️ 22 | - Como criar diferentes comandos customizados ✔️ 23 | - Como otimizar testes com a criação e restauração da sessão do usuário ✔️ 24 | - Como criar testes de acessibilidade automatizados ✔️ 25 | - Como utilizar _feature flags_ em testes automatizados ✔️ 26 | - Como configurar uma esteira de integração contínua onde os testes sejam executados em paralelo ✔️ 27 | - Como configurar _test retries_ ✔️ 28 | - Como gerar artefatos para ajudar na depuração de falhas na integração contínua ✔️ 29 | 30 | Agora é hora de colocar os novos conhecimentos em prática. 31 | 32 | Quer manter contato comigo? Participe do grupo [**Talking About Testing**](https://www.linkedin.com/groups/12492726/) no LinkedIn. 33 | 34 | Confira também os [outros cursos](https://talking-about-testing.vercel.app/) da Escola Talking About Testing. 35 | 36 | Por fim, compartilhe o certificado do curso em seu perfil do LinkedIn para mostrar que você pode criar testes automatizados com Cypress utilizando desde de recursos simples, até estar tudo rodando na integração contínua. Use as _hashtags_ **#TalkingAboutTesting #EscolaTAT #CypressSimulator #Cypress**. 37 | 38 | > 👨‍🏫 Lembre-se de me marcar em sua publicação. [Aqui está meu perfil no LinkedIn](https://www.linkedin.com/in/walmyr-lima-e-silva-filho). 39 | 40 | Bons testes e até o próximo curso! 🚀 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "curso-cypress-simulator", 3 | "version": "1.0.0", 4 | "description": "Curso 'Cypress Simulator' da Escola Talking About Testing.", 5 | "main": "src/index.html", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Testing", 11 | "Cypress.io", 12 | "Talking About Testing", 13 | "Cypress Simulator", 14 | "GitHub Actions", 15 | "Escola TAT" 16 | ], 17 | "author": "Walmyr (https://walmyr.dev/)", 18 | "license": "MIT", 19 | "type": "commonjs" 20 | } 21 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Interactive Cypress Simulator 7 | 8 | 9 | 10 | 11 |
12 |

Cypress Simulator

13 |

Explore and experiment with Cypress commands in real-time!

14 |
15 | 18 | 21 |
22 |
23 |
24 |

Let's get started!

25 |
26 | 27 |
28 |
29 |
30 |

Security Check

31 |
32 |

Please solve this simple math problem to continue:

33 |
34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 |

Useful Commands

42 |
    43 |
  • cy.visit(url) - Navigate to a page
  • 44 |
  • cy.get(selector) - Get DOM elements
  • 45 |
  • cy.contains(text) - Find elements by text
  • 46 |
  • cy.request(method, url) - Make an HTTP request
  • 47 |
  • cy.exec(cmd) - Execute a system command
  • 48 |
  • cy.log(message) - Print a message to the Cypress Command Log
  • 49 |
50 |
51 |
52 |

Cypress Code

53 |

To get help, type help and hit the run button.

54 |

Or, simply write and run a Cypress command, like cy.get('button').

55 | 56 | 57 |
58 |
59 |

Cypress Output

60 | 68 |

 69 |     
70 | 80 |
81 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | const loginForm = document.getElementById("login") 3 | const loginButton = document.querySelector("#login form button") 4 | const mainContent = document.querySelector(".content") 5 | const logoutButton = document.getElementById("logoutButton") 6 | const sandwichMenu = document.getElementById("sandwich-menu") 7 | const dropdownMenu = document.getElementById("dropdown-menu") 8 | const codeInput = document.getElementById("codeInput") 9 | const runButton = document.getElementById("runButton") 10 | const outputSection = document.querySelector(".output") 11 | const outputArea = document.getElementById("outputArea") 12 | const expandCollapseDiv = document.querySelector(".expand-collapse") 13 | const cookieConsentBanner = document.getElementById("cookieConsent") 14 | const acceptCookiesBtn = document.getElementById("acceptCookies") 15 | const declineCookiesBtn = document.getElementById("declineCookies") 16 | const captchaSection = document.getElementById("captcha") 17 | const captchaChallenge = document.querySelector(".captcha-challenge") 18 | const captchaInput = document.getElementById("captchaInput") 19 | const verifyCaptchaButton = document.getElementById("verifyCaptcha") 20 | const captchaError = document.getElementById("captchaError") 21 | 22 | // eslint-disable-next-line no-undef 23 | lucide.createIcons() 24 | 25 | const urlParams = new URLSearchParams(window.location.search) 26 | const chancesOfError = urlParams.get("chancesOfError") 27 | const skipCaptcha = urlParams.get("skipCaptcha") === "true" 28 | 29 | const checkExistingSession = () => { 30 | const sessionData = localStorage.getItem("cypressSimulatorSession") 31 | if (sessionData) { 32 | const { expiresAt } = JSON.parse(sessionData) 33 | if (new Date().getTime() < expiresAt) { 34 | loginForm.style.display = "none" 35 | captchaSection.style.display = "none" 36 | mainContent.style.display = "flex" 37 | sandwichMenu.style.display = "flex" 38 | } else { 39 | localStorage.removeItem("cypressSimulatorSession") 40 | } 41 | } 42 | } 43 | 44 | checkExistingSession() 45 | 46 | const cypressCommands = { 47 | "cy.visit": "Visit a URL", 48 | "cy.get": "Get DOM elements by selector", 49 | "cy.contains": "Find elements by text and optionally click", 50 | "cy.request": "Make an HTTP request", 51 | "cy.exec": "Execute a system command", 52 | "cy.log": "Print a message to the Cypress Command Log", 53 | "cy.clearAllCookies": "Clear all cookies", 54 | "cy.clearAllLocalStorage": "Clear localStorage data for all origins with which the test has interacted", 55 | "cy.clearAllSessionStorage": "Clear sessionStorage data for all origins with which the test has interacted", 56 | "cy.clearCookie": "Clear a specific browser cookie", 57 | "cy.clearCookies": "Clear browser cookies for a domain", 58 | "cy.clearLocalStorage": "Clear data in localStorage for current domain and subdomain", 59 | "cy.clock": "cy.clock() overrides native global functions related to time allowing them to be controlled synchronously via cy.tick() or the yielded clock object", 60 | "cy.debug": "Set a debugger and log what the previous command yields", 61 | "cy.document": "Get the window.document of the page that is currently active", 62 | "cy.fixture": "Load a fixed set of data located in a file", 63 | "cy.focused": "Get the DOM element that is currently focused", 64 | "cy.getAllCookies": "Get all browser cookies", 65 | "cy.getAllLocalStorage": "Get localStorage data for all origins with which the test has interacted", 66 | "cy.getAllSessionStorage": "Get sessionStorage data for all origins with which the test has interacted", 67 | "cy.getCookie": "Get a browser cookie by its name", 68 | "cy.getCookies": "Get browser cookies for the current domain or the specified domain", 69 | "cy.go": "Navigate back or forward to the previous or next URL in the browser's history", 70 | "cy.hash": "Get the current URL hash of the page that is currently active", 71 | "cy.intercept": "Spy and stub network requests and responses", 72 | "cy.location": "Get the global window.location object of the page that is currently active", 73 | "cy.origin": "Visit multiple domains of different origin in a single test", 74 | "cy.pause": "Stop cy commands from running and allow interaction with the application under test.", 75 | "cy.readFile": "Read a file and yield its contents", 76 | "cy.reload": "Reload the page", 77 | "cy.root": "Get the root DOM element", 78 | "cy.screenshot": "Take a screenshot of the application under test", 79 | "cy.scrollTo": "Scroll to a specific position", 80 | "cy.session": "Cache and restore cookies, localStorage, and sessionStorage (i.e. session data) in order to recreate a consistent browser context between tests", 81 | "cy.setCookie": "Set a browser cookie", 82 | "cy.spy": "Wrap a method in a spy in order to record calls to and arguments of the function", 83 | "cy.stub": "Replace a function, record its usage and control its behavior", 84 | "cy.task": "Execute code in Node via the task plugin event", 85 | "cy.tick": "Move time after overriding a native time function with cy.clock()", 86 | "cy.title": "Get the document.title property of the page that is currently active", 87 | "cy.url": "Get the current URL of the page that is currently active", 88 | "cy.viewport": "Control the size and orientation of the screen for your application", 89 | "cy.wait": "Wait for a number of milliseconds or wait for an aliased resource to resolve before moving on to the next command", 90 | "cy.window": "Get the window object of the page that is currently active", 91 | "cy.wrap": "Yield the object passed into .wrap(). If the object is a promise, yield its resolved value", 92 | "cy.writeFile": "Write to a file with the specified contents", 93 | "cy.on": "Liston to a single browser event, which is unbound when the test ends", 94 | ".and": "An alias of .should", 95 | ".as": "Assign an alias for later use", 96 | ".blur": "Blur a focused element", 97 | ".check": "Check checkbox(es) or radio(s)", 98 | ".children": "Get the children of each element within a set of DOM elements", 99 | ".clear": "Clear the value of an input or textarea", 100 | ".click": "Click a DOM element", 101 | ".closest": "Get the first DOM element that matches the selector (whether it be itself or one of its ancestors)", 102 | ".dblclick": "Double-click a DOM element", 103 | ".each": "Iterate through an array like structure (arrays or objects with a length property)", 104 | ".end": "End a chain of commands", 105 | ".eq": "Get A DOM element at a specific index in an array of elements", 106 | ".filter": "Get the DOM elements that match a specific selector", 107 | ".find": "Get the descendent DOM elements of a specific selector", 108 | ".first": "Get the first DOM element within a set of DOM elements", 109 | ".focus": "Focus on a DOM element", 110 | ".invoke": "Invoke a function on the previously yielded subject", 111 | ".its": "Get a property's value on the previously yielded subject", 112 | ".last": "Get the last DOM element within a set of DOM elements", 113 | ".next": "Get the immediately following sibling of each DOM element within a set of DOM elements", 114 | ".nextAll": "Get all following siblings of each DOM element in a set of matched DOM elements", 115 | ".nextUntil": "Get all following siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided", 116 | ".not": "Filter DOM element(s) from a set of DOM elements", 117 | ".parent": "Get the parent DOM element of a set of DOM elements", 118 | ".parents": "Get the parent DOM elements of a set of DOM elements", 119 | ".parentsUntil": "Get all ancestors of each DOM element in a set of matched DOM elements up to, but not including, the element provided", 120 | ".prev": "Get the immediately preceding sibling of each element in a set of the elements", 121 | ".prevAll": "Get all previous siblings of each DOM element in a set of matched DOM elements", 122 | ".prevUntil": "Get all previous siblings of each DOM element in a set of matched DOM elements up to, but not including, the element provided", 123 | ".rightClick": "Right click a DOM element", 124 | ".scrollIntoView": "Scroll an element into view", 125 | ".select": "Select an