diff --git a/spec/factories.rb b/spec/factories.rb index 77deec79a..739078ec7 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -362,6 +362,24 @@ FactoryBot.define do feasibility "feasible" valuation_finished true end + + trait :hidden do + hidden_at Time.current + end + + trait :with_ignored_flag do + ignored_flag_at Time.current + end + + trait :flagged do + after :create do |investment| + Flag.flag(create(:user), investment) + end + end + + trait :with_confirmed_hide do + confirmed_hide_at Time.current + end end factory :budget_phase, class: 'Budget::Phase' do diff --git a/spec/features/admin/hidden_budget_investments_spec.rb b/spec/features/admin/hidden_budget_investments_spec.rb new file mode 100644 index 000000000..2b001830b --- /dev/null +++ b/spec/features/admin/hidden_budget_investments_spec.rb @@ -0,0 +1,108 @@ +require 'rails_helper' + +feature 'Admin hidden budget investments' do + + let(:budget) { create(:budget) } + let(:group) { create(:budget_group, name: 'Music', budget: budget) } + let(:heading) { create(:budget_heading, name: 'Black metal', price: 666666, group: group) } + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario 'Disabled with a feature flag' do + Setting['feature.budgets'] = nil + + expect{ visit admin_hidden_budget_investments_path }.to raise_exception(FeatureFlags::FeatureDisabled) + + Setting['feature.budgets'] = true + end + + scenario 'List shows all relevant info' do + investment = create(:budget_investment, :hidden, heading: heading) + + visit admin_hidden_budget_investments_path + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + end + + scenario 'Restore' do + investment = create(:budget_investment, :hidden, heading: heading) + + visit admin_hidden_budget_investments_path + + click_link 'Restore' + + expect(page).not_to have_content(investment.title) + + investment.reload + + expect(investment).to be_ignored_flag + end + + scenario 'Confirm hide' do + investment = create(:budget_investment, :hidden, heading: heading) + visit admin_hidden_budget_investments_path + + click_link('Pending') + expect(page).to have_content(investment.title) + + click_link 'Confirm moderation' + + expect(page).not_to have_content(investment.title) + + click_link('Confirmed') + expect(page).to have_content(investment.title) + + expect(investment.reload).to be_confirmed_hide + end + + scenario "Current filter is properly highlighted" do + visit admin_hidden_budget_investments_path + expect(page).not_to have_link('All') + expect(page).to have_link('Pending') + expect(page).to have_link('Confirmed') + + visit admin_hidden_budget_investments_path(filter: 'without_confirmed_hide') + expect(page).to have_link('All') + expect(page).to have_link('Confirmed') + expect(page).not_to have_link('Pending') + + visit admin_hidden_budget_investments_path(filter: 'with_confirmed_hide') + expect(page).to have_link('All') + expect(page).to have_link('Pending') + expect(page).not_to have_link('Confirmed') + end + + scenario 'Filtering investments' do + create(:budget_investment, :hidden, heading: heading, title: 'Unconfirmed investment') + create(:budget_investment, :hidden, :with_confirmed_hide, heading: heading, title: 'Confirmed investment') + + visit admin_hidden_budget_investments_path(filter: 'without_confirmed_hide') + expect(page).to have_content('Unconfirmed investment') + expect(page).not_to have_content('Confirmed investment') + + visit admin_hidden_budget_investments_path(filter: 'all') + expect(page).to have_content('Unconfirmed investment') + expect(page).to have_content('Confirmed investment') + + visit admin_hidden_budget_investments_path(filter: 'with_confirmed_hide') + expect(page).not_to have_content('Unconfirmed investment') + expect(page).to have_content('Confirmed investment') + end + + scenario "Action links remember the pagination setting and the filter" do + per_page = Kaminari.config.default_per_page + (per_page + 2).times { create(:budget_investment, :hidden, :with_confirmed_hide, heading: heading) } + + visit admin_hidden_budget_investments_path(filter: 'with_confirmed_hide', page: 2) + + click_on('Restore', match: :first, exact: true) + + expect(current_url).to include('filter=with_confirmed_hide') + expect(current_url).to include('page=2') + end + +end diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 1b0f7f31f..d3687a84f 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -1567,4 +1567,69 @@ feature 'Budget Investments' do end end + + scenario 'Flagging an investment as innapropriate', :js do + user = create(:user) + investment = create(:budget_investment, heading: heading) + + login_as(user) + + visit budget_investment_path(budget, investment) + + within "#budget_investment_#{investment.id}" do + find("#flag-expand-investment-#{investment.id}").click + find("#flag-investment-#{investment.id}").click + + expect(page).to have_css("#unflag-expand-investment-#{investment.id}") + end + + expect(Flag.flagged?(user, investment)).to be + end + + scenario 'Unflagging an investment', :js do + user = create(:user) + investment = create(:budget_investment, heading: heading) + Flag.flag(user, investment) + + login_as(user) + + visit budget_investment_path(budget, investment) + + within "#budget_investment_#{investment.id}" do + find("#unflag-expand-investment-#{investment.id}").click + find("#unflag-investment-#{investment.id}").click + + expect(page).to have_css("#flag-expand-investment-#{investment.id}") + end + + expect(Flag.flagged?(user, investment)).not_to be + end + + scenario 'Flagging an investment updates the DOM properly', :js do + user = create(:user) + investment = create(:budget_investment, heading: heading) + + login_as(user) + + visit budget_investment_path(budget, investment) + + within "#budget_investment_#{investment.id}" do + find("#flag-expand-investment-#{investment.id}").click + find("#flag-investment-#{investment.id}").click + + expect(page).to have_css("#unflag-expand-investment-#{investment.id}") + end + + expect(Flag.flagged?(user, investment)).to be + + within "#budget_investment_#{investment.id}" do + find("#unflag-expand-investment-#{investment.id}").click + find("#unflag-investment-#{investment.id}").click + + expect(page).to have_css("#flag-expand-investment-#{investment.id}") + end + + expect(Flag.flagged?(user, investment)).not_to be + end + end diff --git a/spec/features/moderation/budget_investments_spec.rb b/spec/features/moderation/budget_investments_spec.rb new file mode 100644 index 000000000..7cb4f5020 --- /dev/null +++ b/spec/features/moderation/budget_investments_spec.rb @@ -0,0 +1,246 @@ +require 'rails_helper' + +feature 'Moderate budget investments' do + + let(:budget) { create(:budget) } + let(:group) { create(:budget_group, name: 'Culture', budget: budget) } + let(:heading) { create(:budget_heading, name: 'More libraries', price: 666666, group: group) } + + background do + @mod = create(:moderator) + @investment = create(:budget_investment, heading: heading, author: create(:user)) + end + + scenario 'Disabled with a feature flag' do + Setting['feature.budgets'] = nil + login_as(@mod.user) + + expect{ visit moderation_budget_investments_path }.to raise_exception(FeatureFlags::FeatureDisabled) + + Setting['feature.budgets'] = true + end + + scenario 'Hiding an investment', :js do + login_as(@mod.user) + visit budget_investment_path(budget, @investment) + + accept_confirm { click_link 'Hide' } + + expect(page).to have_css('.faded', count: 2) + + visit budget_investments_path(budget.id, heading_id: heading.id) + + expect(page).not_to have_content(@investment.title) + end + + scenario "Hiding an investment's author", :js do + login_as(@mod.user) + visit budget_investment_path(budget, @investment) + + accept_confirm { click_link 'Hide author' } + + expect(page).to have_current_path(debates_path) + + visit budget_investments_path(budget.id, heading_id: heading.id) + + expect(page).not_to have_content(@investment.title) + end + + scenario 'Can not hide own investment' do + @investment.update(author: @mod.user) + login_as(@mod.user) + + visit budget_investment_path(budget, @investment) + + within "#budget_investment_#{@investment.id}" do + expect(page).not_to have_link('Hide') + expect(page).not_to have_link('Hide author') + end + end + + feature '/moderation/ screen' do + + background do + login_as(@mod.user) + end + + feature 'moderate in bulk' do + feature 'When an investment has been selected for moderation' do + + background do + visit moderation_budget_investments_path + + within('.menu.simple') do + click_link 'All' + end + + within("#investment_#{@investment.id}") do + check "budget_investment_#{@investment.id}_check" + end + + expect(page).not_to have_css("investment#{@investment.id}") + end + + scenario 'Hide the investment' do + click_button 'Hide budget investments' + expect(page).not_to have_css("investment_#{@investment.id}") + + @investment.reload + + expect(@investment.author).not_to be_hidden + end + + scenario 'Block the author' do + click_button 'Block authors' + expect(page).not_to have_css("investment_#{@investment.id}") + + @investment.reload + + expect(@investment.author).to be_hidden + end + + scenario 'Ignore the investment' do + click_button 'Mark as viewed' + expect(page).not_to have_css("investment_#{@investment.id}") + + @investment.reload + + expect(@investment).to be_ignored_flag + expect(@investment).not_to be_hidden + expect(@investment.author).not_to be_hidden + end + end + + scenario 'select all/none', :js do + create_list(:budget_investment, 2, heading: heading, author: create(:user)) + + visit moderation_budget_investments_path + + within('.js-check') { click_on 'All' } + + expect(all('input[type=checkbox]')).to all(be_checked) + + within('.js-check') { click_on 'None' } + + all('input[type=checkbox]').each do |checkbox| + expect(checkbox).not_to be_checked + end + end + + scenario 'remembering page, filter and order' do + create_list(:budget_investment, 52, heading: heading, author: create(:user)) + + visit moderation_budget_investments_path(filter: 'all', page: '2', order: 'created_at') + + click_button 'Mark as viewed' + + expect(page).to have_selector('.js-order-selector[data-order="created_at"]') + + expect(current_url).to include('filter=all') + expect(current_url).to include('page=2') + expect(current_url).to include('order=created_at') + end + end + + scenario 'Current filter is properly highlighted' do + visit moderation_budget_investments_path + + expect(page).not_to have_link('Pending') + expect(page).to have_link('All') + expect(page).to have_link('Marked as viewed') + + visit moderation_budget_investments_path(filter: 'all') + + within('.menu.simple') do + expect(page).not_to have_link('All') + expect(page).to have_link('Pending') + expect(page).to have_link('Marked as viewed') + end + + visit moderation_budget_investments_path(filter: 'pending_flag_review') + + within('.menu.simple') do + expect(page).to have_link('All') + expect(page).not_to have_link('Pending') + expect(page).to have_link('Marked as viewed') + end + + visit moderation_budget_investments_path(filter: 'with_ignored_flag') + + within('.menu.simple') do + expect(page).to have_link('All') + expect(page).to have_link('Pending') + expect(page).not_to have_link('Marked as viewed') + end + end + + scenario 'Filtering investments' do + create(:budget_investment, heading: heading, title: 'Books investment') + create(:budget_investment, :flagged, heading: heading, title: 'Non-selected investment') + create(:budget_investment, :hidden, heading: heading, title: 'Hidden investment') + create(:budget_investment, :flagged, :with_ignored_flag, heading: heading, title: 'Ignored investment') + + visit moderation_budget_investments_path(filter: 'all') + + expect(page).to have_content('Books investment') + expect(page).to have_content('Non-selected investment') + expect(page).not_to have_content('Hidden investment') + expect(page).to have_content('Ignored investment') + + visit moderation_budget_investments_path(filter: 'pending_flag_review') + + expect(page).not_to have_content('Books investment') + expect(page).to have_content('Non-selected investment') + expect(page).not_to have_content('Hidden investment') + expect(page).not_to have_content('Ignored investment') + + visit moderation_budget_investments_path(filter: 'with_ignored_flag') + + expect(page).not_to have_content('Books investment') + expect(page).not_to have_content('Non-selected investment') + expect(page).not_to have_content('Hidden investment') + expect(page).to have_content('Ignored investment') + end + + scenario 'sorting investments' do + flagged_investment = create(:budget_investment, + heading: heading, + title: 'Flagged investment', + created_at: Time.current - 1.day, + flags_count: 5 + ) + + flagged_new_investment = create(:budget_investment, + heading: heading, + title: 'Flagged new investment', + created_at: Time.current - 12.hours, + flags_count: 3 + ) + + latest_investment = create(:budget_investment, + heading: heading, + title: 'Latest investment', + created_at: Time.current + ) + + visit moderation_budget_investments_path(order: 'created_at') + + expect(flagged_new_investment.title).to appear_before(flagged_investment.title) + + visit moderation_budget_investments_path(order: 'flags') + + expect(flagged_investment.title).to appear_before(flagged_new_investment.title) + + visit moderation_budget_investments_path(filter: 'all', order: 'created_at') + + expect(latest_investment.title).to appear_before(flagged_new_investment.title) + expect(flagged_new_investment.title).to appear_before(flagged_investment.title) + + visit moderation_budget_investments_path(filter: 'all', order: 'flags') + + expect(flagged_investment.title).to appear_before(flagged_new_investment.title) + expect(flagged_new_investment.title).to appear_before(latest_investment.title) + end + end + +end