Merge pull request #4993 from consul/refactor_public_polls
Refactor and simplify public polls views
This commit is contained in:
@@ -1,28 +1,7 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
App.Polls = {
|
||||
generateToken: function() {
|
||||
var strings;
|
||||
strings = Array.apply(null, {
|
||||
length: 6
|
||||
}).map(function() {
|
||||
return Math.random().toString(36).substr(2); // remove `0.`
|
||||
});
|
||||
return strings.join("").substring(0, 64);
|
||||
},
|
||||
replaceToken: function(token) {
|
||||
$(".js-question-answer").each(function() {
|
||||
var token_param;
|
||||
token_param = this.search.slice(-6);
|
||||
if (token_param === "token=") {
|
||||
this.href = this.href + token;
|
||||
}
|
||||
});
|
||||
},
|
||||
initialize: function() {
|
||||
var token;
|
||||
token = App.Polls.generateToken();
|
||||
App.Polls.replaceToken(token);
|
||||
$(".zoom-link").on("click", function(event) {
|
||||
var answer;
|
||||
answer = $(event.target).closest("div.answer");
|
||||
|
||||
@@ -1633,9 +1633,10 @@
|
||||
}
|
||||
|
||||
.poll-question-answers {
|
||||
@include flex-with-gap($line-height / 4);
|
||||
flex-wrap: wrap;
|
||||
|
||||
.button {
|
||||
margin-right: $line-height / 4;
|
||||
min-width: rem-calc(168);
|
||||
|
||||
@include breakpoint(medium down) {
|
||||
|
||||
31
app/components/polls/questions/answers_component.html.erb
Normal file
31
app/components/polls/questions/answers_component.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<div class="poll-question-answers">
|
||||
<% if can?(:answer, question) && !question.poll.voted_in_booth?(current_user) %>
|
||||
<% question_answers.each do |question_answer| %>
|
||||
<% if already_answered?(question_answer) && !voted_before_sign_in? %>
|
||||
<span class="button answered"
|
||||
title="<%= t("poll_questions.show.voted", answer: question_answer.title) %>">
|
||||
<%= question_answer.title %>
|
||||
</span>
|
||||
<% else %>
|
||||
<%= button_to answer_question_path(question, answer: question_answer.title),
|
||||
remote: true,
|
||||
title: t("poll_questions.show.vote_answer", answer: question_answer.title),
|
||||
class: "button secondary hollow" do %>
|
||||
<%= question_answer.title %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% elsif !user_signed_in? %>
|
||||
<% question_answers.each do |question_answer| %>
|
||||
<%= link_to question_answer.title, new_user_session_path, class: "button secondary hollow" %>
|
||||
<% end %>
|
||||
<% elsif !current_user.level_two_or_three_verified? %>
|
||||
<% question_answers.each do |question_answer| %>
|
||||
<%= link_to question_answer.title, verification_path, class: "button secondary hollow" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% question_answers.each do |question_answer| %>
|
||||
<span class="button secondary hollow disabled"><%= question_answer.title %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
28
app/components/polls/questions/answers_component.rb
Normal file
28
app/components/polls/questions/answers_component.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
class Polls::Questions::AnswersComponent < ApplicationComponent
|
||||
attr_reader :question
|
||||
delegate :can?, :current_user, :user_signed_in?, to: :helpers
|
||||
|
||||
def initialize(question)
|
||||
@question = question
|
||||
end
|
||||
|
||||
def already_answered?(question_answer)
|
||||
user_answers.find_by(answer: question_answer.title).present?
|
||||
end
|
||||
|
||||
def voted_before_sign_in?
|
||||
user_answers.any? do |vote|
|
||||
vote.updated_at < current_user.current_sign_in_at
|
||||
end
|
||||
end
|
||||
|
||||
def question_answers
|
||||
question.question_answers
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_answers
|
||||
@user_answers ||= question.answers.by_author(current_user)
|
||||
end
|
||||
end
|
||||
@@ -4,6 +4,6 @@
|
||||
</h3>
|
||||
|
||||
<div id="<%= dom_id(question) %>_answers" class="padding">
|
||||
<%= render "polls/questions/answers", question: question, token: token %>
|
||||
<%= render Polls::Questions::AnswersComponent.new(question) %>
|
||||
</div>
|
||||
</div>
|
||||
7
app/components/polls/questions/question_component.rb
Normal file
7
app/components/polls/questions/question_component.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class Polls::Questions::QuestionComponent < ApplicationComponent
|
||||
attr_reader :question
|
||||
|
||||
def initialize(question:)
|
||||
@question = question
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
<div class="small-12 medium-6 column end answer <%= cycle("first", "") %>" id="answer_<%= answer.id %>">
|
||||
<h3><%= answer.title %></h3>
|
||||
|
||||
<% if answer.images.any? %>
|
||||
<%= render "polls/gallery", answer: answer %>
|
||||
<% end %>
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<div class="margin-top">
|
||||
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
|
||||
<%= wysiwyg(answer.description) %>
|
||||
</div>
|
||||
<div class="read-more">
|
||||
<button type="button" id="read_more_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide">
|
||||
<%= t("polls.show.read_more", answer: answer.title) %>
|
||||
</button>
|
||||
<button type="button" id="read_less_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide"
|
||||
class="hide">
|
||||
<%= t("polls.show.read_less", answer: answer.title) %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.documents.present? %>
|
||||
<div class="document-link">
|
||||
<p>
|
||||
<span class="icon-document"></span>
|
||||
<strong><%= t("polls.show.documents") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.documents.each do |document| %>
|
||||
<%= link_to document.title,
|
||||
document.attachment,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.videos.present? %>
|
||||
<div class="video-link">
|
||||
<p>
|
||||
<span class="icon-video"></span>
|
||||
<strong><%= t("polls.show.videos") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.videos.each do |video| %>
|
||||
<%= link_to video.title,
|
||||
video.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
class Polls::Questions::ReadMoreAnswerComponent < ApplicationComponent
|
||||
with_collection_parameter :answer
|
||||
attr_reader :answer
|
||||
delegate :wysiwyg, to: :helpers
|
||||
|
||||
def initialize(answer:)
|
||||
@answer = answer
|
||||
end
|
||||
end
|
||||
25
app/components/polls/results/question_component.html.erb
Normal file
25
app/components/polls/results/question_component.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<h3 id="<%= question.title.parameterize %>"><%= question.title %></h3>
|
||||
<table id="question_<%= question.id %>_results_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<th scope="col" class="<%= answer_styles(answer) %>">
|
||||
<% if most_voted_answer?(answer) %>
|
||||
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
|
||||
<% end %>
|
||||
<%= answer.title %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<td id="answer_<%= answer.id %>_result" class="<%= answer_styles(answer) %>">
|
||||
<%= answer.total_votes %>
|
||||
(<%= answer.total_votes_percentage.round(2) %>%)
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
15
app/components/polls/results/question_component.rb
Normal file
15
app/components/polls/results/question_component.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Polls::Results::QuestionComponent < ApplicationComponent
|
||||
attr_reader :question
|
||||
|
||||
def initialize(question:)
|
||||
@question = question
|
||||
end
|
||||
|
||||
def answer_styles(answer)
|
||||
"win" if most_voted_answer?(answer)
|
||||
end
|
||||
|
||||
def most_voted_answer?(answer)
|
||||
answer.id == question.most_voted_answer_id
|
||||
end
|
||||
end
|
||||
@@ -6,11 +6,17 @@ class Polls::QuestionsController < ApplicationController
|
||||
|
||||
def answer
|
||||
answer = @question.answers.find_or_initialize_by(author: current_user)
|
||||
token = params[:token]
|
||||
|
||||
answer.answer = params[:answer]
|
||||
answer.save_and_record_voter_participation(token)
|
||||
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
|
||||
end
|
||||
format.js do
|
||||
render :answer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
class PollsController < ApplicationController
|
||||
include FeatureFlags
|
||||
include PollsHelper
|
||||
|
||||
feature_flag :polls
|
||||
|
||||
@@ -20,16 +19,8 @@ class PollsController < ApplicationController
|
||||
|
||||
def show
|
||||
@questions = @poll.questions.for_render.sort_for_list
|
||||
@token = poll_voter_token(@poll, current_user)
|
||||
@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
|
||||
|
||||
@@ -12,14 +12,6 @@ module PollsHelper
|
||||
booth.name + location
|
||||
end
|
||||
|
||||
def poll_voter_token(poll, user)
|
||||
Poll::Voter.find_by(poll: poll, user: user, origin: "web")&.token || ""
|
||||
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)
|
||||
|
||||
@@ -14,11 +14,11 @@ class Poll::Answer < ApplicationRecord
|
||||
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||
|
||||
def save_and_record_voter_participation(token)
|
||||
def save_and_record_voter_participation
|
||||
transaction do
|
||||
touch if persisted?
|
||||
save!
|
||||
Poll::Voter.find_or_create_by!(user: author, poll: poll, origin: "web", token: token)
|
||||
Poll::Voter.find_or_create_by!(user: author, poll: poll, origin: "web")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<div class="poll-question-answers">
|
||||
<% 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) ||
|
||||
question.poll.voted_in_booth?(current_user)) %>
|
||||
<span class="button answered"
|
||||
title="<%= t("poll_questions.show.voted", answer: answer.title) %>">
|
||||
<%= answer.title %>
|
||||
</span>
|
||||
<% else %>
|
||||
<%= link_to answer.title,
|
||||
answer_question_path(question, answer: answer.title, token: token),
|
||||
method: :post,
|
||||
remote: true,
|
||||
title: t("poll_questions.show.vote_answer", answer: answer.title),
|
||||
class: "button secondary hollow js-question-answer" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% elsif !user_signed_in? %>
|
||||
<% question.question_answers.order(id: :desc).each do |answer| %>
|
||||
<%= link_to answer.title, new_user_session_path, class: "button secondary hollow" %>
|
||||
<% end %>
|
||||
<% elsif !current_user.level_two_or_three_verified? %>
|
||||
<% question.question_answers.order(id: :desc).each do |answer| %>
|
||||
<%= link_to answer.title, verification_path, class: "button secondary hollow" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% question.question_answers.order(id: :desc).each do |answer| %>
|
||||
<span class="button secondary hollow disabled"><%= answer.title %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,2 +1 @@
|
||||
<% token = poll_voter_token(@question.poll, current_user) %>
|
||||
$("#<%= dom_id(@question) %>_answers").html("<%= j render("polls/questions/answers", question: @question, token: token) %>");
|
||||
$("#<%= dom_id(@question) %>_answers").html("<%= j render Polls::Questions::AnswersComponent.new(@question) %>");
|
||||
|
||||
@@ -16,34 +16,7 @@
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-9 column" data-equalizer-watch>
|
||||
<%- @poll.questions.each do |question| %>
|
||||
<% most_voted_answer_id = question.most_voted_answer_id %>
|
||||
<h3 id="<%= question.title.parameterize %>"><%= question.title %></h3>
|
||||
<table id="question_<%= question.id %>_results_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<th scope="col" <%= answer.id == most_voted_answer_id ? "class=win" : "" %>>
|
||||
<% if answer.id == most_voted_answer_id %>
|
||||
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
|
||||
<% end %>
|
||||
<%= answer.title %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<%- question.question_answers.each do |answer| %>
|
||||
<td id="answer_<%= answer.id %>_result" <%= answer.id == most_voted_answer_id ? "class=win" : "" %>>
|
||||
<%= answer.total_votes %>
|
||||
(<%= answer.total_votes_percentage.round(2) %>%)
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
<%= render Polls::Results::QuestionComponent.with_collection(@poll.questions) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% @questions.each do |question| %>
|
||||
<%= render "polls/questions/question", question: question, token: @token %>
|
||||
<% end %>
|
||||
<%= render Polls::Questions::QuestionComponent.with_collection(@questions) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -48,68 +46,7 @@
|
||||
|
||||
<div id="poll_more_info_answers" class="expanded poll-more-info-answers">
|
||||
<div class="row padding">
|
||||
<% @poll_questions_answers.each do |answer| %>
|
||||
<div class="small-12 medium-6 column end answer <%= cycle("first", "") %>" id="answer_<%= answer.id %>">
|
||||
<h3><%= answer.title %></h3>
|
||||
|
||||
<% if answer.images.any? %>
|
||||
<%= render "gallery", answer: answer %>
|
||||
<% end %>
|
||||
|
||||
<% if answer.description.present? %>
|
||||
<div class="margin-top">
|
||||
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
|
||||
<%= wysiwyg(answer.description) %>
|
||||
</div>
|
||||
<div class="read-more">
|
||||
<button type="button" id="read_more_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide">
|
||||
<%= t("polls.show.read_more", answer: answer.title) %>
|
||||
</button>
|
||||
<button type="button" id="read_less_<%= answer.id %>"
|
||||
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
|
||||
data-toggler="hide"
|
||||
class="hide">
|
||||
<%= t("polls.show.read_less", answer: answer.title) %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.documents.present? %>
|
||||
<div class="document-link">
|
||||
<p>
|
||||
<span class="icon-document"></span>
|
||||
<strong><%= t("polls.show.documents") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.documents.each do |document| %>
|
||||
<%= link_to document.title,
|
||||
document.attachment,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if answer.videos.present? %>
|
||||
<div class="video-link">
|
||||
<p>
|
||||
<span class="icon-video"></span>
|
||||
<strong><%= t("polls.show.videos") %></strong>
|
||||
</p>
|
||||
|
||||
<% answer.videos.each do |video| %>
|
||||
<%= link_to video.title,
|
||||
video.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow" %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render Polls::Questions::ReadMoreAnswerComponent.with_collection(@poll_questions_answers) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -146,8 +146,7 @@ section "Creating Poll Voters" do
|
||||
document_number: user.document_number,
|
||||
user: user,
|
||||
poll: poll,
|
||||
origin: "web",
|
||||
token: SecureRandom.hex(32))
|
||||
origin: "web")
|
||||
end
|
||||
|
||||
def randomly_answer_questions(poll, user)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class RemoveTokenFromPollVoter < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
remove_column :poll_voters, :token, :string
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_11_03_112944) do
|
||||
ActiveRecord::Schema.define(version: 2022_09_15_154808) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_trgm"
|
||||
@@ -1210,7 +1210,6 @@ ActiveRecord::Schema.define(version: 2021_11_03_112944) do
|
||||
t.integer "user_id"
|
||||
t.string "origin"
|
||||
t.integer "officer_id"
|
||||
t.string "token"
|
||||
t.index ["booth_assignment_id"], name: "index_poll_voters_on_booth_assignment_id"
|
||||
t.index ["document_number"], name: "index_poll_voters_on_document_number"
|
||||
t.index ["officer_assignment_id"], name: "index_poll_voters_on_officer_assignment_id"
|
||||
|
||||
110
spec/components/polls/questions/answers_component_spec.rb
Normal file
110
spec/components/polls/questions/answers_component_spec.rb
Normal file
@@ -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
|
||||
@@ -0,0 +1,32 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Polls::Questions::ReadMoreAnswerComponent do
|
||||
include Rails.application.routes.url_helpers
|
||||
let(:poll) { create(:poll) }
|
||||
let(:question) { create(:poll_question, poll: poll) }
|
||||
let(:answer) { create(:poll_question_answer, question: question) }
|
||||
|
||||
it "renders answers with videos" do
|
||||
create(:poll_answer_video, answer: answer, title: "Awesome video", url: "youtube.com/watch?v=123")
|
||||
|
||||
render_inline Polls::Questions::ReadMoreAnswerComponent.new(answer: answer)
|
||||
|
||||
expect(page).to have_link("Awesome video", href: "youtube.com/watch?v=123")
|
||||
end
|
||||
|
||||
it "renders answers with images" do
|
||||
create(:image, imageable: answer, title: "The yes movement")
|
||||
|
||||
render_inline Polls::Questions::ReadMoreAnswerComponent.new(answer: answer)
|
||||
|
||||
expect(page).to have_css "img[alt='The yes movement']"
|
||||
end
|
||||
|
||||
it "renders answers with documents" do
|
||||
create(:document, documentable: answer, title: "The yes movement")
|
||||
|
||||
render_inline Polls::Questions::ReadMoreAnswerComponent.new(answer: answer)
|
||||
|
||||
expect(page).to have_link("The yes movement")
|
||||
end
|
||||
end
|
||||
@@ -144,7 +144,6 @@ FactoryBot.define do
|
||||
poll { budget&.poll || association(:poll, budget: budget) }
|
||||
trait :from_web do
|
||||
origin { "web" }
|
||||
token { SecureRandom.hex(32) }
|
||||
end
|
||||
|
||||
trait :from_booth do
|
||||
|
||||
@@ -46,7 +46,7 @@ describe Poll::Answer do
|
||||
answer = create(:poll_answer, question: question, author: author, answer: "Yes")
|
||||
expect(answer.poll.voters).to be_blank
|
||||
|
||||
answer.save_and_record_voter_participation("token")
|
||||
answer.save_and_record_voter_participation
|
||||
expect(poll.reload.voters.size).to eq(1)
|
||||
voter = poll.voters.first
|
||||
|
||||
@@ -57,12 +57,12 @@ describe Poll::Answer do
|
||||
|
||||
it "updates a poll_voter with user and poll data" do
|
||||
answer = create(:poll_answer, question: question, author: author, answer: "Yes")
|
||||
answer.save_and_record_voter_participation("token")
|
||||
answer.save_and_record_voter_participation
|
||||
|
||||
expect(poll.reload.voters.size).to eq(1)
|
||||
|
||||
answer = create(:poll_answer, question: question, author: author, answer: "No")
|
||||
answer.save_and_record_voter_participation("token")
|
||||
answer.save_and_record_voter_participation
|
||||
|
||||
expect(poll.reload.voters.size).to eq(1)
|
||||
|
||||
@@ -76,7 +76,7 @@ describe Poll::Answer do
|
||||
answer = build(:poll_answer)
|
||||
|
||||
expect do
|
||||
answer.save_and_record_voter_participation("token")
|
||||
answer.save_and_record_voter_participation
|
||||
end.to raise_error(ActiveRecord::RecordInvalid)
|
||||
|
||||
expect(answer).not_to be_persisted
|
||||
|
||||
@@ -196,21 +196,19 @@ describe Poll::Voter do
|
||||
|
||||
it "sets user info" do
|
||||
user = create(:user, document_number: "1234A", document_type: "1")
|
||||
voter = build(:poll_voter, user: user, token: "1234abcd")
|
||||
voter = build(:poll_voter, user: user)
|
||||
voter.save!
|
||||
|
||||
expect(voter.document_number).to eq("1234A")
|
||||
expect(voter.document_type).to eq("1")
|
||||
expect(voter.token).to eq("1234abcd")
|
||||
end
|
||||
|
||||
it "sets user info with skip verification enabled" do
|
||||
Setting["feature.user.skip_verification"] = true
|
||||
user = create(:user)
|
||||
voter = build(:poll_voter, user: user, token: "1234abcd")
|
||||
voter.save!
|
||||
voter = build(:poll_voter, user: user)
|
||||
|
||||
expect(voter.token).to eq("1234abcd")
|
||||
expect { voter.save! }.not_to raise_exception
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,8 +3,10 @@ module Polls
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link answer.to_s
|
||||
expect(page).not_to have_link(answer.to_s)
|
||||
click_button answer
|
||||
|
||||
expect(page).to have_css("span.answered", text: answer)
|
||||
expect(page).not_to have_button(answer)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -152,14 +152,6 @@ describe "Polls" do
|
||||
expect(page).to have_current_path(poll_path(poll.slug))
|
||||
end
|
||||
|
||||
scenario "Show answers with videos" do
|
||||
create(:poll_answer_video, poll: poll, title: "Awesome video", url: "youtube.com/watch?v=123")
|
||||
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to have_link("Awesome video", href: "youtube.com/watch?v=123")
|
||||
end
|
||||
|
||||
scenario "Lists questions from proposals as well as regular ones" do
|
||||
normal_question = create(:poll_question, poll: poll)
|
||||
proposal_question = create(:poll_question, poll: poll, proposal: create(:proposal))
|
||||
@@ -191,18 +183,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)
|
||||
@@ -215,15 +195,6 @@ describe "Polls" do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Answer images are shown" do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
create(:image, imageable: question.question_answers.first, title: "The yes movement")
|
||||
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to have_css "img[alt='The yes movement']"
|
||||
end
|
||||
|
||||
scenario "Buttons to slide through images work back and forth" do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
create(:image, imageable: question.question_answers.last, title: "The no movement")
|
||||
@@ -248,8 +219,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 +234,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_link("Yes")
|
||||
expect(page).not_to have_link("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_link("Yes")
|
||||
expect(page).not_to have_link("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_link("Yes")
|
||||
expect(page).to have_link("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_link("Yes")
|
||||
expect(page).to have_link("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_link("Yes")
|
||||
expect(page).to have_link("No")
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Level 2 users answering" do
|
||||
poll.update!(geozone_restricted: true)
|
||||
poll.geozones << geozone
|
||||
@@ -359,10 +258,10 @@ describe "Polls" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link "Yes"
|
||||
click_button "Yes"
|
||||
|
||||
expect(page).not_to have_link("Yes")
|
||||
expect(page).to have_link("No")
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).to have_button "No"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -377,15 +276,15 @@ describe "Polls" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link "Yes"
|
||||
click_button "Yes"
|
||||
|
||||
expect(page).not_to have_link("Yes")
|
||||
expect(page).to have_link("No")
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).to have_button "No"
|
||||
|
||||
click_link "No"
|
||||
click_button "No"
|
||||
|
||||
expect(page).not_to have_link("No")
|
||||
expect(page).to have_link("Yes")
|
||||
expect(page).not_to have_button "No"
|
||||
expect(page).to have_button "Yes"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -400,30 +299,30 @@ describe "Polls" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link "Yes"
|
||||
click_button "Yes"
|
||||
|
||||
expect(page).not_to have_link("Yes")
|
||||
expect(page).to have_link("No")
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).to have_button "No"
|
||||
end
|
||||
|
||||
click_link "Sign out"
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link "Yes"
|
||||
click_button "Yes"
|
||||
|
||||
expect(page).not_to have_link("Yes")
|
||||
expect(page).to have_link("No")
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).to have_button "No"
|
||||
end
|
||||
|
||||
click_link "Sign out"
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link "No"
|
||||
click_button "No"
|
||||
|
||||
expect(page).not_to have_link("No")
|
||||
expect(page).to have_link("Yes")
|
||||
expect(page).not_to have_button "No"
|
||||
expect(page).to have_button "Yes"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -450,6 +349,20 @@ describe "Polls" do
|
||||
expect("Not restricted").to appear_before("Geozone Poll")
|
||||
expect("Geozone Poll").to appear_before("A Poll")
|
||||
end
|
||||
|
||||
scenario "Level 2 users answering in a browser without javascript", :no_js do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
user = create(:user, :level_two)
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_button "Yes"
|
||||
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).to have_button "No"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "Booth & Website", :with_frozen_time do
|
||||
@@ -481,8 +394,8 @@ describe "Polls" do
|
||||
expect(page).to have_content("Yes")
|
||||
expect(page).to have_content("No")
|
||||
|
||||
expect(page).not_to have_link("Yes")
|
||||
expect(page).not_to have_link("No")
|
||||
expect(page).not_to have_button "Yes"
|
||||
expect(page).not_to have_button "No"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,8 +23,8 @@ describe "Voter" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
click_link answer_yes.title
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
click_button answer_yes.title
|
||||
expect(page).not_to have_button(answer_yes.title)
|
||||
end
|
||||
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
@@ -38,8 +38,8 @@ describe "Voter" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
expect(page).not_to have_link(answer_yes.title, href: "/questions/#{question.id}/answer?answer=#{answer_yes.title}&token=")
|
||||
expect(page).not_to have_link(answer_no.title, href: "/questions/#{question.id}/answer?answer=#{answer_no.title}&token=")
|
||||
expect(page).to have_link(answer_yes.title, href: verification_path)
|
||||
expect(page).to have_link(answer_no.title, href: verification_path)
|
||||
end
|
||||
|
||||
expect(page).to have_content("You must verify your account in order to answer")
|
||||
@@ -145,7 +145,7 @@ describe "Voter" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
expect(page).not_to have_button(answer_yes.title)
|
||||
end
|
||||
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
@@ -173,7 +173,7 @@ describe "Voter" do
|
||||
|
||||
expect(page).to have_content "You have already participated in this poll. If you vote again it will be overwritten."
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
expect(page).not_to have_button(answer_yes.title)
|
||||
end
|
||||
|
||||
unfreeze_time
|
||||
@@ -184,8 +184,8 @@ describe "Voter" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
expect(page).to have_link(answer_yes.title)
|
||||
expect(page).to have_link(answer_no.title)
|
||||
expect(page).to have_button(answer_yes.title)
|
||||
expect(page).to have_button(answer_no.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -209,7 +209,7 @@ describe "Voter" do
|
||||
visit poll_path(poll)
|
||||
|
||||
within("#poll_question_#{question.id}_answers") do
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
expect(page).not_to have_button(answer_yes.title)
|
||||
end
|
||||
|
||||
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
|
||||
|
||||
Reference in New Issue
Block a user