Files
grecia/spec/system/admin/budgets_spec.rb
Javi Martín 5311daadfe Use a button for non-GET table actions
Links acting like buttons have a few disadvantages.

First, screen readers will announce them as "links". Screen reader users
usually associate links with "things that get you somewhere" and buttons
with "things that perform an action". So when something like "Delete,
link" is announced, they'll probably think this is a link which will
take them to another page where they can delete a record.

Furthermore, the URL of the link for the "destroy" action might be the
same as the URL for the "show" action (only one is accessed with a
DELETE request and the other one with a GET request). That means screen
readers could announce the link like "Delete, visited link", which is
very confusing.

They also won't work when opening links in a new tab, since opening
links in a new tab always results in a GET request to the URL the link
points to.

Finally, submit buttons work without JavaScript enabled, so they'll work
even if the JavaScript in the page hasn't loaded (for whatever reason).

For all these reasons (and probably many more), using a button to send
forms is IMHO superior to using links.

There's one disadvantage, though. Using `button_to` we create a <form>
tag, which means we'll generate invalid HTML if the table is inside
another form. If we run into this issue, we need to use `button_tag`
with a `form` attribute and then generate a form somewhere else inside
the HTML (with `content_for`).

Note we're using `button_to` with a block so it generates a <button>
tag. Using it in a different way the text would result in an <input />
tag, and input elements can't have pseudocontent added via CSS.

The following code could be a starting point to use the `button_tag`
with a `form` attribute. One advantage of this approach is screen
readers wouldn't announce "leaving form" while navigating through these
buttons. However, it doesn't work in Internet Explorer.

```
ERB:

<% content_for(:hidden_content, form_tag(path, form_options) {}) %>
<%= button_tag text, button_options %>

Ruby:

def form_id
  path.gsub("/", "_")
end

def form_options
  { id: form_id, method: options[:method] }
end

def button_options
  html_options.except(:method).merge(form: form_id)
end

Layout:

<%= content_for :hidden_content %> # Right before the `</body>`
```
2021-09-20 20:27:37 +02:00

378 lines
12 KiB
Ruby

