Git seems to have gotten confused and some specs where duplicated and others missing This commits restructures commits to sync them with Madrid's fork
1127 lines
39 KiB
Ruby
1127 lines
39 KiB
Ruby
require 'rails_helper'
|
|
|
|
describe Budget::Investment do
|
|
let(:investment) { build(:budget_investment) }
|
|
|
|
describe "Concerns" do
|
|
it_behaves_like "notifiable"
|
|
end
|
|
|
|
it "is valid" do
|
|
expect(investment).to be_valid
|
|
end
|
|
|
|
it "is not valid without an author" do
|
|
investment.author = nil
|
|
expect(investment).not_to be_valid
|
|
end
|
|
|
|
describe "#title" do
|
|
it "is not valid without a title" do
|
|
investment.title = nil
|
|
expect(investment).not_to be_valid
|
|
end
|
|
|
|
it "is not valid when very short" do
|
|
investment.title = "abc"
|
|
expect(investment).not_to be_valid
|
|
end
|
|
|
|
it "is not valid when very long" do
|
|
investment.title = "a" * 81
|
|
expect(investment).not_to be_valid
|
|
end
|
|
end
|
|
|
|
it_behaves_like "acts as imageable", "budget_investment_image"
|
|
|
|
it "sanitizes description" do
|
|
investment.description = "<script>alert('danger');</script>"
|
|
investment.valid?
|
|
expect(investment.description).to eq("alert('danger');")
|
|
end
|
|
|
|
it "set correct group and budget ids" do
|
|
budget = create(:budget)
|
|
group_1 = create(:budget_group, budget: budget)
|
|
group_2 = create(:budget_group, budget: budget)
|
|
|
|
heading_1 = create(:budget_heading, group: group_1)
|
|
heading_2 = create(:budget_heading, group: group_2)
|
|
|
|
investment = create(:budget_investment, heading: heading_1)
|
|
|
|
expect(investment.budget_id).to eq budget.id
|
|
expect(investment.group_id).to eq group_1.id
|
|
|
|
investment.update(heading: heading_2)
|
|
|
|
expect(investment.budget_id).to eq budget.id
|
|
expect(investment.group_id).to eq group_2.id
|
|
end
|
|
|
|
describe "#unfeasibility_explanation blank" do
|
|
it "is valid if valuation not finished" do
|
|
investment.unfeasibility_explanation = ""
|
|
investment.valuation_finished = false
|
|
expect(investment).to be_valid
|
|
end
|
|
|
|
it "is valid if valuation finished and feasible" do
|
|
investment.unfeasibility_explanation = ""
|
|
investment.feasibility = "feasible"
|
|
investment.valuation_finished = true
|
|
expect(investment).to be_valid
|
|
end
|
|
|
|
it "is not valid if valuation finished and unfeasible" do
|
|
investment.unfeasibility_explanation = ""
|
|
investment.feasibility = "unfeasible"
|
|
investment.valuation_finished = true
|
|
expect(investment).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe "#price blank" do
|
|
it "is valid if valuation not finished" do
|
|
investment.price = ""
|
|
investment.valuation_finished = false
|
|
expect(investment).to be_valid
|
|
end
|
|
|
|
it "is valid if valuation finished and unfeasible" do
|
|
investment.price = ""
|
|
investment.unfeasibility_explanation = "reason"
|
|
investment.feasibility = "unfeasible"
|
|
investment.valuation_finished = true
|
|
expect(investment).to be_valid
|
|
end
|
|
|
|
it "is not valid if valuation finished and feasible" do
|
|
investment.price = ""
|
|
investment.feasibility = "feasible"
|
|
investment.valuation_finished = true
|
|
expect(investment).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe "#code" do
|
|
let(:investment) { create(:budget_investment) }
|
|
|
|
it "returns the proposal id" do
|
|
expect(investment.code).to include(investment.id.to_s)
|
|
end
|
|
|
|
it "returns the administrator id when assigned" do
|
|
investment.administrator = create(:administrator)
|
|
expect(investment.code).to include("#{investment.id}-A#{investment.administrator.id}")
|
|
end
|
|
end
|
|
|
|
describe "#send_unfeasible_email" do
|
|
let(:investment) { create(:budget_investment) }
|
|
|
|
it "sets the time when the unfeasible email was sent" do
|
|
expect(investment.unfeasible_email_sent_at).not_to be
|
|
investment.send_unfeasible_email
|
|
expect(investment.unfeasible_email_sent_at).to be
|
|
end
|
|
|
|
it "send an email" do
|
|
expect {investment.send_unfeasible_email}.to change { ActionMailer::Base.deliveries.count }.by(1)
|
|
end
|
|
end
|
|
|
|
describe "#should_show_votes?" do
|
|
it "returns true in selecting phase" do
|
|
budget = create(:budget, phase: "selecting")
|
|
investment = create(:budget_investment, budget: budget)
|
|
|
|
expect(investment.should_show_votes?).to eq(true)
|
|
end
|
|
|
|
it "returns false in any other phase" do
|
|
Budget::Phase::PHASE_KINDS.reject {|phase| phase == "selecting"}.each do |phase|
|
|
budget = create(:budget, phase: phase)
|
|
investment = create(:budget_investment, budget: budget)
|
|
|
|
expect(investment.should_show_votes?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#should_show_vote_count?" do
|
|
it "returns true in valuating phase" do
|
|
budget = create(:budget, phase: "valuating")
|
|
investment = create(:budget_investment, budget: budget)
|
|
|
|
expect(investment.should_show_vote_count?).to eq(true)
|
|
end
|
|
|
|
it "returns false in any other phase" do
|
|
Budget::Phase::PHASE_KINDS.reject {|phase| phase == "valuating"}.each do |phase|
|
|
budget = create(:budget, phase: phase)
|
|
investment = create(:budget_investment, budget: budget)
|
|
|
|
expect(investment.should_show_vote_count?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#should_show_ballots?" do
|
|
it "returns true in balloting phase for selected investments" do
|
|
budget = create(:budget, phase: "balloting")
|
|
investment = create(:budget_investment, :selected, budget: budget)
|
|
|
|
expect(investment.should_show_ballots?).to eq(true)
|
|
end
|
|
|
|
it "returns false for unselected investments" do
|
|
budget = create(:budget, phase: "balloting")
|
|
investment = create(:budget_investment, :unselected, budget: budget)
|
|
|
|
expect(investment.should_show_ballots?).to eq(false)
|
|
end
|
|
|
|
it "returns false in any other phase" do
|
|
Budget::Phase::PHASE_KINDS.reject {|phase| phase == "balloting"}.each do |phase|
|
|
budget = create(:budget, phase: phase)
|
|
investment = create(:budget_investment, :selected, budget: budget)
|
|
|
|
expect(investment.should_show_ballots?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#should_show_price?" do
|
|
let(:budget) { create(:budget, :publishing_prices) }
|
|
let(:investment) do
|
|
create(:budget_investment, :selected, budget: budget)
|
|
end
|
|
|
|
it "returns true for selected investments which budget's phase is publishing_prices or later" do
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_price?).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "returns false in any other phase" do
|
|
(Budget::Phase::PHASE_KINDS - Budget::Phase::PUBLISHED_PRICES_PHASES).each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_price?).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "returns false if investment is not selected" do
|
|
investment.selected = false
|
|
|
|
expect(investment.should_show_price?).to eq(false)
|
|
end
|
|
|
|
it "returns false if price is not present" do
|
|
investment.price = nil
|
|
|
|
expect(investment.should_show_price?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#should_show_price_explanation?" do
|
|
let(:budget) { create(:budget, :publishing_prices) }
|
|
let(:investment) do
|
|
create(:budget_investment, :selected, budget: budget, price_explanation: "because of reasons")
|
|
end
|
|
|
|
it "returns true for selected with price_explanation & budget in publishing_prices or later" do
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_price_explanation?).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "returns false in any other phase" do
|
|
(Budget::Phase::PHASE_KINDS - Budget::Phase::PUBLISHED_PRICES_PHASES).each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_price_explanation?).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "returns false if investment is not selected" do
|
|
investment.selected = false
|
|
|
|
expect(investment.should_show_price_explanation?).to eq(false)
|
|
end
|
|
|
|
it "returns false if price_explanation is not present" do
|
|
investment.price_explanation = ""
|
|
|
|
expect(investment.should_show_price_explanation?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#should_show_unfeasibility_explanation?" do
|
|
let(:budget) { create(:budget) }
|
|
let(:investment) do
|
|
create(:budget_investment, budget: budget,
|
|
unfeasibility_explanation: "because of reasons",
|
|
valuation_finished: true,
|
|
feasibility: "unfeasible")
|
|
end
|
|
|
|
it "returns true for unfeasible investments with unfeasibility explanation and valuation finished" do
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_unfeasibility_explanation?).to eq(true)
|
|
end
|
|
end
|
|
|
|
it "returns false in valuation has not finished" do
|
|
investment.update(valuation_finished: false)
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_unfeasibility_explanation?).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "returns false if not unfeasible" do
|
|
investment.update(feasibility: "undecided")
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_unfeasibility_explanation?).to eq(false)
|
|
end
|
|
end
|
|
|
|
it "returns false if unfeasibility explanation blank" do
|
|
investment.update(unfeasibility_explanation: "")
|
|
Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase|
|
|
budget.update(phase: phase)
|
|
|
|
expect(investment.should_show_unfeasibility_explanation?).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#by_budget" do
|
|
|
|
it "returns investments scoped by budget" do
|
|
budget1 = create(:budget)
|
|
budget2 = create(:budget)
|
|
|
|
group1 = create(:budget_group, budget: budget1)
|
|
group2 = create(:budget_group, budget: budget2)
|
|
|
|
heading1 = create(:budget_heading, group: group1)
|
|
heading2 = create(:budget_heading, group: group2)
|
|
|
|
investment1 = create(:budget_investment, heading: heading1)
|
|
investment2 = create(:budget_investment, heading: heading1)
|
|
investment3 = create(:budget_investment, heading: heading2)
|
|
|
|
investments_by_budget = Budget::Investment.by_budget(budget1)
|
|
|
|
expect(investments_by_budget).to include investment1
|
|
expect(investments_by_budget).to include investment2
|
|
expect(investments_by_budget).to_not include investment3
|
|
end
|
|
end
|
|
|
|
describe "#by_admin" do
|
|
it "returns investments assigned to specific administrator" do
|
|
investment1 = create(:budget_investment, administrator_id: 33)
|
|
create(:budget_investment)
|
|
|
|
by_admin = described_class.by_admin(33)
|
|
|
|
expect(by_admin.size).to eq(1)
|
|
expect(by_admin.first).to eq(investment1)
|
|
end
|
|
end
|
|
|
|
describe "by_valuator" do
|
|
it "returns investments assigned to specific valuator" do
|
|
investment1 = create(:budget_investment)
|
|
investment2 = create(:budget_investment)
|
|
investment3 = create(:budget_investment)
|
|
|
|
valuator1 = create(:valuator)
|
|
valuator2 = create(:valuator)
|
|
|
|
investment1.valuators << valuator1
|
|
investment2.valuators << valuator2
|
|
investment3.valuators << [valuator1, valuator2]
|
|
|
|
by_valuator = described_class.by_valuator(valuator1.id)
|
|
|
|
expect(by_valuator.size).to eq(2)
|
|
expect(by_valuator.sort).to eq([investment1, investment3].sort)
|
|
end
|
|
end
|
|
|
|
describe "#by_valuator_group" do
|
|
|
|
it "returns investments assigned to a valuator's group" do
|
|
valuator = create(:valuator)
|
|
valuator_group = create(:valuator_group, valuators: [valuator])
|
|
assigned_investment = create(:budget_investment, valuators: [valuator],
|
|
valuator_groups: [valuator_group])
|
|
another_assigned_investment = create(:budget_investment, valuator_groups: [valuator_group])
|
|
unassigned_investment = create(:budget_investment, valuators: [valuator], valuator_groups: [])
|
|
create(:budget_investment, valuators: [valuator], valuator_groups: [create(:valuator_group)])
|
|
|
|
by_valuator_group = described_class.by_valuator_group(valuator.valuator_group_id)
|
|
|
|
expect(by_valuator_group.size).to eq(2)
|
|
expect(by_valuator_group).to contain_exactly(assigned_investment, another_assigned_investment)
|
|
end
|
|
end
|
|
|
|
describe "scopes" do
|
|
describe "valuation_open" do
|
|
it "returns all investments with false valuation_finished" do
|
|
investment1 = create(:budget_investment, valuation_finished: true)
|
|
investment2 = create(:budget_investment)
|
|
|
|
valuation_open = described_class.valuation_open
|
|
|
|
expect(valuation_open.size).to eq(1)
|
|
expect(valuation_open.first).to eq(investment2)
|
|
end
|
|
end
|
|
|
|
describe "without_admin" do
|
|
it "returns all open investments without assigned admin" do
|
|
investment1 = create(:budget_investment, valuation_finished: true)
|
|
investment2 = create(:budget_investment, administrator: create(:administrator))
|
|
investment3 = create(:budget_investment)
|
|
|
|
without_admin = described_class.without_admin
|
|
|
|
expect(without_admin.size).to eq(1)
|
|
expect(without_admin.first).to eq(investment3)
|
|
end
|
|
end
|
|
|
|
describe "managed" do
|
|
it "returns all open investments with assigned admin but without assigned valuators" do
|
|
investment1 = create(:budget_investment, administrator: create(:administrator))
|
|
investment2 = create(:budget_investment, administrator: create(:administrator), valuation_finished: true)
|
|
investment3 = create(:budget_investment, administrator: create(:administrator))
|
|
investment1.valuators << create(:valuator)
|
|
|
|
managed = described_class.managed
|
|
|
|
expect(managed.size).to eq(1)
|
|
expect(managed.first).to eq(investment3)
|
|
end
|
|
end
|
|
|
|
describe "valuating" do
|
|
it "returns all investments with assigned valuator but valuation not finished" do
|
|
investment1 = create(:budget_investment)
|
|
investment2 = create(:budget_investment)
|
|
investment3 = create(:budget_investment, valuation_finished: true)
|
|
|
|
investment2.valuators << create(:valuator)
|
|
investment3.valuators << create(:valuator)
|
|
|
|
valuating = described_class.valuating
|
|
|
|
expect(valuating.size).to eq(1)
|
|
expect(valuating.first).to eq(investment2)
|
|
end
|
|
|
|
it "returns all investments with assigned valuator groups but valuation not finished" do
|
|
investment1 = create(:budget_investment)
|
|
investment2 = create(:budget_investment)
|
|
investment3 = create(:budget_investment, valuation_finished: true)
|
|
|
|
investment2.valuator_groups << create(:valuator_group)
|
|
investment3.valuator_groups << create(:valuator_group)
|
|
|
|
valuating = described_class.valuating
|
|
|
|
expect(valuating.size).to eq(1)
|
|
expect(valuating.first).to eq(investment2)
|
|
end
|
|
end
|
|
|
|
describe "valuation_finished" do
|
|
it "returns all investments with valuation finished" do
|
|
investment1 = create(:budget_investment)
|
|
investment2 = create(:budget_investment)
|
|
investment3 = create(:budget_investment, valuation_finished: true)
|
|
|
|
investment2.valuators << create(:valuator)
|
|
investment3.valuators << create(:valuator)
|
|
|
|
valuation_finished = described_class.valuation_finished
|
|
|
|
expect(valuation_finished.size).to eq(1)
|
|
expect(valuation_finished.first).to eq(investment3)
|
|
end
|
|
end
|
|
|
|
describe "feasible" do
|
|
it "returns all feasible investments" do
|
|
feasible_investment = create(:budget_investment, :feasible)
|
|
create(:budget_investment)
|
|
|
|
expect(described_class.feasible).to eq [feasible_investment]
|
|
end
|
|
end
|
|
|
|
describe "unfeasible" do
|
|
it "returns all unfeasible investments" do
|
|
unfeasible_investment = create(:budget_investment, :unfeasible)
|
|
create(:budget_investment, :feasible)
|
|
|
|
expect(described_class.unfeasible).to eq [unfeasible_investment]
|
|
end
|
|
end
|
|
|
|
describe "not_unfeasible" do
|
|
it "returns all feasible and undecided investments" do
|
|
unfeasible_investment = create(:budget_investment, :unfeasible)
|
|
undecided_investment = create(:budget_investment, :undecided)
|
|
feasible_investment = create(:budget_investment, :feasible)
|
|
|
|
expect(described_class.not_unfeasible.sort).to eq [undecided_investment, feasible_investment].sort
|
|
end
|
|
end
|
|
|
|
describe "undecided" do
|
|
it "returns all undecided investments" do
|
|
unfeasible_investment = create(:budget_investment, :unfeasible)
|
|
undecided_investment = create(:budget_investment, :undecided)
|
|
feasible_investment = create(:budget_investment, :feasible)
|
|
|
|
expect(described_class.undecided).to eq [undecided_investment]
|
|
end
|
|
end
|
|
|
|
describe "selected" do
|
|
it "returns all selected investments" do
|
|
selected_investment = create(:budget_investment, :selected)
|
|
unselected_investment = create(:budget_investment, :unselected)
|
|
|
|
expect(described_class.selected).to eq [selected_investment]
|
|
end
|
|
end
|
|
|
|
describe "unselected" do
|
|
it "returns all unselected not_unfeasible investments" do
|
|
selected_investment = create(:budget_investment, :selected)
|
|
unselected_unfeasible_investment = create(:budget_investment, :unselected, :unfeasible)
|
|
unselected_undecided_investment = create(:budget_investment, :unselected, :undecided)
|
|
unselected_feasible_investment = create(:budget_investment, :unselected, :feasible)
|
|
|
|
expect(described_class.unselected.sort).to eq [unselected_undecided_investment, unselected_feasible_investment].sort
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "apply_filters_and_search" do
|
|
|
|
let(:budget) { create(:budget) }
|
|
|
|
it "returns feasible investments" do
|
|
investment1 = create(:budget_investment, :feasible, budget: budget)
|
|
investment2 = create(:budget_investment, :feasible, budget: budget)
|
|
investment3 = create(:budget_investment, :unfeasible, budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, {}, :feasible)
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
|
|
it "returns unfeasible investments" do
|
|
investment1 = create(:budget_investment, :unfeasible, budget: budget)
|
|
investment2 = create(:budget_investment, :unfeasible, budget: budget)
|
|
investment3 = create(:budget_investment, :feasible, budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, {}, :unfeasible)
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
|
|
it "returns selected investments" do
|
|
budget.update(phase: "balloting")
|
|
|
|
investment1 = create(:budget_investment, :feasible, :selected, budget: budget)
|
|
investment2 = create(:budget_investment, :feasible, :selected, budget: budget)
|
|
investment3 = create(:budget_investment, :feasible, :unselected, budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, {}, :selected)
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
|
|
it "returns unselected investments" do
|
|
budget.update(phase: "balloting")
|
|
|
|
investment1 = create(:budget_investment, :feasible, :unselected, budget: budget)
|
|
investment2 = create(:budget_investment, :feasible, :unselected, budget: budget)
|
|
investment3 = create(:budget_investment, :feasible, :selected, budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, {}, :unselected)
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
|
|
it "returns investmens by heading" do
|
|
group = create(:budget_group, budget: budget)
|
|
|
|
heading1 = create(:budget_heading, group: group)
|
|
heading2 = create(:budget_heading, group: group)
|
|
|
|
investment1 = create(:budget_investment, heading: heading1, budget: budget)
|
|
investment2 = create(:budget_investment, heading: heading1, budget: budget)
|
|
investment3 = create(:budget_investment, heading: heading2, budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, heading_id: heading1.id)
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
|
|
it "returns investments by search string" do
|
|
investment1 = create(:budget_investment, title: "health for all", budget: budget)
|
|
investment2 = create(:budget_investment, title: "improved health", budget: budget)
|
|
investment3 = create(:budget_investment, title: "finance", budget: budget)
|
|
|
|
results = described_class.apply_filters_and_search(budget, search: "health")
|
|
|
|
expect(results).to include investment1
|
|
expect(results).to include investment2
|
|
expect(results).not_to include investment3
|
|
end
|
|
end
|
|
|
|
describe "search" do
|
|
|
|
context "attributes" do
|
|
|
|
it "searches by title" do
|
|
budget_investment = create(:budget_investment, title: 'save the world')
|
|
results = described_class.search('save the world')
|
|
expect(results).to eq([budget_investment])
|
|
end
|
|
|
|
it "searches by author name" do
|
|
author = create(:user, username: 'Danny Trejo')
|
|
budget_investment = create(:budget_investment, author: author)
|
|
results = described_class.search('Danny')
|
|
expect(results).to eq([budget_investment])
|
|
end
|
|
|
|
end
|
|
|
|
context "tags" do
|
|
it "searches by tags" do
|
|
investment = create(:budget_investment, tag_list: 'Latina')
|
|
|
|
results = described_class.search('Latina')
|
|
expect(results.first).to eq(investment)
|
|
|
|
results = described_class.search('Latin')
|
|
expect(results.first).to eq(investment)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
describe 'Permissions' do
|
|
let(:budget) { create(:budget) }
|
|
let(:group) { create(:budget_group, budget: budget) }
|
|
let(:heading) { create(:budget_heading, group: group) }
|
|
let(:user) { create(:user, :level_two) }
|
|
let(:luser) { create(:user) }
|
|
let(:district_sp) { create(:budget_investment, budget: budget, group: group, heading: heading) }
|
|
|
|
describe '#reason_for_not_being_selectable_by' do
|
|
it "rejects not logged in users" do
|
|
expect(district_sp.reason_for_not_being_selectable_by(nil)).to eq(:not_logged_in)
|
|
end
|
|
|
|
it "rejects not verified users" do
|
|
expect(district_sp.reason_for_not_being_selectable_by(luser)).to eq(:not_verified)
|
|
end
|
|
|
|
it "rejects organizations" do
|
|
create(:organization, user: user)
|
|
expect(district_sp.reason_for_not_being_selectable_by(user)).to eq(:organization)
|
|
end
|
|
|
|
it "rejects selections when selecting is not allowed (via admin setting)" do
|
|
budget.phase = "reviewing"
|
|
expect(district_sp.reason_for_not_being_selectable_by(user)).to eq(:no_selecting_allowed)
|
|
end
|
|
|
|
it "accepts valid selections when selecting is allowed" do
|
|
budget.phase = "selecting"
|
|
expect(district_sp.reason_for_not_being_selectable_by(user)).to be_nil
|
|
end
|
|
|
|
it "rejects votes in two headings of the same group" do
|
|
carabanchel = create(:budget_heading, group: group)
|
|
salamanca = create(:budget_heading, group: group)
|
|
|
|
carabanchel_investment = create(:budget_investment, heading: carabanchel)
|
|
salamanca_investment = create(:budget_investment, heading: salamanca)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
|
|
expect(salamanca_investment.valid_heading?(user)).to eq(false)
|
|
end
|
|
|
|
it "accepts votes in multiple headings of the same group" do
|
|
group.update(max_votable_headings: 2)
|
|
|
|
carabanchel = create(:budget_heading, group: group)
|
|
salamanca = create(:budget_heading, group: group)
|
|
|
|
carabanchel_investment = create(:budget_investment, heading: carabanchel)
|
|
salamanca_investment = create(:budget_investment, heading: salamanca)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
|
|
expect(salamanca_investment.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "accepts votes in any heading previously voted in" do
|
|
group.update(max_votable_headings: 2)
|
|
|
|
carabanchel = create(:budget_heading, group: group)
|
|
salamanca = create(:budget_heading, group: group)
|
|
|
|
carabanchel_investment = create(:budget_investment, heading: carabanchel)
|
|
salamanca_investment = create(:budget_investment, heading: salamanca)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
create(:vote, votable: salamanca_investment, voter: user)
|
|
|
|
expect(carabanchel_investment.valid_heading?(user)).to eq(true)
|
|
expect(salamanca_investment.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "allows votes in a group with a single heading" do
|
|
all_city_investment = create(:budget_investment, heading: heading)
|
|
expect(all_city_investment.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "allows votes in a group with a single heading after voting in that heading" do
|
|
all_city_investment1 = create(:budget_investment, heading: heading)
|
|
all_city_investment2 = create(:budget_investment, heading: heading)
|
|
|
|
create(:vote, votable: all_city_investment1, voter: user)
|
|
|
|
expect(all_city_investment2.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "allows votes in a group with a single heading after voting in another group" do
|
|
districts = create(:budget_group, budget: budget)
|
|
carabanchel = create(:budget_heading, group: districts)
|
|
|
|
all_city_investment = create(:budget_investment, heading: heading)
|
|
carabanchel_investment = create(:budget_investment, heading: carabanchel)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
|
|
expect(all_city_investment.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "allows votes in a group with multiple headings after voting in group with a single heading" do
|
|
districts = create(:budget_group, budget: budget)
|
|
carabanchel = create(:budget_heading, group: districts)
|
|
salamanca = create(:budget_heading, group: districts)
|
|
|
|
all_city_investment = create(:budget_investment, heading: heading)
|
|
carabanchel_investment = create(:budget_investment, heading: carabanchel)
|
|
|
|
create(:vote, votable: all_city_investment, voter: user)
|
|
|
|
expect(carabanchel_investment.valid_heading?(user)).to eq(true)
|
|
end
|
|
|
|
describe "#can_vote_in_another_heading?" do
|
|
|
|
let(:districts) { create(:budget_group, budget: budget) }
|
|
let(:carabanchel) { create(:budget_heading, group: districts) }
|
|
let(:salamanca) { create(:budget_heading, group: districts) }
|
|
let(:latina) { create(:budget_heading, group: districts) }
|
|
|
|
let(:carabanchel_investment) { create(:budget_investment, heading: carabanchel) }
|
|
let(:salamanca_investment) { create(:budget_investment, heading: salamanca) }
|
|
let(:latina_investment) { create(:budget_investment, heading: latina) }
|
|
|
|
it "returns true if the user has voted in less headings than the maximum" do
|
|
districts.update(max_votable_headings: 2)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
|
|
expect(salamanca_investment.can_vote_in_another_heading?(user)).to eq(true)
|
|
end
|
|
|
|
it "returns false if the user has already voted in the maximum number of headings" do
|
|
districts.update(max_votable_headings: 2)
|
|
|
|
create(:vote, votable: carabanchel_investment, voter: user)
|
|
create(:vote, votable: salamanca_investment, voter: user)
|
|
|
|
expect(latina_investment.can_vote_in_another_heading?(user)).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#headings_voted_by_user" do
|
|
it "returns the headings voted by a user" do
|
|
user1 = create(:user)
|
|
user2 = create(:user)
|
|
|
|
budget = create(:budget)
|
|
group = create(:budget_group, budget: budget)
|
|
|
|
new_york = create(:budget_heading, group: group)
|
|
san_franciso = create(:budget_heading, group: group)
|
|
another_heading = create(:budget_heading, group: group)
|
|
|
|
new_york_investment = create(:budget_investment, heading: new_york)
|
|
san_franciso_investment = create(:budget_investment, heading: san_franciso)
|
|
another_investment = create(:budget_investment, heading: san_franciso)
|
|
|
|
create(:vote, votable: new_york_investment, voter: user1)
|
|
create(:vote, votable: san_franciso_investment, voter: user1)
|
|
|
|
expect(another_investment.headings_voted_by_user(user1)).to include(new_york.id)
|
|
expect(another_investment.headings_voted_by_user(user1)).to include(san_franciso.id)
|
|
expect(another_investment.headings_voted_by_user(user1)).to_not include(another_heading.id)
|
|
|
|
expect(another_investment.headings_voted_by_user(user2)).to_not include(new_york.id)
|
|
expect(another_investment.headings_voted_by_user(user2)).to_not include(san_franciso.id)
|
|
expect(another_investment.headings_voted_by_user(user2)).to_not include(another_heading.id)
|
|
end
|
|
end
|
|
|
|
describe "#voted_in?" do
|
|
|
|
let(:user) { create(:user) }
|
|
let(:investment) { create(:budget_investment) }
|
|
|
|
it "returns true if the user has voted in this heading" do
|
|
create(:vote, votable: investment, voter: user)
|
|
|
|
expect(investment.voted_in?(investment.heading, user)).to eq(true)
|
|
end
|
|
|
|
it "returns false if the user has not voted in this heading" do
|
|
expect(investment.voted_in?(investment.heading, user)).to eq(false)
|
|
end
|
|
|
|
end
|
|
|
|
describe "Order" do
|
|
describe "#sort_by_confidence_score" do
|
|
|
|
it "orders by confidence_score" do
|
|
least_voted = create(:budget_investment, cached_votes_up: 1)
|
|
most_voted = create(:budget_investment, cached_votes_up: 10)
|
|
some_votes = create(:budget_investment, cached_votes_up: 5)
|
|
|
|
expect(described_class.sort_by_confidence_score.first).to eq most_voted
|
|
expect(described_class.sort_by_confidence_score.second).to eq some_votes
|
|
expect(described_class.sort_by_confidence_score.third).to eq least_voted
|
|
end
|
|
|
|
it "orders by confidence_score and then by id" do
|
|
least_voted = create(:budget_investment, cached_votes_up: 1)
|
|
most_voted = create(:budget_investment, cached_votes_up: 10)
|
|
most_voted2 = create(:budget_investment, cached_votes_up: 10)
|
|
least_voted2 = create(:budget_investment, cached_votes_up: 1)
|
|
|
|
expect(described_class.sort_by_confidence_score.first).to eq most_voted2
|
|
expect(described_class.sort_by_confidence_score.second).to eq most_voted
|
|
expect(described_class.sort_by_confidence_score.third).to eq least_voted2
|
|
expect(described_class.sort_by_confidence_score.fourth).to eq least_voted
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "responsible_name" do
|
|
let(:user) { create(:user, document_number: "123456") }
|
|
let!(:investment) { create(:budget_investment, author: user) }
|
|
|
|
it "gets updated with the document_number" do
|
|
expect(investment.responsible_name).to eq("123456")
|
|
end
|
|
|
|
it "does not get updated if the user is erased" do
|
|
user.erase
|
|
user.update(document_number: nil)
|
|
expect(user.document_number).to be_blank
|
|
investment.touch
|
|
expect(investment.responsible_name).to eq("123456")
|
|
end
|
|
end
|
|
|
|
describe "total votes" do
|
|
it "takes into account physical votes in addition to web votes" do
|
|
b = create(:budget, :selecting)
|
|
g = create(:budget_group, budget: b)
|
|
h = create(:budget_heading, group: g)
|
|
i = create(:budget_investment, budget: b, group: g, heading: h)
|
|
|
|
i.register_selection(create(:user, :level_two))
|
|
expect(i.total_votes).to eq(1)
|
|
|
|
i.physical_votes = 10
|
|
expect(i.total_votes).to eq(11)
|
|
end
|
|
end
|
|
|
|
describe "#with_supports" do
|
|
it "returns proposals with supports" do
|
|
inv1 = create(:budget_investment)
|
|
inv2 = create(:budget_investment)
|
|
create(:vote, votable: inv1)
|
|
|
|
expect(described_class.with_supports).to include(inv1)
|
|
expect(described_class.with_supports).not_to include(inv2)
|
|
end
|
|
end
|
|
|
|
describe "Final Voting" do
|
|
|
|
describe 'Permissions' do
|
|
let(:budget) { create(:budget) }
|
|
let(:group) { create(:budget_group, budget: budget) }
|
|
let(:heading) { create(:budget_heading, group: group) }
|
|
let(:user) { create(:user, :level_two) }
|
|
let(:luser) { create(:user) }
|
|
let(:ballot) { create(:budget_ballot, budget: budget) }
|
|
let(:investment) { create(:budget_investment, :selected, budget: budget, heading: heading) }
|
|
|
|
describe '#reason_for_not_being_ballotable_by' do
|
|
it "rejects not logged in users" do
|
|
expect(investment.reason_for_not_being_ballotable_by(nil, ballot)).to eq(:not_logged_in)
|
|
end
|
|
|
|
it "rejects not verified users" do
|
|
expect(investment.reason_for_not_being_ballotable_by(luser, ballot)).to eq(:not_verified)
|
|
end
|
|
|
|
it "rejects organizations" do
|
|
create(:organization, user: user)
|
|
expect(investment.reason_for_not_being_ballotable_by(user, ballot)).to eq(:organization)
|
|
end
|
|
|
|
it "rejects votes when voting is not allowed (wrong phase)" do
|
|
budget.phase = "reviewing"
|
|
expect(investment.reason_for_not_being_ballotable_by(user, ballot)).to eq(:no_ballots_allowed)
|
|
end
|
|
|
|
it "rejects non-selected investments" do
|
|
investment.selected = false
|
|
expect(investment.reason_for_not_being_ballotable_by(user, ballot)).to eq(:not_selected)
|
|
end
|
|
|
|
it "accepts valid ballots when voting is allowed" do
|
|
budget.phase = "balloting"
|
|
expect(investment.reason_for_not_being_ballotable_by(user, ballot)).to be_nil
|
|
end
|
|
|
|
it "accepts valid selections" do
|
|
budget.phase = "selecting"
|
|
expect(investment.reason_for_not_being_selectable_by(user)).to be_nil
|
|
end
|
|
|
|
it "rejects users with different headings" do
|
|
budget.phase = "balloting"
|
|
group = create(:budget_group, budget: budget)
|
|
california = create(:budget_heading, group: group)
|
|
new_york = create(:budget_heading, group: group)
|
|
|
|
inv1 = create(:budget_investment, :selected, budget: budget, group: group, heading: california)
|
|
inv2 = create(:budget_investment, :selected, budget: budget, group: group, heading: new_york)
|
|
ballot = create(:budget_ballot, user: user, budget: budget)
|
|
ballot.investments << inv1
|
|
|
|
expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:different_heading_assigned_html)
|
|
end
|
|
|
|
it "rejects proposals with price higher than current available money" do
|
|
budget.phase = "balloting"
|
|
districts = create(:budget_group, budget: budget)
|
|
carabanchel = create(:budget_heading, group: districts, price: 35)
|
|
inv1 = create(:budget_investment, :selected, budget: budget, group: districts, heading: carabanchel, price: 30)
|
|
inv2 = create(:budget_investment, :selected, budget: budget, group: districts, heading: carabanchel, price: 10)
|
|
|
|
ballot = create(:budget_ballot, user: user, budget: budget)
|
|
ballot.investments << inv1
|
|
|
|
expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:not_enough_money_html)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
describe "Reclassification" do
|
|
|
|
let(:budget) { create(:budget, phase: "balloting") }
|
|
let(:group) { create(:budget_group, budget: budget) }
|
|
let(:heading1) { create(:budget_heading, group: group) }
|
|
let(:heading2) { create(:budget_heading, group: group) }
|
|
|
|
describe "heading_changed?" do
|
|
|
|
it "returns true if budget is in balloting phase and heading has changed" do
|
|
investment = create(:budget_investment, heading: heading1)
|
|
investment.heading = heading2
|
|
|
|
expect(investment.heading_changed?).to eq(true)
|
|
end
|
|
|
|
it "returns false if heading has not changed" do
|
|
investment = create(:budget_investment)
|
|
investment.heading = investment.heading
|
|
|
|
expect(investment.heading_changed?).to eq(false)
|
|
end
|
|
|
|
it "returns false if budget is not balloting phase" do
|
|
Budget::Phase::PHASE_KINDS.reject {|phase| phase == "balloting"}.each do |phase|
|
|
budget.update(phase: phase)
|
|
investment = create(:budget_investment, budget: budget)
|
|
|
|
investment.heading = heading2
|
|
|
|
expect(investment.heading_changed?).to eq(false)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
describe "log_heading_change" do
|
|
|
|
it "stores the previous heading before being reclassified" do
|
|
investment = create(:budget_investment, heading: heading1)
|
|
|
|
expect(investment.heading_id).to eq(heading1.id)
|
|
expect(investment.previous_heading_id).to eq(nil)
|
|
|
|
investment.heading = heading2
|
|
investment.save
|
|
|
|
investment.reload
|
|
expect(investment.heading_id).to eq(heading2.id)
|
|
expect(investment.previous_heading_id).to eq(heading1.id)
|
|
end
|
|
|
|
end
|
|
|
|
describe "store_reclassified_votes" do
|
|
|
|
it "stores the votes for a reclassified investment" do
|
|
investment = create(:budget_investment, :selected, heading: heading1)
|
|
|
|
3.times do
|
|
ballot = create(:budget_ballot, budget: budget)
|
|
ballot.investments << investment
|
|
end
|
|
|
|
expect(investment.ballot_lines_count).to eq(3)
|
|
|
|
investment.heading = heading2
|
|
investment.store_reclassified_votes("heading_changed")
|
|
|
|
reclassified_vote = Budget::ReclassifiedVote.first
|
|
|
|
expect(Budget::ReclassifiedVote.count).to eq(3)
|
|
expect(reclassified_vote.investment_id).to eq(investment.id)
|
|
expect(reclassified_vote.user_id).to eq(Budget::Ballot.first.user.id)
|
|
expect(reclassified_vote.reason).to eq("heading_changed")
|
|
end
|
|
end
|
|
|
|
describe "remove_reclassified_votes" do
|
|
|
|
it "removes votes from invesment" do
|
|
investment = create(:budget_investment, :selected, heading: heading1)
|
|
|
|
3.times do
|
|
ballot = create(:budget_ballot, budget: budget)
|
|
ballot.investments << investment
|
|
end
|
|
|
|
expect(investment.ballot_lines_count).to eq(3)
|
|
|
|
investment.heading = heading2
|
|
investment.remove_reclassified_votes
|
|
|
|
investment.reload
|
|
expect(investment.ballot_lines_count).to eq(0)
|
|
end
|
|
|
|
end
|
|
|
|
describe "check_for_reclassification" do
|
|
|
|
it "stores reclassfied votes and removes actual votes if an investment has been reclassified" do
|
|
investment = create(:budget_investment, :selected, heading: heading1)
|
|
|
|
3.times do
|
|
ballot = create(:budget_ballot, budget: budget)
|
|
ballot.investments << investment
|
|
end
|
|
|
|
expect(investment.ballot_lines_count).to eq(3)
|
|
|
|
investment.heading = heading2
|
|
investment.save
|
|
investment.reload
|
|
|
|
expect(investment.ballot_lines_count).to eq(0)
|
|
expect(Budget::ReclassifiedVote.count).to eq(3)
|
|
end
|
|
|
|
it "does not store reclassified votes nor remove actual votes if the investment has not been reclassifed" do
|
|
investment = create(:budget_investment, :selected, heading: heading1)
|
|
|
|
3.times do
|
|
ballot = create(:budget_ballot, budget: budget)
|
|
ballot.investments << investment
|
|
end
|
|
|
|
expect(investment.ballot_lines_count).to eq(3)
|
|
|
|
investment.save
|
|
investment.reload
|
|
|
|
expect(investment.ballot_lines_count).to eq(3)
|
|
expect(Budget::ReclassifiedVote.count).to eq(0)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
end
|