Files
grecia/spec/models/budget/investment_spec.rb
Javi Martín 7ca55c44e0 Apply Rails/SaveBang rubocop rule
Having exceptions is better than having silent bugs.

There are a few methods I've kept the same way they were.

The `RelatedContentScore#score_with_opposite` method is a bit peculiar:
it creates scores for both itself and the opposite related content,
which means the opposite related content will try to create the same
scores as well.

We've already got a test to check `Budget::Ballot#add_investment` when
creating a line fails ("Edge case voting a non-elegible investment").

Finally, the method `User#send_oauth_confirmation_instructions` doesn't
update the record when the email address isn't already present, leading
to the test "Try to register with the email of an already existing user,
when an unconfirmed email was provided by oauth" fo fail if we raise an
exception for an invalid user. That's because updating a user's email
doesn't update the database automatically, but instead a confirmation
email is sent.

There are also a few false positives for classes which don't have bang
methods (like the GraphQL classes) or destroying attachments.

For these reasons, I'm adding the rule with a "Refactor" severity,
meaning it's a rule we can break if necessary.
2019-10-23 14:39:31 +02:00

1362 lines
46 KiB
Ruby

require "rails_helper"
describe Budget::Investment do
let(:investment) { build(:budget_investment) }
describe "Concerns" do
it_behaves_like "notifiable"
it_behaves_like "sanitizable"
it_behaves_like "globalizable", :budget_investment
it_behaves_like "acts as imageable", :budget_investment_image
it_behaves_like "acts as paranoid", :budget_investment
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 "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
it "logs previous heading value if it is changed" do
budget = create(:budget, phase: "balloting")
group = create(:budget_group, budget: budget)
heading_1 = create(:budget_heading, group: group)
heading_2 = create(:budget_heading, group: group)
investment = create(:budget_investment, heading: heading_1)
expect(investment.previous_heading_id).to eq nil
investment.update!(heading: heading_2)
expect(investment.previous_heading_id).to eq heading_1.id
end
it "stores original heading id" do
investment = create(:budget_investment)
expect(investment.original_heading_id).to eq investment.heading_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, :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, :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, :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, :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, :unfeasible, :finished, budget: budget)
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.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 match_array [investment1, investment2]
expect(investments_by_budget).not_to 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 = Budget::Investment.by_admin(33)
expect(by_admin).to eq [investment1]
end
end
describe "by_valuator" do
it "returns investments assigned to a valuator" do
alfred = create(:valuator)
batman = create(:valuator)
manor = create(:budget_investment, valuators: [alfred])
batcave = create(:budget_investment, valuators: [alfred, batman])
by_valuator = Budget::Investment.by_valuator(alfred)
expect(by_valuator).to match_array [manor, batcave]
end
it "does not return investments assigned to a different valuator" do
jekyll = create(:valuator)
hyde = create(:valuator)
create(:budget_investment, valuators: [hyde])
by_valuator = Budget::Investment.by_valuator(jekyll)
expect(by_valuator).to be_empty
end
end
describe "#by_valuator_group" do
let(:aquaman) { create(:valuator) }
let(:justice_league) { create(:valuator_group, valuators: [aquaman]) }
it "returns investments assigned to a valuator's group" do
water_power = create(:budget_investment, valuator_groups: [justice_league], valuators: [aquaman])
solar_power = create(:budget_investment, valuator_groups: [justice_league])
by_valuator_group = Budget::Investment.by_valuator_group(justice_league)
expect(by_valuator_group).to contain_exactly(solar_power, water_power)
end
it "does not return investments assigned to no groups" do
create(:budget_investment, valuators: [aquaman], valuator_groups: [])
expect(Budget::Investment.by_valuator_group(justice_league)).to be_empty
end
it "does not return investments assigned to a different group" do
create(:budget_investment, valuators: [aquaman], valuator_groups: [create(:valuator_group)])
expect(Budget::Investment.by_valuator_group(justice_league)).to be_empty
end
end
describe "scoped_filter" do
let!(:budget) { create(:budget, slug: "budget_slug") }
let!(:heading) { create(:budget_heading, budget: budget) }
let!(:investment) { create(:budget_investment, :feasible, heading: heading) }
it "finds budget by id or slug" do
results = Budget::Investment.scoped_filter({ budget_id: budget.id }, nil)
expect(results).to eq [investment]
results = Budget::Investment.scoped_filter({ budget_id: "budget_slug" }, nil)
expect(results).to eq [investment]
end
it "does not raise error if budget is not found" do
result = Budget::Investment.scoped_filter({ budget_id: "wrong_budget" }, nil)
expect(result).to be_empty
end
end
describe "scopes" do
describe "valuation_open" do
it "returns investments with valuation open" do
investment = create(:budget_investment, valuation_finished: false)
expect(Budget::Investment.valuation_open).to eq [investment]
end
it "does not return investments with valuation finished" do
create(:budget_investment, valuation_finished: true)
expect(Budget::Investment.valuation_open).to be_empty
end
end
describe "valuation_finished" do
it "returns investments with valuation finished" do
investment = create(:budget_investment, valuation_finished: true)
expect(Budget::Investment.valuation_finished).to eq [investment]
end
it "does not return investments with valuation open" do
create(:budget_investment, valuation_finished: false)
expect(Budget::Investment.valuation_finished).to be_empty
end
end
describe "without_admin" do
it "returns open investments without assigned admin" do
investment = create(:budget_investment, :open, administrator: nil)
expect(Budget::Investment.without_admin).to eq [investment]
end
it "does not return investments with valuation finished" do
create(:budget_investment, :finished)
expect(Budget::Investment.without_admin).to be_empty
end
it "does not return investment with an admin" do
create(:budget_investment, :with_administrator)
expect(Budget::Investment.without_admin).to be_empty
end
end
describe "managed" do
it "returns open investments with assigned admin but without assigned valuators" do
investment = create(:budget_investment, :with_administrator)
expect(Budget::Investment.managed).to eq [investment]
end
it "does not return investments without assigned admin" do
create(:budget_investment, administrator: nil)
expect(Budget::Investment.managed).to be_empty
end
it "does not return investments with assigned valuator" do
create(:budget_investment, :with_administrator, :with_valuator)
expect(Budget::Investment.managed).to be_empty
end
it "does not return finished investments" do
create(:budget_investment, :with_administrator, :finished)
expect(Budget::Investment.managed).to be_empty
end
end
describe "valuating" do
it "returns investments with assigned valuator but valuation not finished" do
investment = create(:budget_investment, :open, :with_valuator)
expect(Budget::Investment.valuating).to eq [investment]
end
it "returns investments with assigned valuator groups but valuation not finished" do
investment = create(:budget_investment, :open, valuator_groups: [create(:valuator_group)])
expect(Budget::Investment.valuating).to eq [investment]
end
it "does not return investments with valuation finished" do
create(:budget_investment, :finished, :with_valuator)
create(:budget_investment, :finished, valuator_groups: [create(:valuator_group)])
expect(Budget::Investment.valuating).to be_empty
end
it "does not return investments without valuator nor valuator group" do
create(:budget_investment, :open)
expect(Budget::Investment.valuating).to be_empty
end
end
describe "feasible" do
it "returns feasible investments" do
feasible_investment = create(:budget_investment, :feasible)
expect(Budget::Investment.feasible).to eq [feasible_investment]
end
it "does not return unfeasible nor undecided investments" do
create(:budget_investment, :undecided)
create(:budget_investment, :unfeasible)
expect(Budget::Investment.feasible).to be_empty
end
end
describe "unfeasible" do
it "returns unfeasible investments" do
unfeasible_investment = create(:budget_investment, :unfeasible)
expect(Budget::Investment.unfeasible).to eq [unfeasible_investment]
end
it "does not return feasible nor undecided investments" do
create(:budget_investment, :feasible)
create(:budget_investment, :undecided)
expect(Budget::Investment.unfeasible).to be_empty
end
end
describe "not_unfeasible" do
it "returns feasible and undecided investments" do
undecided_investment = create(:budget_investment, :undecided)
feasible_investment = create(:budget_investment, :feasible)
expect(Budget::Investment.not_unfeasible).to match_array [undecided_investment, feasible_investment]
end
it "does not return unfeasible investments" do
create(:budget_investment, :unfeasible)
expect(Budget::Investment.not_unfeasible).to be_empty
end
end
describe "undecided" do
it "returns undecided investments" do
undecided_investment = create(:budget_investment, :undecided)
expect(Budget::Investment.undecided).to eq [undecided_investment]
end
it "does not return feasible nor unfeasible investments" do
create(:budget_investment, :feasible)
create(:budget_investment, :unfeasible)
expect(Budget::Investment.undecided).to be_empty
end
end
describe "selected" do
it "returns selected investments" do
selected_investment = create(:budget_investment, :selected)
expect(Budget::Investment.selected).to eq [selected_investment]
end
it "does not return unselected investments" do
create(:budget_investment, :unselected)
expect(Budget::Investment.selected).to be_empty
end
end
describe "unselected" do
it "returns all unselected not_unfeasible investments" do
unselected_undecided_investment = create(:budget_investment, :unselected, :undecided)
unselected_feasible_investment = create(:budget_investment, :unselected, :feasible)
expect(Budget::Investment.unselected).to match_array [unselected_undecided_investment, unselected_feasible_investment]
end
it "does not return selected investments" do
create(:budget_investment, :selected)
expect(Budget::Investment.unselected).to be_empty
end
it "does not return unfeasible investments" do
create(:budget_investment, :unselected, :unfeasible)
expect(Budget::Investment.unselected).to be_empty
end
end
describe "sort_by_title" do
it "sorts using the title in the current locale" do
create(:budget_investment, title_en: "CCCC", title_es: "BBBB", description_en: "CCCC", description_es: "BBBB")
create(:budget_investment, title_en: "DDDD", title_es: "AAAA", description_en: "DDDD", description_es: "AAAA")
expect(Budget::Investment.sort_by_title.map(&:title)).to eq %w[CCCC DDDD]
end
it "takes into consideration title fallbacks when there is no translation for current locale" do
create(:budget_investment, title: "BBBB")
I18n.with_locale(:es) do
create(:budget_investment, title: "AAAA")
end
expect(Budget::Investment.sort_by_title.map(&:title)).to eq %w[AAAA BBBB]
end
end
describe "search_by_title_or_id" do
it "does not return investments by description" do
create(:budget_investment, title: "Something", description: "Awesome")
expect(Budget::Investment.search_by_title_or_id("Awesome")).to be_empty
end
it "returns investment by given id" do
investment = create(:budget_investment)
expect(Budget::Investment.search_by_title_or_id(investment.id.to_s)).to eq([investment])
end
it "returns investments by given title" do
investment = create(:budget_investment, title: "Investment title")
expect(Budget::Investment.search_by_title_or_id("Investment title")).to eq([investment])
end
it "finds investments with numbers in their title" do
investment = create(:budget_investment, title: "99 red balloons")
expect(Budget::Investment.search_by_title_or_id("99")).to eq([investment])
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 = Budget::Investment.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 = Budget::Investment.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 = Budget::Investment.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 = Budget::Investment.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)
investment2 = create(:budget_investment, heading: heading1)
investment3 = create(:budget_investment, heading: heading2)
results = Budget::Investment.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 = Budget::Investment.apply_filters_and_search(budget, search: "health")
expect(results).to match_array [investment1, investment2]
expect(results).not_to include investment3
end
end
describe "search" do
context "attributes" do
let(:attributes) do
{ title: "save the world",
description: "in order to save the world one must think about...",
title_es: "para salvar el mundo uno debe pensar en...",
description_es: "uno debe pensar" }
end
it "searches by title" do
budget_investment = create(:budget_investment, attributes)
results = Budget::Investment.search("save the world")
expect(results).to eq([budget_investment])
end
it "searches by title across all languages" do
budget_investment = create(:budget_investment, attributes)
results = Budget::Investment.search("salvar el mundo")
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 = Budget::Investment.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 = Budget::Investment.search("Latina")
expect(results.first).to eq(investment)
results = Budget::Investment.search("Latin")
expect(results.first).to eq(investment)
end
it "gets and sets valuation tags through virtual attributes" do
investment = create(:budget_investment)
investment.valuation_tag_list = %w[Code Test Refactor]
expect(investment.valuation_tag_list).to match_array(%w[Code Test Refactor])
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, 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)
create(:budget_investment, heading: carabanchel, voters: [user])
salamanca_investment = create(:budget_investment, heading: salamanca)
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)
create(:budget_investment, heading: carabanchel, voters: [user])
salamanca_investment = create(:budget_investment, heading: salamanca)
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, voters: [user])
salamanca_investment = create(:budget_investment, heading: salamanca, voters: [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
create(:budget_investment, heading: heading, voters: [user])
investment_for_same_heading = create(:budget_investment, heading: heading)
expect(investment_for_same_heading.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)
create(:budget_investment, heading: carabanchel, voters: [user])
investment_from_different_group = create(:budget_investment, heading: heading)
expect(investment_from_different_group.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)
2.times { create(:budget_heading, group: districts) }
create(:budget_investment, heading: heading, voters: [user])
investment = create(:budget_investment, heading: districts.headings.sample)
expect(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 "#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(Budget::Investment.sort_by_confidence_score).to eq [most_voted, some_votes, 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(Budget::Investment.sort_by_confidence_score).to eq [
most_voted2, most_voted, least_voted2, 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
budget = create(:budget, :selecting)
investment = create(:budget_investment, budget: budget)
investment.register_selection(create(:user, :level_two))
expect(investment.total_votes).to eq(1)
investment.physical_votes = 10
expect(investment.total_votes).to eq(11)
end
end
describe "#with_supports" do
it "returns proposals with supports" do
inv1 = create(:budget_investment, voters: [create(:user)])
inv2 = create(:budget_investment)
expect(Budget::Investment.with_supports).to eq [inv1]
expect(Budget::Investment.with_supports).not_to include(inv2)
end
end
describe "Final Voting" do
describe "Permissions" do
let(:budget) { create(:budget) }
let(:heading) { create(:budget_heading, budget: budget) }
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, heading: california)
inv2 = create(:budget_investment, :selected, budget: budget, heading: new_york)
ballot = create(:budget_ballot, user: user, budget: budget, investments: [inv1])
expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:different_heading_assigned)
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, heading: carabanchel, price: 30)
inv2 = create(:budget_investment, :selected, budget: budget, heading: carabanchel, price: 10)
ballot = create(:budget_ballot, user: user, budget: budget, investments: [inv1])
expect(inv2.reason_for_not_being_ballotable_by(user, ballot)).to eq(:not_enough_money)
end
end
end
end
describe "Reclassification" do
let(:budget) { create(:budget, :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 { create(:user, ballot_lines: [investment]) }
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 { create(:user, ballot_lines: [investment]) }
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 { create(:user, ballot_lines: [investment]) }
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 { create(:user, ballot_lines: [investment]) }
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
describe "scoped_filter" do
let(:budget) { create(:budget, :balloting) }
let(:investment) { create(:budget_investment, budget: budget) }
describe "with without_admin filter" do
let(:params) { { advanced_filters: ["without_admin"], budget_id: budget.id } }
it "returns only investment without admin" do
create(:budget_investment,
:finished,
budget: budget)
create(:budget_investment,
:with_administrator,
budget: budget)
investment3 = create(:budget_investment, budget: budget)
expect(Budget::Investment.scoped_filter(params, "all")).to eq([investment3])
end
end
describe "with without_valuator filter" do
let(:params) { { advanced_filters: ["without_valuator"], budget_id: budget.id } }
it "returns only investment without valuator" do
create(:budget_investment,
:finished,
budget: budget)
investment2 = create(:budget_investment,
:with_administrator,
budget: budget)
investment3 = create(:budget_investment,
budget: budget)
expect(Budget::Investment.scoped_filter(params, "all"))
.to contain_exactly(investment2, investment3)
end
end
describe "with under_valuation filter" do
let(:params) { { advanced_filters: ["under_valuation"], budget_id: budget.id } }
it "returns only investment under valuation" do
investment1 = create(:budget_investment, :with_administrator, :open, :with_valuator,
budget: budget)
create(:budget_investment, :with_administrator, budget: budget)
create(:budget_investment, budget: budget)
expect(Budget::Investment.scoped_filter(params, "all")).to eq([investment1])
end
end
describe "with valuation_finished filter" do
let(:params) { { advanced_filters: ["valuation_finished"], budget_id: budget.id } }
it "returns only investment with valuation finished" do
investment1 = create(:budget_investment,
:selected,
budget: budget)
create(:budget_investment,
:with_administrator,
budget: budget)
create(:budget_investment,
budget: budget)
expect(Budget::Investment.scoped_filter(params, "all")).to eq([investment1])
end
end
describe "with winners filter" do
let(:params) { { advanced_filters: ["winners"], budget_id: budget.id } }
it "returns only investment winners" do
investment1 = create(:budget_investment, :winner, :finished, budget: budget)
create(:budget_investment, :with_administrator, budget: budget)
create(:budget_investment, budget: budget)
expect(Budget::Investment.scoped_filter(params, "all")).to eq([investment1])
end
end
end
describe "admin_and_valuator_users_associated" do
let(:investment) { create(:budget_investment) }
let(:valuator_group) { create(:valuator_group) }
let(:valuator) { create(:valuator) }
let(:administrator) { create(:administrator) }
it "returns empty array if not valuators or administrator assigned" do
expect(investment.admin_and_valuator_users_associated).to eq([])
end
it "returns all valuator and administrator users" do
valuator_group.valuators << valuator
investment.valuator_groups << valuator_group
expect(investment.admin_and_valuator_users_associated).to eq([valuator])
investment.administrator = administrator
expect(investment.admin_and_valuator_users_associated).to eq([valuator, administrator])
end
it "returns uniq valuators or administrator users" do
valuator_group.valuators << valuator
investment.valuator_groups << valuator_group
investment.valuators << valuator
investment.administrator = administrator
expect(investment.admin_and_valuator_users_associated).to eq([valuator, administrator])
end
end
describe "milestone_tags" do
context "without milestone_tags" do
let(:investment) { create(:budget_investment) }
it "do not have milestone_tags" do
expect(investment.milestone_tag_list).to eq([])
expect(investment.milestone_tags).to eq([])
end
it "add a new milestone_tag" do
investment.milestone_tag_list = "tag1,tag2"
expect(investment.milestone_tag_list).to eq(["tag1", "tag2"])
end
end
context "with milestone_tags" do
let(:investment) { create(:budget_investment, :with_milestone_tags) }
it "has milestone_tags" do
expect(investment.milestone_tag_list.count).to eq(1)
end
end
end
end