Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Eastwood <contact@ericeastwood.com>2017-05-31 08:50:53 +0300
committerEric Eastwood <contact@ericeastwood.com>2017-06-15 17:01:56 +0300
commitea090291bba6bb665b3631cc5a2659e6673a6959 (patch)
tree1daf4c15aee8afc0eebef94a345eb077d0390632 /spec/lib/gitlab/slash_commands
parent42aaae9916b7b76da968579fcc722067947df018 (diff)
Rename "Slash commands" to "Quick actions"
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/27070 Deprecate "chat commands" in favor of "slash commands" We looked for things like: - `slash commmand` - `slash_command` - `slash-command` - `SlashCommand`
Diffstat (limited to 'spec/lib/gitlab/slash_commands')
-rw-r--r--spec/lib/gitlab/slash_commands/command_definition_spec.rb225
-rw-r--r--spec/lib/gitlab/slash_commands/command_spec.rb111
-rw-r--r--spec/lib/gitlab/slash_commands/deploy_spec.rb90
-rw-r--r--spec/lib/gitlab/slash_commands/dsl_spec.rb109
-rw-r--r--spec/lib/gitlab/slash_commands/extractor_spec.rb223
-rw-r--r--spec/lib/gitlab/slash_commands/issue_new_spec.rb78
-rw-r--r--spec/lib/gitlab/slash_commands/issue_search_spec.rb48
-rw-r--r--spec/lib/gitlab/slash_commands/issue_show_spec.rb59
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/access_spec.rb49
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb47
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb17
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb25
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb52
13 files changed, 576 insertions, 557 deletions
diff --git a/spec/lib/gitlab/slash_commands/command_definition_spec.rb b/spec/lib/gitlab/slash_commands/command_definition_spec.rb
deleted file mode 100644
index 5b9173d3d3f..00000000000
--- a/spec/lib/gitlab/slash_commands/command_definition_spec.rb
+++ /dev/null
@@ -1,225 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::SlashCommands::CommandDefinition do
- subject { described_class.new(:command) }
-
- describe "#all_names" do
- context "when the command has aliases" do
- before do
- subject.aliases = [:alias1, :alias2]
- end
-
- it "returns an array with the name and aliases" do
- expect(subject.all_names).to eq([:command, :alias1, :alias2])
- end
- end
-
- context "when the command doesn't have aliases" do
- it "returns an array with the name" do
- expect(subject.all_names).to eq([:command])
- end
- end
- end
-
- describe "#noop?" do
- context "when the command has an action block" do
- before do
- subject.action_block = proc { }
- end
-
- it "returns false" do
- expect(subject.noop?).to be false
- end
- end
-
- context "when the command doesn't have an action block" do
- it "returns true" do
- expect(subject.noop?).to be true
- end
- end
- end
-
- describe "#available?" do
- let(:opts) { { go: false } }
-
- context "when the command has a condition block" do
- before do
- subject.condition_block = proc { go }
- end
-
- context "when the condition block returns true" do
- before do
- opts[:go] = true
- end
-
- it "returns true" do
- expect(subject.available?(opts)).to be true
- end
- end
-
- context "when the condition block returns false" do
- it "returns false" do
- expect(subject.available?(opts)).to be false
- end
- end
- end
-
- context "when the command doesn't have a condition block" do
- it "returns true" do
- expect(subject.available?(opts)).to be true
- end
- end
- end
-
- describe "#execute" do
- let(:context) { OpenStruct.new(run: false) }
-
- context "when the command is a noop" do
- it "doesn't execute the command" do
- expect(context).not_to receive(:instance_exec)
-
- subject.execute(context, {}, nil)
-
- expect(context.run).to be false
- end
- end
-
- context "when the command is not a noop" do
- before do
- subject.action_block = proc { self.run = true }
- end
-
- context "when the command is not available" do
- before do
- subject.condition_block = proc { false }
- end
-
- it "doesn't execute the command" do
- subject.execute(context, {}, nil)
-
- expect(context.run).to be false
- end
- end
-
- context "when the command is available" do
- context "when the commnd has no arguments" do
- before do
- subject.action_block = proc { self.run = true }
- end
-
- context "when the command is provided an argument" do
- it "executes the command" do
- subject.execute(context, {}, true)
-
- expect(context.run).to be true
- end
- end
-
- context "when the command is not provided an argument" do
- it "executes the command" do
- subject.execute(context, {}, nil)
-
- expect(context.run).to be true
- end
- end
- end
-
- context "when the command has 1 required argument" do
- before do
- subject.action_block = ->(arg) { self.run = arg }
- end
-
- context "when the command is provided an argument" do
- it "executes the command" do
- subject.execute(context, {}, true)
-
- expect(context.run).to be true
- end
- end
-
- context "when the command is not provided an argument" do
- it "doesn't execute the command" do
- subject.execute(context, {}, nil)
-
- expect(context.run).to be false
- end
- end
- end
-
- context "when the command has 1 optional argument" do
- before do
- subject.action_block = proc { |arg = nil| self.run = arg || true }
- end
-
- context "when the command is provided an argument" do
- it "executes the command" do
- subject.execute(context, {}, true)
-
- expect(context.run).to be true
- end
- end
-
- context "when the command is not provided an argument" do
- it "executes the command" do
- subject.execute(context, {}, nil)
-
- expect(context.run).to be true
- end
- end
- end
-
- context 'when the command defines parse_params block' do
- before do
- subject.parse_params_block = ->(raw) { raw.strip }
- subject.action_block = ->(parsed) { self.received_arg = parsed }
- end
-
- it 'executes the command passing the parsed param' do
- subject.execute(context, {}, 'something ')
-
- expect(context.received_arg).to eq('something')
- end
- end
- end
- end
- end
-
- describe '#explain' do
- context 'when the command is not available' do
- before do
- subject.condition_block = proc { false }
- subject.explanation = 'Explanation'
- end
-
- it 'returns nil' do
- result = subject.explain({}, {}, nil)
-
- expect(result).to be_nil
- end
- end
-
- context 'when the explanation is a static string' do
- before do
- subject.explanation = 'Explanation'
- end
-
- it 'returns this static string' do
- result = subject.explain({}, {}, nil)
-
- expect(result).to eq 'Explanation'
- end
- end
-
- context 'when the explanation is dynamic' do
- before do
- subject.explanation = proc { |arg| "Dynamic #{arg}" }
- end
-
- it 'invokes the proc' do
- result = subject.explain({}, {}, 'explanation')
-
- expect(result).to eq 'Dynamic explanation'
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb
new file mode 100644
index 00000000000..28d7f9858c3
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/command_spec.rb
@@ -0,0 +1,111 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Command, service: true do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ describe '#execute' do
+ subject do
+ described_class.new(project, user, params).execute
+ end
+
+ context 'when no command is available' do
+ let(:params) { { text: 'issue show 1' } }
+ let(:project) { create(:empty_project, has_external_issue_tracker: true) }
+
+ it 'displays 404 messages' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('404 not found')
+ end
+ end
+
+ context 'when an unknown command is triggered' do
+ let(:params) { { command: '/gitlab', text: "unknown command 123" } }
+
+ it 'displays the help message' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('Unknown command')
+ expect(subject[:text]).to match('/gitlab issue show')
+ end
+ end
+
+ context 'the user can not create an issue' do
+ let(:params) { { text: "issue create my new issue" } }
+
+ it 'rejects the actions' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('Whoops! This action is not allowed')
+ end
+ end
+
+ context 'when trying to do deployment' do
+ let(:params) { { text: 'deploy staging to production' } }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:pipeline) { create(:ci_pipeline, project: project) }
+ let!(:staging) { create(:environment, name: 'staging', project: project) }
+ let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
+
+ let!(:manual) do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+ end
+
+ context 'and user can not create deployment' do
+ it 'returns action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('Whoops! This action is not allowed')
+ end
+ end
+
+ context 'and user has deployment permission' do
+ before do
+ build.project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: build.ref, project: project)
+ end
+
+ it 'returns action' do
+ expect(subject[:text]).to include('Deployment started from staging to production')
+ expect(subject[:response_type]).to be(:in_channel)
+ end
+
+ context 'when duplicate action exists' do
+ let!(:manual2) do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'second',
+ environment: 'production')
+ end
+
+ it 'returns error' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to include('Too many actions defined')
+ end
+ end
+ end
+ end
+ end
+
+ describe '#match_command' do
+ subject { described_class.new(project, user, params).match_command.first }
+
+ context 'IssueShow is triggered' do
+ let(:params) { { text: 'issue show 123' } }
+
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueShow) }
+ end
+
+ context 'IssueCreate is triggered' do
+ let(:params) { { text: 'issue create my title' } }
+
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueNew) }
+ end
+
+ context 'IssueSearch is triggered' do
+ let(:params) { { text: 'issue search my query' } }
+
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueSearch) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb
new file mode 100644
index 00000000000..d919f7260db
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Deploy, service: true do
+ describe '#execute' do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:regex_match) { described_class.match('deploy staging to production') }
+
+ before do
+ # Make it possible to trigger protected manual actions for developers.
+ #
+ project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: 'master', project: project)
+ end
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'if no environment is defined' do
+ it 'does not execute an action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
+ end
+ end
+
+ context 'with environment' do
+ let!(:staging) { create(:environment, name: 'staging', project: project) }
+ let!(:pipeline) { create(:ci_pipeline, project: project) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
+
+ context 'without actions' do
+ it 'does not execute an action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
+ end
+ end
+
+ context 'with action' do
+ let!(:manual1) do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+ end
+
+ it 'returns success result' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with('Deployment started from staging to production')
+ end
+
+ context 'when duplicate action exists' do
+ let!(:manual2) do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'second',
+ environment: 'production')
+ end
+
+ it 'returns error' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq('Too many actions defined')
+ end
+ end
+
+ context 'when teardown action exists' do
+ let!(:teardown) do
+ create(:ci_build, :manual, :teardown_environment,
+ pipeline: pipeline, name: 'teardown', environment: 'production')
+ end
+
+ it 'returns the success message' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with('Deployment started from staging to production')
+ end
+ end
+ end
+ end
+ end
+
+ describe 'self.match' do
+ it 'matches the environment' do
+ match = described_class.match('deploy staging to production')
+
+ expect(match[:from]).to eq('staging')
+ expect(match[:to]).to eq('production')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/dsl_spec.rb b/spec/lib/gitlab/slash_commands/dsl_spec.rb
deleted file mode 100644
index 33b49a5ddf9..00000000000
--- a/spec/lib/gitlab/slash_commands/dsl_spec.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::SlashCommands::Dsl do
- before :all do
- DummyClass = Struct.new(:project) do
- include Gitlab::SlashCommands::Dsl # rubocop:disable RSpec/DescribedClass
-
- desc 'A command with no args'
- command :no_args, :none do
- "Hello World!"
- end
-
- params 'The first argument'
- explanation 'Static explanation'
- command :explanation_with_aliases, :once, :first do |arg|
- arg
- end
-
- desc do
- "A dynamic description for #{noteable.upcase}"
- end
- params 'The first argument', 'The second argument'
- command :dynamic_description do |args|
- args.split
- end
-
- command :cc
-
- explanation do |arg|
- "Action does something with #{arg}"
- end
- condition do
- project == 'foo'
- end
- command :cond_action do |arg|
- arg
- end
-
- parse_params do |raw_arg|
- raw_arg.strip
- end
- command :with_params_parsing do |parsed|
- parsed
- end
- end
- end
-
- describe '.command_definitions' do
- it 'returns an array with commands definitions' do
- no_args_def, explanation_with_aliases_def, dynamic_description_def,
- cc_def, cond_action_def, with_params_parsing_def =
- DummyClass.command_definitions
-
- expect(no_args_def.name).to eq(:no_args)
- expect(no_args_def.aliases).to eq([:none])
- expect(no_args_def.description).to eq('A command with no args')
- expect(no_args_def.explanation).to eq('')
- expect(no_args_def.params).to eq([])
- expect(no_args_def.condition_block).to be_nil
- expect(no_args_def.action_block).to be_a_kind_of(Proc)
- expect(no_args_def.parse_params_block).to be_nil
-
- expect(explanation_with_aliases_def.name).to eq(:explanation_with_aliases)
- expect(explanation_with_aliases_def.aliases).to eq([:once, :first])
- expect(explanation_with_aliases_def.description).to eq('')
- expect(explanation_with_aliases_def.explanation).to eq('Static explanation')
- expect(explanation_with_aliases_def.params).to eq(['The first argument'])
- expect(explanation_with_aliases_def.condition_block).to be_nil
- expect(explanation_with_aliases_def.action_block).to be_a_kind_of(Proc)
- expect(explanation_with_aliases_def.parse_params_block).to be_nil
-
- expect(dynamic_description_def.name).to eq(:dynamic_description)
- expect(dynamic_description_def.aliases).to eq([])
- expect(dynamic_description_def.to_h(noteable: 'issue')[:description]).to eq('A dynamic description for ISSUE')
- expect(dynamic_description_def.explanation).to eq('')
- expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument'])
- expect(dynamic_description_def.condition_block).to be_nil
- expect(dynamic_description_def.action_block).to be_a_kind_of(Proc)
- expect(dynamic_description_def.parse_params_block).to be_nil
-
- expect(cc_def.name).to eq(:cc)
- expect(cc_def.aliases).to eq([])
- expect(cc_def.description).to eq('')
- expect(cc_def.explanation).to eq('')
- expect(cc_def.params).to eq([])
- expect(cc_def.condition_block).to be_nil
- expect(cc_def.action_block).to be_nil
- expect(cc_def.parse_params_block).to be_nil
-
- expect(cond_action_def.name).to eq(:cond_action)
- expect(cond_action_def.aliases).to eq([])
- expect(cond_action_def.description).to eq('')
- expect(cond_action_def.explanation).to be_a_kind_of(Proc)
- expect(cond_action_def.params).to eq([])
- expect(cond_action_def.condition_block).to be_a_kind_of(Proc)
- expect(cond_action_def.action_block).to be_a_kind_of(Proc)
- expect(cond_action_def.parse_params_block).to be_nil
-
- expect(with_params_parsing_def.name).to eq(:with_params_parsing)
- expect(with_params_parsing_def.aliases).to eq([])
- expect(with_params_parsing_def.description).to eq('')
- expect(with_params_parsing_def.explanation).to eq('')
- expect(with_params_parsing_def.params).to eq([])
- expect(with_params_parsing_def.condition_block).to be_nil
- expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc)
- expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc)
- end
- end
-end
diff --git a/spec/lib/gitlab/slash_commands/extractor_spec.rb b/spec/lib/gitlab/slash_commands/extractor_spec.rb
deleted file mode 100644
index d7f77486b3e..00000000000
--- a/spec/lib/gitlab/slash_commands/extractor_spec.rb
+++ /dev/null
@@ -1,223 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::SlashCommands::Extractor do
- let(:definitions) do
- Class.new do
- include Gitlab::SlashCommands::Dsl
-
- command(:reopen, :open) { }
- command(:assign) { }
- command(:labels) { }
- command(:power) { }
- end.command_definitions
- end
-
- let(:extractor) { described_class.new(definitions) }
-
- shared_examples 'command with no argument' do
- it 'extracts command' do
- msg, commands = extractor.extract_commands(original_msg)
-
- expect(commands).to eq [['reopen']]
- expect(msg).to eq final_msg
- end
- end
-
- shared_examples 'command with a single argument' do
- it 'extracts command' do
- msg, commands = extractor.extract_commands(original_msg)
-
- expect(commands).to eq [['assign', '@joe']]
- expect(msg).to eq final_msg
- end
- end
-
- shared_examples 'command with multiple arguments' do
- it 'extracts command' do
- msg, commands = extractor.extract_commands(original_msg)
-
- expect(commands).to eq [['labels', '~foo ~"bar baz" label']]
- expect(msg).to eq final_msg
- end
- end
-
- describe '#extract_commands' do
- describe 'command with no argument' do
- context 'at the start of content' do
- it_behaves_like 'command with no argument' do
- let(:original_msg) { "/reopen\nworld" }
- let(:final_msg) { "world" }
- end
- end
-
- context 'in the middle of content' do
- it_behaves_like 'command with no argument' do
- let(:original_msg) { "hello\n/reopen\nworld" }
- let(:final_msg) { "hello\nworld" }
- end
- end
-
- context 'in the middle of a line' do
- it 'does not extract command' do
- msg = "hello\nworld /reopen"
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq "hello\nworld /reopen"
- end
- end
-
- context 'at the end of content' do
- it_behaves_like 'command with no argument' do
- let(:original_msg) { "hello\n/reopen" }
- let(:final_msg) { "hello" }
- end
- end
- end
-
- describe 'command with a single argument' do
- context 'at the start of content' do
- it_behaves_like 'command with a single argument' do
- let(:original_msg) { "/assign @joe\nworld" }
- let(:final_msg) { "world" }
- end
-
- it 'allows slash in command arguments' do
- msg = "/assign @joe / @jane\nworld"
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to eq [['assign', '@joe / @jane']]
- expect(msg).to eq 'world'
- end
- end
-
- context 'in the middle of content' do
- it_behaves_like 'command with a single argument' do
- let(:original_msg) { "hello\n/assign @joe\nworld" }
- let(:final_msg) { "hello\nworld" }
- end
- end
-
- context 'in the middle of a line' do
- it 'does not extract command' do
- msg = "hello\nworld /assign @joe"
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq "hello\nworld /assign @joe"
- end
- end
-
- context 'at the end of content' do
- it_behaves_like 'command with a single argument' do
- let(:original_msg) { "hello\n/assign @joe" }
- let(:final_msg) { "hello" }
- end
- end
-
- context 'when argument is not separated with a space' do
- it 'does not extract command' do
- msg = "hello\n/assign@joe\nworld"
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq "hello\n/assign@joe\nworld"
- end
- end
- end
-
- describe 'command with multiple arguments' do
- context 'at the start of content' do
- it_behaves_like 'command with multiple arguments' do
- let(:original_msg) { %(/labels ~foo ~"bar baz" label\nworld) }
- let(:final_msg) { "world" }
- end
- end
-
- context 'in the middle of content' do
- it_behaves_like 'command with multiple arguments' do
- let(:original_msg) { %(hello\n/labels ~foo ~"bar baz" label\nworld) }
- let(:final_msg) { "hello\nworld" }
- end
- end
-
- context 'in the middle of a line' do
- it 'does not extract command' do
- msg = %(hello\nworld /labels ~foo ~"bar baz" label)
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq %(hello\nworld /labels ~foo ~"bar baz" label)
- end
- end
-
- context 'at the end of content' do
- it_behaves_like 'command with multiple arguments' do
- let(:original_msg) { %(hello\n/labels ~foo ~"bar baz" label) }
- let(:final_msg) { "hello" }
- end
- end
-
- context 'when argument is not separated with a space' do
- it 'does not extract command' do
- msg = %(hello\n/labels~foo ~"bar baz" label\nworld)
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq %(hello\n/labels~foo ~"bar baz" label\nworld)
- end
- end
- end
-
- it 'extracts command with multiple arguments and various prefixes' do
- msg = %(hello\n/power @user.name %9.10 ~"bar baz.2"\nworld)
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to eq [['power', '@user.name %9.10 ~"bar baz.2"']]
- expect(msg).to eq "hello\nworld"
- end
-
- it 'extracts multiple commands' do
- msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/reopen)
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to eq [['power', '@user.name %9.10 ~"bar baz.2" label'], ['reopen']]
- expect(msg).to eq "hello\nworld"
- end
-
- it 'does not alter original content if no command is found' do
- msg = 'Fixes #123'
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq 'Fixes #123'
- end
-
- it 'does not extract commands inside a blockcode' do
- msg = "Hello\r\n```\r\nThis is some text\r\n/close\r\n/assign @user\r\n```\r\n\r\nWorld"
- expected = msg.delete("\r")
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq expected
- end
-
- it 'does not extract commands inside a blockquote' do
- msg = "Hello\r\n>>>\r\nThis is some text\r\n/close\r\n/assign @user\r\n>>>\r\n\r\nWorld"
- expected = msg.delete("\r")
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq expected
- end
-
- it 'does not extract commands inside a HTML tag' do
- msg = "Hello\r\n<div>\r\nThis is some text\r\n/close\r\n/assign @user\r\n</div>\r\n\r\nWorld"
- expected = msg.delete("\r")
- msg, commands = extractor.extract_commands(msg)
-
- expect(commands).to be_empty
- expect(msg).to eq expected
- end
- end
-end
diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
new file mode 100644
index 00000000000..4de50d4a8bb
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::IssueNew, service: true do
+ describe '#execute' do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:regex_match) { described_class.match("issue create bird is the word") }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'without description' do
+ it 'creates the issue' do
+ expect { subject }.to change { project.issues.count }.by(1)
+
+ expect(subject[:response_type]).to be(:in_channel)
+ end
+ end
+
+ context 'with description' do
+ let(:description) { "Surfin bird" }
+ let(:regex_match) { described_class.match("issue create bird is the word\n#{description}") }
+
+ it 'creates the issue with description' do
+ subject
+
+ expect(Issue.last.description).to eq(description)
+ end
+ end
+
+ context "with more newlines between the title and the description" do
+ let(:description) { "Surfin bird" }
+ let(:regex_match) { described_class.match("issue create bird is the word\n\n#{description}\n") }
+
+ it 'creates the issue' do
+ expect { subject }.to change { project.issues.count }.by(1)
+ end
+ end
+
+ context 'issue cannot be created' do
+ let!(:issue) { create(:issue, project: project, title: 'bird is the word') }
+ let(:regex_match) { described_class.match("issue create #{'a' * 512}}") }
+
+ it 'displays the errors' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("- Title is too long")
+ end
+ end
+ end
+
+ describe '.match' do
+ it 'matches the title without description' do
+ match = described_class.match("issue create my title")
+
+ expect(match[:title]).to eq('my title')
+ expect(match[:description]).to eq("")
+ end
+
+ it 'matches the title with description' do
+ match = described_class.match("issue create my title\n\ndescription")
+
+ expect(match[:title]).to eq('my title')
+ expect(match[:description]).to eq('description')
+ end
+
+ it 'matches the alias new' do
+ match = described_class.match("issue new my title")
+
+ expect(match).not_to be_nil
+ expect(match[:title]).to eq('my title')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
new file mode 100644
index 00000000000..06fff0afc50
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::IssueSearch, service: true do
+ describe '#execute' do
+ let!(:issue) { create(:issue, project: project, title: 'find me') }
+ let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
+ let(:project) { create(:empty_project) }
+ let(:user) { issue.author }
+ let(:regex_match) { described_class.match("issue search find") }
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'when the user has no access' do
+ it 'only returns the open issues' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("not found")
+ end
+ end
+
+ context 'the user has access' do
+ before do
+ project.team << [user, :master]
+ end
+
+ it 'returns all results' do
+ expect(subject).to have_key(:attachments)
+ expect(subject[:text]).to eq("Here are the 2 issues I found:")
+ end
+ end
+
+ context 'without hits on the query' do
+ it 'returns an empty collection' do
+ expect(subject[:text]).to match("not found")
+ end
+ end
+ end
+
+ describe 'self.match' do
+ let(:query) { "my search keywords" }
+ it 'matches the query' do
+ match = described_class.match("issue search #{query}")
+
+ expect(match[:query]).to eq(query)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
new file mode 100644
index 00000000000..1899f664ccd
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::IssueShow, service: true do
+ describe '#execute' do
+ let(:issue) { create(:issue, project: project) }
+ let(:project) { create(:empty_project) }
+ let(:user) { issue.author }
+ let(:regex_match) { described_class.match("issue show #{issue.iid}") }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'the issue exists' do
+ let(:title) { subject[:attachments].first[:title] }
+
+ it 'returns the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(title).to start_with(issue.title)
+ end
+
+ context 'when its reference is given' do
+ let(:regex_match) { described_class.match("issue show #{issue.to_reference}") }
+
+ it 'shows the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(title).to start_with(issue.title)
+ end
+ end
+ end
+
+ context 'the issue does not exist' do
+ let(:regex_match) { described_class.match("issue show 2343242") }
+
+ it "returns not found" do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("not found")
+ end
+ end
+ end
+
+ describe '.match' do
+ it 'matches the iid' do
+ match = described_class.match("issue show 123")
+
+ expect(match[:iid]).to eq("123")
+ end
+
+ it 'accepts a reference' do
+ match = described_class.match("issue show #{Issue.reference_prefix}123")
+
+ expect(match[:iid]).to eq("123")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb
new file mode 100644
index 00000000000..ef3d217f7be
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Presenters::Access do
+ describe '#access_denied' do
+ subject { described_class.new.access_denied }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'displays an error message' do
+ expect(subject[:text]).to match("is not allowed")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ describe '#not_found' do
+ subject { described_class.new.not_found }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user the resource was not found' do
+ expect(subject[:text]).to match("not found!")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ describe '#authorize' do
+ context 'with an authorization URL' do
+ subject { described_class.new('http://authorize.me').authorize }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user to authorize' do
+ expect(subject[:text]).to match("connect your GitLab account")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ context 'without authorization url' do
+ subject { described_class.new.authorize }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user to authorize' do
+ expect(subject[:text]).to match("Couldn't identify you")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
new file mode 100644
index 00000000000..dee3c77db27
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Presenters::Deploy do
+ let(:build) { create(:ci_build) }
+
+ describe '#present' do
+ subject { described_class.new(build).present('staging', 'prod') }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'messages the channel of the deploy' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with("Deployment started from staging to prod")
+ end
+ end
+
+ describe '#no_actions' do
+ subject { described_class.new(nil).no_actions }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'tells the user there is no action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
+ end
+ end
+
+ describe '#too_many_actions' do
+ subject { described_class.new([]).too_many_actions }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'tells the user there is no action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("Too many actions defined")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb
new file mode 100644
index 00000000000..7f81ebb47db
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Presenters::IssueNew do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:attachment) { subject[:attachments].first }
+
+ subject { described_class.new(issue).present }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'shows the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject).to have_key(:attachments)
+ expect(attachment[:title]).to start_with(issue.title)
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb
new file mode 100644
index 00000000000..7e57a0addcb
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Presenters::IssueSearch do
+ let(:project) { create(:empty_project) }
+ let(:message) { subject[:text] }
+
+ before do
+ create_list(:issue, 2, project: project)
+ end
+
+ subject { described_class.new(project.issues).present }
+
+ it 'formats the message correct' do
+ is_expected.to have_key(:text)
+ is_expected.to have_key(:status)
+ is_expected.to have_key(:response_type)
+ is_expected.to have_key(:attachments)
+ end
+
+ it 'shows a list of results' do
+ expect(subject[:response_type]).to be(:ephemeral)
+
+ expect(message).to start_with("Here are the 2 issues I found")
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb
new file mode 100644
index 00000000000..2a6ed860737
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Gitlab::SlashCommands::Presenters::IssueShow do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:attachment) { subject[:attachments].first }
+
+ subject { described_class.new(issue).present }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'shows the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject).to have_key(:attachments)
+ expect(attachment[:title]).to start_with(issue.title)
+ end
+
+ context 'with upvotes' do
+ before do
+ create(:award_emoji, :upvote, awardable: issue)
+ end
+
+ it 'shows the upvote count' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(attachment[:text]).to start_with("**Open** ยท :+1: 1")
+ end
+ end
+
+ context 'with labels' do
+ let(:label) { create(:label, project: project, title: 'mep') }
+ let(:label1) { create(:label, project: project, title: 'mop') }
+
+ before do
+ issue.labels << [label, label1]
+ end
+
+ it 'shows the labels' do
+ labels = attachment[:fields].find { |f| f[:title] == 'Labels' }
+
+ expect(labels[:value]).to eq("mep, mop")
+ end
+ end
+
+ context 'confidential issue' do
+ let(:issue) { create(:issue, project: project) }
+
+ it 'shows an ephemeral response' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(attachment[:text]).to start_with("**Open**")
+ end
+ end
+end