diff --git a/app/models/budget/stats.rb b/app/models/budget/stats.rb index 24ba6fafc..541c56c3b 100644 --- a/app/models/budget/stats.rb +++ b/app/models/budget/stats.rb @@ -10,6 +10,10 @@ class Budget::Stats total_participants_web total_participants_booths] end + def participants + User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact) + end + private def total_participants @@ -52,10 +56,6 @@ class Budget::Stats supports(budget).count end - def participants - User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact) - end - def authors budget.investments.pluck(:author_id) end diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index 9e1710cf4..0d9faa1ee 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -196,7 +196,7 @@ FactoryBot.define do transient { user nil } ballot do - association :budget_ballot, budget: investment.budget, user: user || association(:user) + association :budget_ballot, budget: investment.budget.reload, user: user || association(:user) end end diff --git a/spec/models/budget/stats_spec.rb b/spec/models/budget/stats_spec.rb index 247c0c40b..99044648c 100644 --- a/spec/models/budget/stats_spec.rb +++ b/spec/models/budget/stats_spec.rb @@ -1,206 +1,225 @@ require "rails_helper" describe Budget::Stats do + let(:budget) { create(:budget) } + let(:stats) { Budget::Stats.new(budget) } + let(:investment) { create(:budget_investment, :selected, budget: budget) } - before do - @budget = create(:budget) - @heading = create(:budget_heading, budget: @budget, price: 1000) + describe "#participants" do + let(:author) { investment.author } + let(:author_and_voter) { create(:user) } + let(:voter) { create(:user) } + let(:voter_and_balloter) { create(:user) } + let(:balloter) { create(:user) } + let(:poll_balloter) { create(:user, :level_two) } + let(:non_participant) { create(:user, :level_two) } - @investment1 = create(:budget_investment, :selected, author: create(:user, gender: "female"), - heading: @heading, price: 200, ballot_lines_count: 900, winner: true) - @investment2 = create(:budget_investment, :selected, author: create(:user, gender: "female"), - heading: @heading, price: 300, ballot_lines_count: 800, winner: true) - @investment3 = create(:budget_investment, :selected, author: create(:user, gender: "female", - date_of_birth: 40.years.ago), heading: @heading, price: 400, - ballot_lines_count: 880, winner: true) - @investment4 = create(:budget_investment, :selected, author: create(:user, gender: "male"), - heading: @heading, price: 100, ballot_lines_count: 915, winner: true) - @investment5 = create(:budget_investment, :unfeasible, author: create(:user, gender: "male", - date_of_birth: 25.years.ago), heading: @heading) + before do + create(:budget_investment, :selected, budget: budget, author: author_and_voter) - @support1 = create(:vote, votable: @investment1, voter: create(:user, gender: "male")) - @support2 = create(:vote, votable: @investment2, voter: create(:user)) + create(:vote, votable: investment, voter: author_and_voter) + create(:vote, votable: investment, voter: voter) + create(:vote, votable: investment, voter: voter_and_balloter) - @budget_ballot_line1 = create(:budget_ballot_line, - user: create(:user, gender: "female", date_of_birth: 54.years.ago), - investment: @investment1) - @budget_ballot_line2 = create(:budget_ballot_line, user: create(:user, gender: "female"), - investment: @investment2) - @budget_ballot_line3 = create(:budget_ballot_line, user: create(:user, gender: "male"), - investment: @investment3) + create(:budget_ballot_line, investment: investment, user: balloter) + create(:budget_ballot_line, investment: investment, user: voter_and_balloter) - @poll_voter = create(:poll_voter, :from_booth, budget: @budget) + create(:poll_voter, :from_booth, user: poll_balloter, budget: budget) - @budget_ballot4 = create(:budget_ballot, budget: @budget, physical: true, user: nil) - @budget_ballot_line4 = create(:budget_ballot_line, ballot: @budget_ballot4, - investment: @investment4) - end - - let(:stats) { Budget::Stats.new(@budget).generate } - - context "#total_participants" do - - it "returns the number of total participants" do - expect(stats[:total_participants]).to be 11 + create(:poll_voter, :from_booth, user: non_participant, budget: create(:budget)) end + it "returns unique participants, including authors" do + expect(stats.participants).to match_array( + [author, author_and_voter, voter, voter_and_balloter, balloter, poll_balloter] + ) + expect(stats.generate[:total_participants]).to be 6 + end end - context "#total_participants_support_phase" do - + describe "#total_participants_support_phase" do it "returns the number of total participants in the support phase" do - expect(stats[:total_participants_support_phase]).to be 2 + 2.times { create(:vote, votable: investment) } + create(:budget_ballot_line, investment: investment) + + expect(stats.generate[:total_participants_support_phase]).to be 2 end + it "counts a user who is voter and balloter" do + voter_and_balloter = create(:user) + create(:vote, votable: investment, voter: voter_and_balloter) + create(:budget_ballot_line, investment: investment, user: voter_and_balloter) + + expect(stats.generate[:total_participants_support_phase]).to be 1 + end end - context "#total_participants_vote_phase" do - + describe "#total_participants_vote_phase" do it "returns the number of total participants in the votes phase" do - expect(stats[:total_participants_vote_phase]).to be 4 + 2.times { create(:budget_ballot_line, investment: investment) } + create(:vote, votable: investment) + + expect(stats.generate[:total_participants_vote_phase]).to be 2 end + it "counts a user who is voter and balloter" do + voter_and_balloter = create(:user) + create(:vote, votable: investment, voter: voter_and_balloter) + create(:budget_ballot_line, investment: investment, user: voter_and_balloter) + + expect(stats.generate[:total_participants_vote_phase]).to be 1 + end end - context "#total_participants_web" do - + describe "#total_participants_web" do it "returns the number of total participants in the votes phase via web" do - expect(stats[:total_participants_web]).to be 3 - end + 2.times { create(:budget_ballot_line, investment: investment) } + create(:poll_voter, :from_booth, budget: budget) + expect(stats.generate[:total_participants_web]).to be 2 + end end - context "#total_participants_booths" do - + describe "#total_participants_booths" do it "returns the number of total participants in the votes phase in booths" do - expect(stats[:total_participants_booths]).to be 1 - end + 2.times { create(:poll_voter, :from_booth, budget: budget) } + create(:budget_ballot_line, investment: investment) + expect(stats.generate[:total_participants_booths]).to be 2 + end end - context "#total_budget_investments" do - + describe "#total_budget_investments" do it "returns the number of total budget investments" do - expect(stats[:total_budget_investments]).to be 5 - end + 2.times { create(:budget_investment, budget: budget) } + create(:budget_investment, budget: create(:budget)) + expect(stats.generate[:total_budget_investments]).to be 2 + end end - context "#total_votes" do - + describe "#total_votes" do it "returns the number of total votes" do - expect(stats[:total_votes]).to be 4 - end + create(:budget_ballot_line, investment: investment) + create(:budget_ballot_line, investment: create(:budget_investment, :selected, budget: budget)) + expect(stats.generate[:total_votes]).to be 2 + end end - context "#total_selected_investments" do - + describe "#total_selected_investments" do it "returns the number of total selected investments" do - expect(stats[:total_selected_investments]).to be 4 - end + 3.times { create(:budget_investment, :selected, budget: budget) } + create(:budget_investment, :selected, budget: create(:budget)) + create(:budget_investment, :unfeasible, budget: budget) + expect(stats.generate[:total_selected_investments]).to be 3 + end end - context "#total_unfeasible_investments" do - + describe "#total_unfeasible_investments" do it "returns the number of total unfeasible investments" do - expect(stats[:total_unfeasible_investments]).to be 1 - end + 3.times { create(:budget_investment, :unfeasible, budget: budget) } + create(:budget_investment, :unfeasible, budget: create(:budget)) + create(:budget_investment, :selected, budget: budget) + expect(stats.generate[:total_unfeasible_investments]).to be 3 + end end - context "#total_male_participants" do - - it "returns the number of total male participants" do - expect(stats[:total_male_participants]).to be 4 - end - - end - - context "#total_female_participants" do - - it "returns the number of total female participants" do - expect(stats[:total_female_participants]).to be 6 - end - - end - - context "#total_supports" do - + describe "#total_supports" do it "returns the number of total supports" do - expect(stats[:total_supports]).to be 2 - end + 2.times { create(:vote, votable: investment) } + expect(stats.generate[:total_supports]).to be 2 + end end - context "#total_unknown_gender_or_age" do + describe "Participants by gender" do + before do + 3.times { create(:user, gender: "male") } + 2.times { create(:user, gender: "female") } + create(:user, gender: nil) - it "returns the number of total unknown participants' gender or age" do - expect(stats[:total_unknown_gender_or_age]).to be 1 + allow(stats).to receive(:participants).and_return(User.all) end + describe "#total_male_participants" do + it "returns the number of total male participants" do + expect(stats.generate[:total_male_participants]).to be 3 + end + end + + describe "#total_female_participants" do + it "returns the number of total female participants" do + expect(stats.generate[:total_female_participants]).to be 2 + end + end + + describe "#total_unknown_gender_or_age" do + it "returns the number of total unknown participants' gender or age" do + expect(stats.generate[:total_unknown_gender_or_age]).to be 1 + end + end + + describe "#male_percentage" do + it "returns the percentage of male participants" do + expect(stats.generate[:male_percentage]).to be 60.0 + end + end + + describe "#female_percentage" do + it "returns the percentage of female participants" do + expect(stats.generate[:female_percentage]).to be 40.0 + end + end end - context "#participants_by_age" do + describe "#participants_by_age" do + before do + [21, 22, 23, 23, 34, 42, 43, 44, 50, 51].each do |age| + create(:user, date_of_birth: age.years.ago) + end + + allow(stats).to receive(:participants).and_return(User.all) + end it "returns the age groups hash" do - expect(stats[:participants_by_age]["16 - 19"][:count]).to be 0 - expect(stats[:participants_by_age]["20 - 24"][:count]).to be 7 - expect(stats[:participants_by_age]["25 - 29"][:count]).to be 1 - expect(stats[:participants_by_age]["30 - 34"][:count]).to be 0 - expect(stats[:participants_by_age]["35 - 39"][:count]).to be 1 - expect(stats[:participants_by_age]["40 - 44"][:count]).to be 1 - expect(stats[:participants_by_age]["45 - 49"][:count]).to be 0 - expect(stats[:participants_by_age]["50 - 54"][:count]).to be 1 - expect(stats[:participants_by_age]["55 - 59"][:count]).to be 0 - expect(stats[:participants_by_age]["60 - 64"][:count]).to be 0 - expect(stats[:participants_by_age]["65 - 69"][:count]).to be 0 - expect(stats[:participants_by_age]["70 - 74"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["16 - 19"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["20 - 24"][:count]).to be 4 + expect(stats.generate[:participants_by_age]["25 - 29"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["30 - 34"][:count]).to be 1 + expect(stats.generate[:participants_by_age]["35 - 39"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["40 - 44"][:count]).to be 3 + expect(stats.generate[:participants_by_age]["45 - 49"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["50 - 54"][:count]).to be 2 + expect(stats.generate[:participants_by_age]["55 - 59"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["60 - 64"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["65 - 69"][:count]).to be 0 + expect(stats.generate[:participants_by_age]["70 - 74"][:count]).to be 0 end - end - context "#male_percentage" do - - it "returns the percentage of male participants" do - expect(stats[:male_percentage]).to be 40.0 + describe "#headings" do + before do + investment.heading.update_column(:population, 1234) + create(:budget_investment, heading: investment.heading) + 2.times { create(:vote, votable: investment) } + create(:budget_ballot_line, investment: investment) end - end - - context "#female_percentage" do - - it "returns the percentage of female participants" do - expect(stats[:female_percentage]).to be 60.0 - end - - end - - context "#headings" do - it "returns headings data" do - heading_stats = stats[:headings][@heading.id] - expect(heading_stats[:total_investments_count]).to be 5 + heading_stats = stats.generate[:headings][investment.heading.id] + expect(heading_stats[:total_investments_count]).to be 2 expect(heading_stats[:total_participants_support_phase]).to be 2 - expect(heading_stats[:total_participants_vote_phase]).to be 4 - expect(heading_stats[:total_participants_all_phase]).to be 6 + expect(heading_stats[:total_participants_vote_phase]).to be 1 + expect(heading_stats[:total_participants_all_phase]).to be 3 expect(heading_stats[:percentage_participants_support_phase]).to be 100.0 expect(heading_stats[:percentage_district_population_support_phase]).to be 0.162 expect(heading_stats[:percentage_participants_vote_phase]).to be 100.0 - expect(heading_stats[:percentage_district_population_vote_phase]).to be 0.324 - expect(heading_stats[:percentage_participants_all_phase]).to be 100.0 - expect(heading_stats[:percentage_district_population_all_phase]).to be 0.486 - - expect(heading_stats[:total_investments_count]).to be 5 - expect(heading_stats[:total_participants_support_phase]).to be 2 - expect(heading_stats[:total_participants_vote_phase]).to be 4 - expect(heading_stats[:total_participants_all_phase]).to be 6 - expect(heading_stats[:percentage_participants_support_phase]).to be 100.0 - expect(heading_stats[:percentage_participants_vote_phase]).to be 100.0 + expect(heading_stats[:percentage_district_population_vote_phase]).to be 0.081 expect(heading_stats[:percentage_participants_all_phase]).to be 100.0 + expect(heading_stats[:percentage_district_population_all_phase]).to be 0.243 end - end - end