summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/slash_commands/issue_move_spec.rb
blob: 962ac3668bcaccd1911f43a48dae3d3541c62939 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# frozen_string_literal: true

require 'spec_helper'

describe Gitlab::SlashCommands::IssueMove, service: true do
  describe '#match' do
    shared_examples_for 'move command' do |text_command|
      it 'can be parsed to extract the needed fields' do
        match_data = described_class.match(text_command)

        expect(match_data['iid']).to eq('123456')
        expect(match_data['project_path']).to eq('gitlab/gitlab-ci')
      end
    end

    it_behaves_like 'move command', 'issue move #123456 to gitlab/gitlab-ci'
    it_behaves_like 'move command', 'issue move #123456 gitlab/gitlab-ci'
    it_behaves_like 'move command', 'issue move #123456 gitlab/gitlab-ci '
    it_behaves_like 'move command', 'issue move 123456 to gitlab/gitlab-ci'
    it_behaves_like 'move command', 'issue move 123456 gitlab/gitlab-ci'
    it_behaves_like 'move command', 'issue move 123456 gitlab/gitlab-ci '
  end

  describe '#execute' do
    set(:user) { create(:user) }
    set(:issue) { create(:issue) }
    set(:chat_name) { create(:chat_name, user: user) }
    set(:project) { issue.project }
    set(:other_project) { create(:project, namespace: project.namespace) }

    before do
      [project, other_project].each { |prj| prj.add_maintainer(user) }
    end

    subject { described_class.new(project, chat_name) }

    def process_message(message)
      subject.execute(described_class.match(message))
    end

    context 'when the user can move the issue' do
      context 'when the move fails' do
        it 'returns the error message' do
          message = "issue move #{issue.iid} #{project.full_path}"

          expect(process_message(message)).to include(response_type: :ephemeral,
                                                      text: a_string_matching('Cannot move issue'))
        end
      end

      context 'when the move succeeds' do
        let(:message) { "issue move #{issue.iid} #{other_project.full_path}" }

        it 'moves the issue to the new destination' do
          expect { process_message(message) }.to change { Issue.count }.by(1)

          new_issue = issue.reload.moved_to

          expect(new_issue.state).to eq('opened')
          expect(new_issue.project_id).to eq(other_project.id)
          expect(new_issue.author_id).to eq(issue.author_id)

          expect(issue.state).to eq('closed')
          expect(issue.project_id).to eq(project.id)
        end

        it 'returns the new issue' do
          expect(process_message(message))
            .to include(response_type: :in_channel,
                        attachments: [a_hash_including(title_link: a_string_including(other_project.full_path))])
        end

        it 'mentions the old issue' do
          expect(process_message(message))
            .to include(attachments: [a_hash_including(pretext: a_string_including(project.full_path))])
        end
      end
    end

    context 'when the issue does not exist' do
      it 'returns not found' do
        message = "issue move #{issue.iid.succ} #{other_project.full_path}"

        expect(process_message(message)).to include(response_type: :ephemeral,
                                                    text: a_string_matching('not found'))
      end
    end

    context 'when the target project does not exist' do
      it 'returns not found' do
        message = "issue move #{issue.iid} #{other_project.full_path}/foo"

        expect(process_message(message)).to include(response_type: :ephemeral,
                                                    text: a_string_matching('not found'))
      end
    end

    context 'when the user cannot see the target project' do
      it 'returns not found' do
        message = "issue move #{issue.iid} #{other_project.full_path}"
        other_project.team.truncate

        expect(process_message(message)).to include(response_type: :ephemeral,
                                                    text: a_string_matching('not found'))
      end
    end

    context 'when the user does not have the required permissions on the target project' do
      it 'returns the error message' do
        message = "issue move #{issue.iid} #{other_project.full_path}"
        other_project.team.truncate
        other_project.team.add_guest(user)

        expect(process_message(message)).to include(response_type: :ephemeral,
                                                    text: a_string_matching('Cannot move issue'))
      end
    end
  end
end