Merge pull request #6061 from consuldemocracy/poll_text_answers
Add support for essay poll questions
This commit is contained in:
@@ -16,4 +16,13 @@ describe Officing::Results::FormComponent do
|
||||
expect(page).to have_field "Invalid ballots", with: 0, type: :number
|
||||
expect(page).to have_field "Valid ballots", with: 0, type: :number
|
||||
end
|
||||
|
||||
it "does not render open-ended questions" do
|
||||
create(:poll_question_open, poll: poll, title: "What do you want?")
|
||||
|
||||
render_inline Officing::Results::FormComponent.new(poll, Poll::OfficerAssignment.none)
|
||||
|
||||
expect(page).not_to have_content "What do you want?"
|
||||
expect(page).to have_css "fieldset", text: "Agreed?"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,5 +69,26 @@ describe Polls::Questions::QuestionComponent do
|
||||
expect(page).to have_field "Yes", type: :radio, checked: true
|
||||
expect(page).to have_field "No", type: :radio, checked: false
|
||||
end
|
||||
|
||||
context "Open-ended question" do
|
||||
let(:question) { create(:poll_question_open, poll: poll, title: "What do you want?") }
|
||||
before { create(:poll_answer, author: user, question: question, answer: "I don't know") }
|
||||
|
||||
it "renders text area with persisted answer" do
|
||||
render_inline Polls::Questions::QuestionComponent.new(question, form: form)
|
||||
|
||||
expect(page).to have_field "What do you want?", type: :textarea, with: "I don't know"
|
||||
end
|
||||
|
||||
it "renders unsaved form text over the persisted value" do
|
||||
web_vote.answers[question.id] = [
|
||||
build(:poll_answer, question: question, author: user, answer: "Typed (unsaved)")
|
||||
]
|
||||
|
||||
render_inline Polls::Questions::QuestionComponent.new(question, form: form)
|
||||
|
||||
expect(page).to have_field "What do you want?", type: :textarea, with: "Typed (unsaved)"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
47
spec/components/polls/results/question_component_spec.rb
Normal file
47
spec/components/polls/results/question_component_spec.rb
Normal file
@@ -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
|
||||
36
spec/components/polls/results_component_spec.rb
Normal file
36
spec/components/polls/results_component_spec.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Polls::ResultsComponent do
|
||||
let(:poll) { create(:poll) }
|
||||
|
||||
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, :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_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%)" }]
|
||||
|
||||
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
|
||||
@@ -60,6 +60,7 @@ FactoryBot.define do
|
||||
|
||||
trait :yes_no do
|
||||
after(:create) do |question|
|
||||
create(:votation_type_unique, questionable: question)
|
||||
create(:poll_question_option, question: question, title: "Yes")
|
||||
create(:poll_question_option, question: question, title: "No")
|
||||
end
|
||||
@@ -94,6 +95,12 @@ FactoryBot.define do
|
||||
create(:votation_type_multiple, questionable: question, max_votes: evaluator.max_votes)
|
||||
end
|
||||
end
|
||||
|
||||
factory :poll_question_open do
|
||||
after(:create) do |question|
|
||||
create(:votation_type_open, questionable: question)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :poll_question_option, class: "Poll::Question::Option" do
|
||||
|
||||
@@ -9,6 +9,10 @@ FactoryBot.define do
|
||||
max_votes { 3 }
|
||||
end
|
||||
|
||||
factory :votation_type_open do
|
||||
vote_type { "open" }
|
||||
end
|
||||
|
||||
questionable factory: :poll_question
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,8 @@ describe Abilities::Administrator do
|
||||
let(:future_poll) { create(:poll, :future) }
|
||||
let(:current_poll_question) { create(:poll_question) }
|
||||
let(:future_poll_question) { create(:poll_question, poll: future_poll) }
|
||||
let(:future_poll_question_open) { create(:poll_question_open, poll: future_poll) }
|
||||
let(:future_poll_question_option_open) { future_poll_question_open.question_options.new }
|
||||
let(:current_poll_question_option) { create(:poll_question_option) }
|
||||
let(:future_poll_question_option) { create(:poll_question_option, poll: future_poll) }
|
||||
let(:current_poll_option_video) { create(:poll_option_video, option: current_poll_question_option) }
|
||||
@@ -143,6 +145,9 @@ describe Abilities::Administrator do
|
||||
it { should_not be_able_to(:create, current_poll_question_option) }
|
||||
it { should_not be_able_to(:update, current_poll_question_option) }
|
||||
it { should_not be_able_to(:destroy, current_poll_question_option) }
|
||||
it { should_not be_able_to(:create, future_poll_question_option_open) }
|
||||
it { should_not be_able_to(:update, future_poll_question_option_open) }
|
||||
it { should_not be_able_to(:destroy, future_poll_question_option_open) }
|
||||
|
||||
it { should be_able_to(:create, future_poll_option_video) }
|
||||
it { should be_able_to(:update, future_poll_option_video) }
|
||||
|
||||
@@ -30,23 +30,9 @@ describe Poll::Answer do
|
||||
expect(answer).not_to be_valid
|
||||
end
|
||||
|
||||
it "is not valid if there's already an answer to that question" do
|
||||
author = create(:user)
|
||||
question = create(:poll_question, :yes_no)
|
||||
|
||||
create(:poll_answer, author: author, question: question)
|
||||
|
||||
answer = build(:poll_answer, author: author, question: question)
|
||||
|
||||
expect(answer).not_to be_valid
|
||||
end
|
||||
|
||||
it "is not valid when user already reached multiple answers question max votes" do
|
||||
author = create(:user)
|
||||
question = create(:poll_question_multiple, :abc, max_votes: 2)
|
||||
create(:poll_answer, author: author, question: question, answer: "Answer A")
|
||||
create(:poll_answer, author: author, question: question, answer: "Answer B")
|
||||
answer = build(:poll_answer, author: author, question: question, answer: "Answer C")
|
||||
it "is not valid without an answer when question is open-ended" do
|
||||
answer.question = create(:poll_question_open)
|
||||
answer.answer = nil
|
||||
|
||||
expect(answer).not_to be_valid
|
||||
end
|
||||
|
||||
@@ -86,4 +86,204 @@ RSpec.describe Poll::Question do
|
||||
expect(question.options_total_votes).to eq 3
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_or_initialize_user_answer" do
|
||||
let(:user) { create(:user) }
|
||||
let(:other_user) { create(:user) }
|
||||
|
||||
context "unique question" do
|
||||
let(:question) { create(:poll_question_unique, :abc) }
|
||||
let(:answer_a) { question.question_options.find_by(title: "Answer A") }
|
||||
let(:answer_b) { question.question_options.find_by(title: "Answer B") }
|
||||
|
||||
it "finds the existing answer for the same user" do
|
||||
existing_answer = create(:poll_answer, question: question, author: user, option: answer_a)
|
||||
create(:poll_answer, question: question, author: other_user, option: answer_b)
|
||||
|
||||
answer = question.find_or_initialize_user_answer(user, option_id: answer_b.id)
|
||||
|
||||
expect(answer).to eq existing_answer
|
||||
expect(answer.author).to eq user
|
||||
expect(answer.option).to eq answer_b
|
||||
expect(answer.answer).to eq "Answer B"
|
||||
end
|
||||
|
||||
it "initializes a new answer when only another user has answered" do
|
||||
create(:poll_answer, question: question, author: other_user, option: answer_a)
|
||||
|
||||
answer = question.find_or_initialize_user_answer(user, option_id: answer_a.id)
|
||||
|
||||
expect(answer).to be_new_record
|
||||
expect(answer.author).to eq user
|
||||
expect(answer.option).to eq answer_a
|
||||
expect(answer.answer).to eq "Answer A"
|
||||
end
|
||||
|
||||
it "raises when option_id is invalid" do
|
||||
expect do
|
||||
question.find_or_initialize_user_answer(user, option_id: 999999)
|
||||
end.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it "raises when option_id is nil" do
|
||||
expect do
|
||||
question.find_or_initialize_user_answer(user, answer_text: "ignored")
|
||||
end.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context "multiple question" do
|
||||
let(:question) { create(:poll_question_multiple, :abc, max_votes: 3) }
|
||||
let(:answer_a) { question.question_options.find_by(title: "Answer A") }
|
||||
let(:answer_b) { question.question_options.find_by(title: "Answer B") }
|
||||
|
||||
it "finds the existing answer for the same user and option" do
|
||||
existing_answer = create(:poll_answer, question: question, author: user, option: answer_a)
|
||||
create(:poll_answer, question: question, author: other_user, option: answer_a)
|
||||
|
||||
answer = question.find_or_initialize_user_answer(user, option_id: answer_a.id)
|
||||
|
||||
expect(answer).to eq existing_answer
|
||||
expect(answer.author).to eq user
|
||||
expect(answer.option).to eq answer_a
|
||||
expect(answer.answer).to eq "Answer A"
|
||||
end
|
||||
|
||||
it "initializes a new answer when selecting a different option" do
|
||||
create(:poll_answer, question: question, author: user, option: answer_a)
|
||||
create(:poll_answer, question: question, author: other_user, option: answer_b)
|
||||
|
||||
answer = question.find_or_initialize_user_answer(user, option_id: answer_b.id)
|
||||
|
||||
expect(answer).to be_new_record
|
||||
expect(answer.author).to eq user
|
||||
expect(answer.option).to eq answer_b
|
||||
expect(answer.answer).to eq "Answer B"
|
||||
end
|
||||
end
|
||||
|
||||
context "Open-ended question" do
|
||||
let(:question) { create(:poll_question_open) }
|
||||
|
||||
it "ignores invalid option_id and uses answer_text" do
|
||||
answer = question.find_or_initialize_user_answer(user, option_id: 999999, answer_text: "Hi")
|
||||
expect(answer.option).to be nil
|
||||
expect(answer.answer).to eq "Hi"
|
||||
end
|
||||
|
||||
it "ignores option_id when nil and assigns answer with option set to nil" do
|
||||
answer = question.find_or_initialize_user_answer(user, answer_text: "Hi")
|
||||
|
||||
expect(answer.option).to be nil
|
||||
expect(answer.answer).to eq "Hi"
|
||||
end
|
||||
|
||||
it "reuses the existing poll answer for the user and updates answer" do
|
||||
existing = create(:poll_answer, question: question, author: user, answer: "Before")
|
||||
|
||||
answer = question.find_or_initialize_user_answer(user, answer_text: "After")
|
||||
expect(answer).to eq existing
|
||||
expect(answer.author).to eq user
|
||||
expect(answer.answer).to eq "After"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "scopes" do
|
||||
describe ".for_physical_votes" do
|
||||
it "returns unique and multiple, but not open_ended" do
|
||||
question_unique = create(:poll_question_unique)
|
||||
question_multiple = create(:poll_question_multiple)
|
||||
question_open_ended = create(:poll_question_open)
|
||||
|
||||
result = Poll::Question.for_physical_votes
|
||||
|
||||
expect(result).to match_array [question_unique, question_multiple]
|
||||
expect(result).not_to include question_open_ended
|
||||
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
|
||||
|
||||
@@ -44,6 +44,21 @@ describe Poll::WebVote do
|
||||
expect(voter.poll_id).to eq answer.poll.id
|
||||
end
|
||||
|
||||
it "updates existing multiple options instead of adding new ones" do
|
||||
question = create(:poll_question_multiple, :abc, poll: poll, max_votes: 2)
|
||||
option_a = question.question_options.find_by(title: "Answer A")
|
||||
option_b = question.question_options.find_by(title: "Answer B")
|
||||
option_c = question.question_options.find_by(title: "Answer C")
|
||||
|
||||
create(:poll_answer, author: user, question: question, option: option_a)
|
||||
create(:poll_answer, author: user, question: question, option: option_b)
|
||||
|
||||
web_vote.update(question.id.to_s => { option_id: [option_c.id.to_s] })
|
||||
|
||||
expect(question.reload.answers.size).to eq 1
|
||||
expect(question.reload.answers.first.option).to eq option_c
|
||||
end
|
||||
|
||||
it "does not save the answer if the voter is invalid" do
|
||||
allow_any_instance_of(Poll::Voter).to receive(:valid?).and_return(false)
|
||||
|
||||
@@ -55,6 +70,28 @@ describe Poll::WebVote do
|
||||
expect(question.answers).to be_blank
|
||||
end
|
||||
|
||||
it "does not save the answer if it exceeds the allowed max votes" do
|
||||
question = create(:poll_question_multiple, :abc, poll: poll, max_votes: 2)
|
||||
|
||||
result = web_vote.update(question.id.to_s => { option_id: question.question_options.ids.map(&:to_s) })
|
||||
|
||||
expect(result).to be false
|
||||
expect(poll.voters).to be_blank
|
||||
expect(question.answers).to be_blank
|
||||
end
|
||||
|
||||
it "does not save the answer if unique question receives multiple options" do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
|
||||
result = web_vote.update(
|
||||
question.id.to_s => { option_id: question.question_options.ids.map(&:to_s) }
|
||||
)
|
||||
|
||||
expect(result).to be false
|
||||
expect(poll.voters).to be_blank
|
||||
expect(question.answers).to be_blank
|
||||
end
|
||||
|
||||
it "creates a voter but does not create answers when leaving everything blank" do
|
||||
web_vote.update({})
|
||||
|
||||
@@ -119,5 +156,47 @@ describe Poll::WebVote do
|
||||
expect(Poll::Answer.count).to be 2
|
||||
end
|
||||
end
|
||||
|
||||
context "Open-ended questions" do
|
||||
let!(:open_ended_question) { create(:poll_question_open, poll: poll) }
|
||||
|
||||
it "creates one answer when text is present" do
|
||||
web_vote.update(open_ended_question.id.to_s => { answer: " Hi " })
|
||||
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
open_answer = open_ended_question.reload.answers.find_by(author: user)
|
||||
|
||||
expect(open_answer.answer).to eq "Hi"
|
||||
expect(open_answer.option_id).to be nil
|
||||
end
|
||||
|
||||
it "does not create an answer but create voters when text is blank or only spaces" do
|
||||
web_vote.update(open_ended_question.id.to_s => { answer: " " })
|
||||
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
expect(open_ended_question.reload.answers.where(author: user)).to be_empty
|
||||
end
|
||||
|
||||
it "deletes existing answer but keeps voters when leaving open-ended blank" do
|
||||
create(:poll_answer, question: open_ended_question, author: user, answer: "Old answer")
|
||||
|
||||
web_vote.update(open_ended_question.id.to_s => { answer: " " })
|
||||
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
expect(open_ended_question.reload.answers.where(author: user)).to be_empty
|
||||
end
|
||||
|
||||
it "updates existing open answer without creating duplicates" do
|
||||
existing = create(:poll_answer, question: open_ended_question, author: user, answer: "Old text")
|
||||
|
||||
web_vote.update(open_ended_question.id.to_s => { answer: " New text " })
|
||||
|
||||
updated = open_ended_question.reload.answers.find_by(author: user)
|
||||
expect(updated.id).to eq existing.id
|
||||
expect(updated.answer).to eq "New text"
|
||||
expect(updated.option_id).to be nil
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe VotationType do
|
||||
let(:vote_types) { %i[votation_type_unique votation_type_multiple] }
|
||||
let(:vote_types) { %i[votation_type_unique votation_type_multiple votation_type_open] }
|
||||
let(:votation_type) { build(vote_types.sample) }
|
||||
|
||||
it "is valid" do
|
||||
@@ -27,9 +27,51 @@ describe VotationType do
|
||||
|
||||
expect(votation_type).to be_valid
|
||||
|
||||
votation_type.vote_type = "open"
|
||||
|
||||
expect(votation_type).to be_valid
|
||||
|
||||
votation_type.vote_type = "multiple"
|
||||
|
||||
expect(votation_type).not_to be_valid
|
||||
expect(votation_type.errors[:max_votes]).to include "can't be blank"
|
||||
end
|
||||
|
||||
describe "#cannot_be_open_ended_if_question_has_options" do
|
||||
it "allows changing to open-ended when the question has no options" do
|
||||
votation_type = create(:votation_type_unique)
|
||||
|
||||
votation_type.vote_type = :open
|
||||
|
||||
expect(votation_type).to be_valid
|
||||
end
|
||||
|
||||
it "blocks changing to open-ended when the question has options" do
|
||||
votation_type = create(:votation_type_unique)
|
||||
create(:poll_question_option, question: votation_type.questionable)
|
||||
|
||||
votation_type.vote_type = :open
|
||||
|
||||
expect(votation_type).not_to be_valid
|
||||
error = votation_type.errors[:vote_type].first
|
||||
expect(error).to eq "can't change to open-ended type " \
|
||||
"because you've already defined possible valid answers for this question"
|
||||
end
|
||||
end
|
||||
|
||||
describe "scopes" do
|
||||
describe ".accepts_options" do
|
||||
it "includes unique and multiple, excludes open_ended" do
|
||||
question_unique = create(:poll_question_unique)
|
||||
question_multiple = create(:poll_question_multiple)
|
||||
question_open_ended = create(:poll_question_open)
|
||||
|
||||
accepts_options = VotationType.accepts_options
|
||||
|
||||
expect(accepts_options).to match_array [question_unique.votation_type,
|
||||
question_multiple.votation_type]
|
||||
expect(accepts_options).not_to include question_open_ended.votation_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -71,26 +71,63 @@ describe "Admin poll questions", :admin do
|
||||
poll = create(:poll, :future)
|
||||
visit admin_poll_path(poll)
|
||||
click_link "Create question"
|
||||
expect(page).to have_content "It's only possible to answer one time to the question."
|
||||
end
|
||||
|
||||
scenario "Unique" do
|
||||
fill_in "Question", with: "Question with unique answer"
|
||||
select "Unique answer", from: "Votation type"
|
||||
|
||||
expect(page).to have_content "It's only possible to answer one time to the question."
|
||||
expect(page).not_to have_content "Allows to choose multiple answers."
|
||||
expect(page).not_to have_field "Maximum number of votes"
|
||||
expect(page).not_to have_content "Open-ended question that allows users to provide " \
|
||||
"a single answer in their own words."
|
||||
|
||||
click_button "Save"
|
||||
|
||||
expect(page).to have_content "Question with unique answer"
|
||||
expect(page).to have_content "Unique answer"
|
||||
expect(page).not_to have_content "Maximum number of votes"
|
||||
expect(page).to have_link "Add answer"
|
||||
expect(page).to have_table "Valid answers"
|
||||
end
|
||||
|
||||
scenario "Multiple" do
|
||||
fill_in "Question", with: "Question with multiple answers"
|
||||
select "Multiple answers", from: "Votation type"
|
||||
|
||||
expect(page).not_to have_content "It's only possible to answer one time to the question."
|
||||
expect(page).to have_content "Allows to choose multiple answers."
|
||||
expect(page).not_to have_content "Open-ended question that allows users to provide " \
|
||||
"a single answer in their own words."
|
||||
|
||||
fill_in "Maximum number of votes", with: 6
|
||||
click_button "Save"
|
||||
|
||||
expect(page).to have_content "Question with multiple answers"
|
||||
expect(page).to have_content "Multiple answers"
|
||||
expect(page).to have_text "Maximum number of votes 6", normalize_ws: true
|
||||
expect(page).to have_link "Add answer"
|
||||
expect(page).to have_table "Valid answers"
|
||||
end
|
||||
|
||||
scenario "Open-ended" do
|
||||
fill_in "Question", with: "What do you want?"
|
||||
select "Open-ended", from: "Votation type"
|
||||
|
||||
expect(page).not_to have_content "Allows to choose multiple answers."
|
||||
expect(page).not_to have_field "Maximum number of votes"
|
||||
expect(page).to have_content "Open-ended question that allows users to provide " \
|
||||
"a single answer in their own words."
|
||||
|
||||
click_button "Save"
|
||||
|
||||
expect(page).to have_content "What do you want?"
|
||||
expect(page).to have_content "Open-ended"
|
||||
expect(page).not_to have_content "Maximum number of votes"
|
||||
expect(page).not_to have_link "Add answer"
|
||||
expect(page).not_to have_table "Valid answers"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -134,7 +171,7 @@ describe "Admin poll questions", :admin do
|
||||
|
||||
scenario "Update" do
|
||||
poll = create(:poll, :future)
|
||||
question = create(:poll_question, poll: poll)
|
||||
question = create(:poll_question_open, poll: poll)
|
||||
old_title = question.title
|
||||
new_title = "Vegetables are great and everyone should have one"
|
||||
|
||||
@@ -145,6 +182,12 @@ describe "Admin poll questions", :admin do
|
||||
end
|
||||
|
||||
expect(page).to have_link "Go back", href: admin_poll_path(poll)
|
||||
expect(page).to have_select "Votation type", selected: "Open-ended"
|
||||
expect(page).not_to have_content "Allows to choose multiple answers."
|
||||
expect(page).not_to have_field "Maximum number of votes"
|
||||
expect(page).to have_content "Open-ended question that allows users to provide " \
|
||||
"a single answer in their own words."
|
||||
|
||||
fill_in "Question", with: new_title
|
||||
|
||||
click_button "Save"
|
||||
|
||||
@@ -4,8 +4,8 @@ describe "Officing Results", :with_frozen_time do
|
||||
let(:poll) { create(:poll, ends_at: 1.day.ago) }
|
||||
let(:booth) { create(:poll_booth, polls: [poll]) }
|
||||
let(:poll_officer) { create(:poll_officer) }
|
||||
let(:question_1) { create(:poll_question, poll: poll) }
|
||||
let(:question_2) { create(:poll_question, poll: poll) }
|
||||
let(:question_1) { create(:poll_question_unique, poll: poll) }
|
||||
let(:question_2) { create(:poll_question_unique, poll: poll) }
|
||||
|
||||
before do
|
||||
create(:poll_shift, :recount_scrutiny_task, officer: poll_officer, booth: booth, date: Date.current)
|
||||
@@ -15,6 +15,8 @@ describe "Officing Results", :with_frozen_time do
|
||||
create(:poll_question_option, title: "Today", question: question_2, given_order: 1)
|
||||
create(:poll_question_option, title: "Tomorrow", question: question_2, given_order: 2)
|
||||
|
||||
create(:poll_question_open, poll: poll, title: "What do you want?")
|
||||
|
||||
login_as(poll_officer.user)
|
||||
set_officing_booth(booth)
|
||||
end
|
||||
@@ -69,6 +71,8 @@ describe "Officing Results", :with_frozen_time do
|
||||
fill_in "Tomorrow", with: "444"
|
||||
end
|
||||
|
||||
expect(page).not_to have_css "fieldset", text: "What do you want?"
|
||||
|
||||
fill_in "Totally blank ballots", with: "66"
|
||||
fill_in "Invalid ballots", with: "77"
|
||||
fill_in "Valid ballots", with: "88"
|
||||
@@ -100,6 +104,7 @@ describe "Officing Results", :with_frozen_time do
|
||||
booth_assignment_id: partial_result.booth_assignment_id)
|
||||
|
||||
within("#question_#{question_1.id}_0_result") { expect(page).to have_content("7777") }
|
||||
expect(page).not_to have_content "What do you want?"
|
||||
|
||||
visit new_officing_poll_result_path(poll)
|
||||
|
||||
@@ -136,5 +141,6 @@ describe "Officing Results", :with_frozen_time do
|
||||
within("#total_results") { expect(page).to have_content("8") }
|
||||
within("#question_#{question_1.id}_0_result") { expect(page).to have_content("5555") }
|
||||
within("#question_#{question_1.id}_1_result") { expect(page).to have_content("200") }
|
||||
expect(page).not_to have_content "What do you want?"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -180,15 +180,11 @@ describe "Polls" do
|
||||
|
||||
scenario "Level 2 users answering" do
|
||||
poll.update!(geozone_restricted_to: [geozone])
|
||||
create(:poll_question, :yes_no, poll: poll, title: "Do you agree?")
|
||||
question = create(:poll_question, :yes_no, poll: poll, title: "Do you agree?")
|
||||
|
||||
login_as(create(:user, :level_two, geozone: geozone))
|
||||
visit poll_path(poll)
|
||||
vote_for_poll_via_web(poll, question => "Yes")
|
||||
|
||||
within_fieldset("Do you agree?") { choose "Yes" }
|
||||
click_button "Vote"
|
||||
|
||||
expect(page).to have_content "Thank you for voting!"
|
||||
expect(page).to have_content "You have already participated in this poll. " \
|
||||
"If you vote again it will be overwritten."
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe "Poll Results" do
|
||||
scenario "List each Poll question" do
|
||||
user1 = create(:user, :level_two)
|
||||
user2 = create(:user, :level_two)
|
||||
user3 = create(:user, :level_two)
|
||||
|
||||
poll = create(:poll, results_enabled: true)
|
||||
question1 = create(:poll_question, poll: poll)
|
||||
option1 = create(:poll_question_option, question: question1, title: "Yes")
|
||||
option2 = create(:poll_question_option, question: question1, title: "No")
|
||||
|
||||
question2 = create(:poll_question, poll: poll)
|
||||
option3 = create(:poll_question_option, question: question2, title: "Blue")
|
||||
option4 = create(:poll_question_option, question: question2, title: "Green")
|
||||
option5 = create(:poll_question_option, question: question2, title: "Yellow")
|
||||
|
||||
login_as user1
|
||||
vote_for_poll_via_web(poll, question1 => "Yes", question2 => "Blue")
|
||||
logout
|
||||
|
||||
login_as user2
|
||||
vote_for_poll_via_web(poll, question1 => "Yes", question2 => "Green")
|
||||
logout
|
||||
|
||||
login_as user3
|
||||
vote_for_poll_via_web(poll, question1 => "No", question2 => "Yellow")
|
||||
logout
|
||||
|
||||
travel_to(poll.ends_at + 1.day)
|
||||
|
||||
visit results_poll_path(poll)
|
||||
|
||||
expect(page).to have_content(question1.title)
|
||||
expect(page).to have_content(question2.title)
|
||||
|
||||
within("#question_#{question1.id}_results_table") do
|
||||
expect(find("#option_#{option1.id}_result")).to have_content("2 (66.67%)")
|
||||
expect(find("#option_#{option2.id}_result")).to have_content("1 (33.33%)")
|
||||
end
|
||||
|
||||
within("#question_#{question2.id}_results_table") do
|
||||
expect(find("#option_#{option3.id}_result")).to have_content("1 (33.33%)")
|
||||
expect(find("#option_#{option4.id}_result")).to have_content("1 (33.33%)")
|
||||
expect(find("#option_#{option5.id}_result")).to have_content("1 (33.33%)")
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Results for polls with questions but without options" do
|
||||
poll = create(:poll, :expired, results_enabled: true)
|
||||
question = create(:poll_question, poll: poll)
|
||||
|
||||
visit results_poll_path(poll)
|
||||
|
||||
expect(page).to have_content question.title
|
||||
end
|
||||
end
|
||||
@@ -8,9 +8,10 @@ describe "Poll Votation Type" do
|
||||
login_as(author)
|
||||
end
|
||||
|
||||
scenario "Unique and multiple answers" do
|
||||
create(:poll_question_unique, :yes_no, poll: poll, title: "Is it that bad?")
|
||||
scenario "Unique, multiple and open answers" do
|
||||
create(:poll_question, :yes_no, poll: poll, title: "Is it that bad?")
|
||||
create(:poll_question_multiple, :abcde, poll: poll, max_votes: 3, title: "Which ones do you prefer?")
|
||||
create(:poll_question_open, poll: poll, title: "What do you think?")
|
||||
|
||||
visit poll_path(poll)
|
||||
|
||||
@@ -21,6 +22,10 @@ describe "Poll Votation Type" do
|
||||
check "Answer C"
|
||||
end
|
||||
|
||||
within(".poll-question-open-ended") do
|
||||
fill_in "What do you think?", with: "I believe it's great"
|
||||
end
|
||||
|
||||
click_button "Vote"
|
||||
|
||||
expect(page).to have_content "Thank you for voting!"
|
||||
@@ -39,6 +44,10 @@ describe "Poll Votation Type" do
|
||||
expect(page).to have_field "Answer E", type: :checkbox, checked: false
|
||||
end
|
||||
|
||||
within(".poll-question-open-ended") do
|
||||
expect(page).to have_field "What do you think?", with: "I believe it's great"
|
||||
end
|
||||
|
||||
expect(page).to have_button "Vote"
|
||||
end
|
||||
|
||||
|
||||
@@ -18,12 +18,9 @@ describe "Voter" do
|
||||
user = create(:user, :level_two)
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
within_fieldset("Is this question stupid?") { choose "Yes" }
|
||||
click_button "Vote"
|
||||
vote_for_poll_via_web(poll, question => "Yes")
|
||||
|
||||
expect(page).to have_content "Thank you for voting!"
|
||||
expect(page).to have_content "You have already participated in this poll. " \
|
||||
"If you vote again it will be overwritten."
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user