From f33005173678e4a6402e3d6ebe6c1cd6bf8158f0 Mon Sep 17 00:00:00 2001 From: vmg192 Date: Sun, 14 Dec 2025 15:53:12 -0300 Subject: [PATCH] =?UTF-8?q?##=20Testes=20Cucumber=20BDD=20-=20Corrigidos?= =?UTF-8?q?=20todos=20os=2025=20cen=C3=A1rios=20(133=20steps)=20-=20**100%?= =?UTF-8?q?=20passando**=20-=20Todas=20as=20features=20implementadas=20por?= =?UTF-8?q?=20completo=20t=C3=AAm=20Happy=20e=20Sad=20paths.=20-=20Algumas?= =?UTF-8?q?=20features=20parcialmente=20implementadas=20com=20alguns=20tes?= =?UTF-8?q?tes=20faltando,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Aplicação - `sigaa_import_service.rb`: corrigido mapeamento de nomes de turmas - `csv_formatter_service.rb`: CSV anonimizado (sem matrícula/nome) - `resultados.html.erb`: alteração no estilo de visualização dos resultados ## Infraestrutura - `reset_db.sh` e `seeds.rb`: corrigido para ter todos os usuários iniciais --- README.md | 6 +- app/controllers/avaliacoes_controller.rb | 33 ++++ app/controllers/sigaa_imports_controller.rb | 8 +- app/services/csv_formatter_service.rb | 8 +- app/services/sigaa_import_service.rb | 27 ++- app/views/avaliacoes/resultados.html.erb | 123 ++++++++++-- db/schema.rb | 5 - db/seeds.rb | 24 ++- features/atualizar_base_de_dados.feature | 9 +- features/cadastra_usuarios.feature | 20 ++ "features/cadastra_usu\303\241rios.feature" | 32 --- features/cria_template_formulario.feature | 1 + features/definir_senha.feature | 1 + .../edicao_remocao_template.feature | 2 + features/importa_dados_sigaa.feature | 8 +- features/responder_formulario.feature | 21 +- .../atualizar_base_dados_steps.rb | 38 ++-- .../step_definitions/cria_avaliacao_steps.rb | 24 ++- .../importa_dados_sigaa_steps.rb | 146 +++++++------- features/step_definitions/relatorio_steps.rb | 83 +++++++- .../responder_formulario_steps.rb | 184 ++++++++++++++++++ .../step_definitions/resultados_adm_steps.rb | 58 +----- features/step_definitions/resultados_steps.rb | 74 +++++-- features/step_definitions/shared_steps.rb | 44 +++-- .../step_definitions/student_view_steps.rb | 86 ++++++-- .../visualizacao_formulario_steps.rb | 34 +--- features/visualiza_templates.feature | 1 + .../visualizacao_formulario.feature | 0 .../visualizacao_formulario_resultado.feature | 0 reset_db.sh | 6 +- spec/services/csv_formatter_service_spec.rb | 20 +- 31 files changed, 789 insertions(+), 337 deletions(-) create mode 100644 features/cadastra_usuarios.feature delete mode 100644 "features/cadastra_usu\303\241rios.feature" rename "features/edi\303\247\303\243o_remo\303\247\303\243o_template.feature" => features/edicao_remocao_template.feature (98%) create mode 100644 features/step_definitions/responder_formulario_steps.rb rename "features/visualiza\303\247\303\243o_formul\303\241rio.feature" => features/visualizacao_formulario.feature (100%) rename "features/visualiza\303\247\303\243o_formulario_resultado.feature" => features/visualizacao_formulario_resultado.feature (100%) diff --git a/README.md b/README.md index e03c0fa3cb..af77f53a93 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ Acesse: http://localhost:3000 ## Testes ```bash -# Rodar testes BDD +# Rodar todos os testes BDD (25 cenários, 133 steps) +bundle exec cucumber --tags "not @wip" + +# Rodar feature específica bundle exec cucumber features/sistema_login.feature ``` + diff --git a/app/controllers/avaliacoes_controller.rb b/app/controllers/avaliacoes_controller.rb index e855f9a70e..8ff5e9b7dd 100644 --- a/app/controllers/avaliacoes_controller.rb +++ b/app/controllers/avaliacoes_controller.rb @@ -56,8 +56,12 @@ def resultados # Pré-carrega dependências para evitar N+1. begin @submissoes = @avaliacao.submissoes.includes(:aluno, :respostas) + @perguntas = @avaliacao.modelo.perguntas.order(:id) + @question_stats = build_question_statistics(@avaliacao) rescue ActiveRecord::StatementInvalid @submissoes = [] + @perguntas = [] + @question_stats = {} flash.now[:alert] = "Erro ao carregar submissões." end @@ -69,4 +73,33 @@ def resultados end end end + + private + + def build_question_statistics(avaliacao) + avaliacao.modelo.perguntas.each_with_object({}) do |pergunta, stats| + respostas = Resposta.joins(:submissao) + .where(submissoes: { avaliacao_id: avaliacao.id }) + .where(questao_id: pergunta.id) + + if [ "multipla_escolha", "checkbox", "escala" ].include?(pergunta.tipo) + # Conta cada opção escolhida + stats[pergunta.id] = { + type: pergunta.tipo, + data: respostas.group(:conteudo).count, + total: respostas.count, + responses: [] + } + else + # Para texto, inclui as respostas para exibição + text_responses = respostas.pluck(:conteudo).compact.reject(&:blank?) + stats[pergunta.id] = { + type: pergunta.tipo, + data: {}, + total: respostas.count, + responses: text_responses + } + end + end + end end diff --git a/app/controllers/sigaa_imports_controller.rb b/app/controllers/sigaa_imports_controller.rb index 2f208da9b6..40dff6936f 100644 --- a/app/controllers/sigaa_imports_controller.rb +++ b/app/controllers/sigaa_imports_controller.rb @@ -9,14 +9,15 @@ def new def create # Usa automaticamente o arquivo class_members.json do projeto file_path = Rails.root.join("class_members.json") + classes_file_path = Rails.root.join("classes.json") unless File.exist?(file_path) redirect_to new_sigaa_import_path, alert: "Arquivo class_members.json não encontrado no projeto." return end - # Processa a importação - service = SigaaImportService.new(file_path) + # Processa a importação (passa classes.json se existir) + service = SigaaImportService.new(file_path, classes_file_path) @results = service.process if @results[:errors].any? @@ -34,13 +35,14 @@ def create def update # Usa automaticamente o arquivo class_members.json do projeto (atualização) file_path = Rails.root.join("class_members.json") + classes_file_path = Rails.root.join("classes.json") unless File.exist?(file_path) redirect_to new_sigaa_import_path, alert: "Arquivo class_members.json não encontrado no projeto." return end - service = SigaaImportService.new(file_path) + service = SigaaImportService.new(file_path, classes_file_path) @results = service.process if @results[:errors].any? diff --git a/app/services/csv_formatter_service.rb b/app/services/csv_formatter_service.rb index b38cf162c0..20744f31e7 100644 --- a/app/services/csv_formatter_service.rb +++ b/app/services/csv_formatter_service.rb @@ -10,8 +10,8 @@ def generate csv << headers @avaliacao.submissoes.includes(:aluno, :respostas).each do |submissao| - aluno = submissao.aluno - row = [ aluno.matricula, aluno.nome ] + # Usar ID anônimo em vez do nome/matrícula do aluno para privacidade + row = [ submissao.id ] # Organiza as respostas pela ordem das questões se possível, ou mapeamento simples # Assumindo que queremos mapear questões para colunas @@ -31,8 +31,8 @@ def generate private def headers - # Cabeçalhos estáticos para informações do Aluno - base_headers = [ "Matrícula", "Nome" ] + # Cabeçalho anônimo (sem identificação do aluno para privacidade) + base_headers = [ "Submissão" ] # Cabeçalhos dinâmicos para questões # Identificando questões únicas respondidas ou todas as questões do modelo diff --git a/app/services/sigaa_import_service.rb b/app/services/sigaa_import_service.rb index 7d4842387a..967f9f78ec 100644 --- a/app/services/sigaa_import_service.rb +++ b/app/services/sigaa_import_service.rb @@ -2,8 +2,9 @@ require "csv" class SigaaImportService - def initialize(file_path) + def initialize(file_path, classes_file_path = nil) @file_path = file_path + @classes_file_path = classes_file_path @results = { turmas_created: 0, turmas_updated: 0, @@ -50,13 +51,18 @@ def process def process_json data = JSON.parse(File.read(@file_path)) + classes_lookup = build_classes_lookup # class_members.json é um array de turmas data.each do |turma_data| + # Busca o nome real da turma em classes.json + class_key = [ turma_data["code"], turma_data["semester"] ] + class_name = classes_lookup[class_key] || turma_data["code"] + # Mapeia campos do formato real para o esperado normalized_data = { "codigo" => turma_data["code"], - "nome" => turma_data["code"], # Usa o código como nome se não tiver + "nome" => class_name, "semestre" => turma_data["semester"], "participantes" => [] } @@ -88,6 +94,23 @@ def process_json end end + # Constrói um hash de lookup para nomes de turmas a partir de classes.json + def build_classes_lookup + return {} unless @classes_file_path && File.exist?(@classes_file_path) + + begin + classes_data = JSON.parse(File.read(@classes_file_path)) + classes_data.each_with_object({}) do |item, hash| + # Usa code + semester como chave composta + key = [ item["code"], item.dig("class", "semester") ] + hash[key] = item["name"] + end + rescue JSON::ParserError + @results[:errors] << "Arquivo classes.json inválido" + {} + end + end + def process_csv CSV.foreach(@file_path, headers: true, col_sep: ",") do |row| # Assumindo estrutura do CSV diff --git a/app/views/avaliacoes/resultados.html.erb b/app/views/avaliacoes/resultados.html.erb index 532c50a395..5e12b205c6 100644 --- a/app/views/avaliacoes/resultados.html.erb +++ b/app/views/avaliacoes/resultados.html.erb @@ -1,4 +1,8 @@ <% content_for :page_title, "Gerenciamento - Gestão de Envios - Resultados" %> + + + +

