require 'rails_helper' feature 'Internal valuation comments on Budget::Investments' do let(:user) { create(:user) } let(:valuator_user) { create(:valuator).user } let(:admin_user) { create(:administrator).user } let(:budget) { create(:budget, :valuating) } let(:group) { create(:budget_group, budget: budget) } let(:heading) { create(:budget_heading, group: group) } let(:investment) { create(:budget_investment, budget: budget, group: group, heading: heading) } background do Setting['feature.budgets'] = true investment.valuators << valuator_user.valuator login_as(valuator_user) end after do Setting['feature.budgets'] = nil end context 'Show valuation comments' do context 'Show valuation comments without public comments' do background do public_comment = create(:comment, commentable: investment, body: 'Public comment') create(:comment, commentable: investment, author: valuator_user, body: 'Public valuator comment') create(:comment, commentable: investment, author: admin_user, parent: public_comment) valuator_valuation = create(:comment, :valuation, commentable: investment, author: valuator_user, body: 'Valuator Valuation') create(:comment, :valuation, commentable: investment, author: admin_user, body: 'Admin Valuation') admin_response = create(:comment, :valuation, commentable: investment, author: admin_user, body: 'Admin Valuation response', parent: valuator_valuation) create(:comment, :valuation, commentable: investment, author: admin_user, body: 'Valuator Valuation response', parent: admin_response) end scenario 'Valuation Show page without public comments' do visit valuation_budget_budget_investment_path(budget, investment) expect(page).not_to have_content('Comment as admin') expect(page).not_to have_content('Public comment') expect(page).not_to have_content('Public valuator comment') expect(page).to have_content('Leave your comment') expect(page).to have_content('Valuator Valuation') expect(page).to have_content('Admin Valuation') expect(page).to have_content('Admin Valuation response') expect(page).to have_content('Valuator Valuation response') end scenario 'Valuation Edit page without public comments' do visit edit_valuation_budget_budget_investment_path(budget, investment) expect(page).not_to have_content('Comment as admin') expect(page).not_to have_content('Public comment') expect(page).not_to have_content('Public valuator comment') expect(page).to have_content('Leave your comment') expect(page).to have_content('Valuator Valuation') expect(page).to have_content('Admin Valuation') expect(page).to have_content('Admin Valuation response') expect(page).to have_content('Valuator Valuation response') end end scenario 'Collapsable comments', :js do parent_comment = create(:comment, :valuation, author: valuator_user, body: "Main comment", commentable: investment) child_comment = create(:comment, :valuation, author: valuator_user, body: "First child", commentable: investment, parent: parent_comment) grandchild_comment = create(:comment, :valuation, author: valuator_user, parent: child_comment, body: "Last child", commentable: investment) visit valuation_budget_budget_investment_path(budget, investment) expect(page).to have_css('.comment', count: 3) find("#comment_#{child_comment.id}_children_arrow").click expect(page).to have_css('.comment', count: 2) expect(page).not_to have_content grandchild_comment.body find("#comment_#{child_comment.id}_children_arrow").click expect(page).to have_css('.comment', count: 3) expect(page).to have_content grandchild_comment.body find("#comment_#{parent_comment.id}_children_arrow").click expect(page).to have_css('.comment', count: 1) expect(page).not_to have_content child_comment.body expect(page).not_to have_content grandchild_comment.body end scenario 'Comment order' do create(:comment, :valuation, commentable: investment, author: valuator_user, body: 'Valuator Valuation', created_at: Time.current - 1) admin_valuation = create(:comment, :valuation, commentable: investment, author: admin_user, body: 'Admin Valuation', created_at: Time.current - 2) visit valuation_budget_budget_investment_path(budget, investment) expect(admin_valuation.body).to appear_before('Valuator Valuation') end scenario 'Turns links into html links' do create(:comment, :valuation, author: admin_user, commentable: investment, body: 'Check http://rubyonrails.org/') visit valuation_budget_budget_investment_path(budget, investment) within first('.comment') do expect(page).to have_content('Check http://rubyonrails.org/') expect(page).to have_link('http://rubyonrails.org/', href: 'http://rubyonrails.org/') expect(find_link('http://rubyonrails.org/')[:rel]).to eq('nofollow') expect(find_link('http://rubyonrails.org/')[:target]).to eq('_blank') end end scenario 'Sanitizes comment body for security' do comment_with_js = " "\ "click me http://www.url.com" create(:comment, :valuation, author: admin_user, commentable: investment, body: comment_with_js) visit valuation_budget_budget_investment_path(budget, investment) within first('.comment') do expect(page).to have_content("click me http://www.url.com") expect(page).to have_link('http://www.url.com', href: 'http://www.url.com') expect(page).not_to have_link('click me') end end scenario 'Paginated comments' do per_page = 10 (per_page + 2).times do create(:comment, :valuation, commentable: investment, author: valuator_user) end visit valuation_budget_budget_investment_path(budget, investment) expect(page).to have_css('.comment', count: per_page) within("ul.pagination") do expect(page).to have_content("1") expect(page).to have_content("2") expect(page).not_to have_content("3") click_link "Next", exact: false end expect(page).to have_css('.comment', count: 2) end end context 'Valuation comment creation' do scenario 'Normal users cannot create valuation comments altering public comments form' do comment = build(:comment, body: 'HACKERMAN IS HERE', valuation: true, author: user) expect(comment).not_to be_valid expect(comment.errors.size).to eq(1) end scenario 'Create comment', :js do visit valuation_budget_budget_investment_path(budget, investment) fill_in "comment-body-budget_investment_#{investment.id}", with: 'Have you thought about...?' click_button 'Publish comment' within "#comments" do expect(page).to have_content('Have you thought about...?') end visit budget_investment_path(investment.budget, investment) expect(page).not_to have_content('Have you thought about...?') end scenario 'Errors on create without comment text', :js do visit valuation_budget_budget_investment_path(budget, investment) click_button 'Publish comment' expect(page).to have_content "Can't be blank" end scenario 'Reply to existing valuation', :js do comment = create(:comment, :valuation, author: admin_user, commentable: investment) login_as(valuator_user) visit valuation_budget_budget_investment_path(budget, investment) click_link "Reply" within "#js-comment-form-comment_#{comment.id}" do fill_in "comment-body-comment_#{comment.id}", with: 'It will be done next week.' click_button 'Publish reply' end within "#comment_#{comment.id}" do expect(page).to have_content 'It will be done next week.' end expect(page).not_to have_selector("#js-comment-form-comment_#{comment.id}", visible: true) visit budget_investment_path(investment.budget, investment) expect(page).not_to have_content('It will be done next week.') end scenario 'Errors on reply without comment text', :js do comment = create(:comment, :valuation, author: admin_user, commentable: investment) visit valuation_budget_budget_investment_path(budget, investment) click_link "Reply" within "#js-comment-form-comment_#{comment.id}" do click_button 'Publish reply' expect(page).to have_content "Can't be blank" end end scenario "Multiple nested replies", :js do parent = create(:comment, :valuation, author: valuator_user, commentable: investment) 7.times do create(:comment, :valuation, author: admin_user, commentable: investment, parent: parent) parent = parent.children.first end visit valuation_budget_budget_investment_path(budget, investment) expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment") expect(page).to have_no_css('.comment-votes') expect(page).to have_no_css('.js-flag-actions') expect(page).to have_no_css('.js-moderation-actions') end end scenario "Erasing a comment's author" do comment = create(:comment, :valuation, author: valuator_user, commentable: investment, body: "this should be visible") comment.user.erase visit valuation_budget_budget_investment_path(budget, investment) within "#comment_#{comment.id}" do expect(page).to have_content('User deleted') expect(page).to have_content('this should be visible') end end feature "Administrators" do scenario "can create valuation comment as an administrator", :js do login_as(admin_user) visit valuation_budget_budget_investment_path(budget, investment) fill_in "comment-body-budget_investment_#{investment.id}", with: "I am your Admin!" check "comment-as-administrator-budget_investment_#{investment.id}" click_button "Publish comment" within "#comments" do expect(page).to have_content "I am your Admin!" expect(page).to have_content "Administrator ##{admin_user.administrator.id}" expect(page).to have_css "div.is-admin" expect(page).to have_css "img.admin-avatar" end end scenario "can create valuation reply as an administrator", :js do comment = create(:comment, :valuation, author: valuator_user, commentable: investment) login_as(admin_user) visit valuation_budget_budget_investment_path(budget, investment) click_link "Reply" within "#js-comment-form-comment_#{comment.id}" do fill_in "comment-body-comment_#{comment.id}", with: "Top of the world!" check "comment-as-administrator-comment_#{comment.id}" click_button 'Publish reply' end within "#comment_#{comment.id}" do expect(page).to have_content "Top of the world!" expect(page).to have_content "Administrator ##{admin_user.administrator.id}" expect(page).to have_css "div.is-admin" expect(page).to have_css "img.admin-avatar" end expect(page).not_to have_selector("#js-comment-form-comment_#{comment.id}", visible: true) end end end