spec/system/budgets/ballots_spec.rb
require "rails_helper"
require "sessions_helper"
describe "Ballots" do
let(:user) { create(:user, :level_two) }
let!(:budget) { create(:budget, :balloting) }
let!(:states) { create(:budget_group, budget: budget, name: "States") }
let!(:california) { create(:budget_heading, group: states, name: "California", price: 1000) }
let!(:new_york) { create(:budget_heading, group: states, name: "New York", price: 1000000) }
context "Load" do
let(:user) do
create(:user, :level_two, ballot_lines: [create(:budget_investment, :selected, heading: california)])
end
before do
budget.update!(slug: "budget_slug")
login_as(user)
end
scenario "finds ballot using budget slug" do
visit budget_ballot_path("budget_slug")
expect(page).to have_content("You have voted one investment")
end
end
context "Lines Load" do
before do
create(:budget_investment, :selected, heading: california, title: "More rain")
budget.update!(slug: "budget_slug")
login_as(user)
end
scenario "finds ballot lines using budget slug" do
visit budget_investments_path("budget_slug", states, california)
add_to_ballot("More rain")
within("#sidebar") { expect(page).to have_content "More rain" }
end
end
context "Voting" do
before { login_as(user) }
let!(:city) { create(:budget_group, budget: budget, name: "City") }
let!(:districts) { create(:budget_group, budget: budget, name: "Districts") }
context "Group and Heading Navigation" do
scenario "Headings" do
create(:budget_heading, group: city, name: "Investments Type1")
create(:budget_heading, group: city, name: "Investments Type2")
create(:budget_heading, group: districts, name: "District 1")
create(:budget_heading, group: districts, name: "District 2")
visit budget_path(budget)
within("#groups_and_headings") do
expect(page).to have_link "Investments Type1"
expect(page).to have_link "Investments Type2"
expect(page).to have_link "District 1"
expect(page).to have_link "District 2"
end
end
scenario "Investments" do
create(:budget_heading, group: city, name: "Under the city")
create(:budget_heading, group: city, name: "Above the city") do |heading|
create(:budget_investment, :selected, heading: heading, title: "Solar panels")
create(:budget_investment, :selected, heading: heading, title: "Observatory")
end
create(:budget_heading, group: districts, name: "District 1") do |heading|
create(:budget_investment, :selected, heading: heading, title: "New park")
create(:budget_investment, :selected, heading: heading, title: "Zero-emission zone")
end
create(:budget_heading, group: districts, name: "District 2") do |heading|
create(:budget_investment, :selected, heading: heading, title: "Climbing wall")
end
visit budget_path(budget)
click_link "Above the city"
expect(page).to have_css(".budget-investment", count: 2)
expect(page).to have_content "Solar panels"
expect(page).to have_content "Observatory"
visit budget_path(budget)
click_link "District 1"
expect(page).to have_css(".budget-investment", count: 2)
expect(page).to have_content "New park"
expect(page).to have_content "Zero-emission zone"
visit budget_path(budget)
click_link "District 2"
expect(page).to have_css(".budget-investment", count: 1)
expect(page).to have_content "Climbing wall"
end
end
context "Adding and Removing Investments" do
scenario "Add a investment" do
create(:budget_investment, :selected, heading: new_york, price: 10000, title: "Bring back King Kong")
create(:budget_investment, :selected, heading: new_york, price: 20000, title: "Paint cabs black")
visit budget_investments_path(budget, heading_id: new_york)
add_to_ballot("Bring back King Kong")
expect(page).to have_css("#total_amount", text: "€10,000")
expect(page).to have_css("#amount_available", text: "€990,000")
within("#sidebar") do
expect(page).to have_content "Bring back King Kong"
expect(page).to have_content "€10,000"
expect(page).to have_link "Check my votes"
end
add_to_ballot("Paint cabs black")
expect(page).to have_css("#total_amount", text: "€30,000")
expect(page).to have_css("#amount_available", text: "€970,000")
within("#sidebar") do
expect(page).to have_content "Paint cabs black"
expect(page).to have_content "€20,000"
expect(page).to have_link "Check my votes"
end
end
scenario "Removing a investment" do
investment = create(:budget_investment, :selected, heading: new_york, price: 10000, balloters: [user])
visit budget_investments_path(budget, heading_id: new_york)
expect(page).to have_content investment.title
expect(page).to have_css("#total_amount", text: "€10,000")
expect(page).to have_css("#amount_available", text: "€990,000")
within("#sidebar") do
expect(page).to have_content investment.title
expect(page).to have_content "€10,000"
expect(page).to have_link "Check my votes"
end
within("#budget_investment_#{investment.id}") do
click_button "Remove vote"
end
expect(page).to have_css("#total_amount", text: "€0")
expect(page).to have_css("#amount_available", text: "€1,000,000")
within("#sidebar") do
expect(page).not_to have_content investment.title
expect(page).not_to have_content "€10,000"
expect(page).to have_link "Check my votes"
end
end
scenario "map and content block shoud be visible before and after" do
stub_const("#{Budgets::InvestmentsController}::PER_PAGE", 1)
create(
:budget_investment, :selected, :with_map_location,
heading: new_york,
price: 10000,
title: "More bridges",
)
create(
:budget_investment, :selected, :with_map_location,
heading: new_york,
price: 5000,
title: "Less bridges"
)
create(:heading_content_block, heading: new_york, body: "<li>New Block</li>")
new_york.update!(allow_custom_content: true)
visit budget_investments_path(budget, heading_id: new_york, order: :price)
within("#sidebar") do
expect(page).to have_content "OpenStreetMap"
expect(page).to have_content "New Block"
expect(page).to have_css ".map-icon", visible: :all, count: 2
end
add_to_ballot("More bridges")
within("#sidebar") do
expect(page).to have_content "More bridges"
expect(page).to have_content "OpenStreetMap"
expect(page).to have_content "New Block"
expect(page).to have_css ".map-icon", visible: :all, count: 2
end
within(".budget-investment", text: "More bridges") do
click_button "Remove vote"
end
within("#sidebar") do
expect(page).not_to have_content "More bridges"
expect(page).to have_content "OpenStreetMap"
expect(page).to have_content "New Block"
expect(page).to have_css ".map-icon", visible: :all, count: 2
end
end
end
#Break up or simplify with helpers
context "Balloting in multiple headings" do
scenario "Independent progress bar for headings" do
city_heading = create(:budget_heading, group: city, name: "All city", price: 10000000)
district_heading1 = create(:budget_heading, group: districts, name: "District 1", price: 1000000)
district_heading2 = create(:budget_heading, group: districts, name: "District 2", price: 2000000)
create(:budget_investment, :selected, heading: city_heading, price: 10000, title: "Cheap")
create(:budget_investment, :selected, heading: district_heading1, price: 20000, title: "Average")
create(:budget_investment, :selected, heading: district_heading2, price: 30000, title: "Expensive")
visit budget_investments_path(budget, heading_id: city_heading)
add_to_ballot("Cheap")
expect(page).to have_css("#total_amount", text: "€10,000")
expect(page).to have_css("#amount_available", text: "€9,990,000")
within("#sidebar") do
expect(page).to have_content "Cheap"
expect(page).to have_content "€10,000"
end
visit budget_investments_path(budget, heading_id: district_heading1)
expect(page).to have_css("#total_amount", text: "€0")
expect(page).to have_css("#amount_available", text: "€1,000,000")
add_to_ballot("Average")
expect(page).to have_css("#total_amount", text: "€20,000")
expect(page).to have_css("#amount_available", text: "€980,000")
within("#sidebar") do
expect(page).to have_content "Average"
expect(page).to have_content "€20,000"
expect(page).not_to have_content "Cheap"
expect(page).not_to have_content "€10,000"
end
visit budget_investments_path(budget, heading_id: city_heading)
expect(page).to have_css("#total_amount", text: "€10,000")
expect(page).to have_css("#amount_available", text: "€9,990,000")
within("#sidebar") do
expect(page).to have_content "Cheap"
expect(page).to have_content "€10,000"
expect(page).not_to have_content "Average"
expect(page).not_to have_content "€20,000"
end
visit budget_investments_path(budget, heading_id: district_heading2)
expect(page).to have_content("You have active votes in another heading: District 1")
end
end
scenario "Display progress bar after first vote" do
create(:budget_investment, :selected, heading: new_york, price: 10000, title: "Park expansion")
visit budget_investments_path(budget, heading_id: new_york.id)
add_to_ballot("Park expansion")
within("#progress_bar") do
expect(page).to have_css("#total_amount", text: "€10,000")
end
end
end
context "Groups" do
before { login_as(user) }
scenario "Select my heading" do
create(:budget_investment, :selected, heading: california, title: "Green beach")
visit budget_investments_path(budget, heading_id: california)
add_to_ballot("Green beach")
visit budget_group_path(budget, states)
expect(page).to have_content "California"
expect(page).to have_css("#budget_heading_#{california.id}.is-active")
end
scenario "Change my heading" do
create(:budget_investment, :selected, heading: california, title: "Early ShakeAlert", balloters: [user])
create(:budget_investment, :selected, heading: new_york, title: "Avengers Tower")
visit budget_investments_path(budget, heading_id: california.id)
within(".budget-investment", text: "Early ShakeAlert") do
click_button "Remove vote"
expect(page).to have_button "Vote"
end
visit budget_investments_path(budget, heading_id: new_york.id)
add_to_ballot("Avengers Tower")
visit budget_group_path(budget, states)
expect(page).to have_css("#budget_heading_#{new_york.id}.is-active")
expect(page).not_to have_css("#budget_heading_#{california.id}.is-active")
end
scenario "View another heading" do
create(:budget_investment, :selected, heading: california, balloters: [user])
visit budget_investments_path(budget, heading_id: new_york.id)
expect(page).not_to have_css "#progressbar"
expect(page).to have_content "You have active votes in another heading: California"
expect(page).to have_link california.name,
href: budget_investments_path(budget, heading_id: california.id)
end
end
context "Showing the ballot" do
scenario "Displaying the correct group, heading, count & amount" do
group1 = create(:budget_group, budget: budget)
group2 = create(:budget_group, budget: budget)
create(:budget_heading, name: "District A", group: group1, price: 100)
heading1 = create(:budget_heading, name: "District 1", group: group1, price: 100)
heading2 = create(:budget_heading, name: "District 2", group: group2, price: 50)
create(:budget_heading, name: "District Z", group: group1, price: 100)
investment1 = create(:budget_investment, :selected, price: 10, heading: heading1)
investment2 = create(:budget_investment, :selected, price: 10, heading: heading1)
investment3 = create(:budget_investment, :selected, price: 5, heading: heading2)
investment4 = create(:budget_investment, :selected, price: 5, heading: heading2)
investment5 = create(:budget_investment, :selected, price: 5, heading: heading2)
user = create(:user, :level_two,
ballot_lines: [investment1, investment2, investment3, investment4, investment5])
login_as(user)
visit budget_ballot_path(budget)
expect(page).to have_content("You have voted 5 investments")
within("#budget_group_#{group1.id}") do
expect(page).to have_content "#{group1.name} - #{heading1.name}"
expect(page).to have_content "Amount spent €20"
expect(page).to have_link "Still available to you €80", href: budget_group_path(budget, group1)
end
within("#budget_group_#{group2.id}") do
expect(page).to have_content "#{group2.name} - #{heading2.name}"
expect(page).to have_content "Amount spent €15"
expect(page).to have_content "Still available to you €35"
end
end
end
scenario "Removing investments from ballot" do
investment = create(:budget_investment, :selected, price: 10, heading: new_york)
user = create(:user, :level_two, ballot_lines: [investment])
login_as(user)
visit budget_ballot_path(budget)
expect(page).to have_content("You have voted one investment")
within("#budget_investment_#{investment.id}") do
click_link "Remove vote"
end
expect(page).to have_current_path(budget_ballot_path(budget))
expect(page).to have_content("You have voted 0 investments")
end
scenario "Removing investments from ballot (sidebar)" do
investment1 = create(:budget_investment, :selected, price: 10000, heading: new_york)
investment2 = create(:budget_investment, :selected, price: 20000, heading: new_york)
user = create(:user, :level_two, ballot_lines: [investment1, investment2])
login_as(user)
visit budget_investments_path(budget, heading_id: new_york.id)
expect(page).to have_css("#total_amount", text: "€30,000")
expect(page).to have_css("#amount_available", text: "€970,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
end
within("#sidebar #budget_investment_#{investment1.id}_sidebar") do
click_link "Remove vote"
end
expect(page).to have_css("#total_amount", text: "€20,000")
expect(page).to have_css("#amount_available", text: "€980,000")
within("#sidebar") do
expect(page).not_to have_content investment1.title
expect(page).not_to have_content "€10,000"
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
end
end
describe "Back link" do
scenario "after adding and removing an investment from the ballot" do
create(:budget_investment, :selected, heading: new_york, price: 10, title: "Sully monument")
login_as(user)
visit budget_investments_path(budget, heading_id: new_york.id)
add_to_ballot("Sully monument")
within(".budget-heading") do
click_link "Check my votes"
end
expect(page).to have_content("You have voted one investment")
within(".ballot-list li", text: "Sully monument") do
click_link "Remove vote"
end
expect(page).to have_content("You have voted 0 investments")
click_link "Go back"
expect(page).to have_current_path(budget_investments_path(budget, heading_id: new_york.id))
expect(page).to have_link "Check my votes"
end
scenario "before adding any investments" do
login_as(user)
visit budget_investments_path(budget, heading_id: new_york.id)
within(".budget-heading") do
click_link "Check my votes"
end
expect(page).to have_content("You have voted 0 investments")
click_link "Go back"
expect(page).to have_current_path(budget_investments_path(budget, heading_id: new_york.id))
expect(page).to have_link "Check my votes"
end
end
context "Permissions" do
scenario "User not logged in" do
investment = create(:budget_investment, :selected, heading: new_york)
visit budget_investments_path(budget, heading_id: new_york.id)
within("#budget_investment_#{investment.id}") do
click_button "Vote"
expect(page).to have_content "You must sign in or sign up to continue."
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "User not verified" do
unverified_user = create(:user)
investment = create(:budget_investment, :selected, heading: new_york)
login_as(unverified_user)
visit budget_investments_path(budget, heading_id: new_york.id)
within("#budget_investment_#{investment.id}") do
click_button "Vote"
expect(page).to have_content "Only verified users can vote on investments"
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "User is organization" do
org = create(:organization)
investment = create(:budget_investment, :selected, heading: new_york)
login_as(org.user)
visit budget_investments_path(budget, heading_id: new_york.id)
within("#budget_investment_#{investment.id}") do
click_button "Vote"
expect(page).to have_content "Organization"
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "Unselected investments" do
investment = create(:budget_investment, heading: new_york, title: "WTF asdfasfd")
login_as(user)
visit budget_investments_path(budget, heading_id: new_york)
expect(page).not_to have_css("#budget_investment_#{investment.id}")
end
scenario "Investments with feasibility undecided are not shown" do
investment = create(:budget_investment, :undecided, heading: new_york)
login_as(user)
visit budget_investments_path(budget, heading_id: new_york)
within("#budget-investments") do
expect(page).not_to have_css("div.ballot")
expect(page).not_to have_css("#budget_investment_#{investment.id}")
end
end
scenario "Different district" do
bi1 = create(:budget_investment, :selected, heading: california)
bi2 = create(:budget_investment, :selected, heading: new_york)
user = create(:user, :level_two, ballot_lines: [bi1])
login_as(user)
visit budget_investments_path(budget, heading: new_york)
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).to have_content("already voted a different heading")
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "Insufficient funds (on page load)" do
bi1 = create(:budget_investment, :selected, heading: california, price: 600)
bi2 = create(:budget_investment, :selected, heading: california, price: 500)
user = create(:user, :level_two, ballot_lines: [bi1])
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).to have_content("You have already assigned the available budget")
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "Insufficient funds (added after create)" do
create(:budget_investment, :selected, heading: california, price: 600, title: "Build replicants")
create(:budget_investment, :selected, heading: california, price: 500, title: "Build terminators")
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
add_to_ballot("Build replicants")
within(".budget-investment", text: "Build terminators") do
click_button "Vote"
expect(page).to have_content("You have already assigned the available budget")
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "Insufficient funds (removed after destroy)" do
bi1 = create(:budget_investment, :selected, heading: california, price: 600)
bi2 = create(:budget_investment, :selected, heading: california, price: 500)
user = create(:user, :level_two, ballot_lines: [bi1])
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).to have_content("You have already assigned the available budget")
expect(page).not_to have_button "Vote", disabled: :all
expect(page).not_to have_button "Remove vote"
end
within("#budget_investment_#{bi1.id}") do
click_button "Remove vote"
expect(page).to have_button "Vote"
end
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).not_to have_content("You have already assigned the available budget")
expect(page).to have_button "Remove vote"
end
end
scenario "Insufficient funds (removed after destroying from sidebar)" do
bi1 = create(:budget_investment, :selected, heading: california, price: 600)
bi2 = create(:budget_investment, :selected, heading: california, price: 500)
user = create(:user, :level_two, ballot_lines: [bi1])
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).to have_content("You have already assigned the available budget")
expect(page).not_to have_button "Vote", disabled: :all
end
within("#budget_investment_#{bi1.id}_sidebar") do
click_link "Remove vote"
end
expect(page).not_to have_css "#budget_investment_#{bi1.id}_sidebar"
within("#budget_investment_#{bi2.id}") do
click_button "Vote"
expect(page).not_to have_content("You have already assigned the available budget")
expect(page).to have_button "Remove vote"
end
end
scenario "Edge case voting a non-elegible investment" do
investment1 = create(:budget_investment, :selected, heading: new_york, price: 10000)
admin_user = create(:administrator).user
login_as user
visit budget_investments_path(budget, heading_id: new_york)
expect(page).to have_button "Vote"
in_browser(:admin) do
login_as admin_user
visit edit_admin_budget_group_heading_path(budget, states, new_york)
fill_in "Money amount", with: 10
click_button "Save heading"
expect(page).to have_content "Heading updated successfully"
within "tr", text: "New York" do
expect(page).to have_css "td", exact_text: "€10"
end
end
within("#budget_investment_#{investment1.id}") do
click_button "Vote"
expect(page).to have_css ".participation-not-allowed", visible: :hidden
expect(page).not_to have_content "Remove"
click_button "Vote"
expect(page).to have_css ".participation-not-allowed"
expect(page).not_to have_button "Vote", disabled: :all
end
end
scenario "Balloting is disabled when budget isn't in the balotting phase" do
budget.update!(phase: "accepting")
bi1 = create(:budget_investment, :selected, heading: california, price: 600)
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
within("#budget_investment_#{bi1.id}") do
expect(page).not_to have_css("div.ballot")
end
end
end
context "Hide money" do
scenario "Do not show prices on sidebar or ballot show" do
budget_hide_money = create(:budget, :balloting, :approval, :hide_money)
group_no_price = create(:budget_group, budget: budget_hide_money)
heading_no_price = create(:budget_heading, group: group_no_price, max_ballot_lines: 2)
investment_1 = create(:budget_investment, :selected, heading: heading_no_price, price: 3000)
investment_2 = create(:budget_investment, :selected, heading: heading_no_price, price: 4000)
user = create(:user, :level_two, ballot_lines: [investment_1, investment_2])
login_as(user)
visit budget_investments_path(budget_hide_money, heading_id: heading_no_price.id)
within("#sidebar") do
expect(page).to have_content investment_1.title
expect(page).to have_content investment_2.title
expect(page).not_to have_content investment_1.price
expect(page).not_to have_content investment_2.price
expect(page).not_to have_content "€"
click_link "Check my votes"
end
expect(page).to have_content investment_1.title
expect(page).to have_content investment_2.title
expect(page).not_to have_content investment_1.price
expect(page).not_to have_content investment_2.price
expect(page).not_to have_content "€"
end
end
end