diff --git a/app/components/polls/results/question_component.html.erb b/app/components/polls/results/question_component.html.erb
index 512d012f8..422ec44bb 100644
--- a/app/components/polls/results/question_component.html.erb
+++ b/app/components/polls/results/question_component.html.erb
@@ -1,25 +1,46 @@
<%= question.title %>
-
-
- <%- question.question_options.each do |option| %>
- |
- <% if most_voted_option?(option) %>
- <%= t("polls.show.results.most_voted_answer") %>
- <% end %>
- <%= option.title %>
- |
- <% end %>
-
-
-
-
- <%- question.question_options.each do |option| %>
-
- <%= option.total_votes %>
- (<%= option.total_votes_percentage.round(2) %>%)
+ <% if question.accepts_options? %>
+
+
+ <%- question.question_options.each do |option| %>
+ |
+ <% if most_voted_option?(option) %>
+ <%= t("polls.show.results.most_voted_answer") %>
+ <% end %>
+ <%= option.title %>
+ |
+ <% end %>
+
+
+ |
+
+ <%- question.question_options.each do |option| %>
+ |
+ <%= option.total_votes %>
+ (<%= option.total_votes_percentage.round(2) %>%)
+ |
+ <% end %>
+
+
+ <% else %>
+
+
+ | <%= t("polls.show.results.open_ended.valid") %> |
+ <%= t("polls.show.results.open_ended.blank") %> |
+
+
+
+
+ |
+ <%= question.open_ended_valid_answers_count %>
+ (<%= question.open_ended_valid_percentage.round(2) %>%)
|
- <% end %>
-
-
+
+ <%= question.open_ended_blank_answers_count %>
+ (<%= question.open_ended_blank_percentage.round(2) %>%)
+ |
+
+
+ <% end %>
diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb
index f40d47d33..d6c9fc763 100644
--- a/app/models/poll/question.rb
+++ b/app/models/poll/question.rb
@@ -87,6 +87,26 @@ class Poll::Question < ApplicationRecord
answer
end
+ def open_ended_valid_answers_count
+ answers.count
+ end
+
+ def open_ended_blank_answers_count
+ poll.voters.count - open_ended_valid_answers_count
+ end
+
+ def open_ended_valid_percentage
+ return 0.0 if open_ended_total_answers.zero?
+
+ (open_ended_valid_answers_count * 100.0) / open_ended_total_answers
+ end
+
+ def open_ended_blank_percentage
+ return 0.0 if open_ended_total_answers.zero?
+
+ (open_ended_blank_answers_count * 100.0) / open_ended_total_answers
+ end
+
private
def find_by_attributes(user, option_id)
@@ -96,4 +116,8 @@ class Poll::Question < ApplicationRecord
{ author: user }
end
end
+
+ def open_ended_total_answers
+ open_ended_valid_answers_count + open_ended_blank_answers_count
+ end
end
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml
index f4f37c0a9..ae79e1ba7 100644
--- a/config/locales/en/general.yml
+++ b/config/locales/en/general.yml
@@ -639,6 +639,9 @@ en:
results:
title: "Questions"
most_voted_answer: "Most voted answer: "
+ open_ended:
+ valid: Valid
+ blank: Blank
poll_header:
back_to_proposal: Back to proposal
poll_questions:
diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml
index ca07be430..dd7e63c3e 100644
--- a/config/locales/es/general.yml
+++ b/config/locales/es/general.yml
@@ -639,6 +639,9 @@ es:
results:
title: "Preguntas"
most_voted_answer: "Respuesta más votada: "
+ open_ended:
+ valid: Válidos
+ blank: En blanco
poll_header:
back_to_proposal: Volver a la propuesta
poll_questions:
diff --git a/spec/components/polls/results/question_component_spec.rb b/spec/components/polls/results/question_component_spec.rb
new file mode 100644
index 000000000..562bb0d28
--- /dev/null
+++ b/spec/components/polls/results/question_component_spec.rb
@@ -0,0 +1,47 @@
+require "rails_helper"
+
+describe Polls::Results::QuestionComponent do
+ context "question that accepts options" do
+ let(:question) { create(:poll_question, :yes_no) }
+ let(:option_yes) { question.question_options.find_by(title: "Yes") }
+ let(:option_no) { question.question_options.find_by(title: "No") }
+
+ it "renders results table content" do
+ create(:poll_answer, question: question, option: option_yes)
+ create(:poll_answer, question: question, option: option_no)
+
+ render_inline Polls::Results::QuestionComponent.new(question)
+
+ expect(page).to have_table with_rows: [{ "Most voted answer: Yes" => "1 (50.0%)",
+ "No" => "1 (50.0%)" }]
+
+ page.find("table") do |table|
+ expect(table).to have_css "th.win", count: 1
+ expect(table).to have_css "td.win", count: 1
+ end
+ end
+ end
+
+ context "question that does not accept options" do
+ let(:open_ended_question) { create(:poll_question_open) }
+
+ it "renders open_ended headers and empty counts when there are no participants" do
+ render_inline Polls::Results::QuestionComponent.new(open_ended_question)
+
+ expect(page).to have_table with_rows: [{ "Valid" => "0 (0.0%)",
+ "Blank" => "0 (0.0%)" }]
+ end
+
+ it "renders counts and percentages provided by the model metrics" do
+ allow(open_ended_question).to receive_messages(
+ open_ended_valid_answers_count: 3,
+ open_ended_blank_answers_count: 1
+ )
+
+ render_inline Polls::Results::QuestionComponent.new(open_ended_question)
+
+ expect(page).to have_table with_rows: [{ "Valid" => "3 (75.0%)",
+ "Blank" => "1 (25.0%)" }]
+ end
+ end
+end
diff --git a/spec/components/polls/results_component_spec.rb b/spec/components/polls/results_component_spec.rb
index 26c086215..d3a7257e3 100644
--- a/spec/components/polls/results_component_spec.rb
+++ b/spec/components/polls/results_component_spec.rb
@@ -3,47 +3,34 @@ require "rails_helper"
describe Polls::ResultsComponent do
let(:poll) { create(:poll) }
- let(:question_1) { create(:poll_question, poll: poll, title: "Do you like Consul Democracy?") }
- let(:option_yes) { create(:poll_question_option, question: question_1, title: "Yes") }
- let(:option_no) { create(:poll_question_option, question: question_1, title: "No") }
+ let(:question_1) { create(:poll_question, :yes_no, poll: poll, title: "Do you like Consul Democracy?") }
+ let(:option_yes) { question_1.question_options.find_by(title: "Yes") }
+ let(:option_no) { question_1.question_options.find_by(title: "No") }
- let(:question_2) { create(:poll_question, poll: poll, title: "What's your favorite color?") }
- let(:option_blue) { create(:poll_question_option, question: question_2, title: "Blue") }
- let(:option_green) { create(:poll_question_option, question: question_2, title: "Green") }
- let(:option_yellow) { create(:poll_question_option, question: question_2, title: "Yellow") }
+ let(:question_2) { create(:poll_question, :abc, poll: poll, title: "Which option do you prefer?") }
+ let(:option_a) { question_2.question_options.find_by(title: "Answer A") }
+ let(:option_b) { question_2.question_options.find_by(title: "Answer B") }
+ let(:option_c) { question_2.question_options.find_by(title: "Answer C") }
it "renders results content" do
create_list(:poll_answer, 2, question: question_1, option: option_yes)
create(:poll_answer, question: question_1, option: option_no)
- create(:poll_answer, question: question_2, option: option_blue)
- create(:poll_answer, question: question_2, option: option_green)
- create(:poll_answer, question: question_2, option: option_yellow)
+ create(:poll_answer, question: question_2, option: option_a)
+ create(:poll_answer, question: question_2, option: option_b)
+ create(:poll_answer, question: question_2, option: option_c)
render_inline Polls::ResultsComponent.new(poll)
expect(page).to have_content "Do you like Consul Democracy?"
+ expect(page).to have_table "question_#{question_1.id}_results_table",
+ with_rows: [{ "Most voted answer: Yes" => "2 (66.67%)",
+ "No" => "1 (33.33%)" }]
- page.find("#question_#{question_1.id}_results_table") do |table|
- expect(table).to have_css "#option_#{option_yes.id}_result", text: "2 (66.67%)", normalize_ws: true
- expect(table).to have_css "#option_#{option_no.id}_result", text: "1 (33.33%)", normalize_ws: true
- end
-
- expect(page).to have_content "What's your favorite color?"
-
- page.find("#question_#{question_2.id}_results_table") do |table|
- expect(table).to have_css "#option_#{option_blue.id}_result", text: "1 (33.33%)", normalize_ws: true
- expect(table).to have_css "#option_#{option_green.id}_result", text: "1 (33.33%)", normalize_ws: true
- expect(table).to have_css "#option_#{option_yellow.id}_result", text: "1 (33.33%)", normalize_ws: true
- end
- end
-
- it "renders results for polls with questions but without answers" do
- poll = create(:poll, :expired, results_enabled: true)
- question = create(:poll_question, poll: poll)
-
- render_inline Polls::ResultsComponent.new(poll)
-
- expect(page).to have_content question.title
+ expect(page).to have_content "Which option do you prefer?"
+ expect(page).to have_table "question_#{question_2.id}_results_table",
+ with_rows: [{ "Most voted answer: Answer A" => "1 (33.33%)",
+ "Answer B" => "1 (33.33%)",
+ "Answer C" => "1 (33.33%)" }]
end
end
diff --git a/spec/models/poll/question_spec.rb b/spec/models/poll/question_spec.rb
index f0f5e0882..f882b0503 100644
--- a/spec/models/poll/question_spec.rb
+++ b/spec/models/poll/question_spec.rb
@@ -188,4 +188,87 @@ RSpec.describe Poll::Question do
end
end
end
+
+ context "open-ended results" do
+ let(:poll) { create(:poll) }
+ let!(:question_open) { create(:poll_question_open, poll: poll) }
+
+ it "includes voters who didn't answer any questions in blank answers count" do
+ create(:poll_voter, poll: poll)
+
+ expect(question_open.open_ended_blank_answers_count).to eq 1
+ expect(question_open.open_ended_valid_answers_count).to eq 0
+ end
+
+ describe "#open_ended_valid_answers_count" do
+ it "returns 0 when there are no answers" do
+ expect(question_open.open_ended_valid_answers_count).to eq 0
+ end
+
+ it "counts answers" do
+ create(:poll_answer, question: question_open, answer: "Hello")
+ create(:poll_answer, question: question_open, answer: "Bye")
+
+ expect(question_open.open_ended_valid_answers_count).to eq 2
+ end
+ end
+
+ describe "#open_ended_blank_answers_count" do
+ let(:another_question) { create(:poll_question, :yes_no, poll: poll) }
+ let(:option_yes) { another_question.question_options.find_by(title: "Yes") }
+ let(:option_no) { another_question.question_options.find_by(title: "No") }
+
+ it "counts valid participants of the poll who did not answer the open-ended question" do
+ voters = create_list(:poll_voter, 3, poll: poll)
+ voters.each do |voter|
+ create(:poll_answer, question: another_question, author: voter.user, option: option_yes)
+ end
+ create(:poll_answer, question: question_open, author: voters.sample.user, answer: "Free text")
+
+ expect(question_open.open_ended_valid_answers_count).to eq 1
+ expect(question_open.open_ended_blank_answers_count).to eq 2
+ end
+
+ it "returns 0 when there are no valid participants in the poll" do
+ expect(question_open.open_ended_blank_answers_count).to eq 0
+ end
+
+ it "counts every user one time even if they answered many questions" do
+ multiple_question = create(:poll_question_multiple, :abc, poll: poll)
+ option_a = multiple_question.question_options.find_by(title: "Answer A")
+ option_b = multiple_question.question_options.find_by(title: "Answer B")
+ another_question_open = create(:poll_question_open, poll: poll)
+
+ voter = create(:poll_voter, poll: poll)
+
+ create(:poll_answer, question: multiple_question, author: voter.user, option: option_a)
+ create(:poll_answer, question: multiple_question, author: voter.user, option: option_b)
+ create(:poll_answer, question: another_question, author: voter.user, option: option_yes)
+ create(:poll_answer, question: another_question_open, author: voter.user, answer: "Free text")
+
+ expect(question_open.open_ended_blank_answers_count).to eq 1
+ end
+ end
+
+ describe "percentages" do
+ it "returns 0.0 when there aren't any answers" do
+ expect(question_open.open_ended_valid_percentage).to eq 0.0
+ expect(question_open.open_ended_blank_percentage).to eq 0.0
+ end
+
+ it "calculates valid and blank percentages based on counts" do
+ another_question = create(:poll_question, :yes_no, poll: poll)
+ option_yes = another_question.question_options.find_by(title: "Yes")
+
+ voters = create_list(:poll_voter, 4, poll: poll)
+ voters.each do |voter|
+ create(:poll_answer, question: another_question, author: voter.user, option: option_yes)
+ end
+ create(:poll_answer, question: question_open, author: voters.sample.user, answer: "A")
+
+ expect(question_open.open_ended_valid_percentage).to eq 25.0
+ expect(question_open.open_ended_blank_percentage).to eq 75.0
+ end
+ end
+ end
end