diff --git a/app/views/polls/questions/_answers.html.erb b/app/components/polls/questions/answers_component.html.erb similarity index 92% rename from app/views/polls/questions/_answers.html.erb rename to app/components/polls/questions/answers_component.html.erb index 08030bc0e..4e61ee767 100644 --- a/app/views/polls/questions/_answers.html.erb +++ b/app/components/polls/questions/answers_component.html.erb @@ -1,8 +1,8 @@
<% if can?(:answer, question) && !question.poll.voted_in_booth?(current_user) %> <% question.question_answers.each do |answer| %> - <% if @answers_by_question_id[question.id] == answer.title && - (!voted_before_sign_in(question) || + <% if answers_by_question_id[question.id] == answer.title && + (!voted_before_sign_in? || question.poll.voted_in_booth?(current_user)) %> "> diff --git a/app/components/polls/questions/answers_component.rb b/app/components/polls/questions/answers_component.rb new file mode 100644 index 000000000..1d64198a4 --- /dev/null +++ b/app/components/polls/questions/answers_component.rb @@ -0,0 +1,31 @@ +class Polls::Questions::AnswersComponent < ApplicationComponent + attr_reader :question + delegate :can?, :current_user, :user_signed_in?, to: :helpers + + def initialize(question) + @question = question + end + + def answers_by_question_id + if params[:answer] + { question.id => params[:answer] } + else + stored_answers_by_question_id + end + end + + def voted_before_sign_in? + question.answers.where(author: current_user).any? do |vote| + vote.updated_at < current_user.current_sign_in_at + end + end + + private + + def stored_answers_by_question_id + poll_answers = ::Poll::Answer.by_question(question.poll.question_ids).by_author(current_user&.id) + poll_answers.each_with_object({}) do |answer, answers_by_question_id| + answers_by_question_id[answer.question_id] = answer.answer + end + end +end diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb index 51269cff1..3731aa2f9 100644 --- a/app/controllers/polls/questions_controller.rb +++ b/app/controllers/polls/questions_controller.rb @@ -10,8 +10,6 @@ class Polls::QuestionsController < ApplicationController answer.answer = params[:answer] answer.save_and_record_voter_participation - @answers_by_question_id = { @question.id => params[:answer] } - respond_to do |format| format.html do redirect_to request.referer diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb index f96298914..af2dc563a 100644 --- a/app/controllers/polls_controller.rb +++ b/app/controllers/polls_controller.rb @@ -21,13 +21,6 @@ class PollsController < ApplicationController @questions = @poll.questions.for_render.sort_for_list @poll_questions_answers = Poll::Question::Answer.where(question: @poll.questions) .with_content.order(:given_order) - - @answers_by_question_id = {} - poll_answers = ::Poll::Answer.by_question(@poll.question_ids).by_author(current_user&.id) - poll_answers.each do |answer| - @answers_by_question_id[answer.question_id] = answer.answer - end - @commentable = @poll @comment_tree = CommentTree.new(@commentable, params[:page], @current_order) end diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb index ee4ddb375..5a27d25db 100644 --- a/app/helpers/polls_helper.rb +++ b/app/helpers/polls_helper.rb @@ -12,10 +12,6 @@ module PollsHelper booth.name + location end - def voted_before_sign_in(question) - question.answers.where(author: current_user).any? { |vote| current_user.current_sign_in_at > vote.updated_at } - end - def link_to_poll(text, poll) if can?(:results, poll) link_to text, results_poll_path(id: poll.slug || poll.id) diff --git a/app/views/polls/questions/_question.html.erb b/app/views/polls/questions/_question.html.erb index ade9c5910..5fd7eeb8b 100644 --- a/app/views/polls/questions/_question.html.erb +++ b/app/views/polls/questions/_question.html.erb @@ -4,6 +4,6 @@
- <%= render "polls/questions/answers", question: question %> + <%= render Polls::Questions::AnswersComponent.new(question) %>
diff --git a/app/views/polls/questions/answer.js.erb b/app/views/polls/questions/answer.js.erb index f98441d0f..2c4380238 100644 --- a/app/views/polls/questions/answer.js.erb +++ b/app/views/polls/questions/answer.js.erb @@ -1 +1 @@ -$("#<%= dom_id(@question) %>_answers").html("<%= j render("polls/questions/answers", question: @question) %>"); +$("#<%= dom_id(@question) %>_answers").html("<%= j render Polls::Questions::AnswersComponent.new(@question) %>"); diff --git a/spec/components/polls/questions/answers_component_spec.rb b/spec/components/polls/questions/answers_component_spec.rb new file mode 100644 index 000000000..e0a543a16 --- /dev/null +++ b/spec/components/polls/questions/answers_component_spec.rb @@ -0,0 +1,110 @@ +require "rails_helper" + +describe Polls::Questions::AnswersComponent do + include Rails.application.routes.url_helpers + let(:poll) { create(:poll) } + let(:question) { create(:poll_question, :yes_no, poll: poll) } + + it "renders answers in given order" do + render_inline Polls::Questions::AnswersComponent.new(question) + + expect("Yes").to appear_before("No") + end + + it "renders buttons to vote question answers" do + sign_in(create(:user, :verified)) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_button "Yes" + expect(page).to have_button "No" + end + + it "renders a span instead of a button for existing user answers" do + user = create(:user, :verified) + allow(user).to receive(:current_sign_in_at).and_return(user.created_at) + create(:poll_answer, author: user, question: question, answer: "Yes") + sign_in(user) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_selector "span", text: "Yes" + expect(page).not_to have_button "Yes" + expect(page).to have_button "No" + end + + it "hides current answer and shows buttons in successive sessions" do + user = create(:user, :verified) + create(:poll_answer, author: user, question: question, answer: "Yes") + allow(user).to receive(:current_sign_in_at).and_return(Time.current) + sign_in(user) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_button "Yes" + expect(page).to have_button "No" + end + + it "when user is not signed in, renders answers links pointing to user sign in path" do + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_link "Yes", href: new_user_session_path + expect(page).to have_link "No", href: new_user_session_path + end + + it "when user is not verified, renders answers links pointing to user verification in path" do + sign_in(create(:user)) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_link "Yes", href: verification_path + expect(page).to have_link "No", href: verification_path + end + + it "when user already voted in booth it renders disabled answers" do + user = create(:user, :level_two) + create(:poll_voter, :from_booth, poll: poll, user: user) + sign_in(user) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_selector "span.disabled", text: "Yes" + expect(page).to have_selector "span.disabled", text: "No" + end + + it "user cannot vote when poll expired it renders disabled answers" do + question = create(:poll_question, :yes_no, poll: create(:poll, :expired)) + sign_in(create(:user, :level_two)) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_selector "span.disabled", text: "Yes" + expect(page).to have_selector "span.disabled", text: "No" + end + + describe "geozone" do + let(:poll) { create(:poll, geozone_restricted: true) } + let(:geozone) { create(:geozone) } + let(:question) { create(:poll_question, :yes_no, poll: poll) } + + it "when geozone which is not theirs it renders disabled answers" do + poll.geozones << geozone + sign_in(create(:user, :level_two)) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_selector "span.disabled", text: "Yes" + expect(page).to have_selector "span.disabled", text: "No" + end + + it "reading a same-geozone poll it renders buttons to vote question answers" do + poll.geozones << geozone + sign_in(create(:user, :level_two, geozone: geozone)) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_button "Yes" + expect(page).to have_button "No" + end + end +end diff --git a/spec/system/polls/polls_spec.rb b/spec/system/polls/polls_spec.rb index c4ec85e99..220d832da 100644 --- a/spec/system/polls/polls_spec.rb +++ b/spec/system/polls/polls_spec.rb @@ -191,18 +191,6 @@ describe "Polls" do expect("Second question").to appear_before("Third question") end - scenario "Question answers appear in the given order" do - question = create(:poll_question, poll: poll) - answer1 = create(:poll_question_answer, title: "First", question: question, given_order: 2) - answer2 = create(:poll_question_answer, title: "Second", question: question, given_order: 1) - - visit poll_path(poll) - - within("div#poll_question_#{question.id}") do - expect(answer2.title).to appear_before(answer1.title) - end - end - scenario "More info answers appear in the given order" do question = create(:poll_question, poll: poll) answer1 = create(:poll_question_answer, title: "First", question: question, given_order: 2) @@ -248,8 +236,6 @@ describe "Polls" do visit poll_path(poll) expect(page).to have_content("You must sign in or sign up to participate") - expect(page).to have_link("Yes", href: new_user_session_path) - expect(page).to have_link("No", href: new_user_session_path) end scenario "Level 1 users" do @@ -265,89 +251,19 @@ describe "Polls" do visit poll_path(poll) expect(page).to have_content("You must verify your account in order to answer") - - expect(page).to have_link("Yes", href: verification_path) - expect(page).to have_link("No", href: verification_path) end scenario "Level 2 users in an expired poll" do - expired_poll = create(:poll, :expired, geozone_restricted: true) - expired_poll.geozones << geozone - - question = create(:poll_question, :yes_no, poll: expired_poll) + expired_poll = create(:poll, :expired) + create(:poll_question, :yes_no, poll: expired_poll) login_as(create(:user, :level_two, geozone: geozone)) visit poll_path(expired_poll) - within("#poll_question_#{question.id}_answers") do - expect(page).to have_content("Yes") - expect(page).to have_content("No") - expect(page).not_to have_button "Yes" - expect(page).not_to have_button "No" - end expect(page).to have_content("This poll has finished") end - scenario "Level 2 users in a poll with questions for a geozone which is not theirs" do - poll.update!(geozone_restricted: true) - poll.geozones << create(:geozone) - - question = create(:poll_question, :yes_no, poll: poll) - - login_as(create(:user, :level_two)) - - visit poll_path(poll) - - within("#poll_question_#{question.id}_answers") do - expect(page).to have_content("Yes") - expect(page).to have_content("No") - expect(page).not_to have_button "Yes" - expect(page).not_to have_button "No" - end - end - - scenario "Level 2 users reading a same-geozone poll" do - poll.update!(geozone_restricted: true) - poll.geozones << geozone - - question = create(:poll_question, :yes_no, poll: poll) - - login_as(create(:user, :level_two, geozone: geozone)) - visit poll_path(poll) - - within("#poll_question_#{question.id}_answers") do - expect(page).to have_button "Yes" - expect(page).to have_button "No" - end - end - - scenario "Level 2 users reading a all-geozones poll" do - question = create(:poll_question, :yes_no, poll: poll) - - login_as(create(:user, :level_two)) - visit poll_path(poll) - - within("#poll_question_#{question.id}_answers") do - expect(page).to have_button "Yes" - expect(page).to have_button "No" - end - end - - scenario "Level 2 users who have already answered" do - question = create(:poll_question, :yes_no, poll: poll) - user = create(:user, :level_two) - create(:poll_answer, question: question, author: user, answer: "No") - - login_as user - visit poll_path(poll) - - within("#poll_question_#{question.id}_answers") do - expect(page).to have_button "Yes" - expect(page).to have_button "No" - end - end - scenario "Level 2 users answering" do poll.update!(geozone_restricted: true) poll.geozones << geozone