Esse repositório é dedicado ao Projeto Final do curso de Quality Assurance oferecido pelo Instituto JogaJunto.
Clique nas "►" abaixo para visualizar os conteúdos trabalhados no projeto. Para recolher o conteúdo, basta clicar nas "▼" novamente. 😁
Integrantes da Squad 02: Leanderson Lima 👨🏾💻 | Sara J. M da Cruz 👩🏾💻
Data de Execução dos testes: 01/10/2023 📅
Cenários de Teste | Gherkin 🌟
Este plano de teste descreve os testes a serem executados no Sistema de Vendas do Instituto Joga Junto, com foco na perspectiva do usuário. O sistema é composto por uma aplicação frontend construída com React JS, hospedada na AWS Amplify, e utiliza uma estrutura de backend em NodeJS com um banco de dados MySQL versão 8.
Funcionalidade: Login com cadastro por Google ou Facebook
Cenário: Tentativa de cadastro
Objetivo: o objetivo é que seja possível o cadastro
- Dado que o usuário está na tela de cadastro
- Quando o usuário clica em "ou cadastre-se com" e escolhe a opção de cadastro com Google ou Facebook
- Então o sistema deve apresentar resultados
Resultado: Ao clicar em "ou cadastre-se com" através da alternativa que a plataforma fornece, de cadastrar com o Google ou com o Facebook, porém, não se obtém resultado Deveria ser possível cadastrar-se com essas duas alternativas.
Funcionalidade: Experiência visual do usuário
Cenário: Layout do site
Objetivo: Garantir que haja apenas um texto de registro visível.
- Dado que o usuário está na página de registro
- Quando o usuário visualiza o texto de registro
- Então deve haver apenas um texto de registro visível
Resultado: Ao entrar no site é possível reparar um erro, onde visualizamos que há duas formas de novo cadastramento. Deve haver apenas apenas um texto de registro.
Funcionalidade: Tratamento de tentativa de login com erro
Cenário: Tentativa de login com erro de e-mail
Objetivo: Permitir o login mesmo que não haja cadastro com o e-mail.
- Dado que o usuário está na tela de login
- Quando o usuário tenta efetuar o login com um e-mail que não existe na plataforma
- Então o sistema deve informar que o e-mail não está cadastrado
Resultado: Ao tentar criar o login, entrando na alternativa de registro, o site informa que já existe usuário com o email apresentado. O site não deve permitir o login sem que haja cadastro com o e-mail.
Funcionalidade: Restrição de acesso à plataforma
Cenário: Acesso após várias tentativas de login
Objetivo: Permitir o acesso somente após um cadastro bem-sucedido.
- Dado que o usuário está na tela de login
- Quando o usuário tenta fazer o login várias vezes com credenciais incorretas
- Então o sistema não deve permitir o acesso à plataforma
Resultado: Ao apresentar o mesmo login várias vezes, consegue-se abrir a plataforma. O sistema só deve permitir o acesso somente após um cadastro bem-sucedido.
Funcionalidade: Exibição de preço de produto
Cenário: Exibição de preço ao clicar em "Preço"
Objetivo: Mostrar o preço do produto cadastrado.
- Dado que o usuário está logado na plataforma
- Quando o usuário rola a página para baixo e clica em "Preço"
- Então o sistema deve exibir apenas o preço do produto cadastrado
Resultado: Ao entrar na plataforma, rola a página para baixo e clica em "Preço". Deveria aparecer somente o preço do produto cadastrado, mas estão aparecendo vários outros preços.
Funcionalidade: Exibição da imagem de produto cadastrado
Cenário: Exibição da imagem ao cadastrar o produto
Objetivo: Garantir que a imagem seja a do produto cadastrado.
- Dado que o usuário está cadastrando um produto
- Quando o usuário confere se a imagem está correta
- Então o sistema deve permitir a conclusão do cadastro do produto
Resultado: Ao cadastrar o produto a imagem se sobrepôe às informações. A imagem deve permanecer no mesmo lugar e o site deve permitir que o usuário conclua o cadastro do produto.
Funcionalidade: Pesquisa de produtos
Cenário: Utilizar o campo de pesquisa para buscar um produto
Objetivo: Garantir que o produto pesquisado seja exibido em uma página específica
- Dado que o usuário está na plataforma
- Quando o usuário clica no ícone de pesquisa e digita o nome do produto
- Então o sistema deve gerar o resultado correspondente ao produto pesquisado
Resultado: Ao clicar no ícone de pesquisa e digitar o nome do produto, não gera nenhum resultado. Deveria aparecer o produto pesquisado em uma página específica.
Funcionalidade: Exibição do site de forma correta
Cenário: Exibição de palavras e textos de modo a facilitar a interação do usuário
Objetivo: Mostrar todas as palavras e textos corretamente
- Dado que o usuário está acessando o site através de um celular
- Quando o usuário entra com o login
- Então o sistema deve exibir todas as palavras corretamente
Resultado: Com o celular iPhone, que tem o sistema iOS, ao entrar com o login é possível identificar diversas palavras incompletas na plataforma. O site deve mostrar todas as palavras corretamente no sistema operacional iOS.
Funcionalidade: Exibição de informações que estão no perfil do usuário
Cenário: Clicar no ícone "perfil" do site
Objetivo: Permitir o acesso e a possível edição das informações de perfil
- Dado que o usuário está cadastrado
- Quando o usuário entra com o login e clica no ícone "perfil" na barra superior da página
- Então o sistema deve exibir as informações de perfil e possibilitar editá-las
Resultado: Com o celular iPhone, que tem o sistema iOS, ao fazer o login e clicar no ícone "perfil" que aparece na barra superior da página deveria aparecer as informações do perfil, para possibilitar o acesso e a alteração das informações, porém tais informações não aparecem.
Funcionalidade: Registro de um novo produto
Cenário: Usuário cadastrando um produto novo
Objetivo: Permitir o registro do produto com sucesso
- Dado que o usuário está cadastrando o produto usando um celular
- Quando o usuário entra com o login e clica no ícone "Adicionar" e coloca as informações
- Então o sistema deve permitir o registro do produto na plataforma
Resultado: Com o celular com sistema operacional iOS, ao entrar com o login e clicar no ícone "Adicionar" e inserir as informações. Deveria ser possível registrar o produto na plataforma com sucesso. Porém o site não segue com o cadastro.
Funcionalidade: Botão de contato com suporte
Cenário: Tentativa de contato com suporte
Objetivo: Direcionar para um chat onde seja possível a comunicação com a central de atendimento ou suporte técnico
- Dado que o usuário está logado na plataforma
- Quando o usuário clica no ícone "contato" na barra superior da página
- Então o sistema deve direcionar para a central de atendimento
Resultado: Ao tentar entrar em contato, clicando no ícone "contato" na barra superior da página, o site nos direciona para um GitHub que não corresponde à area onde obterá ajuda. O sistema deve direcionar para um chat onde seja possível a comunicação com o time responsável em auxiliar o usuário.
Funcionalidade: Filtragem de produtos de acordo com a categoria
Cenário: Tentativa de visualizar cada produto com sua respectiva categoria
Objetivo: Apresentar os produtos de acordo com suas categorias para aprimorar a interação do usuário com os itens cadastrados.
- Dado que o usuário está logado na plataforma.
- Quando o usuário clica nos ícones correspondentes às categorias "Todos", "Roupas", "Calçados" e "Acessórios".
- Então o sistema deve exibir os produtos de acordo com a categoria solicitada.
Resultado: A parte correspondente à categoria "Roupas" está correta. No entanto, nas categorias "Calçados" e "Acessórios", os produtos cadastrados correspondentes não são exibidos.
Funcionalidade: Mostrar as informações do produto cadastrado Cenário: Na intenção de saber todas as informações fornecidas do produto
Objetivo: Mostrar todas as informações do produto que forem postas na hora do cadastro do produto
- Dado que o usuário está logado na plataforma.
- Quando o usuário busca pela informação fornecidas.
- Então o sistema deve exibir as informações correspondentes ao produto.
Resultado: A informação de frete não aparece na apresentação do produto.
Report Bugs | Criticidade | Evidências | Bitrix 🌟
Este é o arquivo no qual registramos os bugs, incluindo a classificação de sua criticidade.
O arquivo correspondente pode ser encontrado nesse mesmo repositório, na pasta 'Evidencias'."
Para melhor visualização, abaixo estão as evidências de forma mais detalhada:
Como solicitado no case do projeto final, utilizamos a ferramenta Bitrix e a metodolodia Kanban para execução dos testes funcionais, cada caso de teste era um card e todos foram concluídos com sucesso:
Testes automatizados 🌟
A automação de testes, realizada pela nossa squad, foi dividida em três etapas, seguindo o conhecimento adquirido ao longo do curso. É importante destacar que o caso de teste selecionado para as duas primeiras etapas foi o de número 12 e a última etapa foi o de número 1.
► Testes automatizados I | Programação Estruturada 🌟
Nessa abordagem fizemos uma automação com um estilo de programação estruturada:
## ID: ZBH-0012 - Filtrar por produto
import sys
from selenium.webdriver import Firefox
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from time import sleep
sys.path.append("projetols")
navegador = Firefox()
navegador.get("https://projetofinal.jogajuntoinstituto.org/")
sleep(2)
campo_email = navegador.find_element(By.NAME, "email")
campo_email.send_keys("leanderson.devlima@gmail.com")
campo_senha = navegador.find_element(By.NAME, "password")
campo_senha.send_keys("jcjcjc@33")
sleep(2)
botao = navegador.find_element(By.XPATH, '//*[@id="root"]/main/form/button')
botao.click()
sleep(2)
def green(message):
print("\033[92m" + message + "\033[0m")
def red(message):
print("\033[91m" + message + "\033[0m")
def check_category_success(navegador, link_xpath, item_name):
try:
link = navegador.find_element(By.XPATH, link_xpath)
link.click()
sleep(2)
if item_name in navegador.page_source:
green(f"\nO acesso à categoria '{item_name}' foi bem-sucedido!")
else:
raise NoSuchElementException()
except NoSuchElementException:
red(f"\nO acesso à categoria '{item_name}' não foi bem-sucedido! (Categoria não encontrada)")
def check_item_in_category(navegador, link_xpath, item_name, category_name):
try:
link = navegador.find_element(By.XPATH, link_xpath)
link.click()
sleep(3)
if item_name in navegador.page_source:
green(f"-► Item '{item_name}' encontrado na categoria '{category_name}'")
else:
raise NoSuchElementException()
except NoSuchElementException:
red(f"-► Item '{item_name}' não encontrado na categoria '{category_name}'")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[1]/li', "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[3]/div[1]/img', "roupateste", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[4]/div[1]/img', "Cal", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[5]/div[1]/img', "Oculos SP", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[6]/div[1]/img', "Miçanga BA", "Todos")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[2]/li', "Roupas")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "roupateste", "Roupas")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[3]/li', "Calçados")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "Cal", "Calçados")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[4]/li', "Acessórios")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "Oculos SP", "Acessórios")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[2]/img', "Miçanga BA", "Acessórios")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[5]/li', "Elemento Inexistente")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[7]/div[1]/img', "Acesorio3(nao existe)", "Todos")
sleep(2)
navegador.quit()
Detalhes desse código e seus resultados estão na próxima etapa dos testes automatizados e o arquivo correspondente está nesse repositório no caminho Automacao\automacao.py.
► Testes automatizados II | Programação Orientada a Objetos 🌟
Nessa abordagem usamos um estilo de programação Orientado a Objetos onde cada fução foi dividida em arquivos diferentes:
def green(message):
print("\033[92m" + message + "\033[0m")
def red(message):
print("\033[91m" + message + "\033[0m")
Essa função que está em Automacao\terminal.py tem o propósito de pintar no temrinal de verde e de vermelho, sendo intuitivamente verde para um caso de sucesso e vermelho em caso de falha ou bug.
from selenium.webdriver.common.by import By
def login(navegador, email, senha):
campo_email = navegador.find_element(By.NAME, "email")
campo_email.send_keys(email)
campo_senha = navegador.find_element(By.NAME, "password")
campo_senha.send_keys(senha)
Essa função tem o propósito inserir o email e a senha nos campos corretos da nossa aplicação alvo. O arquivo correspondente está em Automacao\login.py.
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from time import sleep
from terminal import green, red
def check_category_success(navegador, link_xpath, item_name):
try:
link = navegador.find_element(By.XPATH, link_xpath)
link.click()
sleep(2)
if item_name in navegador.page_source:
green(f"\nO acesso à categoria '{item_name}' foi bem-sucedido!")
else:
raise NoSuchElementException()
except NoSuchElementException:
red(f"\nO acesso à categoria '{item_name}' não foi bem-sucedido! (Categoria não encontrada)")
Essa função tem o propósito de encontrar a categoria e informar no terminal em caso de sucesso. O laço de repetição escolhido foi o 'try' 'except' pois em caso de falha ao encontrar a categoria o código iria exibir um erro de 'NoSuchElementException', o que interromperia a execução do mesmo. Porém o 'raise' que está dentro de 'else' obriga o código a executar o comando que está em 'except'. Exibindo no terminal a informação referente a uma operação malsucedida. O arquivo que se refere a essa função está em Automacao\check_category.py.
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from time import sleep
from terminal import green, red
def check_item_in_category(navegador, link_xpath, item_name, category_name):
try:
link = navegador.find_element(By.XPATH, link_xpath)
link.click()
sleep(3)
if item_name in navegador.page_source:
green(f"-► Item '{item_name}' encontrado na categoria '{category_name}'")
else:
raise NoSuchElementException()
except NoSuchElementException:
red(f"-► Item '{item_name}' não encontrado na categoria '{category_name}'")
A mesma lógica da função 'check_category_success' foi usada para a função 'check_item_in_category'. O arquivo correspondente está em Automacao\check_item.py.
## ID: ZBH-0012 - Filtrar por produto
import sys
from selenium.webdriver import Firefox
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from time import sleep
from check_category import check_category_success
from check_item import check_item_in_category
from login import login
sys.path.append("projetols")
navegador = Firefox()
navegador.get("https://projetofinal.jogajuntoinstituto.org/")
sleep(1)
login(navegador, "leanderson.devlima@gmail.com", "jcjcjc@33")
sleep(1)
botao = navegador.find_element(By.XPATH, '//*[@id="root"]/main/form/button')
botao.click()
sleep(1)
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[1]/li', "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[3]/div[1]/img', "roupateste", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[4]/div[1]/img', "Cal", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[5]/div[1]/img', "Oculos SP", "Todos")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[6]/div[1]/img', "Miçanga BA", "Todos")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[2]/li', "Roupas")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "roupateste", "Roupas")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[3]/li', "Calçados")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "Cal", "Calçados")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[4]/li', "Acessórios")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[1]/img', "Oculos SP", "Acessórios")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div/div[2]/img', "Miçanga BA", "Acessórios")
check_category_success(navegador, '/html/body/div/header/section[2]/nav/ul/div[2]/div[1]/div[5]/li', "Elemento Inexistente")
check_item_in_category(navegador, '/html/body/div/header/section[2]/div/div/div/div[7]/div[1]/img', "Acesorio3(nao existe)", "Todos")
sleep(3)
navegador.quit()
Por fim temos o arquivo Automacao\main.py onde ele importa todas essas funções e passa os argumentos solicitados por elas para que possam ser executadas.
Resultado no terminal:
► Testes automatizados III | Biblioteca Behave 🌟
Automação utilizando a biblioteca Behave.
Para realização dessa parte da atividade nossa squad usou o cenário de testes ZBH-0001 - Login.
Estrutura padrão:
No arquivo automacao.feature estão as etapas do teste que será realizado.
Feature: Acessar categorias de produtos
@testeLogin
Scenario: Fazer login
Given o usuário está na página inicial
When o usuário insere os dados para login, email e senha
And o usuário clica no botão Iniciar sessão
Then o sistema permite o login e fecha o navegador
No arquivo steps.py:
from behave import given, when, then
from selenium.webdriver import Firefox
from selenium.webdriver.common.by import By
from time import sleep
@given("o usuário está na página inicial")
def step_given_acessar_pagina_inicial(context):
context.navegador = Firefox()
context.navegador.get("https://projetofinal.jogajuntoinstituto.org/")
@when("o usuário insere os dados para login, email e senha")
def step_when_fazer_login(context):
context.email = "leanderson.devlima@gmail.com"
context.senha = "jcjcjc@33"
campo_email = context.navegador.find_element(By.NAME, "email")
campo_senha = context.navegador.find_element(By.NAME, "password")
campo_email.send_keys(context.email)
campo_senha.send_keys(context.senha)
@when("o usuário clica no botão Iniciar sessão")
def step_button_click(context):
botao = context.navegador.find_element(By.XPATH, '//*[@id="root"]/main/form/button')
botao.click()
sleep(3)
@then('o sistema permite o login e fecha o navegador')
def login_success(context):
expected_url = "https://projetofinal.jogajuntoinstituto.org/products"
current_url = context.navegador.current_url
assert current_url == expected_url, "URL incorreta após o login. O login falhou."
context.navegador.quit()
O propósito desse último teste, conforme foi explicado e demonstrado durante a apresentação, foi executar um login com sucesso e fechar o navegador em seguida.
A execução dessa parte do trabalho mostrou que nossa squad deve procurar criar mais intimidade com essa estrutura de execução de testes e com a biblioteca behave, porém com esforço, dedicação e trabalho em equipe, conseguimos finalizar a parte de automação com sucesso.
Testes de API 🌟
A estrutura da API foi construída manualmente com base no Swagger, uma vez que não foi viável importá-la automaticamente no Postman.
De início foi definida uma variável para que não precisassemos inserir a mesma URL em cada requisição.
O primeiro método GET serviu para verificar se a API estava em funcionamento. O que durante a apresentação foi demonstrado com sucesso.
Em seguida o POST faz o registro de um usuário.
O próximo POST faz o login desse mesmo usuário gerando um token. O que nos leva para o próximo GET onde o token, que era dinâmico, nos obrigava a fazer o login constantemente para pegar um novo token. Para encurtar esse processo, configuramos no Pre-request o seguinte Script:
pm.sendRequest({
url: 'http://apipf.jogajuntoinstituto.org/login',
method: 'POST',
header: {
'accept': 'application/json',
'Content-Type': 'application/json'
},
body: {
mode: 'raw',
raw: JSON.stringify({
"email": "leanderson.devlima@gmail.com",
"password": "xxxx@senha"
})
}
}, function (err, res) {
pm.environment.set('tokenJogaJunto', res.json().token);
});
Nesse pré-requisito (pre-request) está ocorrendo o seguinte:
-
Uma solicitação POST está sendo enviada para a URL 'http://apipf.jogajuntoinstituto.org/login'.
-
A solicitação inclui um cabeçalho (header) que indica que o cliente aceita uma resposta no formato JSON e informa que o conteúdo enviado é no formato JSON.
-
O corpo da solicitação (body) contém um objeto JSON que representa as informações de login, com um endereço de e-mail e senha.
-
A resposta à solicitação será processada em uma função que verifica se ocorreu algum erro e, se não houver erros, extrai o token de autenticação da resposta JSON e o armazena no ambiente de trabalho do Postman com a chave 'tokenJogaJunto'. Isso é feito para que o token de autenticação possa ser usado em solicitações subsequentes.
Resumidamente, esse script está fazendo a solicitação de login, enviando as credenciais de login e armazenando o token de autenticação na variável 'tokenJogaJunto'. Seguindo adiante dando o comando GET.
Na sequencia o POST nos permite cadastrar um produto para um usuário que já está logado.
Ao cadastrar um produto obtemos seu ID, o que nos permite usar método DELETE:
Cada etapa do funcionamento da API foi demonstrada com sucesso durante a apresentação.
Considerações Finais e Agradecimentos 🌟
Queremos expressar nossa sincera gratidão ao Instituto JogaJunto pela oportunidade incrível de participar do curso de QA e do emocionante projeto Trip. Este curso e projeto moldaram significativamente nossa jornada de aprendizado, e estamos imensamente agradecidos por isso.
Durante todo o processo, o trabalho em equipe e a colaboratividade foram os pilares do nosso sucesso. Cada desafio e obstáculo que enfrentamos foi superado graças à dedicação e parceria entre todos os membros da squad. A Sara e eu trabalhamos incansavelmente para entregar um projeto que refletisse o nosso compromisso com a qualidade e a excelência.
Infelizmente, tivemos algumas desistências ao longo do caminho, o que nos sobrecarregou, mas decidimos enfrentar esses desafios com determinação. Isso nos ensinou a importância da resiliência e do trabalho em equipe.
Por fim, agradecemos profundamente ao Instituto JogaJunto por compartilhar seu conhecimento, orientação e apoio. Este curso não apenas nos forneceu as habilidades técnicas necessárias, mas também nos inspirou a crescer como profissionais e como indivíduos.
Foi uma honra ter feito parte do projeto Trip e ser chamado de "tripper". Esperamos que este projeto seja apenas o começo de uma jornada incrível em qualidade de software. Obrigado por acreditar em nós e nos capacitar a alcançar nosso potencial.
Com gratidão,
Leanderson Lima 👨🏾💻 | Sara J. M da Cruz 👩🏾💻