Automação de fluxos críticos do e‑commerce (cadastro, login, busca, carrinho, checkout, avaliações e mais) usando Cypress 12 e Page Object Model. O projeto foi traduzido para pt‑BR e agora possui qualidade automatizada com ESLint + Husky (pre-commit) e remoção automática de comentários no commit.
🚧 Projeto em Desenvolvimento Ativo - Novas funcionalidades sendo adicionadas constantemente!
O AutomationExercise é uma plataforma de e-commerce 100% gratuita e pública criada especificamente para praticar automação de testes. É perfeita para:
- ✅ Aprender automação sem custos
- ✅ Praticar Cypress em cenários reais
- ✅ Desenvolver Page Objects e DSL
- ✅ Testar fluxos completos de e-commerce
- ✅ Contribuir para a comunidade de QA
- URL: https://automationexercise.com/
- Status: ✅ Online e Funcionando
- Custo: 🆓 Totalmente Gratuito
- Registro: ✅ Não é necessário
- Limitações: ❌ Nenhuma
- ✅ Cadastro e Login de usuários
- ✅ Busca de produtos por categoria
- ✅ Carrinho de compras completo
- ✅ Checkout com dados pessoais
- ✅ Avaliações de produtos
- ✅ Upload de arquivos no contato
- ✅ Carrosséis e navegação
- ✅ Responsividade mobile/desktop
- 🆓 Gratuito: Sem custos ou limitações
- 🌍 Público: Acesso imediato para todos
- 🔄 Estável: Sistema bem mantido
- 📱 Completo: Fluxos reais de e-commerce
- 🎨 Interface moderna: Design atual
- 🚀 Performance: Carregamento rápido
- ✅ Testes E2E organizados em
cypress/e2e - ✅ Page Objects em
cypress/pages(nomes em pt‑BR) - ✅ Comando customizado
cy.loginemcypress/support/commands.js - ✅ ESLint com regras recomendadas + rule set para Cypress
- ✅ Husky + lint-staged: padronização automática no pre-commit
- ✅ Remoção automática de comentários nos arquivos staged
- 🚧 DSL (Domain Specific Language) para testes mais legíveis
- Node.js >= 18 (recomendado) / >= 16 (mínimo)
- npm (ou yarn/pnpm)
- Navegadores: Chrome e Firefox
git clone https://github.com/jenafree/ecommerce-cypress-tests.git
cd ecommerce-cypress-testsnpm installnpx cypress installnpm run cy:opennpm run cy:chrome:headlessnpm run cy:chrome:headless -- --spec cypress/e2e/login-usuario.cy.jsnpm run lintnpm run lint:fixDSL (Domain Specific Language) é uma linguagem especializada para um domínio específico. No nosso projeto de testes, criamos uma DSL em português que torna os testes mais legíveis e próximos da linguagem natural.
cy.get('[data-testid="login-email"]').type('[email protected]');
cy.get('[data-testid="login-password"]').type('senha123');
cy.get('[data-testid="login-button"]').click();
cy.get('[data-testid="welcome-message"]').should('contain', 'Bem-vindo');// Comando customizado cy.login
cy.login('[email protected]', 'senha123');
// Page Objects em português
PaginaAutenticacao.getLoginEmail().type(email);
PaginaAutenticacao.getLoginPassword().type(senha);
PaginaAutenticacao.getLoginBtn().click();- ✅ Legibilidade: Testes mais fáceis de entender
- ✅ Manutenibilidade: Mudanças centralizadas nos Page Objects
- ✅ Reutilização: Comandos customizados para ações comuns
- ✅ Tradução: Nomes em português para melhor compreensão
- ✅ Consistência: Padrões uniformes em todo o projeto
// cypress/support/commands.js
cy.login(email, senha); // Login automático
cy.adicionarAoCarrinho(); // Adicionar produto ao carrinho
cy.verificarCarrinho(); // Verificar itens no carrinho// cypress/pages/PaginaAutenticacao.js
PaginaAutenticacao.getLoginEmail() // Campo de email
PaginaAutenticacao.getLoginPassword() // Campo de senha
PaginaAutenticacao.getLoginBtn() // Botão de login
// cypress/pages/PaginaCarrinho.js
PaginaCarrinho.getViewCartLink() // Link "Ver carrinho"
PaginaCarrinho.getCheckoutBtn() // Botão "Finalizar compra"describe('Login do usuário', () => {
it('Deve fazer login com sucesso', () => {
// DSL torna o teste mais legível
cy.visit('/login');
cy.login('[email protected]', 'senha123');
cy.verificarLoginSucesso();
});
});No nosso projeto, utilizamos diferentes estratégias para gerenciar a autenticação e persistência de dados:
// cypress/support/commands.js
Cypress.Commands.add('login', (loginEmail, loginPassword) => {
HeaderPage.getSignupLink().click();
AuthPage.getLoginTitle().should('exist');
AuthPage.getLoginEmail().type(loginEmail, { delay: 0 });
AuthPage.getLoginPassword().type(loginPassword, { delay: 0 });
AuthPage.getLoginBtn().click();
});
// Uso nos testes
cy.login('[email protected]', 'senha123');✅ Vantagens:
- Mais realista: Simula o fluxo real de login
- Testa a UI: Valida formulários e validações
- Cobertura completa: Testa todo o processo de autenticação
- Debugging fácil: Visualiza cada passo no Cypress
// Comandos para Store State implementados
cy.salvarNoLocalStorage('authToken', 'abc123xyz');
cy.salvarNoSessionStorage('userData', JSON.stringify(userData));
cy.obterDoLocalStorage('authToken');
cy.obterDoSessionStorage('userData');
cy.limparLocalStorage();
cy.limparSessionStorage();🚀 Comandos Disponíveis:
cy.salvarNoLocalStorage(key, value)- Salva no localStoragecy.salvarNoSessionStorage(key, value)- Salva no sessionStoragecy.obterDoLocalStorage(key)- Obtém do localStoragecy.obterDoSessionStorage(key)- Obtém do sessionStoragecy.limparLocalStorage()- Limpa localStoragecy.limparSessionStorage()- Limpa sessionStorage
// cypress/e2e/login-usuario.cy.js
describe('Login do usuário', () => {
it('Deve fazer login com sucesso', () => {
cy.visit('/');
cy.login('[email protected]', 'senha123');
// Verifica se o login funcionou
cy.get('[data-testid="welcome-message"]')
.should('contain', 'Bem-vindo');
});
});// cypress/e2e/login-com-store-state.cy.js
describe('Login com Store State', () => {
it('Deve fazer login via Store State (rápido)', () => {
const userData = {
email: '[email protected]',
name: 'Usuário Teste',
token: 'abc123xyz'
};
// Login via store (muito mais rápido)
cy.loginViaStore(userData);
cy.verificarLogin();
});
});// 1. Navega para a página
cy.visit('/');
// 2. Clica no link de login
cy.get('[data-testid="login-link"]').click();
// 3. Preenche credenciais
cy.get('[data-testid="email"]').type('[email protected]');
cy.get('[data-testid="password"]').type('senha123');
// 4. Submete o formulário
cy.get('[data-testid="login-button"]').click();
// 5. Verifica sucesso
cy.get('[data-testid="welcome"]').should('be.visible');// 1. Define dados de autenticação
const userData = {
email: '[email protected]',
name: 'Usuário Teste',
token: 'abc123xyz'
};
// 2. Login via store (instantâneo)
cy.loginViaStore(userData);
// 3. Verifica se está logado
cy.verificarLogin();// Comando que escolhe automaticamente a melhor estratégia
cy.loginInteligente('[email protected]', 'senha123', userData);
// Primeira execução: login tradicional + salva no store
// Próximas execuções: usa store automaticamente| Aspecto | Login Session | LocalStorage |
|---|---|---|
| Realismo | ✅ Muito alto | |
| Velocidade | ✅ Muito rápido | |
| Cobertura | ✅ Completa | ❌ Limitada |
| Manutenção | ✅ Menos trabalho | |
| Debugging | ✅ Fácil | ❌ Difícil |
| Validações | ✅ Testa tudo | ❌ Pula validações |
// Salvar dados
cy.salvarNoLocalStorage('chave', 'valor');
cy.salvarNoSessionStorage('chave', 'valor');
// Obter dados
cy.obterDoLocalStorage('chave');
cy.obterDoSessionStorage('chave');
// Limpar dados
cy.limparLocalStorage();
cy.limparSessionStorage();// Login via store (rápido)
cy.loginViaStore(userData);
// Login inteligente (híbrido)
cy.loginInteligente(email, senha, userData);
// Logout via store
cy.logoutViaStore();
// Verificações
cy.verificarLogin();
cy.verificarLogout();// Verificar dados no store
cy.verificarStore('chave', 'valor', 'localStorage');
cy.verificarStore('chave', 'valor', 'sessionStorage');
// Verificar dados do usuário
cy.verificarDadosUsuario(expectedUserData);// Preparar dados reutilizáveis
cy.prepararDadosTeste(dados);
// Obter dados de teste
cy.obterDadosTeste();// cypress/e2e/login-com-store-state.cy.js
it('Deve demonstrar performance: Login tradicional vs Store State', () => {
// Mede tempo do login tradicional
const startTime = Date.now();
cy.login(email, senha);
const traditionalTime = Date.now() - startTime;
// Mede tempo do login via store
const startTimeStore = Date.now();
cy.loginViaStore(userData);
const storeTime = Date.now() - startTimeStore;
// Compara performance
cy.log(`🚀 Melhoria: ${Math.round((traditionalTime - storeTime) / traditionalTime * 100)}%`);
});// Salva dados do carrinho no store
const carrinhoData = {
itens: [
{ id: 1, nome: 'Blue Top', preco: '500', quantidade: 2 },
{ id: 2, nome: 'Men Tshirt', preco: '400', quantidade: 1 }
],
total: '1400'
};
cy.salvarNoSessionStorage('carrinho', JSON.stringify(carrinhoData));
// Verifica dados do carrinho
cy.obterDoSessionStorage('carrinho').then((carrinho) => {
const dados = JSON.parse(carrinho);
expect(dados.itens).to.have.length(2);
expect(dados.total).to.equal('1400');
});// Salva preferências no localStorage (persistente)
const preferencias = {
tema: 'dark',
idioma: 'pt-BR',
notificacoes: true
};
cy.salvarNoLocalStorage('preferencias', JSON.stringify(preferencias));
// Recarrega e verifica se foram mantidas
cy.reload();
cy.obterDoLocalStorage('preferencias').then((prefs) => {
const dados = JSON.parse(prefs);
expect(dados.tema).to.equal('dark');
});- ✅ Mantenha o login session para testes de autenticação
- ✅ Use store state para testes de performance
- ✅ Implemente login inteligente para otimização
- ✅ Teste fluxos completos de autenticação
// Comando híbrido já implementado
Cypress.Commands.add('loginInteligente', (email, senha, userData = null) => {
// Tenta login via storage primeiro
cy.window().then((win) => {
const token = win.localStorage.getItem('authToken');
const sessionData = win.sessionStorage.getItem('userData');
if (token && sessionData) {
// Se tem dados no store, usa eles
cy.log('🔐 Login via Store State detectado');
cy.reload();
cy.get('[data-testid="user-menu"], .logged-in, .user-menu').should('be.visible');
} else {
// Se não tem dados, faz login normal
cy.log('🔑 Fazendo login tradicional');
cy.login(email, senha);
// Se foi fornecido userData, salva no store para próximos testes
if (userData) {
cy.salvarNoSessionStorage('userData', JSON.stringify(userData));
if (userData.token) {
cy.salvarNoLocalStorage('authToken', userData.token);
}
}
}
});
});- ✅ Implementar login via storage para testes de performance
- ✅ Criar comandos híbridos que escolhem a melhor estratégia
- ✅ Adicionar validações de dados no storage
- ✅ Documentar padrões de autenticação
- 🚧 Expandir para outros cenários (carrinho, checkout, etc.)
- 🚧 Implementar cache inteligente para dados frequentes
O Husky é uma ferramenta que permite executar scripts automaticamente em diferentes momentos do Git (pre-commit, pre-push, etc.). No nosso projeto, ele garante que:
- ✅ Código seja formatado antes de cada commit
- ✅ ESLint seja executado automaticamente
- ✅ Comentários sejam removidos dos arquivos
- ✅ Qualidade seja mantida sem esforço manual
Antes de cada commit, o Husky executa automaticamente:
# .husky/pre-commit
npx lint-stagedO lint-staged executa apenas nos arquivos que foram modificados:
// package.json
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix"
]
}# 1. Você modifica um arquivo de teste
# cypress/e2e/login-usuario.cy.js
# 2. Adiciona as mudanças
git add cypress/e2e/login-usuario.cy.js
# 3. Tenta fazer o commit
git commit -m "feat: adiciona novo teste de login"🐕 Husky > pre-commit (node v20.11.1)
✔ Preparing...
✔ Running tasks...
✔ Cleaning up...
🔧 lint-staged > Running tasks for *.{js,ts,jsx,tsx}
✔ eslint --fix [1 file]
✅ Commit realizado com sucesso!# Log detalhado do que aconteceu:
[INFO] Husky: Executando pre-commit hook...
[INFO] lint-staged: Processando 1 arquivo modificado
[INFO] ESLint: Corrigindo formatação automaticamente
[INFO] ESLint: Removendo comentários desnecessários
[INFO] ✅ Commit aprovado e realizado!Se o ESLint encontrar erros que não podem ser corrigidos automaticamente:
🐕 Husky > pre-commit (node v20.11.1)
✔ Preparing...
❌ Running tasks...
❌ Cleaning up...
🔧 lint-staged > Running tasks for *.{js,ts,jsx,tsx}
❌ eslint --fix [1 file]
❌ Commit falhou! Corrija os erros e tente novamente.
# Erros encontrados:
# - Linha 15: 'variable' is defined but never used
# - Linha 23: Missing semicolonnpm install husky --save-dev
npx husky installnpx husky add .husky/pre-commit "npx lint-staged"// package.json
{
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix"
]
}
}ecommerce-cypress-tests/
├── cypress/
│ ├── e2e/ # Specs de teste (pt‑BR)
│ │ ├── login-usuario.cy.js
│ │ ├── adicionar-ao-carrinho.cy.js
│ │ └── ...
│ ├── pages/ # Page Objects (pt‑BR)
│ │ ├── PaginaAutenticacao.js
│ │ ├── PaginaCabecalho.js
│ │ └── ...
│ └── support/
│ └── commands.js # Comandos customizados (DSL)
├── .husky/
│ └── pre-commit # Hook de pre-commit
├── eslint.config.cjs # Configuração ESLint
├── package.json # Scripts e lint-staged
└── README.md # Este arquivo
- ✅ Tradução dos nomes de arquivos de specs e Page Objects para pt‑BR
- ✅ Títulos de
describe/ittraduzidos - ✅ Adicionado ESLint (v9) com presets recomendados + Cypress
- ✅ Adicionado Husky + lint-staged (pre-commit)
- ✅ Remoção automática de comentários nos commits
- 🚧 DSL implementada para testes mais legíveis
- ✅ Suíte inicial de testes Cypress com POM
- Expandir DSL com mais comandos customizados
- Criar biblioteca de componentes reutilizáveis
- Implementar BDD (Behavior Driven Development)
- Padronizar mensagens de commit (Conventional Commits)
- CI (GitHub Actions) para lint + testes em matriz de navegadores
- Relatórios de testes (mochawesome / junit)
- Variáveis de ambiente seguras (.env) e perfis de execução
| Comando | Descrição |
|---|---|
npm run cy:open |
Abre o Cypress interativo |
npm run cy:chrome:headed |
Executa no Chrome com UI |
npm run cy:chrome:headless |
Executa no Chrome headless |
npm run cy:firefox:headed |
Executa no Firefox com UI |
npm run lint |
Roda o ESLint |
npm run lint:fix |
Corrige automaticamente |
git checkout -b feat/nova-funcionalidade
# ou
git checkout -b chore/correcao-lint# Edite os arquivos...
# O Husky vai formatar automaticamente no commitgit add .
git commit -m "feat: adiciona novo teste de checkout"git push origin feat/nova-funcionalidade
# Abra PR no GitHubgit commit -m "feat: adiciona teste de login com dados inválidos"
git commit -m "fix: corrige seletor do botão de adicionar ao carrinho"
git commit -m "docs: atualiza README com instruções do Husky"
git commit -m "refactor: reorganiza Page Objects em português"
git commit -m "feat: implementa nova DSL para testes de checkout"git commit -m "fix"
git commit -m "corrige bug"
git commit -m "wip"- ❌ Código inconsistente
- ❌ Erros de linting em produção
- ❌ Commits com formatação ruim
- ❌ Tempo perdido corrigindo manualmente
- ✅ Código sempre formatado
- ✅ Qualidade garantida automaticamente
- ✅ Commits limpos e consistentes
- ✅ Foco no desenvolvimento, não na formatação
Desenvolvido com ❤️ por Neftali Oliveira
- GitHub: @jenafree
- LinkedIn: Neftali Oliveira
# Clique no botão "Fork" no GitHub
# ou use o comando:
git clone https://github.com/SEU_USUARIO/ecommerce-cypress-tests.gitcd ecommerce-cypress-tests
git remote add upstream https://github.com/jenafree/ecommerce-cypress-tests.gitgit fetch upstream
git checkout main
git merge upstream/maingit checkout -b feat/sua-nova-funcionalidade# Faça suas alterações
npm run lint:fix # Formata o código
npm run cy:chrome:headless # Roda os testesgit add .
git commit -m "feat: adiciona nova funcionalidade"
git push origin feat/sua-nova-funcionalidade- Vá para o GitHub
- Clique em "New Pull Request"
- Selecione sua branch
- Descreva suas mudanças
- Aguarde a revisão
- ✅ Novos testes para funcionalidades não cobertas
- ✅ Melhorias nos testes existentes
- ✅ Correções de bugs nos testes
- ✅ Documentação melhorada
- ✅ Otimizações de performance
- ✅ Traduções e melhorias de texto
- ✅ Novos comandos DSL para melhorar legibilidade
- ✅ Page Objects adicionais
Este projeto está licenciado sob a licença ISC.
Em desenvolvimento ativo com ❤️ e qualidade automatizada por Neftali Oliveira! 🚀
Sinta-se à vontade para fazer fork, contribuir e melhorar este projeto!
🚧 Projeto em constante evolução - Novas funcionalidades sendo adicionadas regularmente! s