Resultados da Avaliação

@@ -9,33 +13,110 @@

Turma: <%= @avaliacao.turma.codigo %> - <%= @avaliacao.turma.nome %>

Template: <%= @avaliacao.modelo.titulo %>

+

Total de Submissões: <%= @submissoes.count %>

<% if @submissoes.any? %> -
+
<%= link_to "Download CSV", resultados_avaliacao_path(@avaliacao, format: :csv), class: "bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded" %>
-
- - - - - - - - - - <% @submissoes.each do |submissao| %> - - - - - - <% end %> - -
MatrículaAlunoEnvio
<%= submissao.aluno&.matricula %><%= submissao.aluno&.nome %><%= submissao.respostas.count %> respostas
-
+ +

Estatísticas das Respostas

+ + <% @perguntas.each_with_index do |pergunta, index| %> +
+

+ Questão <%= index + 1 %>: <%= pergunta.enunciado %> +

+

Tipo: <%= pergunta.tipo_humanizado %>

+ + <% stats = @question_stats[pergunta.id] || { type: pergunta.tipo, data: {}, total: 0, responses: [] } %> + + <% if %w[multipla_escolha checkbox escala].include?(pergunta.tipo) && stats[:data].any? %> + +
+ +
+ + <% elsif %w[texto_curto texto_longo].include?(pergunta.tipo) %> + +
+

+ <%= stats[:total] %> respostas recebidas +

+ <% if stats[:responses].present? && stats[:responses].any? %> +
+ <% stats[:responses].each_with_index do |response, resp_index| %> +
+

<%= response %>

+
+ <% end %> +
+ <% elsif stats[:total] > 0 %> +

+ Nenhuma resposta de texto disponível. +

+ <% end %> +
+ <% else %> + +
+

+ <%= stats[:total] %> respostas recebidas +

+
+ <% end %> +
+ <% end %> + <% else %>