require "rails_helper"
describe "Admin budgets", :admin do
it_behaves_like "nested imageable",
"budget",
"new_admin_budgets_wizard_budget_path",
{},
"imageable_fill_new_valid_budget",
"Continue to groups",
"New participatory budget created successfully!"
context "Load" do
before { create(:budget, slug: "budget_slug") }
scenario "finds budget by slug" do
visit edit_admin_budget_path("budget_slug")
expect(page).to have_content("Edit Participatory budget")
end
end
context "Index" do
scenario "Displaying no open budgets text" do
visit admin_budgets_path
expect(page).to have_content("There are no budgets.")
end
scenario "Displaying budgets" do
budget = create(:budget, :accepting)
visit admin_budgets_path
within "tr", text: budget.name do
expect(page).to have_content "Accepting projects"
expect(page).to have_content "Pending: No headings yet"
end
end
scenario "Filters by phase" do
create(:budget, :drafting, name: "Unpublished budget")
create(:budget, :accepting, name: "Accepting budget")
create(:budget, :selecting, name: "Selecting budget")
create(:budget, :balloting, name: "Balloting budget")
create(:budget, :finished, name: "Finished budget")
visit admin_budgets_path
expect(page).to have_content "Accepting budget"
expect(page).to have_content "Selecting budget"
expect(page).to have_content "Balloting budget"
within "tr", text: "Unpublished budget" do
expect(page).to have_content "Draft"
end
within "tr", text: "Finished budget" do
expect(page).to have_content "COMPLETED"
end
click_link "Finished"
expect(page).not_to have_content "Unpublished budget"
expect(page).not_to have_content "Accepting budget"
expect(page).not_to have_content "Selecting budget"
expect(page).not_to have_content "Balloting budget"
expect(page).to have_content "Finished budget"
click_link "Open"
expect(page).to have_content "Unpublished budget"
expect(page).to have_content "Accepting budget"
expect(page).to have_content "Selecting budget"
expect(page).to have_content "Balloting budget"
expect(page).not_to have_content "Finished budget"
end
scenario "Filters are properly highlighted" do
filters_links = { "all" => "All", "open" => "Open", "finished" => "Finished" }
visit admin_budgets_path
expect(page).not_to have_link(filters_links.values.first)
filters_links.keys.drop(1).each { |filter| expect(page).to have_link(filters_links[filter]) }
filters_links.each do |current_filter, link|
visit admin_budgets_path(filter: current_filter)
expect(page).not_to have_link(link)
(filters_links.keys - [current_filter]).each do |filter|
expect(page).to have_link(filters_links[filter])
end
end
end
scenario "Delete budget from index" do
create(:budget, name: "To be deleted")
visit admin_budgets_path
within "tr", text: "To be deleted" do
message = "Are you sure? This action will delete \"To be deleted\" and can't be undone."
accept_confirm(message) { click_button "Delete" }
end
expect(page).to have_content("Budget deleted successfully")
expect(page).to have_content("There are no budgets.")
expect(page).not_to have_content "To be deleted"
end
end
context "Publish" do
let(:budget) { create(:budget, :drafting) }
scenario "Can preview budget before it is published" do
visit edit_admin_budget_path(budget)
within_window(window_opened_by { click_link "Preview" }) do
expect(page).to have_current_path budget_path(budget)
end
end
scenario "Can preview a budget after it is published" do
visit edit_admin_budget_path(budget)
accept_confirm { click_link "Publish budget" }
expect(page).to have_content "Participatory budget published successfully"
expect(page).not_to have_content "This participatory budget is in draft mode"
expect(page).not_to have_link "Publish budget"
within_window(window_opened_by { click_link "Preview" }) do
expect(page).to have_current_path budget_path(budget)
end
end
end
context "Destroy" do
let!(:budget) { create(:budget) }
let(:heading) { create(:budget_heading, budget: budget) }
scenario "Destroy a budget without investments" do
visit edit_admin_budget_path(budget)
click_link "Delete budget"
expect(page).to have_content("Budget deleted successfully")
expect(page).to have_content("There are no budgets.")
end
scenario "Destroy a budget without investments but with administrators and valuators" do
budget.administrators << Administrator.first
budget.valuators << create(:valuator)
visit edit_admin_budget_path(budget)
click_link "Delete budget"
expect(page).to have_content "Budget deleted successfully"
expect(page).to have_content "There are no budgets."
end
scenario "Try to destroy a budget with investments" do
create(:budget_investment, heading: heading)
visit edit_admin_budget_path(budget)
click_link "Delete budget"
expect(page).to have_content("You cannot delete a budget that has associated investments")
expect(page).to have_content("There is 1 budget")
end
scenario "Try to destroy a budget with polls" do
create(:poll, budget: budget)
visit edit_admin_budget_path(budget)
click_link "Delete budget"
expect(page).to have_content("You cannot delete a budget that has an associated poll")
expect(page).to have_content("There is 1 budget")
end
end
context "Edit" do
let(:budget) { create(:budget) }
scenario "Show phases table" do
travel_to(Date.new(2015, 7, 15)) do
budget.update!(phase: "selecting")
budget.phases.valuating.update!(enabled: false)
visit edit_admin_budget_path(budget)
expect(page).to have_select "Active phase", selected: "Selecting projects"
expect(page).to have_table "Phases", with_cols: [
[
"Information",
"Accepting projects",
"Reviewing projects",
"Selecting projects Active",
"Valuating projects",
"Publishing projects prices",
"Voting projects",
"Reviewing voting"
],
[
"2015-07-15 00:00 - 2015-08-14 23:59",
"2015-08-15 00:00 - 2015-09-14 23:59",
"2015-09-15 00:00 - 2015-10-14 23:59",
"2015-10-15 00:00 - 2015-11-14 23:59",
"2015-11-15 00:00 - 2015-12-14 23:59",
"2015-11-15 00:00 - 2016-01-14 23:59",
"2016-01-15 00:00 - 2016-02-14 23:59",
"2016-02-15 00:00 - 2016-03-14 23:59"
],
[
"Yes",
"Yes",
"Yes",
"Yes",
"No",
"Yes",
"Yes",
"Yes"
]
]
within_table "Phases" do
within "tr", text: "Information" do
expect(page).to have_link "Edit"
end
end
end
end
scenario "Show results and stats settings" do
visit edit_admin_budget_path(budget)
within_fieldset "Show results and stats" do
expect(page).to have_field "Show results"
expect(page).to have_field "Show stats"
expect(page).to have_field "Show advanced stats"
end
end
scenario "Show CTA link in public site if added" do
visit edit_admin_budget_path(budget)
expect(page).to have_content("Main call to action (optional)")
fill_in "Text on the link", with: "Participate now"
fill_in "The link takes you to (add a link)", with: "https://consulproject.org"
click_button "Update Budget"
expect(page).to have_content "Participatory budget updated successfully"
visit budgets_path
expect(page).to have_link("Participate now", href: "https://consulproject.org")
end
scenario "Changing name for current locale will update the slug if budget is in draft phase" do
budget.update!(published: false, name: "Old English Name")
visit edit_admin_budget_path(budget)
select "Español", from: :add_language
fill_in "Name", with: "Spanish name"
click_button "Update Budget"
expect(page).to have_content "Participatory budget updated successfully"
visit budget_path(id: "old-english-name")
expect(page).to have_content "Old English Name"
visit edit_admin_budget_path(budget)
select "English", from: :select_language
fill_in "Name", with: "New English Name"
click_button "Update Budget"
expect(page).to have_content "Participatory budget updated successfully"
visit budget_path(id: "new-english-name")
expect(page).to have_content "New English Name"
end
end
context "Update" do
scenario "Update budget" do
visit edit_admin_budget_path(create(:budget))
fill_in "Name", with: "More trees on the streets"
click_button "Update Budget"
expect(page).to have_content("More trees on the streets")
expect(page).to have_current_path(admin_budgets_path)
end
scenario "Deselect all selected staff" do
admin = Administrator.first
valuator = create(:valuator)
budget = create(:budget, administrators: [admin], valuators: [valuator])
visit edit_admin_budget_path(budget)
click_link "1 administrator selected"
uncheck admin.name
expect(page).to have_link "Select administrators"
click_link "1 valuator selected"
uncheck valuator.name
expect(page).to have_link "Select valuators"
click_button "Update Budget"
visit edit_admin_budget_path(budget)
expect(page).to have_link "Select administrators"
expect(page).to have_link "Select valuators"
end
end
context "Calculate Budget's Winner Investments" do
scenario "For a Budget in reviewing balloting" do
budget = create(:budget, :reviewing_ballots)
heading = create(:budget_heading, budget: budget, price: 4)
unselected = create(:budget_investment, :unselected, heading: heading, price: 1,
ballot_lines_count: 3)
winner = create(:budget_investment, :selected, heading: heading, price: 3,
ballot_lines_count: 2)
selected = create(:budget_investment, :selected, heading: heading, price: 2, ballot_lines_count: 1)
visit edit_admin_budget_path(budget)
expect(page).not_to have_content "See results"
click_link "Calculate Winner Investments"
expect(page).to have_content "Winners being calculated, it may take a minute."
expect(page).to have_content winner.title
expect(page).not_to have_content unselected.title
expect(page).not_to have_content selected.title
visit edit_admin_budget_path(budget)
expect(page).to have_content "See results"
end
scenario "For a finished Budget" do
budget = create(:budget, :finished)
allow_any_instance_of(Budget).to receive(:has_winning_investments?).and_return(true)
visit edit_admin_budget_path(budget)
expect(page).to have_content "Calculate Winner Investments"
expect(page).to have_content "See results"
end
scenario "Recalculate for a finished Budget" do
budget = create(:budget, :finished)
create(:budget_investment, :winner, budget: budget)
visit edit_admin_budget_path(budget)
expect(page).to have_content "Recalculate Winner Investments"
expect(page).to have_content "See results"
expect(page).not_to have_content "Calculate Winner Investments"
visit admin_budget_budget_investments_path(budget)
click_link "Advanced filters"
check "Winners"
click_button "Filter"
expect(page).to have_content "Recalculate Winner Investments"
expect(page).not_to have_content "Calculate Winner Investments"
end
end
end