diff options
Diffstat (limited to 'spec/support/features/issuable_quick_actions_shared_examples.rb')
-rw-r--r-- | spec/support/features/issuable_quick_actions_shared_examples.rb | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/spec/support/features/issuable_quick_actions_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb new file mode 100644 index 00000000000..846e697eb96 --- /dev/null +++ b/spec/support/features/issuable_quick_actions_shared_examples.rb @@ -0,0 +1,380 @@ +# Specifications for behavior common to all objects with executable attributes. +# It takes a `issuable_type`, and expect an `issuable`. + +shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type| + include Spec::Support::Helpers::Features::NotesHelpers + + let(:maintainer) { create(:user) } + let(:project) do + case issuable_type + when :merge_request + create(:project, :public, :repository) + when :issue + create(:project, :public) + end + end + let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } + let!(:label_bug) { create(:label, project: project, title: 'bug') } + let!(:label_feature) { create(:label, project: project, title: 'feature') } + let(:new_url_opts) { {} } + + before do + project.add_maintainer(maintainer) + + gitlab_sign_in(maintainer) + end + + after do + # Ensure all outstanding Ajax requests are complete to avoid database deadlocks + wait_for_requests + end + + describe "new #{issuable_type}", :js do + context 'with commands in the description' do + it "creates the #{issuable_type} and interpret commands accordingly" do + case issuable_type + when :merge_request + visit public_send("namespace_project_new_merge_request_path", project.namespace, project, new_url_opts) + when :issue + visit public_send("new_namespace_project_issue_path", project.namespace, project, new_url_opts) + end + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\"" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq "bug description" + expect(issuable.labels).to eq [label_bug] + expect(issuable.milestone).to eq milestone + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + end + + describe "note on #{issuable_type}", :js do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + context 'with a note containing commands' do + it 'creates a note without the commands and interpret the commands accordingly' do + assignee = create(:user, username: 'bob') + add_note("Awesome!\n\n/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"") + + expect(page).to have_content 'Awesome!' + expect(page).not_to have_content '/assign @bob' + expect(page).not_to have_content '/label ~bug' + expect(page).not_to have_content '/milestone %"ASAP"' + + wait_for_requests + issuable.reload + note = issuable.notes.user.first + + expect(note.note).to eq "Awesome!" + expect(issuable.assignees).to eq [assignee] + expect(issuable.labels).to eq [label_bug] + expect(issuable.milestone).to eq milestone + end + end + + context 'with a note containing only commands' do + it 'does not create a note but interpret the commands accordingly' do + assignee = create(:user, username: 'bob') + add_note("/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"") + + expect(page).not_to have_content '/assign @bob' + expect(page).not_to have_content '/label ~bug' + expect(page).not_to have_content '/milestone %"ASAP"' + expect(page).to have_content 'Commands applied' + + issuable.reload + + expect(issuable.notes.user).to be_empty + expect(issuable.assignees).to eq [assignee] + expect(issuable.labels).to eq [label_bug] + expect(issuable.milestone).to eq milestone + end + end + + context "with a note closing the #{issuable_type}" do + before do + expect(issuable).to be_open + end + + context "when current user can close #{issuable_type}" do + it "closes the #{issuable_type}" do + add_note("/close") + + expect(page).not_to have_content '/close' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).to be_closed + end + end + + context "when current user cannot close #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not close the #{issuable_type}" do + add_note("/close") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).to be_open + end + end + end + + context "with a note reopening the #{issuable_type}" do + before do + issuable.close + expect(issuable).to be_closed + end + + context "when current user can reopen #{issuable_type}" do + it "reopens the #{issuable_type}" do + add_note("/reopen") + + expect(page).not_to have_content '/reopen' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).to be_open + end + end + + context "when current user cannot reopen #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not reopen the #{issuable_type}" do + add_note("/reopen") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).to be_closed + end + end + end + + context "with a note changing the #{issuable_type}'s title" do + context "when current user can change title of #{issuable_type}" do + it "reopens the #{issuable_type}" do + add_note("/title Awesome new title") + + expect(page).not_to have_content '/title' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload.title).to eq 'Awesome new title' + end + end + + context "when current user cannot change title of #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not change the #{issuable_type} title" do + add_note("/title Awesome new title") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable.reload.title).not_to eq 'Awesome new title' + end + end + end + + context "with a note marking the #{issuable_type} as todo" do + it "creates a new todo for the #{issuable_type}" do + add_note("/todo") + + expect(page).not_to have_content '/todo' + expect(page).to have_content 'Commands applied' + + todos = TodosFinder.new(maintainer).execute + todo = todos.first + + expect(todos.size).to eq 1 + expect(todo).to be_pending + expect(todo.target).to eq issuable + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer + end + end + + context "with a note marking the #{issuable_type} as done" do + before do + TodoService.new.mark_todo(issuable, maintainer) + end + + it "creates a new todo for the #{issuable_type}" do + todos = TodosFinder.new(maintainer).execute + todo = todos.first + + expect(todos.size).to eq 1 + expect(todos.first).to be_pending + expect(todo.target).to eq issuable + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer + + add_note("/done") + + expect(page).not_to have_content '/done' + expect(page).to have_content 'Commands applied' + + expect(todo.reload).to be_done + end + end + + context "with a note subscribing to the #{issuable_type}" do + it "creates a new todo for the #{issuable_type}" do + expect(issuable.subscribed?(maintainer, project)).to be_falsy + + add_note("/subscribe") + + expect(page).not_to have_content '/subscribe' + expect(page).to have_content 'Commands applied' + + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + end + + context "with a note unsubscribing to the #{issuable_type} as done" do + before do + issuable.subscribe(maintainer, project) + end + + it "creates a new todo for the #{issuable_type}" do + expect(issuable.subscribed?(maintainer, project)).to be_truthy + + add_note("/unsubscribe") + + expect(page).not_to have_content '/unsubscribe' + expect(page).to have_content 'Commands applied' + + expect(issuable.subscribed?(maintainer, project)).to be_falsy + end + end + + context "with a note assigning the #{issuable_type} to the current user" do + it "assigns the #{issuable_type} to the current user" do + add_note("/assign me") + + expect(page).not_to have_content '/assign me' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload.assignees).to eq [maintainer] + end + end + + context "with a note locking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: false) + expect(issuable).not_to be_discussion_locked + end + + context "when current user can lock #{issuable_type} discussion" do + it "locks the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content '/lock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).to be_discussion_locked + end + end + + context "when current user cannot lock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not lock the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).not_to be_discussion_locked + end + end + end + + context "with a note unlocking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: true) + expect(issuable).to be_discussion_locked + end + + context "when current user can unlock #{issuable_type} discussion" do + it "unlocks the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content '/unlock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).not_to be_discussion_locked + end + end + + context "when current user cannot unlock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not unlock the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).to be_discussion_locked + end + end + end + end + + describe "preview of note on #{issuable_type}", :js do + it 'removes quick actions from note and explains them' do + create(:user, username: 'bob') + + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "Awesome!\n/assign @bob " + click_on 'Preview' + + expect(page).to have_content 'Awesome!' + expect(page).not_to have_content '/assign @bob' + expect(page).to have_content 'Assigns @bob.' + end + end + end +end |