Merge pull request #6072 from consuldemocracy/add_option_id_to_partial_results
Avoid duplicate records in partial results
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<% by_question = @partial_results.group_by(&:question_id) %>
|
||||
<% @poll.questions.each do |question| %>
|
||||
<div class="admin-poll-results-question">
|
||||
<h3><%= question.title %></h3>
|
||||
<table class="margin">
|
||||
<thead>
|
||||
@@ -10,12 +9,11 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<% question.question_options.each_with_index do |option, i| %>
|
||||
<% by_answer = by_question[question.id].present? ? by_question[question.id].group_by(&:answer) : {} %>
|
||||
<tr id="question_<%= question.id %>_<%= i %>_result">
|
||||
<td><%= option.title %></td>
|
||||
<td class="text-center"><%= by_answer[option.title].present? ? by_answer[option.title].sum(&:amount) : 0 %></td>
|
||||
<td class="text-center"><%= votes_for(option) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
</div>
|
||||
12
app/components/admin/poll/results/question_component.rb
Normal file
12
app/components/admin/poll/results/question_component.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class Admin::Poll::Results::QuestionComponent < ApplicationComponent
|
||||
attr_reader :question, :partial_results
|
||||
|
||||
def initialize(question, partial_results)
|
||||
@question = question
|
||||
@partial_results = partial_results
|
||||
end
|
||||
|
||||
def votes_for(option)
|
||||
partial_results.where(option: option).sum(:amount)
|
||||
end
|
||||
end
|
||||
41
app/components/officing/results/index_component.html.erb
Normal file
41
app/components/officing/results/index_component.html.erb
Normal file
@@ -0,0 +1,41 @@
|
||||
<% provide :main_class, "officing-results-index" %>
|
||||
|
||||
<%= back_link_to new_officing_poll_result_path(poll) %>
|
||||
<h2><%= poll.name %> - <%= t("officing.results.index.results") %></h2>
|
||||
|
||||
<% if partial_results.present? %>
|
||||
<div class="callout primary">
|
||||
<h3>
|
||||
<%= booth_assignment.booth.name %> - <%= l partial_results.first.date, format: :long %>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("officing.results.index.table_whites") %></th>
|
||||
<th><%= t("officing.results.index.table_nulls") %></th>
|
||||
<th><%= t("officing.results.index.table_total") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="white_results"><%= recounts.sum(:white_amount) %></td>
|
||||
<td id="null_results"><%= recounts.sum(:null_amount) %></td>
|
||||
<td id="total_results"><%= recounts.sum(:total_amount) %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% @poll.questions.each do |question| %>
|
||||
<%= render Admin::Poll::Results::QuestionComponent.new(question, @partial_results) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("officing.results.index.no_results") %>
|
||||
</div>
|
||||
<% end %>
|
||||
10
app/components/officing/results/index_component.rb
Normal file
10
app/components/officing/results/index_component.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class Officing::Results::IndexComponent < ApplicationComponent
|
||||
attr_reader :poll, :partial_results, :booth_assignment, :recounts
|
||||
|
||||
def initialize(poll, partial_results, booth_assignment, recounts)
|
||||
@poll = poll
|
||||
@partial_results = partial_results
|
||||
@booth_assignment = booth_assignment
|
||||
@recounts = recounts
|
||||
end
|
||||
end
|
||||
@@ -13,12 +13,6 @@ class Officing::BaseController < ApplicationController
|
||||
raise CanCan::AccessDenied unless current_user&.poll_officer?
|
||||
end
|
||||
|
||||
def check_officer_assignment
|
||||
if @officer_assignment.blank?
|
||||
go_back_to_new(t("officing.results.flash.error_wrong_booth"))
|
||||
end
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignments ||= current_user.poll_officer.officer_assignments.where(date: Time.current.to_date)
|
||||
end
|
||||
|
||||
@@ -38,21 +38,20 @@ class Officing::ResultsController < Officing::BaseController
|
||||
|
||||
params[:questions].each_pair do |question_id, results|
|
||||
question = @poll.questions.find(question_id)
|
||||
go_back_to_new if question.blank?
|
||||
|
||||
results.each_pair do |answer_index, count|
|
||||
results.each_pair do |option_index, count|
|
||||
next if count.blank?
|
||||
|
||||
answer = question.question_options.find_by(given_order: answer_index.to_i + 1).title
|
||||
go_back_to_new if question.blank?
|
||||
option = question.question_options.find_by(given_order: option_index.to_i + 1)
|
||||
|
||||
partial_result = ::Poll::PartialResult.find_or_initialize_by(
|
||||
booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: Date.current,
|
||||
question_id: question_id,
|
||||
answer: answer
|
||||
option_id: option.id
|
||||
)
|
||||
partial_result.officer_assignment_id = @officer_assignment.id
|
||||
partial_result.answer = option.title
|
||||
partial_result.amount = count.to_i
|
||||
partial_result.author = current_user
|
||||
partial_result.origin = "booth"
|
||||
@@ -79,10 +78,10 @@ class Officing::ResultsController < Officing::BaseController
|
||||
@results << recount
|
||||
end
|
||||
|
||||
def go_back_to_new(alert = nil)
|
||||
def go_back_to_new(alert)
|
||||
params[:d] = Date.current
|
||||
params[:oa] = results_params[:officer_assignment_id]
|
||||
flash.now[:alert] = (alert || t("officing.results.flash.error_create"))
|
||||
flash.now[:alert] = alert
|
||||
load_officer_assignments
|
||||
load_partial_results
|
||||
render :new
|
||||
@@ -123,4 +122,10 @@ class Officing::ResultsController < Officing::BaseController
|
||||
def index_params
|
||||
params.permit(:booth_assignment_id, :date)
|
||||
end
|
||||
|
||||
def check_officer_assignment
|
||||
if @officer_assignment.blank?
|
||||
go_back_to_new(t("officing.results.flash.error_wrong_booth"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
7
app/lib/poll_partial_result_option_finder.rb
Normal file
7
app/lib/poll_partial_result_option_finder.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class PollPartialResultOptionFinder < PollOptionFinder
|
||||
private
|
||||
|
||||
def existing_choices
|
||||
question.partial_results.where(option_id: nil).distinct.pluck(:answer)
|
||||
end
|
||||
end
|
||||
@@ -11,8 +11,8 @@ class Poll::Answer < ApplicationRecord
|
||||
validates :option, uniqueness: { scope: :author_id }, allow_nil: true
|
||||
validate :max_votes
|
||||
|
||||
validates :answer, inclusion: { in: ->(a) { a.question.possible_answers }},
|
||||
unless: ->(a) { a.question.blank? }
|
||||
validates :answer, inclusion: { in: ->(poll_answer) { poll_answer.option.possible_answers }},
|
||||
if: ->(poll_answer) { poll_answer.option.present? }
|
||||
|
||||
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||
|
||||
@@ -5,13 +5,15 @@ class Poll::PartialResult < ApplicationRecord
|
||||
belongs_to :author, -> { with_hidden }, class_name: "User", inverse_of: :poll_partial_results
|
||||
belongs_to :booth_assignment
|
||||
belongs_to :officer_assignment
|
||||
belongs_to :option, class_name: "Poll::Question::Option"
|
||||
|
||||
validates :question, presence: true
|
||||
validates :author, presence: true
|
||||
validates :answer, presence: true
|
||||
validates :answer, inclusion: { in: ->(a) { a.question.possible_answers }},
|
||||
unless: ->(a) { a.question.blank? }
|
||||
validates :answer, inclusion: { in: ->(partial_result) { partial_result.option.possible_answers }},
|
||||
if: ->(partial_result) { partial_result.option.present? }
|
||||
validates :origin, inclusion: { in: ->(*) { VALID_ORIGINS }}
|
||||
validates :option, uniqueness: { scope: [:booth_assignment_id, :date] }, allow_nil: true
|
||||
|
||||
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||
|
||||
@@ -49,10 +49,6 @@ class Poll::Question < ApplicationRecord
|
||||
question_options.max_by(&:total_votes)&.id
|
||||
end
|
||||
|
||||
def possible_answers
|
||||
question_options.joins(:translations).pluck(:title)
|
||||
end
|
||||
|
||||
def options_with_read_more?
|
||||
options_with_read_more.any?
|
||||
end
|
||||
|
||||
@@ -12,6 +12,7 @@ class Poll::Question::Option < ApplicationRecord
|
||||
|
||||
belongs_to :question, class_name: "Poll::Question"
|
||||
has_many :answers, class_name: "Poll::Answer", dependent: :nullify
|
||||
has_many :partial_results, class_name: "Poll::PartialResult", dependent: :nullify
|
||||
has_many :videos, class_name: "Poll::Question::Option::Video",
|
||||
dependent: :destroy,
|
||||
foreign_key: "answer_id",
|
||||
@@ -50,4 +51,8 @@ class Poll::Question::Option < ApplicationRecord
|
||||
def with_read_more?
|
||||
description.present? || images.any? || documents.any? || videos.any?
|
||||
end
|
||||
|
||||
def possible_answers
|
||||
translations.pluck(:title)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render "admin/poll/results/recount", resource: @booth_assignment %>
|
||||
<%= render "admin/poll/results/result" %>
|
||||
|
||||
<% @poll.questions.each do |question| %>
|
||||
<%= render Admin::Poll::Results::QuestionComponent.new(question, @partial_results) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
|
||||
<% if @partial_results.present? %>
|
||||
<%= render "recount", resource: @poll %>
|
||||
<%= render "result" %>
|
||||
|
||||
<% @poll.questions.each do |question| %>
|
||||
<%= render Admin::Poll::Results::QuestionComponent.new(question, @partial_results) %>
|
||||
<% end %>
|
||||
|
||||
<%= render "results_by_booth" %>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,58 +1 @@
|
||||
<%= back_link_to new_officing_poll_result_path(@poll) %>
|
||||
<h2><%= @poll.name %> - <%= t("officing.results.index.results") %></h2>
|
||||
|
||||
<% if @partial_results.present? %>
|
||||
<div class="callout primary">
|
||||
<h3>
|
||||
<%= @booth_assignment.booth.name %> - <%= l @partial_results.first.date, format: :long %>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-9 column">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("officing.results.index.table_whites") %></th>
|
||||
<th><%= t("officing.results.index.table_nulls") %></th>
|
||||
<th><%= t("officing.results.index.table_total") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td id="white_results"><%= @recounts.sum(:white_amount) %></td>
|
||||
<td id="null_results"><%= @recounts.sum(:null_amount) %></td>
|
||||
<td id="total_results"><%= @recounts.sum(:total_amount) %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% by_question = @partial_results.group_by(&:question_id) %>
|
||||
<% @poll.questions.each do |question| %>
|
||||
<h3><%= question.title %></h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("officing.results.index.table_answer") %></th>
|
||||
<th><%= t("officing.results.index.table_votes") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% question.question_options.each_with_index do |option, i| %>
|
||||
<% by_answer = by_question[question.id].present? ? by_question[question.id].group_by(&:answer) : {} %>
|
||||
<tr id="question_<%= question.id %>_<%= i %>_result">
|
||||
<td><%= option.title %></td>
|
||||
<td><%= by_answer[option.title].present? ? by_answer[option.title].first.amount : 0 %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("officing.results.index.no_results") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render Officing::Results::IndexComponent.new(@poll, @partial_results, @booth_assignment, @recounts) %>
|
||||
|
||||
@@ -41,7 +41,6 @@ en:
|
||||
results:
|
||||
flash:
|
||||
create: "Results saved"
|
||||
error_create: "Results NOT saved. Error in data."
|
||||
error_wrong_booth: "Wrong booth. Results NOT saved."
|
||||
new:
|
||||
title: "%{poll} - Add results"
|
||||
@@ -58,8 +57,6 @@ en:
|
||||
index:
|
||||
no_results: "No results"
|
||||
results: Results
|
||||
table_answer: Answer
|
||||
table_votes: Votes
|
||||
table_whites: "Totally blank ballots"
|
||||
table_nulls: "Invalid ballots"
|
||||
table_total: "Valid ballots"
|
||||
|
||||
@@ -41,7 +41,6 @@ es:
|
||||
results:
|
||||
flash:
|
||||
create: "Datos guardados"
|
||||
error_create: "Resultados NO añadidos. Error en los datos"
|
||||
error_wrong_booth: "Urna incorrecta. Resultados NO guardados."
|
||||
new:
|
||||
title: "%{poll} - Añadir resultados"
|
||||
@@ -58,8 +57,6 @@ es:
|
||||
index:
|
||||
no_results: "No hay resultados"
|
||||
results: Resultados
|
||||
table_answer: Respuesta
|
||||
table_votes: Votos
|
||||
table_whites: "Papeletas totalmente en blanco"
|
||||
table_nulls: "Papeletas nulas"
|
||||
table_total: "Papeletas válidas"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class AddOptionIdToPollPartialResults < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
change_table :poll_partial_results do |t|
|
||||
t.references :option, index: true, foreign_key: { to_table: :poll_question_answers }
|
||||
|
||||
t.index [:booth_assignment_id, :date, :option_id], unique: true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_08_14_122241) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_09_09_145207) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_trgm"
|
||||
enable_extension "plpgsql"
|
||||
@@ -1084,9 +1084,12 @@ ActiveRecord::Schema[7.1].define(version: 2025_08_14_122241) do
|
||||
t.text "amount_log", default: ""
|
||||
t.text "officer_assignment_id_log", default: ""
|
||||
t.text "author_id_log", default: ""
|
||||
t.bigint "option_id"
|
||||
t.index ["answer"], name: "index_poll_partial_results_on_answer"
|
||||
t.index ["author_id"], name: "index_poll_partial_results_on_author_id"
|
||||
t.index ["booth_assignment_id", "date", "option_id"], name: "idx_on_booth_assignment_id_date_option_id_2ffcf6ea3b", unique: true
|
||||
t.index ["booth_assignment_id", "date"], name: "index_poll_partial_results_on_booth_assignment_id_and_date"
|
||||
t.index ["option_id"], name: "index_poll_partial_results_on_option_id"
|
||||
t.index ["origin"], name: "index_poll_partial_results_on_origin"
|
||||
t.index ["question_id"], name: "index_poll_partial_results_on_question_id"
|
||||
end
|
||||
@@ -1799,6 +1802,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_08_14_122241) do
|
||||
add_foreign_key "poll_officer_assignments", "poll_booth_assignments", column: "booth_assignment_id"
|
||||
add_foreign_key "poll_partial_results", "poll_booth_assignments", column: "booth_assignment_id"
|
||||
add_foreign_key "poll_partial_results", "poll_officer_assignments", column: "officer_assignment_id"
|
||||
add_foreign_key "poll_partial_results", "poll_question_answers", column: "option_id"
|
||||
add_foreign_key "poll_partial_results", "poll_questions", column: "question_id"
|
||||
add_foreign_key "poll_partial_results", "users", column: "author_id"
|
||||
add_foreign_key "poll_question_answer_videos", "poll_question_answers", column: "answer_id"
|
||||
|
||||
@@ -3,8 +3,10 @@ namespace :consul do
|
||||
task execute_release_tasks: ["settings:rename_setting_keys",
|
||||
"settings:add_new_settings",
|
||||
"cache:clear",
|
||||
"execute_release_2.3.0_tasks"]
|
||||
"execute_release_2.4.0_tasks"]
|
||||
|
||||
desc "Runs tasks needed to upgrade from 2.2.2 to 2.3.0"
|
||||
task "execute_release_2.3.0_tasks": []
|
||||
desc "Runs tasks needed to upgrade from 2.3.1 to 2.4.0"
|
||||
task "execute_release_2.4.0_tasks": [
|
||||
"polls:populate_partial_results_option_id"
|
||||
]
|
||||
end
|
||||
|
||||
@@ -107,4 +107,95 @@ namespace :polls do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Removes duplicate poll partial results"
|
||||
task remove_duplicate_partial_results: :environment do
|
||||
logger = ApplicationLogger.new
|
||||
duplicate_records_logger = DuplicateRecordsLogger.new
|
||||
|
||||
logger.info "Removing duplicate partial results in polls"
|
||||
|
||||
Tenant.run_on_each do
|
||||
Poll::Question.find_each do |question|
|
||||
manageable_titles = PollPartialResultOptionFinder.new(question).manageable_choices.keys
|
||||
|
||||
question.question_options.each do |option|
|
||||
titles = option.translations.where(title: manageable_titles).select(:title).distinct
|
||||
|
||||
groups = question.partial_results.where(option_id: nil, answer: titles)
|
||||
.select(:booth_assignment_id, :date)
|
||||
.group(:booth_assignment_id, :date)
|
||||
.having("count(*) > 1")
|
||||
.pluck(:booth_assignment_id, :date)
|
||||
|
||||
groups.each do |booth_assignment_id, date|
|
||||
partial_results = question.partial_results.where(
|
||||
option_id: nil,
|
||||
booth_assignment_id: booth_assignment_id,
|
||||
date: date,
|
||||
answer: titles
|
||||
)
|
||||
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
|
||||
amounts_by_id = partial_results.pluck(:id, :amount).to_h
|
||||
if amounts_by_id.values.uniq.size > 1
|
||||
log_message = "Found duplicate partial results with different amounts " \
|
||||
"for question_id #{question.id}, " \
|
||||
"booth_assignment_id #{booth_assignment_id} " \
|
||||
"and date #{date}. " \
|
||||
"Keeping ID #{partial_results.first.id} " \
|
||||
"with amount #{partial_results.first.amount}. " \
|
||||
"Deleting partial results with these IDs and amounts: " \
|
||||
"#{amounts_by_id.except(partial_results.first.id)}" + tenant_info.to_s
|
||||
logger.info(log_message)
|
||||
duplicate_records_logger.info(log_message)
|
||||
end
|
||||
|
||||
partial_results.excluding(partial_results.first).each do |partial_result|
|
||||
partial_result.delete
|
||||
|
||||
log_message = "Deleted duplicate record with ID #{partial_result.id} " \
|
||||
"from the #{Poll::PartialResult.table_name} table " \
|
||||
"with question_id #{question.id}, " \
|
||||
"booth_assignment_id #{booth_assignment_id} " \
|
||||
"and date #{date}" + tenant_info.to_s
|
||||
logger.info(log_message)
|
||||
duplicate_records_logger.info(log_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "populates the poll_partial_results option_id column"
|
||||
task populate_partial_results_option_id: :remove_duplicate_partial_results do
|
||||
logger = ApplicationLogger.new
|
||||
logger.info "Updating option_id column in poll_partial_results"
|
||||
|
||||
Tenant.run_on_each do
|
||||
Poll::Question.find_each do |question|
|
||||
option_finder = PollPartialResultOptionFinder.new(question)
|
||||
|
||||
option_finder.manageable_choices.each do |choice, ids|
|
||||
question.partial_results.where(option_id: nil, answer: choice).update_all(option_id: ids.first)
|
||||
end
|
||||
|
||||
option_finder.unmanageable_choices.each do |choice, ids|
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
|
||||
if ids.count == 0
|
||||
logger.warn "Skipping poll_partial_results with the text \"#{choice}\" for the poll_question " \
|
||||
"with ID #{question.id}. This question has no poll_question_answers " \
|
||||
"containing the text \"#{choice}\"" + tenant_info.to_s
|
||||
else
|
||||
logger.warn "Skipping poll_partial_results with the text \"#{choice}\" for the poll_question " \
|
||||
"with ID #{question.id}. The text \"#{choice}\" could refer to any of these " \
|
||||
"IDs in the poll_question_answers table: #{ids.join(", ")}" + tenant_info.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Poll::Results::QuestionComponent do
|
||||
let(:poll) { create(:poll) }
|
||||
let(:question) { create(:poll_question, poll: poll, title: "What do you want?") }
|
||||
let!(:option_yes) { create(:poll_question_option, question: question, title: "Yes") }
|
||||
let!(:option_no) { create(:poll_question_option, question: question, title: "No") }
|
||||
|
||||
it "renders question title and headers" do
|
||||
render_inline Admin::Poll::Results::QuestionComponent.new(question, poll.partial_results)
|
||||
|
||||
expect(page).to have_css "h3", text: "What do you want?"
|
||||
expect(page).to have_css "th", text: "Answer"
|
||||
expect(page).to have_css "th", text: "Votes"
|
||||
end
|
||||
|
||||
it "renders one row per option" do
|
||||
render_inline Admin::Poll::Results::QuestionComponent.new(question, poll.partial_results)
|
||||
|
||||
expect(page).to have_css "tbody tr", count: 2
|
||||
expect(page).to have_css "td", text: "Yes"
|
||||
expect(page).to have_css "td", text: "No"
|
||||
end
|
||||
|
||||
it "sums votes by option" do
|
||||
create(:poll_partial_result, question: question, option: option_yes, amount: 2, date: Date.current)
|
||||
create(:poll_partial_result, question: question, option: option_yes, amount: 1, date: Date.yesterday)
|
||||
create(:poll_partial_result, question: question, option: option_no, amount: 5)
|
||||
|
||||
render_inline Admin::Poll::Results::QuestionComponent.new(question, question.partial_results)
|
||||
|
||||
page.find("tr#question_#{question.id}_0_result") do |yes_result|
|
||||
expect(yes_result).to have_css "td", text: "Yes"
|
||||
expect(yes_result).to have_css "td", text: "3"
|
||||
end
|
||||
|
||||
page.find("tr#question_#{question.id}_1_result") do |no_result|
|
||||
expect(no_result).to have_css "td", text: "No"
|
||||
expect(no_result).to have_css "td", text: "5"
|
||||
end
|
||||
end
|
||||
|
||||
it "shows 0 when an option has no partial results" do
|
||||
render_inline Admin::Poll::Results::QuestionComponent.new(question, poll.partial_results)
|
||||
|
||||
page.find("tr#question_#{question.id}_0_result") do |yes_result|
|
||||
expect(yes_result).to have_css "td", text: "Yes"
|
||||
expect(yes_result).to have_css "td", text: "0"
|
||||
end
|
||||
|
||||
page.find("tr#question_#{question.id}_1_result") do |no_result|
|
||||
expect(no_result).to have_css "td", text: "No"
|
||||
expect(no_result).to have_css "td", text: "0"
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores partial results from other questions" do
|
||||
other_question = create(:poll_question, poll: poll)
|
||||
create(:poll_question_option, question: other_question, title: "Yes")
|
||||
create(:poll_question_option, question: other_question, title: "Irrelevant")
|
||||
create(:poll_partial_result, question: other_question, answer: "Yes", amount: 9)
|
||||
create(:poll_partial_result, question: other_question, answer: "Irrelevant", amount: 9)
|
||||
|
||||
render_inline Admin::Poll::Results::QuestionComponent.new(question, poll.partial_results)
|
||||
|
||||
expect(page).to have_css "td", text: "0", count: 2
|
||||
end
|
||||
end
|
||||
@@ -226,7 +226,14 @@ FactoryBot.define do
|
||||
question factory: [:poll_question, :yes_no]
|
||||
author factory: :user
|
||||
origin { "web" }
|
||||
answer { question.question_options.sample.title }
|
||||
option do
|
||||
if answer
|
||||
question.question_options.find_by(title: answer)
|
||||
else
|
||||
question.question_options.sample
|
||||
end
|
||||
end
|
||||
after(:build) { |poll_partial_result| poll_partial_result.answer ||= poll_partial_result.option&.title }
|
||||
end
|
||||
|
||||
factory :poll_recount, class: "Poll::Recount" do
|
||||
|
||||
@@ -3,6 +3,8 @@ require "rails_helper"
|
||||
describe "polls tasks" do
|
||||
let(:poll) { create(:poll) }
|
||||
let(:user) { create(:user, :level_two) }
|
||||
let(:booth_assignment) { create(:poll_booth_assignment) }
|
||||
let(:other_booth_assignment) { create(:poll_booth_assignment) }
|
||||
|
||||
describe "polls:remove_duplicate_answers" do
|
||||
before { Rake::Task["polls:remove_duplicate_answers"].reenable }
|
||||
@@ -42,7 +44,7 @@ describe "polls tasks" do
|
||||
|
||||
answer_attributes = { question: question, author: user, answer: "Answer A" }
|
||||
create(:poll_answer, answer_attributes.merge(option: option_a))
|
||||
create(:poll_answer, answer_attributes.merge(option: option_b))
|
||||
insert(:poll_answer, answer_attributes.merge(option_id: option_b.id))
|
||||
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
|
||||
@@ -126,10 +128,11 @@ describe "polls tasks" do
|
||||
|
||||
answer = create(:poll_answer, question: yes_no_question, author: user, answer: "Yes", option: nil)
|
||||
abc_answer = create(:poll_answer, question: abc_question, author: user, answer: "Answer A", option: nil)
|
||||
answer_with_inconsistent_option = create(:poll_answer, question: abc_question,
|
||||
insert(:poll_answer, question: abc_question,
|
||||
author: user,
|
||||
answer: "Answer A",
|
||||
option: option_b)
|
||||
option_id: option_b.id)
|
||||
answer_with_inconsistent_option = Poll::Answer.find_by!(option: option_b)
|
||||
answer_with_invalid_option = build(:poll_answer, question: abc_question,
|
||||
author: user,
|
||||
answer: "Non existing",
|
||||
@@ -222,4 +225,309 @@ describe "polls tasks" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "polls:remove_duplicate_partial_results" do
|
||||
before { Rake::Task["polls:remove_duplicate_partial_results"].reenable }
|
||||
|
||||
it "removes duplicate partial results" do
|
||||
question = create(:poll_question_multiple, :abcde, poll: poll, max_votes: 4)
|
||||
|
||||
result_attributes = {
|
||||
question_id: question.id,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: nil
|
||||
}
|
||||
other_result_attributes = result_attributes.merge(answer: "Answer B")
|
||||
|
||||
result = create(:poll_partial_result, result_attributes)
|
||||
other_result = create(:poll_partial_result, other_result_attributes)
|
||||
other_booth_result = create(:poll_partial_result,
|
||||
result_attributes.merge(booth_assignment_id: other_booth_assignment.id))
|
||||
|
||||
2.times { insert(:poll_partial_result, result_attributes) }
|
||||
insert(:poll_partial_result, other_result_attributes)
|
||||
insert(:poll_partial_result, result_attributes.merge(booth_assignment_id: other_booth_assignment.id))
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 7
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 3
|
||||
expect(Poll::PartialResult.all).to match_array [result, other_result, other_booth_result]
|
||||
end
|
||||
|
||||
it "removes duplicate partial results in different languages" do
|
||||
question = create(:poll_question_multiple, max_votes: 2)
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "Yes", title_de: "Ja")
|
||||
create(:poll_question_option, question: question, title_en: "No", title_de: "Nein")
|
||||
create(:poll_question_option, question: question, title_en: "Maybe", title_de: "Vielleicht")
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Yes",
|
||||
option: nil)
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Ja",
|
||||
option: nil)
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 1
|
||||
end
|
||||
|
||||
it "does not remove duplicate partial results when many options are possible" do
|
||||
question = create(:poll_question, title: "How do you pronounce it?")
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "A", title_es: "EI")
|
||||
create(:poll_question_option, question: question, title_en: "E", title_es: "I")
|
||||
create(:poll_question_option, question: question, title_en: "I", title_es: "AI")
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "I",
|
||||
option: nil)
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "AI",
|
||||
option: nil)
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
end
|
||||
|
||||
it "does not remove partial results with the same text and different options" do
|
||||
question = create(:poll_question_multiple, :abcde, max_votes: 4)
|
||||
option_a = question.question_options.find_by(title: "Answer A")
|
||||
option_b = question.question_options.find_by(title: "Answer B")
|
||||
|
||||
result_attributes = {
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A"
|
||||
}
|
||||
create(:poll_partial_result, result_attributes.merge(option: option_a))
|
||||
insert(:poll_partial_result, result_attributes.merge(option_id: option_b.id))
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
end
|
||||
|
||||
it "removes duplicate partial results on tenants" do
|
||||
create(:tenant, schema: "partial_results")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
booth_assignment = create(:poll_booth_assignment)
|
||||
|
||||
result_attributes = {
|
||||
question_id: question.id,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: nil
|
||||
}
|
||||
create(:poll_partial_result, result_attributes)
|
||||
insert(:poll_partial_result, result_attributes)
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
end
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
expect(Poll::PartialResult.count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
it "removes duplicates in different languages even when amounts differ" do
|
||||
question = create(:poll_question_multiple, max_votes: 2)
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "Yes", title_de: "Ja")
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Yes",
|
||||
option: nil,
|
||||
amount: 3)
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Ja",
|
||||
option: nil,
|
||||
amount: 5)
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "polls:populate_partial_results_option_id" do
|
||||
before do
|
||||
Rake::Task["polls:remove_duplicate_partial_results"].reenable
|
||||
Rake::Task["polls:populate_partial_results_option_id"].reenable
|
||||
end
|
||||
|
||||
it "populates the option_id column of existing partial results when there's one valid option" do
|
||||
yes_no_question = create(:poll_question, :yes_no, poll: poll)
|
||||
abc_question = create(:poll_question_multiple, :abc, poll: poll)
|
||||
option_a = abc_question.question_options.find_by(title: "Answer A")
|
||||
option_b = abc_question.question_options.find_by(title: "Answer B")
|
||||
|
||||
result = create(:poll_partial_result,
|
||||
question: yes_no_question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Yes",
|
||||
option: nil)
|
||||
abc_result = create(:poll_partial_result,
|
||||
question: abc_question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option: nil)
|
||||
insert(:poll_partial_result,
|
||||
question: abc_question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: option_b.id)
|
||||
inconsistent_result = Poll::PartialResult.find_by!(option: option_b)
|
||||
invalid_result = build(:poll_partial_result,
|
||||
question: abc_question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Non existing",
|
||||
option: nil)
|
||||
invalid_result.save!(validate: false)
|
||||
|
||||
Rake.application.invoke_task("polls:populate_partial_results_option_id")
|
||||
result.reload
|
||||
abc_result.reload
|
||||
inconsistent_result.reload
|
||||
invalid_result.reload
|
||||
|
||||
expect(result.option_id).to eq yes_no_question.question_options.find_by(title: "Yes").id
|
||||
expect(abc_result.option_id).to eq option_a.id
|
||||
expect(inconsistent_result.option_id).to eq option_b.id
|
||||
expect(invalid_result.option_id).to be nil
|
||||
end
|
||||
|
||||
it "does not populate the option_id column when there are several valid options" do
|
||||
question = create(:poll_question, title: "How do you pronounce it?")
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "A", title_es: "EI")
|
||||
create(:poll_question_option, question: question, title_en: "E", title_es: "I")
|
||||
create(:poll_question_option, question: question, title_en: "I", title_es: "AI")
|
||||
|
||||
result = create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "I",
|
||||
option: nil)
|
||||
|
||||
Rake.application.invoke_task("polls:populate_partial_results_option_id")
|
||||
result.reload
|
||||
|
||||
expect(result.option_id).to be nil
|
||||
end
|
||||
|
||||
it "removes duplicate partial results before populating the option_id column" do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
|
||||
localized_question = create(:poll_question_multiple)
|
||||
create(:poll_question_option, question: localized_question, title_en: "Yes", title_de: "Ja")
|
||||
create(:poll_question_option, question: localized_question, title_en: "No", title_de: "Nein")
|
||||
create(:poll_question_option, question: localized_question, title_en: "Maybe", title_de: "Vielleicht")
|
||||
|
||||
result_attributes = {
|
||||
question_id: question.id,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: nil
|
||||
}
|
||||
result = create(:poll_partial_result, result_attributes)
|
||||
insert(:poll_partial_result, result_attributes)
|
||||
|
||||
localized_result_attributes = {
|
||||
question: localized_question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
option: nil
|
||||
}
|
||||
localized_result = create(:poll_partial_result, localized_result_attributes.merge(answer: "Yes"))
|
||||
create(:poll_partial_result, localized_result_attributes.merge(answer: "Ja"))
|
||||
|
||||
result.reload
|
||||
localized_result.reload
|
||||
|
||||
expect(result.option_id).to be nil
|
||||
expect(localized_result.option_id).to be nil
|
||||
|
||||
Rake.application.invoke_task("polls:populate_partial_results_option_id")
|
||||
result.reload
|
||||
localized_result.reload
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
expect(result.option_id).to eq question.question_options.find_by(title: "Answer A").id
|
||||
expect(localized_result.option_id).to eq localized_question.question_options.find_by(title: "Yes").id
|
||||
end
|
||||
|
||||
it "populates the option_id column on tenants" do
|
||||
create(:tenant, schema: "partial_results")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
booth_assignment = create(:poll_booth_assignment)
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option: nil)
|
||||
end
|
||||
|
||||
Rake.application.invoke_task("polls:populate_partial_results_option_id")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
expect(Poll::Question.count).to eq 1
|
||||
expect(Poll::PartialResult.count).to eq 1
|
||||
|
||||
question = Poll::Question.first
|
||||
option_a = question.question_options.find_by(title: "Answer A")
|
||||
|
||||
expect(Poll::PartialResult.first.option_id).to eq option_a.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,17 +89,18 @@ describe Poll::Answer do
|
||||
expect { answer.save }.not_to raise_error
|
||||
end
|
||||
|
||||
it "is valid for answers included in the Poll::Question's question_options list" do
|
||||
it "is valid for answers included in the list of titles for the option" do
|
||||
question = create(:poll_question)
|
||||
create(:poll_question_option, title: "One", question: question)
|
||||
option = create(:poll_question_option, title_en: "One", title_es: "Uno", question: question)
|
||||
|
||||
create(:poll_question_option, title: "Two", question: question)
|
||||
create(:poll_question_option, title: "Three", question: question)
|
||||
create(:poll_question_option, title: "Three", question: create(:poll_question, poll: create(:poll)))
|
||||
|
||||
expect(build(:poll_answer, question: question, answer: "One")).to be_valid
|
||||
expect(build(:poll_answer, question: question, answer: "Two")).to be_valid
|
||||
expect(build(:poll_answer, question: question, answer: "Three")).to be_valid
|
||||
|
||||
expect(build(:poll_answer, question: question, answer: "Four")).not_to be_valid
|
||||
expect(build(:poll_answer, option: option, answer: "One")).to be_valid
|
||||
expect(build(:poll_answer, option: option, answer: "Uno")).to be_valid
|
||||
expect(build(:poll_answer, option: option, answer: "Two")).not_to be_valid
|
||||
expect(build(:poll_answer, option: option, answer: "Three")).not_to be_valid
|
||||
expect(build(:poll_answer, option: option, answer: "Any")).not_to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,17 +2,18 @@ require "rails_helper"
|
||||
|
||||
describe Poll::PartialResult do
|
||||
describe "validations" do
|
||||
it "validates that the answers are included in the Poll::Question's list" do
|
||||
it "validates that the answers are included in the list of titles for the option" do
|
||||
question = create(:poll_question)
|
||||
create(:poll_question_option, title: "One", question: question)
|
||||
option = create(:poll_question_option, title_en: "One", title_es: "Uno", question: question)
|
||||
|
||||
create(:poll_question_option, title: "Two", question: question)
|
||||
create(:poll_question_option, title: "Three", question: question)
|
||||
create(:poll_question_option, title: "Three", question: create(:poll_question, poll: create(:poll)))
|
||||
|
||||
expect(build(:poll_partial_result, question: question, answer: "One")).to be_valid
|
||||
expect(build(:poll_partial_result, question: question, answer: "Two")).to be_valid
|
||||
expect(build(:poll_partial_result, question: question, answer: "Three")).to be_valid
|
||||
|
||||
expect(build(:poll_partial_result, question: question, answer: "Four")).not_to be_valid
|
||||
expect(build(:poll_partial_result, option: option, answer: "One")).to be_valid
|
||||
expect(build(:poll_partial_result, option: option, answer: "Uno")).to be_valid
|
||||
expect(build(:poll_partial_result, option: option, answer: "Two")).not_to be_valid
|
||||
expect(build(:poll_partial_result, option: option, answer: "Three")).not_to be_valid
|
||||
expect(build(:poll_partial_result, option: option, answer: "Any")).not_to be_valid
|
||||
end
|
||||
|
||||
it "dynamically validates the valid origins" do
|
||||
@@ -21,6 +22,75 @@ describe Poll::PartialResult do
|
||||
expect(build(:poll_partial_result, origin: "custom")).to be_valid
|
||||
expect(build(:poll_partial_result, origin: "web")).not_to be_valid
|
||||
end
|
||||
|
||||
describe "option_id uniqueness" do
|
||||
let(:booth_assignment) { create(:poll_booth_assignment) }
|
||||
|
||||
it "is not valid when there are two identical partial results" do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
option = question.question_options.first
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: option,
|
||||
answer: "Answer A")
|
||||
|
||||
partial_result = build(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: option,
|
||||
answer: "Answer A")
|
||||
|
||||
expect(partial_result).not_to be_valid
|
||||
expect { partial_result.save(validate: false) }.to raise_error ActiveRecord::RecordNotUnique
|
||||
end
|
||||
|
||||
it "is not valid when there are two results with the same option and different answer" do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
option = question.question_options.first
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: option,
|
||||
answer: "Answer A")
|
||||
|
||||
partial_result = build(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: option,
|
||||
answer: "Answer B")
|
||||
|
||||
expect(partial_result).not_to be_valid
|
||||
expect { partial_result.save(validate: false) }.to raise_error ActiveRecord::RecordNotUnique
|
||||
end
|
||||
|
||||
it "is valid when there are two identical results and the option is nil" do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
|
||||
create(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: nil,
|
||||
answer: "Answer A")
|
||||
|
||||
partial_result = build(:poll_partial_result,
|
||||
question: question,
|
||||
booth_assignment: booth_assignment,
|
||||
date: Date.current,
|
||||
option: nil,
|
||||
answer: "Answer A")
|
||||
|
||||
expect(partial_result).to be_valid
|
||||
expect { partial_result.save }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "logging changes" do
|
||||
|
||||
@@ -228,7 +228,7 @@ describe "Admin booths assignments", :admin do
|
||||
expect(page).not_to have_css "#recounts_list"
|
||||
end
|
||||
|
||||
scenario "Results for a booth assignment" do
|
||||
scenario "Recounts for a booth assignment" do
|
||||
poll = create(:poll)
|
||||
booth_assignment = create(:poll_booth_assignment, poll: poll)
|
||||
other_booth_assignment = create(:poll_booth_assignment, poll: poll)
|
||||
@@ -285,30 +285,6 @@ describe "Admin booths assignments", :admin do
|
||||
|
||||
click_link "Results"
|
||||
|
||||
expect(page).to have_content(question_1.title)
|
||||
|
||||
within("#question_#{question_1.id}_0_result") do
|
||||
expect(page).to have_content("Yes")
|
||||
expect(page).to have_content(11)
|
||||
end
|
||||
|
||||
within("#question_#{question_1.id}_1_result") do
|
||||
expect(page).to have_content("No")
|
||||
expect(page).to have_content(4)
|
||||
end
|
||||
|
||||
expect(page).to have_content(question_2.title)
|
||||
|
||||
within("#question_#{question_2.id}_0_result") do
|
||||
expect(page).to have_content("Today")
|
||||
expect(page).to have_content(5)
|
||||
end
|
||||
|
||||
within("#question_#{question_2.id}_1_result") do
|
||||
expect(page).to have_content("Tomorrow")
|
||||
expect(page).to have_content(6)
|
||||
end
|
||||
|
||||
within("#white_results") { expect(page).to have_content("21") }
|
||||
within("#null_results") { expect(page).to have_content("44") }
|
||||
within("#total_results") { expect(page).to have_content("66") }
|
||||
|
||||
@@ -343,46 +343,6 @@ describe "Admin polls", :admin do
|
||||
expect(page).to have_content "There are no results"
|
||||
end
|
||||
|
||||
scenario "Show partial results" do
|
||||
poll = create(:poll)
|
||||
|
||||
booth_assignment_1 = create(:poll_booth_assignment, poll: poll)
|
||||
booth_assignment_2 = create(:poll_booth_assignment, poll: poll)
|
||||
booth_assignment_3 = create(:poll_booth_assignment, poll: poll)
|
||||
|
||||
question_1 = create(:poll_question, poll: poll)
|
||||
create(:poll_question_option, title: "Oui", question: question_1)
|
||||
create(:poll_question_option, title: "Non", question: question_1)
|
||||
|
||||
question_2 = create(:poll_question, poll: poll)
|
||||
create(:poll_question_option, title: "Aujourd'hui", question: question_2)
|
||||
create(:poll_question_option, title: "Demain", question: question_2)
|
||||
|
||||
[booth_assignment_1, booth_assignment_2, booth_assignment_3].each do |ba|
|
||||
create(:poll_partial_result,
|
||||
booth_assignment: ba,
|
||||
question: question_1,
|
||||
answer: "Oui",
|
||||
amount: 11)
|
||||
|
||||
create(:poll_partial_result,
|
||||
booth_assignment: ba,
|
||||
question: question_2,
|
||||
answer: "Demain",
|
||||
amount: 5)
|
||||
end
|
||||
|
||||
create(:poll_recount,
|
||||
booth_assignment: booth_assignment_1,
|
||||
white_amount: 21,
|
||||
null_amount: 44,
|
||||
total_amount: 66)
|
||||
|
||||
visit admin_poll_results_path(poll)
|
||||
|
||||
expect(page).to have_content "Results by booth"
|
||||
end
|
||||
|
||||
scenario "Enable stats and results for booth polls" do
|
||||
unvoted_poll = create(:poll)
|
||||
|
||||
@@ -418,8 +378,9 @@ describe "Admin polls", :admin do
|
||||
expect(page).not_to have_content "Results by booth"
|
||||
end
|
||||
|
||||
scenario "Results by answer" do
|
||||
scenario "Show results, recount and details by booth" do
|
||||
poll = create(:poll)
|
||||
|
||||
booth_assignment_1 = create(:poll_booth_assignment, poll: poll)
|
||||
booth_assignment_2 = create(:poll_booth_assignment, poll: poll)
|
||||
booth_assignment_3 = create(:poll_booth_assignment, poll: poll)
|
||||
@@ -436,12 +397,14 @@ describe "Admin polls", :admin do
|
||||
question: question_1,
|
||||
answer: "Yes",
|
||||
amount: 11)
|
||||
|
||||
create(:poll_partial_result,
|
||||
booth_assignment: ba,
|
||||
question: question_2,
|
||||
answer: "Tomorrow",
|
||||
amount: 5)
|
||||
end
|
||||
|
||||
create(:poll_recount,
|
||||
booth_assignment: booth_assignment_1,
|
||||
white_amount: 21,
|
||||
@@ -449,60 +412,21 @@ describe "Admin polls", :admin do
|
||||
total_amount: 66)
|
||||
|
||||
visit admin_poll_path(poll)
|
||||
|
||||
click_link "Results"
|
||||
|
||||
expect(page).to have_content(question_1.title)
|
||||
question_1.question_options.each_with_index do |option, i|
|
||||
within("#question_#{question_1.id}_#{i}_result") do
|
||||
expect(page).to have_content(option.title)
|
||||
expect(page).to have_content([33, 0][i])
|
||||
end
|
||||
end
|
||||
|
||||
expect(page).to have_content(question_2.title)
|
||||
question_2.question_options.each_with_index do |option, i|
|
||||
within("#question_#{question_2.id}_#{i}_result") do
|
||||
expect(page).to have_content(option.title)
|
||||
expect(page).to have_content([0, 15][i])
|
||||
end
|
||||
end
|
||||
expect(page).to have_content "Results by booth"
|
||||
|
||||
within("#white_results") { expect(page).to have_content("21") }
|
||||
within("#null_results") { expect(page).to have_content("44") }
|
||||
within("#total_results") { expect(page).to have_content("66") }
|
||||
end
|
||||
|
||||
scenario "Link to results by booth" do
|
||||
poll = create(:poll)
|
||||
booth_assignment1 = create(:poll_booth_assignment, poll: poll)
|
||||
booth_assignment2 = create(:poll_booth_assignment, poll: poll)
|
||||
expect(page).to have_link("See results", count: 3)
|
||||
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
|
||||
create(:poll_partial_result,
|
||||
booth_assignment: booth_assignment1,
|
||||
question: question,
|
||||
answer: "Yes",
|
||||
amount: 5)
|
||||
|
||||
create(:poll_partial_result,
|
||||
booth_assignment: booth_assignment2,
|
||||
question: question,
|
||||
answer: "Yes",
|
||||
amount: 6)
|
||||
|
||||
visit admin_poll_path(poll)
|
||||
|
||||
click_link "Results"
|
||||
|
||||
expect(page).to have_link("See results", count: 2)
|
||||
|
||||
within("#booth_assignment_#{booth_assignment1.id}_result") do
|
||||
within("#booth_assignment_#{booth_assignment_1.id}_result") do
|
||||
click_link "See results"
|
||||
end
|
||||
|
||||
expect(page).to have_content booth_assignment1.booth.name
|
||||
expect(page).to have_content booth_assignment_1.booth.name
|
||||
expect(page).to have_content "Results"
|
||||
expect(page).to have_content "Yes"
|
||||
expect(page).to have_content "5"
|
||||
|
||||
@@ -123,6 +123,9 @@ describe "Officing Results", :with_frozen_time do
|
||||
click_link "See results"
|
||||
end
|
||||
|
||||
expect(page).to have_content(I18n.l(Date.current.to_date, format: :long))
|
||||
expect(page).to have_content(booth_name)
|
||||
|
||||
within("#question_#{question_1.id}_0_result") do
|
||||
expect(page).to have_content("5555")
|
||||
expect(page).not_to have_content("7777")
|
||||
@@ -134,50 +137,4 @@ describe "Officing Results", :with_frozen_time do
|
||||
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") }
|
||||
end
|
||||
|
||||
scenario "Index lists all questions and answers" do
|
||||
officer_assignment = poll_officer.officer_assignments.first
|
||||
booth_assignment = officer_assignment.booth_assignment
|
||||
booth = booth_assignment.booth
|
||||
|
||||
create(
|
||||
:poll_partial_result,
|
||||
officer_assignment: officer_assignment,
|
||||
booth_assignment: booth_assignment,
|
||||
date: poll.ends_at,
|
||||
question: question_1,
|
||||
amount: 33
|
||||
)
|
||||
|
||||
create(
|
||||
:poll_recount,
|
||||
officer_assignment: officer_assignment,
|
||||
booth_assignment: booth_assignment,
|
||||
date: poll.ends_at,
|
||||
white_amount: 21,
|
||||
null_amount: 44,
|
||||
total_amount: 66
|
||||
)
|
||||
|
||||
visit officing_poll_results_path(poll,
|
||||
date: I18n.l(poll.ends_at.to_date),
|
||||
booth_assignment_id: officer_assignment.booth_assignment_id)
|
||||
|
||||
expect(page).to have_content(I18n.l(poll.ends_at.to_date, format: :long))
|
||||
expect(page).to have_content(booth.name)
|
||||
|
||||
expect(page).to have_content(question_1.title)
|
||||
question_1.question_options.each_with_index do |answer, i|
|
||||
within("#question_#{question_1.id}_#{i}_result") { expect(page).to have_content(answer.title) }
|
||||
end
|
||||
|
||||
expect(page).to have_content(question_2.title)
|
||||
question_2.question_options.each_with_index do |answer, i|
|
||||
within("#question_#{question_2.id}_#{i}_result") { expect(page).to have_content(answer.title) }
|
||||
end
|
||||
|
||||
within("#white_results") { expect(page).to have_content("21") }
|
||||
within("#null_results") { expect(page).to have_content("44") }
|
||||
within("#total_results") { expect(page).to have_content("66") }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user