Files
nairobi/spec/models/proposal_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

1094 lines
34 KiB
Ruby

# coding: utf-8
require "rails_helper"
describe Proposal do
let(:proposal) { build(:proposal) }
describe "Concerns" do
it_behaves_like "has_public_author"
it_behaves_like "notifiable"
it_behaves_like "map validations"
it_behaves_like "globalizable", :retired_proposal
it_behaves_like "sanitizable"
it_behaves_like "acts as paranoid", :proposal
end
it "is valid" do
expect(proposal).to be_valid
end
it "is not valid without an author" do
proposal.author = nil
expect(proposal).not_to be_valid
end
it "is not valid without a summary" do
proposal.summary = nil
expect(proposal).not_to be_valid
end
describe "#title" do
it "is not valid without a title" do
proposal.title = nil
expect(proposal).not_to be_valid
end
it "is not valid when very short" do
proposal.title = "abc"
expect(proposal).not_to be_valid
end
it "is not valid when very long" do
proposal.title = "a" * 81
expect(proposal).not_to be_valid
end
end
describe "#description" do
it "is not valid when very long" do
proposal.description = "a" * 6001
expect(proposal).not_to be_valid
end
end
describe "#video_url" do
it "is not valid when URL is not from Youtube or Vimeo" do
proposal.video_url = "https://twitter.com"
expect(proposal).not_to be_valid
end
it "is valid when URL is from Youtube or Vimeo" do
proposal.video_url = "https://vimeo.com/112681885"
expect(proposal).to be_valid
end
end
describe "#responsible_name" do
it "is mandatory" do
proposal.responsible_name = nil
expect(proposal).not_to be_valid
end
it "is not valid when very short" do
proposal.responsible_name = "abc"
expect(proposal).not_to be_valid
end
it "is not valid when very long" do
proposal.responsible_name = "a" * 61
expect(proposal).not_to be_valid
end
it "is the document_number if level two user" do
author = create(:user, :level_two, document_number: "12345678Z")
proposal.author = author
proposal.responsible_name = nil
expect(proposal).to be_valid
proposal.responsible_name = "12345678Z"
end
it "is the document_number if level three user" do
author = create(:user, :level_three, document_number: "12345678Z")
proposal.author = author
proposal.responsible_name = nil
expect(proposal).to be_valid
proposal.responsible_name = "12345678Z"
end
it "is not updated when the author is deleted" do
author = create(:user, :level_three, document_number: "12345678Z")
proposal.author = author
proposal.save!
proposal.author.erase
proposal.save!
expect(proposal.responsible_name).to eq "12345678Z"
end
end
describe "tag_list" do
it "is not valid with a tag list of more than 6 elements" do
proposal.tag_list = ["Hacienda", "Economía", "Medio Ambiente", "Corrupción", "Fiestas populares", "Prensa", "Huelgas"]
expect(proposal).not_to be_valid
end
it "is valid with a tag list of up to 6 elements" do
proposal.tag_list = ["Hacienda", "Economía", "Medio Ambiente", "Corrupción", "Fiestas populares", "Prensa"]
expect(proposal).to be_valid
end
end
it "is not valid without accepting terms of service" do
proposal.terms_of_service = nil
expect(proposal).not_to be_valid
end
it "has a code" do
Setting["proposal_code_prefix"] = "TEST"
proposal = create(:proposal)
expect(proposal.code).to eq "TEST-#{proposal.created_at.strftime('%Y-%m')}-#{proposal.id}"
Setting["proposal_code_prefix"] = "MAD"
end
describe "#retired_explanation" do
it "is valid when retired timestamp is present and retired explanation is defined" do
proposal.retired_at = Time.current
proposal.retired_explanation = "Duplicated of ..."
proposal.retired_reason = "duplicated"
expect(proposal).to be_valid
end
it "is not valid when retired_at is present and retired explanation is empty" do
proposal.retired_at = Time.current
proposal.retired_explanation = nil
proposal.retired_reason = "duplicated"
expect(proposal).not_to be_valid
end
end
describe "#retired_reason" do
it "is valid when retired timestamp is present and retired reason is defined" do
proposal.retired_at = Time.current
proposal.retired_explanation = "Duplicated of ..."
proposal.retired_reason = "duplicated"
expect(proposal).to be_valid
end
it "is not valid when retired timestamp is present but defined retired reason
is not included in retired reasons" do
proposal.retired_at = Time.current
proposal.retired_explanation = "Duplicated of ..."
proposal.retired_reason = "duplicate"
expect(proposal).not_to be_valid
end
it "is not valid when retired_at is present and retired reason is empty" do
proposal.retired_at = Time.current
proposal.retired_explanation = "Duplicated of ..."
proposal.retired_reason = nil
expect(proposal).not_to be_valid
end
end
describe "#editable?" do
let(:proposal) { create(:proposal) }
before { Setting["max_votes_for_proposal_edit"] = 5 }
it "is true if proposal has no votes yet" do
expect(proposal.total_votes).to eq(0)
expect(proposal.editable?).to be true
end
it "is true if proposal has less than limit votes" do
create_list(:vote, 4, votable: proposal)
expect(proposal.total_votes).to eq(4)
expect(proposal.editable?).to be true
end
it "is false if proposal has more than limit votes" do
create_list(:vote, 6, votable: proposal)
expect(proposal.total_votes).to eq(6)
expect(proposal.editable?).to be false
end
end
describe "#votable_by?" do
let(:proposal) { create(:proposal) }
it "is true for level two verified users" do
user = create(:user, residence_verified_at: Time.current, confirmed_phone: "666333111")
expect(proposal.votable_by?(user)).to be true
end
it "is true for level three verified users" do
user = create(:user, verified_at: Time.current)
expect(proposal.votable_by?(user)).to be true
end
it "is false for anonymous users" do
user = create(:user)
expect(proposal.votable_by?(user)).to be false
end
end
describe "#register_vote" do
let(:proposal) { create(:proposal) }
describe "from level two verified users" do
it "registers vote" do
user = create(:user, residence_verified_at: Time.current, confirmed_phone: "666333111")
expect { proposal.register_vote(user, "yes") }.to change { proposal.reload.votes_for.size }.by(1)
end
end
describe "from level three verified users" do
it "registers vote" do
user = create(:user, verified_at: Time.current)
expect { proposal.register_vote(user, "yes") }.to change { proposal.reload.votes_for.size }.by(1)
end
end
describe "from anonymous users" do
it "does not register vote" do
user = create(:user)
expect { proposal.register_vote(user, "yes") }.to change { proposal.reload.votes_for.size }.by(0)
end
end
it "does not register vote for archived proposals" do
user = create(:user, verified_at: Time.current)
archived_proposal = create(:proposal, :archived)
expect { archived_proposal.register_vote(user, "yes") }.to change { proposal.reload.votes_for.size }.by(0)
end
end
describe "#cached_votes_up" do
describe "with deprecated long tag list" do
it "increases number of cached_total_votes" do
proposal = create(:proposal)
tag_list = ["tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7"]
proposal.update_attribute(:tag_list, tag_list)
expect(proposal.update_cached_votes).to eq(true)
end
end
end
describe "#hot_score" do
let(:now) { Time.current }
it "period is correctly calculated to get exact votes per day" do
new_proposal = create(:proposal, created_at: 23.hours.ago)
2.times { new_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(new_proposal.hot_score).to be 2
old_proposal = create(:proposal, created_at: 25.hours.ago)
2.times { old_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
older_proposal = create(:proposal, created_at: 49.hours.ago)
3.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
end
it "remains the same for not voted proposals" do
new = create(:proposal, created_at: now)
old = create(:proposal, created_at: 1.day.ago)
older = create(:proposal, created_at: 2.months.ago)
expect(new.hot_score).to be 0
expect(old.hot_score).to be 0
expect(older.hot_score).to be 0
end
it "increases for proposals with more positive votes" do
more_positive_votes = create(:proposal)
2.times { more_positive_votes.vote_by(voter: create(:user), vote: "yes") }
less_positive_votes = create(:proposal)
less_positive_votes.vote_by(voter: create(:user), vote: "yes")
expect(more_positive_votes.hot_score).to be > less_positive_votes.hot_score
end
it "increases for proposals with the same amount of positive votes within less days" do
newer_proposal = create(:proposal, created_at: now)
5.times { newer_proposal.vote_by(voter: create(:user), vote: "yes") }
older_proposal = create(:proposal, created_at: 2.days.ago)
5.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
it "increases for proposals voted within the period (last month by default)" do
newer_proposal = create(:proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: newer_proposal, created_at: 3.days.ago) }
older_proposal = create(:proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: older_proposal, created_at: 40.days.ago) }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
describe "actions which affect it" do
let(:proposal) { create(:proposal) }
before do
5.times { proposal.vote_by(voter: create(:user), vote: "yes") }
2.times { proposal.vote_by(voter: create(:user), vote: "no") }
end
it "increases with positive votes" do
previous = proposal.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "yes") }
expect(previous).to be < proposal.hot_score
end
it "decreases with negative votes" do
previous = proposal.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "no") }
expect(previous).to be > proposal.hot_score
end
end
end
describe "custom tag counters when hiding/restoring" do
it "decreases the tag counter when hiden, and increases it when restored" do
proposal = create(:proposal, tag_list: "foo")
tag = Tag.where(name: "foo").first
expect(tag.proposals_count).to eq(1)
proposal.hide
expect(tag.reload.proposals_count).to eq(0)
proposal.restore
expect(tag.reload.proposals_count).to eq(1)
end
end
describe "#confidence_score" do
it "takes into account votes" do
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 100)
expect(proposal.confidence_score).to eq(10000)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 0)
expect(proposal.confidence_score).to eq(1)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 75)
expect(proposal.confidence_score).to eq(7500)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 750)
expect(proposal.confidence_score).to eq(75000)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 10)
expect(proposal.confidence_score).to eq(1000)
end
describe "actions which affect it" do
let(:proposal) { create(:proposal, :with_confidence_score) }
it "increases with like" do
previous = proposal.confidence_score
5.times { proposal.register_vote(create(:user, verified_at: Time.current), true) }
expect(previous).to be < proposal.confidence_score
end
end
end
describe "cache" do
let(:proposal) { create(:proposal) }
it "expires cache when it has a new comment" do
expect { create(:comment, commentable: proposal) }
.to change { proposal.updated_at }
end
it "expires cache when it has a new vote" do
expect { create(:vote, votable: proposal) }
.to change { proposal.updated_at }
end
it "expires cache when it has a new flag" do
expect { create(:flag, flaggable: proposal) }
.to change { proposal.reload.updated_at }
end
it "expires cache when it has a new tag" do
expect { proposal.update(tag_list: "new tag") }
.to change { proposal.updated_at }
end
it "expires cache when hidden" do
expect { proposal.hide }
.to change { proposal.updated_at }
end
it "expires cache when the author is hidden" do
expect { proposal.author.hide }
.to change { [proposal.reload.updated_at, proposal.author.updated_at] }
end
it "expires cache when the author is erased" do
expect { proposal.author.erase }
.to change { [proposal.reload.updated_at, proposal.author.updated_at] }
end
it "expires cache when its author changes" do
expect { proposal.author.update(username: "Eva") }
.to change { [proposal.reload.updated_at, proposal.author.updated_at] }
end
it "expires cache when the author's organization get verified" do
create(:organization, user: proposal.author)
expect { proposal.author.organization.verify }
.to change { [proposal.reload.updated_at, proposal.author.updated_at] }
end
end
describe "voters" do
it "returns users that have voted for the proposal" do
proposal = create(:proposal)
voter1 = create(:user, :level_two, votables: [proposal])
voter2 = create(:user, :level_two, votables: [proposal])
voter3 = create(:user, :level_two)
expect(proposal.voters).to match_array [voter1, voter2]
expect(proposal.voters).not_to include(voter3)
end
it "does not return users that have been erased" do
proposal = create(:proposal)
voter1 = create(:user, :level_two, votables: [proposal])
voter2 = create(:user, :level_two, votables: [proposal])
voter2.erase
expect(proposal.voters).to eq [voter1]
end
it "does not return users that have been blocked" do
proposal = create(:proposal)
voter1 = create(:user, :level_two, votables: [proposal])
voter2 = create(:user, :level_two, votables: [proposal])
voter2.block
expect(proposal.voters).to eq [voter1]
end
end
describe "search" do
context "attributes" do
let(:attributes) do
{ title: "save the world",
summary: "basically",
description: "in order to save the world one must think about...",
title_es: "para salvar el mundo uno debe pensar en...",
summary_es: "basicamente",
description_es: "uno debe pensar" }
end
it "searches by title" do
proposal = create(:proposal, attributes)
results = Proposal.search("save the world")
expect(results).to eq([proposal])
end
it "searches by title across all languages translations" do
proposal = create(:proposal, attributes)
results = Proposal.search("salvar el mundo")
expect(results).to eq([proposal])
end
it "searches by summary" do
proposal = create(:proposal, attributes)
results = Proposal.search("basically")
expect(results).to eq([proposal])
end
it "searches by summary across all languages translations" do
proposal = create(:proposal, attributes)
results = Proposal.search("basicamente")
expect(results).to eq([proposal])
end
it "searches by description" do
proposal = create(:proposal, attributes)
results = Proposal.search("one must think")
expect(results).to eq([proposal])
end
it "searches by description across all languages translations" do
proposal = create(:proposal, attributes)
results = Proposal.search("uno debe pensar")
expect(results).to eq([proposal])
end
it "searches by author name" do
author = create(:user, username: "Danny Trejo")
proposal = create(:proposal, author: author)
results = Proposal.search("Danny")
expect(results).to eq([proposal])
end
it "searches by geozone" do
geozone = create(:geozone, name: "California")
proposal = create(:proposal, geozone: geozone)
results = Proposal.search("California")
expect(results).to eq([proposal])
end
end
context "stemming" do
it "searches word stems" do
proposal = create(:proposal, summary: "Economía")
results = Proposal.search("economía")
expect(results).to eq([proposal])
results = Proposal.search("econo")
expect(results).to eq([proposal])
results = Proposal.search("eco")
expect(results).to eq([proposal])
end
end
context "accents" do
it "searches with accents" do
proposal = create(:proposal, summary: "difusión")
results = Proposal.search("difusion")
expect(results).to eq([proposal])
proposal2 = create(:proposal, summary: "estadisticas")
results = Proposal.search("estadísticas")
expect(results).to eq([proposal2])
proposal3 = create(:proposal, summary: "público")
results = Proposal.search("publico")
expect(results).to eq([proposal3])
end
end
context "case" do
it "searches case insensite" do
proposal = create(:proposal, title: "SHOUT")
results = Proposal.search("shout")
expect(results).to eq([proposal])
proposal2 = create(:proposal, title: "scream")
results = Proposal.search("SCREAM")
expect(results).to eq([proposal2])
end
end
context "tags" do
it "searches by tags" do
proposal = create(:proposal, tag_list: "Latina")
results = Proposal.search("Latina")
expect(results.first).to eq(proposal)
results = Proposal.search("Latin")
expect(results.first).to eq(proposal)
end
end
context "order" do
it "orders by weight" do
proposal_title = create(:proposal, title: "stop corruption")
proposal_description = create(:proposal, description: "stop corruption")
proposal_summary = create(:proposal, summary: "stop corruption")
results = Proposal.search("stop corruption")
expect(results).to eq [proposal_title, proposal_summary, proposal_description]
end
it "orders by weight and then by votes" do
title_some_votes = create(:proposal, title: "stop corruption", cached_votes_up: 5)
title_least_voted = create(:proposal, title: "stop corruption", cached_votes_up: 2)
title_most_voted = create(:proposal, title: "stop corruption", cached_votes_up: 10)
summary_most_voted = create(:proposal, summary: "stop corruption", cached_votes_up: 10)
results = Proposal.search("stop corruption")
expect(results).to eq [title_most_voted, title_some_votes, title_least_voted, summary_most_voted]
end
it "gives much more weight to word matches than votes" do
exact_title_few_votes = create(:proposal, title: "stop corruption", cached_votes_up: 5)
similar_title_many_votes = create(:proposal, title: "stop some of the corruption", cached_votes_up: 500)
results = Proposal.search("stop corruption")
expect(results).to eq [exact_title_few_votes, similar_title_many_votes]
end
end
context "reorder" do
it "is able to reorder by hot_score after searching" do
lowest_score = create(:proposal, title: "stop corruption", cached_votes_up: 1)
highest_score = create(:proposal, title: "stop corruption", cached_votes_up: 2)
average_score = create(:proposal, title: "stop corruption", cached_votes_up: 3)
lowest_score.update_column(:hot_score, 1)
highest_score.update_column(:hot_score, 100)
average_score.update_column(:hot_score, 10)
results = Proposal.search("stop corruption")
expect(results).to eq [average_score, highest_score, lowest_score]
results = results.sort_by_hot_score
expect(results).to eq [highest_score, average_score, lowest_score]
end
it "is able to reorder by confidence_score after searching" do
lowest_score = create(:proposal, title: "stop corruption", cached_votes_up: 1)
highest_score = create(:proposal, title: "stop corruption", cached_votes_up: 2)
average_score = create(:proposal, title: "stop corruption", cached_votes_up: 3)
lowest_score.update_column(:confidence_score, 1)
highest_score.update_column(:confidence_score, 100)
average_score.update_column(:confidence_score, 10)
results = Proposal.search("stop corruption")
expect(results).to eq [average_score, highest_score, lowest_score]
results = results.sort_by_confidence_score
expect(results).to eq [highest_score, average_score, lowest_score]
end
it "is able to reorder by created_at after searching" do
recent = create(:proposal, title: "stop corruption", cached_votes_up: 1, created_at: 1.week.ago)
newest = create(:proposal, title: "stop corruption", cached_votes_up: 2, created_at: Time.current)
oldest = create(:proposal, title: "stop corruption", cached_votes_up: 3, created_at: 1.month.ago)
results = Proposal.search("stop corruption")
expect(results).to eq [oldest, newest, recent]
results = results.sort_by_created_at
expect(results).to eq [newest, recent, oldest]
end
it "is able to reorder by most commented after searching" do
least_commented = create(:proposal, title: "stop corruption", cached_votes_up: 1, comments_count: 1)
most_commented = create(:proposal, title: "stop corruption", cached_votes_up: 2, comments_count: 100)
some_comments = create(:proposal, title: "stop corruption", cached_votes_up: 3, comments_count: 10)
results = Proposal.search("stop corruption")
expect(results).to eq [some_comments, most_commented, least_commented]
results = results.sort_by_most_commented
expect(results).to eq [most_commented, some_comments, least_commented]
end
end
context "no results" do
it "no words match" do
create(:proposal, title: "save world")
results = Proposal.search("destroy planet")
expect(results).to eq([])
end
it "too many typos" do
create(:proposal, title: "fantastic")
results = Proposal.search("frantac")
expect(results).to eq([])
end
it "too much stemming" do
create(:proposal, title: "reloj")
results = Proposal.search("superrelojimetro")
expect(results).to eq([])
end
it "empty" do
create(:proposal, title: "great")
results = Proposal.search("")
expect(results).to eq([])
end
end
end
describe "#last_week" do
it "returns proposals created this week" do
proposal = create(:proposal)
expect(Proposal.last_week).to eq [proposal]
end
it "does not return proposals created more than a week ago" do
create(:proposal, created_at: 8.days.ago)
expect(Proposal.last_week).to be_empty
end
end
describe "for_summary" do
context "categories" do
it "returns proposals tagged with a category" do
create(:tag, :category, name: "culture")
proposal = create(:proposal, tag_list: "culture")
expect(Proposal.for_summary.values.flatten).to eq [proposal]
end
it "does not return proposals tagged without a category" do
create(:tag, :category, name: "culture")
create(:proposal, tag_list: "parks")
expect(Proposal.for_summary.values.flatten).to be_empty
end
end
context "districts" do
it "returns proposals with a geozone" do
california = create(:geozone, name: "california")
proposal = create(:proposal, geozone: california)
expect(Proposal.for_summary.values.flatten).to eq [proposal]
end
it "does not return proposals without a geozone" do
create(:geozone, name: "california")
create(:proposal)
expect(Proposal.for_summary.values.flatten).to be_empty
end
end
it "returns proposals created this week" do
create(:tag, :category, name: "culture")
proposal = create(:proposal, tag_list: "culture")
expect(Proposal.for_summary.values.flatten).to eq [proposal]
end
it "does not return proposals created more than a week ago" do
create(:tag, :category, name: "culture")
create(:proposal, tag_list: "culture", created_at: 8.days.ago)
expect(Proposal.for_summary.values.flatten).to be_empty
end
it "orders proposals by votes" do
create(:tag, :category, name: "culture")
create(:proposal, tag_list: "culture").update_column(:confidence_score, 2)
create(:proposal, tag_list: "culture").update_column(:confidence_score, 10)
create(:proposal, tag_list: "culture").update_column(:confidence_score, 5)
results = Proposal.for_summary.values.flatten
expect(results.map(&:confidence_score)).to eq [10, 5, 2]
end
it "orders groups alphabetically" do
create(:tag, :category, name: "health")
create(:tag, :category, name: "culture")
create(:tag, :category, name: "social services")
health_proposal = create(:proposal, tag_list: "health")
culture_proposal = create(:proposal, tag_list: "culture")
social_proposal = create(:proposal, tag_list: "social services")
results = Proposal.for_summary.values.flatten
expect(results).to eq [culture_proposal, health_proposal, social_proposal]
end
it "returns proposals grouped by tag" do
create(:tag, :category, name: "culture")
create(:tag, :category, name: "health")
proposal1 = create(:proposal, tag_list: "culture")
proposal2 = create(:proposal, tag_list: "culture")
proposal2.update_column(:confidence_score, 100)
proposal3 = create(:proposal, tag_list: "health")
proposal1.update_column(:confidence_score, 10)
proposal2.update_column(:confidence_score, 9)
expect(Proposal.for_summary).to include("culture" => [proposal1, proposal2], "health" => [proposal3])
end
end
describe "#to_param" do
it "returns a friendly url" do
expect(proposal.to_param).to eq "#{proposal.id} #{proposal.title}".parameterize
end
end
describe "retired" do
let!(:proposal1) { create(:proposal) }
let!(:proposal2) { create(:proposal, :retired) }
it "retired? is true" do
expect(proposal1.retired?).to eq false
expect(proposal2.retired?).to eq true
end
it "scope retired" do
expect(Proposal.retired).to eq [proposal2]
end
it "scope not_retired" do
expect(Proposal.not_retired).to eq [proposal1]
end
end
describe "archived" do
let!(:new_proposal) { create(:proposal) }
let!(:archived_proposal) { create(:proposal, :archived) }
it "archived? is true only for proposals created more than n (configured months) ago" do
expect(new_proposal.archived?).to eq false
expect(archived_proposal.archived?).to eq true
end
it "scope archived" do
expect(Proposal.archived).to eq [archived_proposal]
end
it "scope not archived" do
expect(Proposal.not_archived).to eq [new_proposal]
end
end
describe "selected" do
let!(:not_selected_proposal) { create(:proposal) }
let!(:selected_proposal) { create(:proposal, :selected) }
it "selected? is true" do
expect(not_selected_proposal.selected?).to be false
expect(selected_proposal.selected?).to be true
end
it "scope selected" do
expect(Proposal.selected).to eq [selected_proposal]
end
it "scope not_selected" do
expect(Proposal.not_selected).to eq [not_selected_proposal]
end
end
describe "public_for_api scope" do
it "returns proposals" do
proposal = create(:proposal)
expect(Proposal.public_for_api).to eq [proposal]
end
it "does not return hidden proposals" do
create(:proposal, :hidden)
expect(Proposal.public_for_api).to be_empty
end
end
describe "#user_to_notify" do
it "returns voters and followers" do
proposal = create(:proposal)
voter = create(:user, :level_two, votables: [proposal])
follower = create(:user, :level_two, followables: [proposal])
expect(proposal.users_to_notify).to eq([voter, follower])
end
it "returns voters and followers discarding duplicates" do
proposal = create(:proposal)
voter_and_follower = create(:user, :level_two, votables: [proposal], followables: [proposal])
expect(proposal.users_to_notify).to eq([voter_and_follower])
end
it "returns voters and followers except the proposal author" do
author = create(:user, :level_two)
voter_and_follower = create(:user, :level_two)
proposal = create(:proposal, author: author,
voters: [author, voter_and_follower],
followers: [author, voter_and_follower])
expect(proposal.users_to_notify).to eq([voter_and_follower])
end
end
describe "#recommendations" do
let(:user) { create(:user) }
it "does not return any proposals when user has not interests" do
create(:proposal)
expect(Proposal.recommendations(user)).to be_empty
end
it "returns proposals related to the user's interests ordered by cached_votes_up" do
create(:proposal, tag_list: "Sport", followers: [user])
proposal1 = create(:proposal, cached_votes_up: 1, tag_list: "Sport")
proposal2 = create(:proposal, cached_votes_up: 5, tag_list: "Sport")
proposal3 = create(:proposal, cached_votes_up: 10, tag_list: "Sport")
results = Proposal.recommendations(user).sort_by_recommendations
expect(results).to eq [proposal3, proposal2, proposal1]
end
it "does not return proposals unrelated to user interests" do
create(:proposal, tag_list: "Sport", followers: [user])
create(:proposal, tag_list: "Politics")
results = Proposal.recommendations(user)
expect(results).to be_empty
end
it "does not return proposals when user is follower" do
create(:proposal, tag_list: "Sport", followers: [user])
results = Proposal.recommendations(user)
expect(results).to be_empty
end
it "does not return proposals when user is the author" do
create(:proposal, tag_list: "Sport", followers: [user])
create(:proposal, author: user, tag_list: "Sport")
results = Proposal.recommendations(user)
expect(results).to be_empty
end
it "does not return archived proposals" do
create(:proposal, tag_list: "Sport", followers: [user])
create(:proposal, :archived, tag_list: "Sport")
results = Proposal.recommendations(user)
expect(results).to be_empty
end
it "does not return already supported proposals" do
create(:proposal, tag_list: "Health", followers: [user])
create(:proposal, tag_list: "Health", voters: [user])
results = Proposal.recommendations(user)
expect(results).to be_empty
end
end
describe "#send_new_actions_notification_on_create" do
before do
Setting["dashboard.emails"] = true
ActionMailer::Base.deliveries.clear
end
it "send notification after create when there are new actived actions" do
create(:dashboard_action, :proposed_action, :active, day_offset: 0, published_proposal: false)
create(:dashboard_action, :resource, :active, day_offset: 0, published_proposal: false)
create(:proposal, :draft)
expect(ActionMailer::Base.deliveries.count).to eq(1)
end
it "Not send notification after create when there are not new actived actions" do
create(:dashboard_action, :proposed_action, :active, day_offset: 1, published_proposal: false)
create(:dashboard_action, :resource, :active, day_offset: 1, published_proposal: false)
create(:proposal, :draft)
expect(ActionMailer::Base.deliveries.count).to eq(0)
end
end
describe "#send_new_actions_notification_on_published" do
before do
Setting["dashboard.emails"] = true
ActionMailer::Base.deliveries.clear
end
it "send notification after published when there are new actived actions" do
create(:dashboard_action, :proposed_action, :active, day_offset: 0, published_proposal: true)
create(:dashboard_action, :resource, :active, day_offset: 0, published_proposal: true)
proposal = create(:proposal, :draft)
proposal.publish
expect(ActionMailer::Base.deliveries.count).to eq(1)
end
it "Not send notification after published when there are not new actived actions" do
create(:dashboard_action, :proposed_action, :active, day_offset: 1, published_proposal: true)
create(:dashboard_action, :resource, :active, day_offset: 1, published_proposal: true)
proposal = create(:proposal, :draft)
proposal.publish
expect(ActionMailer::Base.deliveries.count).to eq(0)
end
end
describe "milestone_tags" do
context "without milestone_tags" do
let(:proposal) { create(:proposal) }
it "do not have milestone_tags" do
expect(proposal.milestone_tag_list).to eq([])
expect(proposal.milestone_tags).to eq([])
end
it "add a new milestone_tag" do
proposal.milestone_tag_list = "tag1,tag2"
expect(proposal.milestone_tag_list).to eq(["tag1", "tag2"])
end
end
context "with milestone_tags" do
let(:proposal) { create(:proposal, :with_milestone_tags) }
it "has milestone_tags" do
expect(proposal.milestone_tag_list.count).to eq(1)
end
end
end
end