From 8bf52a4ae3aebc8c58f51cff696e99ecafe9c7c8 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Fri, 16 Dec 2016 02:12:21 -0200 Subject: Show directory hierarchy when listing wiki pages --- spec/models/wiki_page_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 5c34b1b0a30..25e7b517fe6 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -7,6 +7,23 @@ describe WikiPage, models: true do subject { WikiPage.new(wiki) } + describe '::group_by_directory' do + context 'when there are no pages' do + it 'returns an empty hash' do + end + end + + context 'when there are pages' do + let!(:page_1) { create_page('page_1', 'content') } + let!(:page_2) { create_page('directory/page_2', 'content') } + let(:pages) { [page_1, page_2] } + + xit 'returns a hash in which keys are directories and values are their pages' do + expected_grouped_pages = { 'root' => [page_1], 'directory' => [page_2] } + end + end + end + describe "#initialize" do context "when initialized with an existing gollum page" do before do -- cgit v1.2.1 From 083442bc716d7e69cbb9e7852159b0f3ba9a4610 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Sat, 17 Dec 2016 16:38:26 -0200 Subject: Add specs for WikiPage.group_by_directory --- spec/models/wiki_page_spec.rb | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 25e7b517fe6..595d4a621c1 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -7,19 +7,37 @@ describe WikiPage, models: true do subject { WikiPage.new(wiki) } - describe '::group_by_directory' do + describe '.group_by_directory' do context 'when there are no pages' do it 'returns an empty hash' do + expect(WikiPage.group_by_directory(nil)).to eq({}) + expect(WikiPage.group_by_directory([])).to eq({}) end end context 'when there are pages' do - let!(:page_1) { create_page('page_1', 'content') } - let!(:page_2) { create_page('directory/page_2', 'content') } - let(:pages) { [page_1, page_2] } + before do + create_page('page_1', 'content') + create_page('dir_1/page_2', 'content') + create_page('dir_1/dir_2/page_3', 'content') + end + + it 'returns a hash in which keys are directories and values are their pages' do + page_1 = wiki.find_page('page_1') + page_2 = wiki.find_page('dir_1/page_2') + page_3 = wiki.find_page('dir_1/dir_2/page_3') + expected_grouped_pages = { + '/' => [page_1], 'dir_1' => [page_2], 'dir_1/dir_2' => [page_3] + } - xit 'returns a hash in which keys are directories and values are their pages' do - expected_grouped_pages = { 'root' => [page_1], 'directory' => [page_2] } + grouped_pages = WikiPage.group_by_directory(wiki.pages) + + grouped_pages.each do |dir, pages| + expected_slugs = expected_grouped_pages.fetch(dir).map(&:slug) + slugs = pages.map(&:slug) + + expect(slugs).to match_array(expected_slugs) + end end end end -- cgit v1.2.1 From 5bbe6559917e1e64cdb047b6235715e2a7f002f2 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Sun, 18 Dec 2016 21:22:20 -0200 Subject: Add component to show the full path of a wiki page when viewing its content --- spec/models/wiki_page_spec.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 595d4a621c1..c40a89b9dfb 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -224,6 +224,46 @@ describe WikiPage, models: true do end end + describe '#directory' do + context 'when the page is at the root directory' do + it 'returns /' do + create_page('file', 'content') + page = wiki.find_page('file') + + expect(page.directory).to eq('/') + end + end + + context 'when the page is inside an actual directory' do + it 'returns the full directory hierarchy' do + create_page('dir_1/dir_1_1/file', 'content') + page = wiki.find_page('dir_1/dir_1_1/file') + + expect(page.directory).to eq('dir_1/dir_1_1') + end + end + end + + describe '#full_path' do + context 'when the page is at the root directory' do + it 'returns /filename.fileextension' do + create_page('file', 'content') + page = wiki.find_page('file') + + expect(page.full_path).to eq('/file.md') + end + end + + context 'when the page is inside an actual directory' do + it 'returns /directory/filename.fileextension' do + create_page('dir/file', 'content') + page = wiki.find_page('dir/file') + + expect(page.full_path).to eq('/dir/file.md') + end + end + end + describe '#historical?' do before do create_page('Update', 'content') -- cgit v1.2.1 From 5607bb8f0921cbfa4586bb7b92acb6666a65b4e2 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Sun, 18 Dec 2016 21:37:10 -0200 Subject: Change WikiPage#directory to always start a directory hierarchy with '/' --- spec/models/wiki_page_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index c40a89b9dfb..91d5fccce60 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -27,7 +27,7 @@ describe WikiPage, models: true do page_2 = wiki.find_page('dir_1/page_2') page_3 = wiki.find_page('dir_1/dir_2/page_3') expected_grouped_pages = { - '/' => [page_1], 'dir_1' => [page_2], 'dir_1/dir_2' => [page_3] + '/' => [page_1], '/dir_1' => [page_2], '/dir_1/dir_2' => [page_3] } grouped_pages = WikiPage.group_by_directory(wiki.pages) @@ -239,7 +239,7 @@ describe WikiPage, models: true do create_page('dir_1/dir_1_1/file', 'content') page = wiki.find_page('dir_1/dir_1_1/file') - expect(page.directory).to eq('dir_1/dir_1_1') + expect(page.directory).to eq('/dir_1/dir_1_1') end end end -- cgit v1.2.1 From f25344e36e9c1b0d0df2211b82b26c6515e96c31 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 19 Dec 2016 02:34:35 -0200 Subject: Change WikiPage.group_by_directory to order by directory and file alphabetical order --- spec/models/wiki_page_spec.rb | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 91d5fccce60..374849e1932 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -17,17 +17,22 @@ describe WikiPage, models: true do context 'when there are pages' do before do - create_page('page_1', 'content') + create_page('dir_1/dir_1_1/page_3', 'content') create_page('dir_1/page_2', 'content') - create_page('dir_1/dir_2/page_3', 'content') + create_page('dir_2/page_5', 'content') + create_page('dir_2/page_4', 'content') + create_page('page_1', 'content') end it 'returns a hash in which keys are directories and values are their pages' do page_1 = wiki.find_page('page_1') page_2 = wiki.find_page('dir_1/page_2') - page_3 = wiki.find_page('dir_1/dir_2/page_3') + page_3 = wiki.find_page('dir_1/dir_1_1/page_3') + page_4 = wiki.find_page('dir_2/page_4') + page_5 = wiki.find_page('dir_2/page_5') expected_grouped_pages = { - '/' => [page_1], '/dir_1' => [page_2], '/dir_1/dir_2' => [page_3] + '/' => [page_1], '/dir_1' => [page_2], '/dir_1/dir_1_1' => [page_3], + '/dir_2' => [page_4, page_5] } grouped_pages = WikiPage.group_by_directory(wiki.pages) @@ -39,6 +44,23 @@ describe WikiPage, models: true do expect(slugs).to match_array(expected_slugs) end end + + it 'returns a hash in which keys (directories) are sorted by alphabetical position' do + expected_ordered_directories = ['/', '/dir_1', '/dir_1/dir_1_1', '/dir_2'] + + grouped_pages = WikiPage.group_by_directory(wiki.pages) + + expect(grouped_pages.keys).to eq(expected_ordered_directories) + end + + it 'returns a hash in which values (pages) are sorted by alphabetical position' do + expected_ordered_page_slugs = ['dir_2/page_4', 'dir_2/page_5'] + + grouped_pages = WikiPage.group_by_directory(wiki.pages) + + dir_2_page_slugs = grouped_pages.fetch('/dir_2').map(&:slug) + expect(dir_2_page_slugs).to eq(expected_ordered_page_slugs) + end end end -- cgit v1.2.1 From b361a67fb019e5c7f5361bbd3c43545da3ab0288 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 26 Dec 2016 13:07:40 -0200 Subject: Add model WikiDirectory --- spec/factories/wiki_directories.rb | 6 +++++ spec/models/wiki_directory_spec.rb | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 spec/factories/wiki_directories.rb create mode 100644 spec/models/wiki_directory_spec.rb (limited to 'spec') diff --git a/spec/factories/wiki_directories.rb b/spec/factories/wiki_directories.rb new file mode 100644 index 00000000000..3f3c864ac2b --- /dev/null +++ b/spec/factories/wiki_directories.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :wiki_directory do + slug '/path_up_to/dir' + initialize_with { new(slug) } + end +end diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb new file mode 100644 index 00000000000..8362a285c54 --- /dev/null +++ b/spec/models/wiki_directory_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +RSpec.describe WikiDirectory, models: true do + describe 'validations' do + subject { build(:wiki_directory) } + + it { is_expected.to validate_presence_of(:slug) } + end + + describe '#initialize' do + context 'when there are pages and directories' do + let(:pages) { [build(:wiki_page)] } + let(:other_directories) { [build(:wiki_directory)] } + let(:directory) { WikiDirectory.new('/path_up_to/dir', pages, other_directories) } + + it 'sets the slug attribute' do + expect(directory.slug).to eq('/path_up_to/dir') + end + + it 'sets the pages attribute' do + expect(directory.pages).to eq(pages) + end + + it 'sets the directories attribute' do + expect(directory.directories).to eq(other_directories) + end + end + + context 'when there are no pages or directories' do + let(:directory) { WikiDirectory.new('/path_up_to/dir') } + + it 'sets the slug attribute' do + expect(directory.slug).to eq('/path_up_to/dir') + end + + it 'sets the pages attribute to an empty array' do + expect(directory.pages).to eq([]) + end + + it 'sets the directories attribute to an empty array' do + expect(directory.directories).to eq([]) + end + end + end +end -- cgit v1.2.1 From c8a1e9682656b6b3ec714e38459e089df2ee106c Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 26 Dec 2016 20:12:15 -0200 Subject: Change WikiPage.group_by_directory to use WikiDirectory --- spec/models/wiki_page_spec.rb | 72 +++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 374849e1932..9eb94cb028d 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -9,9 +9,9 @@ describe WikiPage, models: true do describe '.group_by_directory' do context 'when there are no pages' do - it 'returns an empty hash' do - expect(WikiPage.group_by_directory(nil)).to eq({}) - expect(WikiPage.group_by_directory([])).to eq({}) + it 'returns an empty array' do + expect(WikiPage.group_by_directory(nil)).to eq([]) + expect(WikiPage.group_by_directory([])).to eq([]) end end @@ -23,43 +23,47 @@ describe WikiPage, models: true do create_page('dir_2/page_4', 'content') create_page('page_1', 'content') end + let(:page_1) { wiki.find_page('page_1') } + let(:dir_1) do + WikiDirectory.new('dir_1', [wiki.find_page('dir_1/page_2')]) + end + let(:dir_1_1) do + WikiDirectory.new('dir_1/dir_1_1', [wiki.find_page('dir_1/dir_1_1/page_3')]) + end + let(:dir_2) do + pages = [wiki.find_page('dir_2/page_5'), + wiki.find_page('dir_2/page_4')] + WikiDirectory.new('dir_2', pages) + end - it 'returns a hash in which keys are directories and values are their pages' do - page_1 = wiki.find_page('page_1') - page_2 = wiki.find_page('dir_1/page_2') - page_3 = wiki.find_page('dir_1/dir_1_1/page_3') - page_4 = wiki.find_page('dir_2/page_4') - page_5 = wiki.find_page('dir_2/page_5') - expected_grouped_pages = { - '/' => [page_1], '/dir_1' => [page_2], '/dir_1/dir_1_1' => [page_3], - '/dir_2' => [page_4, page_5] - } + it 'returns an array with pages and directories' do + expected_grouped_entries = [page_1, dir_1, dir_1_1, dir_2] - grouped_pages = WikiPage.group_by_directory(wiki.pages) + grouped_entries = WikiPage.group_by_directory(wiki.pages) - grouped_pages.each do |dir, pages| - expected_slugs = expected_grouped_pages.fetch(dir).map(&:slug) - slugs = pages.map(&:slug) + grouped_entries.each_with_index do |page_or_dir, i| + expected_page_or_dir = expected_grouped_entries[i] + expected_slugs = get_slugs(expected_page_or_dir) + slugs = get_slugs(page_or_dir) expect(slugs).to match_array(expected_slugs) end end - it 'returns a hash in which keys (directories) are sorted by alphabetical position' do - expected_ordered_directories = ['/', '/dir_1', '/dir_1/dir_1_1', '/dir_2'] - - grouped_pages = WikiPage.group_by_directory(wiki.pages) - - expect(grouped_pages.keys).to eq(expected_ordered_directories) - end - - it 'returns a hash in which values (pages) are sorted by alphabetical position' do - expected_ordered_page_slugs = ['dir_2/page_4', 'dir_2/page_5'] + it 'returns an array sorted by alphabetical position' do + # Directories and pages within directories are sorted alphabetically. + # Pages at root come before everything. + expected_order = ['page_1', 'dir_1/page_2', 'dir_1/dir_1_1/page_3', + 'dir_2/page_4', 'dir_2/page_5'] - grouped_pages = WikiPage.group_by_directory(wiki.pages) + grouped_entries = WikiPage.group_by_directory(wiki.pages) - dir_2_page_slugs = grouped_pages.fetch('/dir_2').map(&:slug) - expect(dir_2_page_slugs).to eq(expected_ordered_page_slugs) + actual_order = + grouped_entries.map do |page_or_dir| + get_slugs(page_or_dir) + end. + flatten + expect(actual_order).to eq(expected_order) end end end @@ -336,4 +340,12 @@ describe WikiPage, models: true do page = wiki.wiki.paged(title) wiki.wiki.delete_page(page, commit_details) end + + def get_slugs(page_or_dir) + if page_or_dir.is_a? WikiPage + [page_or_dir.slug] + else + page_or_dir.pages.present? ? page_or_dir.pages.map(&:slug) : [] + end + end end -- cgit v1.2.1 From 84735186a8ae73a722715f286653ccd71e7e48e8 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 26 Dec 2016 23:51:34 -0200 Subject: Add WikiPage#to_partial_path --- spec/models/wiki_page_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 9eb94cb028d..11efd0415d9 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -322,6 +322,14 @@ describe WikiPage, models: true do end end + describe '#to_partial_path' do + it 'returns the relative path to the partial to be used' do + page = build(:wiki_page) + + expect(page.to_partial_path).to eq('projects/wikis/wiki_page') + end + end + private def remove_temp_repo(path) -- cgit v1.2.1 From 7bd68ae0799a982a4113de3480bef0d51ecb2f1c Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 26 Dec 2016 23:52:26 -0200 Subject: Add WikiDirectory#to_partial_path --- spec/models/wiki_directory_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb index 8362a285c54..fac70f8d3c7 100644 --- a/spec/models/wiki_directory_spec.rb +++ b/spec/models/wiki_directory_spec.rb @@ -42,4 +42,12 @@ RSpec.describe WikiDirectory, models: true do end end end + + describe '#to_partial_path' do + it 'returns the relative path to the partial to be used' do + directory = build(:wiki_directory) + + expect(directory.to_partial_path).to eq('projects/wikis/wiki_directory') + end + end end -- cgit v1.2.1 From 94dcadd62ac66cc5c52579ae9c288314bbca0c20 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Tue, 27 Dec 2016 01:44:03 -0200 Subject: Add a breadcrumb at projects/wikis/show.html.haml --- spec/helpers/wiki_helper_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/helpers/wiki_helper_spec.rb (limited to 'spec') diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb new file mode 100644 index 00000000000..92c6f27a867 --- /dev/null +++ b/spec/helpers/wiki_helper_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe WikiHelper do + describe '#breadcrumb' do + context 'when the page is at the root level' do + it 'returns the capitalized page name' do + slug = 'page-name' + + expect(helper.breadcrumb(slug)).to eq('Page name') + end + end + + context 'when the page is inside a directory' do + it 'returns the capitalized name of each directory and of the page itself' do + slug = 'dir_1/page-name' + + expect(helper.breadcrumb(slug)).to eq('Dir_1 / Page name') + end + end + end +end -- cgit v1.2.1 From 104bfa2a3187aefebd4a53be1ad14600dc7781e9 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Tue, 27 Dec 2016 01:52:50 -0200 Subject: Remove WikiPage#full_path --- spec/models/wiki_page_spec.rb | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 11efd0415d9..482f98e22f1 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -270,26 +270,6 @@ describe WikiPage, models: true do end end - describe '#full_path' do - context 'when the page is at the root directory' do - it 'returns /filename.fileextension' do - create_page('file', 'content') - page = wiki.find_page('file') - - expect(page.full_path).to eq('/file.md') - end - end - - context 'when the page is inside an actual directory' do - it 'returns /directory/filename.fileextension' do - create_page('dir/file', 'content') - page = wiki.find_page('dir/file') - - expect(page.full_path).to eq('/dir/file.md') - end - end - end - describe '#historical?' do before do create_page('Update', 'content') -- cgit v1.2.1 From d2b3fe45af8d458b935b3bbfc1558e21c1476d0a Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Tue, 27 Dec 2016 02:05:53 -0200 Subject: Change WikiPage#directory --- spec/models/wiki_page_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 482f98e22f1..109a0499090 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -252,11 +252,11 @@ describe WikiPage, models: true do describe '#directory' do context 'when the page is at the root directory' do - it 'returns /' do + it 'returns an empty string' do create_page('file', 'content') page = wiki.find_page('file') - expect(page.directory).to eq('/') + expect(page.directory).to eq('') end end @@ -265,7 +265,7 @@ describe WikiPage, models: true do create_page('dir_1/dir_1_1/file', 'content') page = wiki.find_page('dir_1/dir_1_1/file') - expect(page.directory).to eq('/dir_1/dir_1_1') + expect(page.directory).to eq('dir_1/dir_1_1') end end end -- cgit v1.2.1 From 48417893d7456dc0d46b0a514a2326cc8ce6076f Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Sat, 31 Dec 2016 17:27:03 -0200 Subject: Remove directories as one of the attributes of WikiDirectory --- spec/models/wiki_directory_spec.rb | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb index fac70f8d3c7..1caaa557085 100644 --- a/spec/models/wiki_directory_spec.rb +++ b/spec/models/wiki_directory_spec.rb @@ -8,10 +8,9 @@ RSpec.describe WikiDirectory, models: true do end describe '#initialize' do - context 'when there are pages and directories' do + context 'when there are pages' do let(:pages) { [build(:wiki_page)] } - let(:other_directories) { [build(:wiki_directory)] } - let(:directory) { WikiDirectory.new('/path_up_to/dir', pages, other_directories) } + let(:directory) { WikiDirectory.new('/path_up_to/dir', pages) } it 'sets the slug attribute' do expect(directory.slug).to eq('/path_up_to/dir') @@ -20,13 +19,9 @@ RSpec.describe WikiDirectory, models: true do it 'sets the pages attribute' do expect(directory.pages).to eq(pages) end - - it 'sets the directories attribute' do - expect(directory.directories).to eq(other_directories) - end end - context 'when there are no pages or directories' do + context 'when there are no pages' do let(:directory) { WikiDirectory.new('/path_up_to/dir') } it 'sets the slug attribute' do @@ -36,10 +31,6 @@ RSpec.describe WikiDirectory, models: true do it 'sets the pages attribute to an empty array' do expect(directory.pages).to eq([]) end - - it 'sets the directories attribute to an empty array' do - expect(directory.directories).to eq([]) - end end end -- cgit v1.2.1 From 7a109402a866db1c84ef9af1c14e148ec944aa22 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 20 Jan 2017 21:57:01 +0800 Subject: Prefer service object over after_save hook Closes #26921 --- spec/models/ci/runner_spec.rb | 2 +- spec/services/ci/update_runner_service_spec.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 spec/services/ci/update_runner_service_spec.rb (limited to 'spec') diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 2b856ca7af7..7b993a454b7 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -291,7 +291,7 @@ describe Ci::Runner, models: true do let!(:last_update) { runner.ensure_runner_queue_value } before do - runner.update(description: 'new runner') + Ci::UpdateRunnerService.new(runner).update(description: 'new runner') end it 'sets a new last_update value' do diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb new file mode 100644 index 00000000000..8429881dd15 --- /dev/null +++ b/spec/services/ci/update_runner_service_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe Ci::UpdateRunnerService, services: true do + let(:runner) { create(:ci_runner) } + + describe '#update' do + before do + allow(runner).to receive(:tick_runner_queue) + + described_class.new(runner).update(description: 'new runner') + end + + it 'updates the runner and ticking the queue' do + expect(runner.description).to eq('new runner') + expect(runner).to have_received(:tick_runner_queue) + end + end +end -- cgit v1.2.1 From 7a4d723e6ba287fe792dca0a8ddc3d8a77b1876c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Sat, 21 Jan 2017 02:38:58 +0800 Subject: Remove the key from the queue when runner is deleted --- spec/models/ci/runner_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 7b993a454b7..6283673d7ae 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -319,6 +319,25 @@ describe Ci::Runner, models: true do end end + describe '#destroy' do + let(:runner) { create(:ci_runner) } + + context 'when there is a tick in the queue' do + let!(:queue_key) { runner.send(:runner_queue_key) } + + before do + runner.tick_runner_queue + runner.destroy + end + + it 'cleans up the queue' do + Gitlab::Redis.with do |redis| + expect(redis.get(queue_key)).to be_nil + end + end + end + end + describe '.assignable_for' do let(:runner) { create(:ci_runner) } let(:project) { create(:project) } -- cgit v1.2.1 From d5fa77d53d73b9d47647443460d2ea95babb52e4 Mon Sep 17 00:00:00 2001 From: Poornima M Date: Wed, 18 Jan 2017 16:08:59 +0530 Subject: Adding links to user & build in Chat Notifications --- spec/factories/ci/builds.rb | 12 ++++++++++ spec/factories/commits.rb | 10 ++++++++ spec/lib/gitlab/data_builder/build_spec.rb | 26 ++++++++++++++++++++ .../chat_message/build_message_spec.rb | 28 ++++++++++++++++++---- 4 files changed, 72 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 0397d5d4001..e4cac0e1058 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -128,5 +128,17 @@ FactoryGirl.define do build.save! end end + + trait :with_commit do + after(:build) do |build| + allow(build).to receive(:commit).and_return build(:commit, :without_author) + end + end + + trait :with_commit_and_author do + after(:build) do |build| + allow(build).to receive(:commit).and_return build(:commit) + end + end end end diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb index ac6eb0a7897..89e260cf65b 100644 --- a/spec/factories/commits.rb +++ b/spec/factories/commits.rb @@ -8,5 +8,15 @@ FactoryGirl.define do initialize_with do new(git_commit, project) end + + after(:build) do |commit| + allow(commit).to receive(:author).and_return build(:author) + end + + trait :without_author do + after(:build) do |commit| + allow(commit).to receive(:author).and_return nil + end + end end end diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb index 6c71e98066b..91c43f2bdc0 100644 --- a/spec/lib/gitlab/data_builder/build_spec.rb +++ b/spec/lib/gitlab/data_builder/build_spec.rb @@ -17,5 +17,31 @@ describe Gitlab::DataBuilder::Build do it { expect(data[:build_allow_failure]).to eq(false) } it { expect(data[:project_id]).to eq(build.project.id) } it { expect(data[:project_name]).to eq(build.project.name_with_namespace) } + + context 'commit author_url' do + context 'when no commit present' do + let(:build) { create(:ci_build) } + + it 'sets to mailing address of git_author_email' do + expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}") + end + end + + context 'when commit present but has no author' do + let(:build) { create(:ci_build, :with_commit) } + + it 'sets to mailing address of git_author_email' do + expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}") + end + end + + context 'when commit and author are present' do + let(:build) { create(:ci_build, :with_commit_and_author) } + + it 'sets to GitLab user url' do + expect(data[:commit][:author_url]).to eq(Gitlab::Routing.url_helpers.user_url(username: build.commit.author.username)) + end + end + end end end diff --git a/spec/models/project_services/chat_message/build_message_spec.rb b/spec/models/project_services/chat_message/build_message_spec.rb index 50ad5013df9..3bd7ec18ae0 100644 --- a/spec/models/project_services/chat_message/build_message_spec.rb +++ b/spec/models/project_services/chat_message/build_message_spec.rb @@ -11,21 +11,28 @@ describe ChatMessage::BuildMessage do project_name: 'project_name', project_url: 'http://example.gitlab.com', + build_id: 1, + build_name: build_name, + build_stage: stage, commit: { status: status, author_name: 'hacker', + author_url: 'http://example.gitlab.com/hacker', duration: duration, }, } end let(:message) { build_message } + let(:stage) { 'test' } + let(:status) { 'success' } + let(:build_name) { 'rspec' } + let(:duration) { 10 } context 'build succeeded' do let(:status) { 'success' } let(:color) { 'good' } - let(:duration) { 10 } let(:message) { build_message('passed') } it 'returns a message with information about succeeded build' do @@ -38,7 +45,6 @@ describe ChatMessage::BuildMessage do context 'build failed' do let(:status) { 'failed' } let(:color) { 'danger' } - let(:duration) { 10 } it 'returns a message with information about failed build' do expect(subject.pretext).to be_empty @@ -47,11 +53,25 @@ describe ChatMessage::BuildMessage do end end - def build_message(status_text = status) + it 'returns a message with information on build' do + expect(subject.fallback).to include("on build ") + end + + it 'returns a message with stage name' do + expect(subject.fallback).to include("of stage #{stage}") + end + + it 'returns a message with link to author' do + expect(subject.fallback).to include("by ") + end + + def build_message(status_text = status, stage_text = stage, build_text = build_name) ":" \ " Commit " \ " of branch" \ - " by hacker #{status_text} in #{duration} #{'second'.pluralize(duration)}" + " by #{status_text}" \ + " on build " \ + " of stage #{stage_text} in #{duration} #{'second'.pluralize(duration)}" end end -- cgit v1.2.1 From 683097666aa01ef6a5b490be67a4a0d9733152e3 Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Mon, 30 Jan 2017 01:07:31 -0200 Subject: Add WikiPage.unhyphenize --- spec/models/wiki_page_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 109a0499090..579ebac7afb 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -68,6 +68,14 @@ describe WikiPage, models: true do end end + describe '.unhyphenize' do + it 'removes hyphens from a name' do + name = 'a-name--with-hyphens' + + expect(WikiPage.unhyphenize(name)).to eq('a name with hyphens') + end + end + describe "#initialize" do context "when initialized with an existing gollum page" do before do -- cgit v1.2.1 From 67cec150cc5a991846a45dffdd699efbb1b65187 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 27 Jan 2017 01:31:42 -0800 Subject: Add controller spec for Profiles::NotificationsController --- .../profiles/notifications_controller_spec.rb | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 spec/controllers/profiles/notifications_controller_spec.rb (limited to 'spec') diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb new file mode 100644 index 00000000000..55acc445e43 --- /dev/null +++ b/spec/controllers/profiles/notifications_controller_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe Profiles::NotificationsController do + describe 'GET show' do + it 'renders' do + user = create_user + sign_in(user) + + get :show + expect(response).to render_template :show + end + end + + describe 'POST update' do + it 'updates only permitted attributes' do + user = create_user + sign_in(user) + + put :update, user: { notification_email: 'new@example.com', admin: true } + + user.reload + expect(user.notification_email).to eq('new@example.com') + expect(user.admin).to eq(false) + expect(controller).to set_flash[:notice].to('Notification settings saved') + end + + it 'shows an error message if the params are invalid' do + user = create_user + sign_in(user) + + put :update, user: { notification_email: '' } + + expect(user.reload.notification_email).to eq('original@example.com') + expect(controller).to set_flash[:alert].to('Failed to save new settings') + end + end + + def create_user + create(:user) do |user| + user.emails.create(email: 'original@example.com') + user.emails.create(email: 'new@example.com') + user.update(notification_email: 'original@example.com') + user.save! + end + end +end -- cgit v1.2.1 From 0a0207ea91fdbe869ac70c23178b876bcbeb3021 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 27 Jan 2017 01:31:53 -0800 Subject: Add notified_of_own_activity to permitted attributes in Profiles::NotificationsController#update --- spec/controllers/profiles/notifications_controller_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb index 55acc445e43..54324cece6c 100644 --- a/spec/controllers/profiles/notifications_controller_spec.rb +++ b/spec/controllers/profiles/notifications_controller_spec.rb @@ -16,10 +16,11 @@ describe Profiles::NotificationsController do user = create_user sign_in(user) - put :update, user: { notification_email: 'new@example.com', admin: true } + put :update, user: { notification_email: 'new@example.com', notified_of_own_activity: true, admin: true } user.reload expect(user.notification_email).to eq('new@example.com') + expect(user.notified_of_own_activity).to eq(true) expect(user.admin).to eq(false) expect(controller).to set_flash[:notice].to('Notification settings saved') end -- cgit v1.2.1 From 3e81bc7b1daec9dfda602165d7e36cf5b6a39e20 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 27 Jan 2017 01:31:57 -0800 Subject: Update NotificationService to respect User#notified_of_own_activity --- spec/services/notification_service_spec.rb | 59 ++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'spec') diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 7cf2cd9968f..839250b7d84 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -146,6 +146,16 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end + it "emails the note author if they've opted into notifications about their activity" do + add_users_with_subscription(note.project, issue) + note.author.notified_of_own_activity = true + reset_delivered_emails! + + notification.new_note(note) + + should_email(note.author) + end + it 'filters out "mentioned in" notes' do mentioned_note = SystemNoteService.cross_reference(mentioned_issue, issue, issue.author) @@ -476,6 +486,20 @@ describe NotificationService, services: true do should_not_email(issue.assignee) end + it "emails the author if they've opted into notifications about their activity" do + issue.author.notified_of_own_activity = true + + notification.new_issue(issue, issue.author) + + should_email(issue.author) + end + + it "doesn't email the author if they haven't opted into notifications about their activity" do + notification.new_issue(issue, issue.author) + + should_not_email(issue.author) + end + it "emails subscribers of the issue's labels" do user_1 = create(:user) user_2 = create(:user) @@ -665,6 +689,19 @@ describe NotificationService, services: true do should_email(subscriber_to_label_2) end + it "emails the current user if they've opted into notifications about their activity" do + subscriber_to_label_2.notified_of_own_activity = true + notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2) + + should_email(subscriber_to_label_2) + end + + it "doesn't email the current user if they haven't opted into notifications about their activity" do + notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2) + + should_not_email(subscriber_to_label_2) + end + it "doesn't send email to anyone but subscribers of the given labels" do notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) @@ -818,6 +855,20 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end + it "emails the author if they've opted into notifications about their activity" do + merge_request.author.notified_of_own_activity = true + + notification.new_merge_request(merge_request, merge_request.author) + + should_email(merge_request.author) + end + + it "doesn't email the author if they haven't opted into notifications about their activity" do + notification.new_merge_request(merge_request, merge_request.author) + + should_not_email(merge_request.author) + end + it "emails subscribers of the merge request's labels" do user_1 = create(:user) user_2 = create(:user) @@ -1013,6 +1064,14 @@ describe NotificationService, services: true do should_not_email(@u_watcher) end + it "notifies the merger when merge_when_build_succeeds is false but they've opted into notifications about their activity" do + merge_request.merge_when_build_succeeds = false + @u_watcher.notified_of_own_activity = true + notification.merge_mr(merge_request, @u_watcher) + + should_email(@u_watcher) + end + it_behaves_like 'participating notifications' do let(:participant) { create(:user, username: 'user-participant') } let(:issuable) { merge_request } -- cgit v1.2.1 From 530d0fda7b97a9a3d8836a36b02e50bc5d408464 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 27 Jan 2017 01:32:00 -0800 Subject: Add checkbox in UI to opt into receiving notifications about your activity --- .../user_changes_notified_of_own_activity_spec.rb | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 spec/features/profiles/user_changes_notified_of_own_activity_spec.rb (limited to 'spec') diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb new file mode 100644 index 00000000000..0709f32bf0c --- /dev/null +++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +feature 'Profile > Notifications > User changes notified_of_own_activity setting', feature: true, js: true do + let(:user) { create(:user) } + + before do + login_as(user) + end + + scenario 'User opts into receiving notifications about their own activity' do + visit profile_notifications_path + + expect(page).not_to have_checked_field('user[notified_of_own_activity]') + + page.find('#user_notified_of_own_activity').set(true) + + expect(page).to have_content('Notification settings saved') + expect(page).to have_checked_field('user[notified_of_own_activity]') + end + + scenario 'User opts out of receiving notifications about their own activity' do + user.update!(notified_of_own_activity: true) + visit profile_notifications_path + + expect(page).to have_checked_field('user[notified_of_own_activity]') + + page.find('#user_notified_of_own_activity').set(false) + + expect(page).to have_content('Notification settings saved') + expect(page).not_to have_checked_field('user[notified_of_own_activity]') + end +end -- cgit v1.2.1 From 946efd9fa690de68c6766cba063ff078af8699e1 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Tue, 31 Jan 2017 18:27:02 -0800 Subject: Add missing newline in Profiles::NotificationsController spec --- spec/controllers/profiles/notifications_controller_spec.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb index 54324cece6c..c056ba852f0 100644 --- a/spec/controllers/profiles/notifications_controller_spec.rb +++ b/spec/controllers/profiles/notifications_controller_spec.rb @@ -7,6 +7,7 @@ describe Profiles::NotificationsController do sign_in(user) get :show + expect(response).to render_template :show end end -- cgit v1.2.1 From 4647d13893d84dea5d0863c48a933dcc8a1ba679 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Tue, 31 Jan 2017 18:27:14 -0800 Subject: Use check and uncheck methods from Capybara DSL in user_changes_notified_of_own_activity_spec --- spec/features/profiles/user_changes_notified_of_own_activity_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb index 0709f32bf0c..e05fbb3715c 100644 --- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb +++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb @@ -12,7 +12,7 @@ feature 'Profile > Notifications > User changes notified_of_own_activity setting expect(page).not_to have_checked_field('user[notified_of_own_activity]') - page.find('#user_notified_of_own_activity').set(true) + check 'user[notified_of_own_activity]' expect(page).to have_content('Notification settings saved') expect(page).to have_checked_field('user[notified_of_own_activity]') @@ -24,7 +24,7 @@ feature 'Profile > Notifications > User changes notified_of_own_activity setting expect(page).to have_checked_field('user[notified_of_own_activity]') - page.find('#user_notified_of_own_activity').set(false) + uncheck 'user[notified_of_own_activity]' expect(page).to have_content('Notification settings saved') expect(page).not_to have_checked_field('user[notified_of_own_activity]') -- cgit v1.2.1 From 0e2c96e709161b35daeae2dad3aefcf9c85a75aa Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Fri, 3 Feb 2017 20:49:45 -0800 Subject: Use `let` in Profiles::NotificationsController spec --- .../profiles/notifications_controller_spec.rb | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb index c056ba852f0..58caf7999cf 100644 --- a/spec/controllers/profiles/notifications_controller_spec.rb +++ b/spec/controllers/profiles/notifications_controller_spec.rb @@ -1,9 +1,17 @@ require 'spec_helper' describe Profiles::NotificationsController do + let(:user) do + create(:user) do |user| + user.emails.create(email: 'original@example.com') + user.emails.create(email: 'new@example.com') + user.update(notification_email: 'original@example.com') + user.save! + end + end + describe 'GET show' do it 'renders' do - user = create_user sign_in(user) get :show @@ -14,7 +22,6 @@ describe Profiles::NotificationsController do describe 'POST update' do it 'updates only permitted attributes' do - user = create_user sign_in(user) put :update, user: { notification_email: 'new@example.com', notified_of_own_activity: true, admin: true } @@ -27,7 +34,6 @@ describe Profiles::NotificationsController do end it 'shows an error message if the params are invalid' do - user = create_user sign_in(user) put :update, user: { notification_email: '' } @@ -36,13 +42,4 @@ describe Profiles::NotificationsController do expect(controller).to set_flash[:alert].to('Failed to save new settings') end end - - def create_user - create(:user) do |user| - user.emails.create(email: 'original@example.com') - user.emails.create(email: 'new@example.com') - user.update(notification_email: 'original@example.com') - user.save! - end - end end -- cgit v1.2.1 From 2e54454e6165a34004678eb45de3530f26a2ae2a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 24 Nov 2016 16:12:30 +0100 Subject: Add limit to the number of events showed in cycle analytics and spec --- .../gitlab/cycle_analytics/events_query_spec.rb | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 spec/lib/gitlab/cycle_analytics/events_query_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb new file mode 100644 index 00000000000..c00e71f6672 --- /dev/null +++ b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Gitlab::CycleAnalytics::EventsQuery do + let(:max_events) { 3 } + let(:project) { create(:project) } + let(:user) { create(:user, :admin) } + let(:options) { { from: 30.days.ago } } + + let(:issue_event) do + Gitlab::CycleAnalytics::IssueEvent.new(project: project, options: options) + end + + subject { described_class.new(project: project, options: options).execute(issue_event) } + + before do + allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return(Issue.all) + stub_const('Gitlab::CycleAnalytics::EventsQuery::MAX_EVENTS', max_events) + + setup_events(count: 5) + end + + it 'limits the rows the max number' do + expect(subject.count).to eq(max_events) + end + + def setup_events(count:) + count.times do + issue = create(:issue, project: project, created_at: 2.days.ago) + milestone = create(:milestone, project: project) + + issue.update(milestone: milestone) + create_merge_request_closing_issue(issue) + end + end +end -- cgit v1.2.1 From 40bc96c902fed5af93653e1c0960125e420783e5 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 28 Nov 2016 09:16:14 +0100 Subject: fix typo [ci skip] --- spec/lib/gitlab/cycle_analytics/events_query_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb index c00e71f6672..a0da93dadee 100644 --- a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::CycleAnalytics::EventsQuery do let(:max_events) { 3 } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:user) { create(:user, :admin) } let(:options) { { from: 30.days.ago } } @@ -19,7 +19,7 @@ describe Gitlab::CycleAnalytics::EventsQuery do setup_events(count: 5) end - it 'limits the rows the max number' do + it 'limits the rows to the max number' do expect(subject.count).to eq(max_events) end -- cgit v1.2.1 From 58a5d4a9e3f662428661d00ae543c6927b3a2ff4 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 28 Nov 2016 16:09:41 +0100 Subject: user project and not empty_project as we need the repo stuff --- spec/lib/gitlab/cycle_analytics/events_query_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb index a0da93dadee..6aac2ed78d9 100644 --- a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::CycleAnalytics::EventsQuery do let(:max_events) { 3 } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user, :admin) } let(:options) { { from: 30.days.ago } } -- cgit v1.2.1 From 682e354df649c4aad7b28e6fd16aae3eccbf7e08 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 6 Feb 2017 16:28:17 +0100 Subject: add spec --- .../cycle_analytics/base_event_fetcher_spec.rb | 44 ++++++++++++++++++++++ .../gitlab/cycle_analytics/events_query_spec.rb | 35 ----------------- 2 files changed, 44 insertions(+), 35 deletions(-) create mode 100644 spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb delete mode 100644 spec/lib/gitlab/cycle_analytics/events_query_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb new file mode 100644 index 00000000000..4aac63e54e2 --- /dev/null +++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe Gitlab::CycleAnalytics::BaseEventFetcher do + let(:max_events) { 2 } + let(:project) { create(:project) } + let(:user) { create(:user, :admin) } + let(:start_time_attrs) { Issue.arel_table[:created_at] } + let(:end_time_attrs) { [Issue::Metrics.arel_table[:first_associated_with_milestone_at]] } + let(:options) { { start_time_attrs: start_time_attrs, + end_time_attrs: end_time_attrs, + from: 30.days.ago } } + + + subject do + described_class.new(project: project, + stage: :issue, + options: options).fetch + end + + before do + allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return(Issue.all) + allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:serialize) do |event| + event + end + + stub_const('Gitlab::CycleAnalytics::BaseEventFetcher::MAX_EVENTS', max_events) + + setup_events(count: 3) + end + + it 'limits the rows to the max number' do + expect(subject.count).to eq(max_events) + end + + def setup_events(count:) + count.times do + issue = create(:issue, project: project, created_at: 2.days.ago) + milestone = create(:milestone, project: project) + + issue.update(milestone: milestone) + create_merge_request_closing_issue(issue) + end + end +end diff --git a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb b/spec/lib/gitlab/cycle_analytics/events_query_spec.rb deleted file mode 100644 index 6aac2ed78d9..00000000000 --- a/spec/lib/gitlab/cycle_analytics/events_query_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -describe Gitlab::CycleAnalytics::EventsQuery do - let(:max_events) { 3 } - let(:project) { create(:project) } - let(:user) { create(:user, :admin) } - let(:options) { { from: 30.days.ago } } - - let(:issue_event) do - Gitlab::CycleAnalytics::IssueEvent.new(project: project, options: options) - end - - subject { described_class.new(project: project, options: options).execute(issue_event) } - - before do - allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return(Issue.all) - stub_const('Gitlab::CycleAnalytics::EventsQuery::MAX_EVENTS', max_events) - - setup_events(count: 5) - end - - it 'limits the rows to the max number' do - expect(subject.count).to eq(max_events) - end - - def setup_events(count:) - count.times do - issue = create(:issue, project: project, created_at: 2.days.ago) - milestone = create(:milestone, project: project) - - issue.update(milestone: milestone) - create_merge_request_closing_issue(issue) - end - end -end -- cgit v1.2.1 From 105154aeaed5dfcd643e4a6955d947e524699e45 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 7 Feb 2017 02:49:37 +0800 Subject: Just pass :services, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8664#note_22853463 --- spec/services/ci/update_runner_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb index 8429881dd15..41372476228 100644 --- a/spec/services/ci/update_runner_service_spec.rb +++ b/spec/services/ci/update_runner_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::UpdateRunnerService, services: true do +describe Ci::UpdateRunnerService, :services do let(:runner) { create(:ci_runner) } describe '#update' do -- cgit v1.2.1 From 80bc66596adee89b423d4da8cafcddf3b98c9678 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 7 Feb 2017 03:05:19 +0800 Subject: Only tick queue if anything is updated Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8664#note_22853522 --- spec/services/ci/update_runner_service_spec.rb | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb index 41372476228..e429fcfc72f 100644 --- a/spec/services/ci/update_runner_service_spec.rb +++ b/spec/services/ci/update_runner_service_spec.rb @@ -6,13 +6,36 @@ describe Ci::UpdateRunnerService, :services do describe '#update' do before do allow(runner).to receive(:tick_runner_queue) + end + + context 'with description params' do + let(:params) { { description: 'new runner' } } + + it 'updates the runner and ticking the queue' do + expect(update).to be_truthy + + runner.reload + + expect(runner).to have_received(:tick_runner_queue) + expect(runner.description).to eq('new runner') + end + end + + context 'when params are not valid' do + let(:params) { { run_untagged: false } } + + it 'does not update and give false because it is not valid' do + expect(update).to be_falsey + + runner.reload - described_class.new(runner).update(description: 'new runner') + expect(runner).not_to have_received(:tick_runner_queue) + expect(runner.run_untagged).to be_truthy + end end - it 'updates the runner and ticking the queue' do - expect(runner.description).to eq('new runner') - expect(runner).to have_received(:tick_runner_queue) + def update + described_class.new(runner).update(params) end end end -- cgit v1.2.1 From bf05c7e035459cdf554b6d651b57ab82031a6bf3 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 7 Feb 2017 09:29:34 +0100 Subject: fix spec --- spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb index 4aac63e54e2..c455cd9b942 100644 --- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb @@ -6,10 +6,11 @@ describe Gitlab::CycleAnalytics::BaseEventFetcher do let(:user) { create(:user, :admin) } let(:start_time_attrs) { Issue.arel_table[:created_at] } let(:end_time_attrs) { [Issue::Metrics.arel_table[:first_associated_with_milestone_at]] } - let(:options) { { start_time_attrs: start_time_attrs, - end_time_attrs: end_time_attrs, - from: 30.days.ago } } - + let(:options) do + { start_time_attrs: start_time_attrs, + end_time_attrs: end_time_attrs, + from: 30.days.ago } + end subject do described_class.new(project: project, -- cgit v1.2.1 From 3a23639bc04729cfdc37e4b8ebf46358c3d5a137 Mon Sep 17 00:00:00 2001 From: Ershad Kunnakkadan Date: Mon, 5 Dec 2016 17:42:22 +0530 Subject: Create directly_addressed Todos when mentioned in beginning of a line --- spec/factories/todos.rb | 4 + spec/lib/gitlab/reference_extractor_spec.rb | 75 ++++++++++ spec/services/todo_service_spec.rb | 206 +++++++++++++++++++++++++++- 3 files changed, 284 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index 275561502cd..b4e4cd97780 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -14,6 +14,10 @@ FactoryGirl.define do action { Todo::MENTIONED } end + trait :directly_addressed do + action { Todo::DIRECTLY_ADDRESSED } + end + trait :on_commit do commit_id RepoHelpers.sample_commit.id target_type "Commit" diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 6b689c41ef6..84cfd934fa0 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -42,14 +42,85 @@ describe Gitlab::ReferenceExtractor, lib: true do > @offteam }) + expect(subject.users).to match_array([]) end + describe 'directly addressed users' do + before do + @u_foo = create(:user, username: 'foo') + @u_foo2 = create(:user, username: 'foo2') + @u_foo3 = create(:user, username: 'foo3') + @u_foo4 = create(:user, username: 'foo4') + @u_foo5 = create(:user, username: 'foo5') + + @u_bar = create(:user, username: 'bar') + @u_bar2 = create(:user, username: 'bar2') + @u_bar3 = create(:user, username: 'bar3') + @u_bar4 = create(:user, username: 'bar4') + + @u_tom = create(:user, username: 'tom') + @u_tom2 = create(:user, username: 'tom2') + end + + context 'when a user is directly addressed' do + it 'accesses the user object which is mentioned in the beginning of the line' do + subject.analyze('@foo What do you think? cc: @bar, @tom') + + expect(subject.directly_addressed_users).to match_array([@u_foo]) + end + + it "doesn't access the user object if it's not mentioned in the beginning of the line" do + subject.analyze('What do you think? cc: @bar') + + expect(subject.directly_addressed_users).to be_empty + end + end + + context 'when multiple users are addressed' do + it 'accesses the user objects which are mentioned in the beginning of the line' do + subject.analyze('@foo @bar What do you think? cc: @tom') + + expect(subject.directly_addressed_users).to match_array([@u_foo, @u_bar]) + end + + it "doesn't access the user objects if they are not mentioned in the beginning of the line" do + subject.analyze('What do you think? cc: @foo @bar @tom') + + expect(subject.directly_addressed_users).to be_empty + end + end + + context 'when multiple users are addressed in different paragraphs' do + it 'accesses user objects which are mentioned in the beginning of each paragraph' do + subject.analyze <<-NOTE.strip_heredoc + @foo What do you think? cc: @tom + + - @bar can you please have a look? + + >>> + @foo2 what do you think? cc: @bar2 + >>> + + @foo3 @foo4 thank you! + + > @foo5 well done! + + 1. @bar3 Can you please check? cc: @tom2 + 2. @bar4 What do you this of this MR? + NOTE + + expect(subject.directly_addressed_users).to match_array([@u_foo, @u_foo3, @u_foo4]) + end + end + end + it 'accesses valid issue objects' do @i0 = create(:issue, project: project) @i1 = create(:issue, project: project) subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.") + expect(subject.issues).to match_array([@i0, @i1]) end @@ -58,6 +129,7 @@ describe Gitlab::ReferenceExtractor, lib: true do @m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict') subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.") + expect(subject.merge_requests).to match_array([@m1, @m0]) end @@ -67,6 +139,7 @@ describe Gitlab::ReferenceExtractor, lib: true do @l2 = create(:label) subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}") + expect(subject.labels).to match_array([@l0, @l1]) end @@ -76,6 +149,7 @@ describe Gitlab::ReferenceExtractor, lib: true do @s2 = create(:project_snippet) subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}") + expect(subject.snippets).to match_array([@s0, @s1]) end @@ -127,6 +201,7 @@ describe Gitlab::ReferenceExtractor, lib: true do it 'handles project issue references' do subject.analyze("this refers issue #{issue.to_reference(project)}") + extracted = subject.issues expect(extracted.size).to eq(1) expect(extracted).to match_array([issue]) diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 13d584a8975..4320365ab57 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -9,7 +9,9 @@ describe TodoService, services: true do let(:admin) { create(:admin) } let(:john_doe) { create(:user) } let(:project) { create(:project) } - let(:mentions) { [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') } + let(:mentions) { 'FYI: ' + [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') } + let(:directly_addressed) { [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') } + let(:directly_addressed_and_mentioned) { member.to_reference + ", what do you think? cc: " + [guest, admin].map(&:to_reference).join(' ') } let(:service) { described_class.new } before do @@ -21,8 +23,10 @@ describe TodoService, services: true do describe 'Issues' do let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } + let(:addressed_issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") } let(:unassigned_issue) { create(:issue, project: project, assignee: nil) } let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) } + let(:addressed_confident_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: directly_addressed) } describe '#new_issue' do it 'creates a todo if assigned' do @@ -52,6 +56,26 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end + it 'creates a directly addressed todo for each valid addressed user' do + service.new_issue(addressed_issue, author) + + should_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: guest, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + end + + it 'creates correct todos for each valid user based on the type of mention' do + issue.update(description: directly_addressed_and_mentioned) + + service.new_issue(issue, author) + + should_create_todo(user: member, target: issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: admin, target: issue, action: Todo::MENTIONED) + should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) + end + it 'does not create todo if user can not see the issue when issue is confidential' do service.new_issue(confidential_issue, john_doe) @@ -63,6 +87,17 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end + it 'does not create directly addressed todo if user cannot see the issue when issue is confidential' do + service.new_issue(addressed_confident_issue, john_doe) + + should_create_todo(user: assignee, target: addressed_confident_issue, author: john_doe, action: Todo::ASSIGNED) + should_create_todo(user: author, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: member, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: admin, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: guest, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: john_doe, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + end + context 'when a private group is mentioned' do let(:group) { create :group, :private } let(:project) { create :project, :private, group: group } @@ -94,12 +129,38 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end + it 'creates a todo for each valid user based on the type of mention' do + issue.update(description: directly_addressed_and_mentioned) + + service.update_issue(issue, author) + + should_create_todo(user: member, target: issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) + should_create_todo(user: admin, target: issue, action: Todo::MENTIONED) + end + + it 'creates a directly addressed todo for each valid addressed user' do + service.update_issue(addressed_issue, author) + + should_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: guest, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + end + it 'does not create a todo if user was already mentioned' do create(:todo, :mentioned, user: member, project: project, target: issue, author: author) expect { service.update_issue(issue, author) }.not_to change(member.todos, :count) end + it 'does not create a directly addressed todo if user was already mentioned or addressed' do + create(:todo, :directly_addressed, user: member, project: project, target: addressed_issue, author: author) + + expect { service.update_issue(addressed_issue, author) }.not_to change(member.todos, :count) + end + it 'does not create todo if user can not see the issue when issue is confidential' do service.update_issue(confidential_issue, john_doe) @@ -111,6 +172,17 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end + it 'does not create a directly addressed todo if user can not see the issue when issue is confidential' do + service.update_issue(addressed_confident_issue, john_doe) + + should_create_todo(user: author, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: assignee, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: member, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: admin, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: guest, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: john_doe, target: addressed_confident_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED) + end + context 'issues with a task list' do it 'does not create todo when tasks are marked as completed' do issue.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}") @@ -125,6 +197,19 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end + it 'does not create directly addressed todo when tasks are marked as completed' do + addressed_issue.update(description: "#{directly_addressed}\n- [x] Task 1\n- [x] Task 2\n") + + service.update_issue(addressed_issue, author) + + should_not_create_todo(user: admin, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: assignee, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: author, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: john_doe, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_issue, action: Todo::DIRECTLY_ADDRESSED) + end + it 'does not raise an error when description not change' do issue.update(title: 'Sample') @@ -244,8 +329,11 @@ describe TodoService, services: true do let!(:second_todo) { create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author) } let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) } let(:note) { create(:note, project: project, noteable: issue, author: john_doe, note: mentions) } + let(:addressed_note) { create(:note, project: project, noteable: issue, author: john_doe, note: directly_addressed) } let(:note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: mentions) } + let(:addressed_note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: directly_addressed) } let(:note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project, note: mentions) } + let(:addressed_note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project, note: directly_addressed) } let(:note_on_project_snippet) { create(:note_on_project_snippet, project: project, author: john_doe, note: mentions) } let(:system_note) { create(:system_note, project: project, noteable: issue) } @@ -276,6 +364,26 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) end + it 'creates a todo for each valid user based on the type of mention' do + note.update(note: directly_addressed_and_mentioned) + + service.new_note(note, john_doe) + + should_create_todo(user: member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: note) + should_create_todo(user: admin, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) + should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) + end + + it 'creates a directly addressed todo for each valid addressed user' do + service.new_note(addressed_note, john_doe) + + should_create_todo(user: member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note) + should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note) + should_create_todo(user: author, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note) + should_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note) + should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note) + end + it 'does not create todo if user can not see the issue when leaving a note on a confidential issue' do service.new_note(note_on_confidential_issue, john_doe) @@ -287,6 +395,17 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) end + it 'does not create a directly addressed todo if user can not see the issue when leaving a note on a confidential issue' do + service.new_note(addressed_note_on_confidential_issue, john_doe) + + should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + should_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_confidential_issue) + end + it 'creates a todo for each valid mentioned user when leaving a note on commit' do service.new_note(note_on_commit, john_doe) @@ -296,6 +415,15 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target_id: nil, target_type: 'Commit', commit_id: note_on_commit.commit_id, author: john_doe, action: Todo::MENTIONED, note: note_on_commit) end + it 'creates a directly addressed todo for each valid mentioned user when leaving a note on commit' do + service.new_note(addressed_note_on_commit, john_doe) + + should_create_todo(user: member, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit) + should_create_todo(user: author, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit) + should_create_todo(user: john_doe, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit) + should_not_create_todo(user: non_member, target_id: nil, target_type: 'Commit', commit_id: addressed_note_on_commit.commit_id, author: john_doe, action: Todo::DIRECTLY_ADDRESSED, note: addressed_note_on_commit) + end + it 'does not create todo when leaving a note on snippet' do should_not_create_any_todo { service.new_note(note_on_project_snippet, john_doe) } end @@ -324,6 +452,7 @@ describe TodoService, services: true do describe 'Merge Requests' do let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } + let(:addressed_mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") } let(:mr_unassigned) { create(:merge_request, source_project: project, author: author, assignee: nil) } describe '#new_merge_request' do @@ -350,6 +479,25 @@ describe TodoService, services: true do should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) end + + it 'creates a todo for each valid user based on the type of mention' do + mr_assigned.update(description: directly_addressed_and_mentioned) + + service.new_merge_request(mr_assigned, author) + + should_create_todo(user: member, target: mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED) + end + + it 'creates a directly addressed todo for each valid addressed user' do + service.new_merge_request(addressed_mr_assigned, author) + + should_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + end end describe '#update_merge_request' do @@ -363,12 +511,37 @@ describe TodoService, services: true do should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) end + it 'creates a todo for each valid user based on the type of mention' do + mr_assigned.update(description: directly_addressed_and_mentioned) + + service.update_merge_request(mr_assigned, author) + + should_create_todo(user: member, target: mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED) + end + + it 'creates a directly addressed todo for each valid addressed user' do + service.update_merge_request(addressed_mr_assigned, author) + + should_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + end + it 'does not create a todo if user was already mentioned' do create(:todo, :mentioned, user: member, project: project, target: mr_assigned, author: author) expect { service.update_merge_request(mr_assigned, author) }.not_to change(member.todos, :count) end + it 'does not create a directly addressed todo if user was already mentioned or addressed' do + create(:todo, :directly_addressed, user: member, project: project, target: addressed_mr_assigned, author: author) + + expect{ service.update_merge_request(addressed_mr_assigned, author) }.not_to change(member.todos, :count) + end + context 'with a task list' do it 'does not create todo when tasks are marked as completed' do mr_assigned.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}") @@ -384,6 +557,20 @@ describe TodoService, services: true do should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) end + it 'does not create directly addressed todo when tasks are marked as completed' do + addressed_mr_assigned.update(description: "#{directly_addressed}\n- [x] Task 1\n- [X] Task 2") + + service.update_merge_request(addressed_mr_assigned, author) + + should_not_create_todo(user: admin, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: assignee, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: author, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: john_doe, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: non_member, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + end + it 'does not raise an error when description not change' do mr_assigned.update(title: 'Sample') @@ -436,6 +623,11 @@ describe TodoService, services: true do service.reassigned_merge_request(mr_assigned, author) should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) end + + it 'does not create a directly addressed todo for guests' do + service.reassigned_merge_request(addressed_mr_assigned, author) + should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + end end describe '#merge_merge_request' do @@ -452,6 +644,11 @@ describe TodoService, services: true do service.merge_merge_request(mr_assigned, john_doe) should_not_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) end + + it 'does not create directly addressed todo for guests' do + service.merge_merge_request(addressed_mr_assigned, john_doe) + should_not_create_todo(user: guest, target: addressed_mr_assigned, action: Todo::DIRECTLY_ADDRESSED) + end end describe '#new_award_emoji' do @@ -509,6 +706,7 @@ describe TodoService, services: true do describe '#new_note' do let(:mention) { john_doe.to_reference } let(:diff_note_on_merge_request) { create(:diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") } + let(:addressed_diff_note_on_merge_request) { create(:diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "#{mention}, hey!") } let(:legacy_diff_note_on_merge_request) { create(:legacy_diff_note_on_merge_request, project: project, noteable: mr_unassigned, author: author, note: "Hey #{mention}") } it 'creates a todo for mentioned user on new diff note' do @@ -517,6 +715,12 @@ describe TodoService, services: true do should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::MENTIONED, note: diff_note_on_merge_request) end + it 'creates a directly addressed todo for addressed user on new diff note' do + service.new_note(addressed_diff_note_on_merge_request, author) + + should_create_todo(user: john_doe, target: mr_unassigned, author: author, action: Todo::DIRECTLY_ADDRESSED, note: addressed_diff_note_on_merge_request) + end + it 'creates a todo for mentioned user on legacy diff note' do service.new_note(legacy_diff_note_on_merge_request, author) -- cgit v1.2.1 From efa0502386a1868f7120ffd4291175291f0094ed Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 3 Feb 2017 14:28:44 +0100 Subject: Enable grouping and pagination in environmnets API --- .../projects/environments_controller_spec.rb | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 7ac1d62d1b1..4ec91738b9b 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -3,9 +3,13 @@ require 'spec_helper' describe Projects::EnvironmentsController do include ApiHelpers - let(:environment) { create(:environment) } - let(:project) { environment.project } - let(:user) { create(:user) } + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + + let(:environment) do + create(:environment, name: 'production', + project: project) + end before do project.team << [user, :master] @@ -22,14 +26,20 @@ describe Projects::EnvironmentsController do end end - context 'when requesting JSON response' do + context 'when requesting JSON response for folders' do + before do + create(:environment, project: project, name: 'staging/review-1') + create(:environment, project: project, name: 'staging/review-2') + end + it 'responds with correct JSON' do get :index, environment_params(format: :json) - first_environment = json_response.first - - expect(first_environment).not_to be_empty - expect(first_environment['name']). to eq environment.name + expect(json_response.count).to eq 2 + expect(json_response.first['name']).to eq 'production' + expect(json_response.second['name']).to eq 'staging' + expect(json_response.second['size']).to eq 2 + expect(json_response.second['latest']['name']).to eq 'staging/review-2' end end end -- cgit v1.2.1 From b3309bb2fad36372b1e4821410691fa9f720bbe4 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 3 Feb 2017 19:47:56 +0000 Subject: Adjustments to receive new data schema --- .../environments/environment_item_spec.js.es6 | 137 +++++++--------- .../environments/environments_store_spec.js.es6 | 48 +----- spec/javascripts/environments/mock_data.js.es6 | 180 +++++---------------- 3 files changed, 106 insertions(+), 259 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index d87cc0996c9..14478f1401d 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -14,33 +14,13 @@ describe('Environment item', () => { beforeEach(() => { mockItem = { name: 'review', - children: [ - { - name: 'review-app', - id: 1, - state: 'available', - external_url: '', - last_deployment: {}, - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-10T15:55:58.778Z', - }, - { - name: 'production', - id: 2, - state: 'available', - external_url: '', - last_deployment: {}, - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-10T15:55:58.778Z', - }, - ], + size: 3 }; component = new window.gl.environmentsList.EnvironmentItem({ el: document.querySelector('tr#environment-row'), propsData: { model: mockItem, - toggleRow: () => {}, canCreateDeployment: false, canReadEnvironment: true, }, @@ -53,7 +33,7 @@ describe('Environment item', () => { }); it('Should render the number of children in a badge', () => { - expect(component.$el.querySelector('.folder-name .badge').textContent).toContain(mockItem.children.length); + expect(component.$el.querySelector('.folder-name .badge').textContent).toContain(mockItem.size); }); }); @@ -63,38 +43,23 @@ describe('Environment item', () => { beforeEach(() => { environment = { - id: 31, name: 'production', - state: 'stopped', - external_url: 'http://external.com', - environment_type: null, - last_deployment: { - id: 66, - iid: 6, - sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - ref: { - name: 'master', - ref_path: 'root/ci-folders/tree/master', - }, - tag: true, - 'last?': true, - user: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit: { - id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - short_id: '500aabcb', - title: 'Update .gitlab-ci.yml', - author_name: 'Administrator', - author_email: 'admin@example.com', - created_at: '2016-11-07T18:28:13.000+00:00', - message: 'Update .gitlab-ci.yml', - author: { + size: 1, + latest: { + state: 'stopped', + external_url: 'http://external.com', + environment_type: null, + last_deployment: { + id: 66, + iid: 6, + sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + ref: { + name: 'master', + ref_path: 'root/ci-folders/tree/master', + }, + tag: true, + 'last?': true, + user: { name: 'Administrator', username: 'root', id: 1, @@ -102,34 +67,50 @@ describe('Environment item', () => { avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', web_url: 'http://localhost:3000/root', }, - commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - }, - deployable: { - id: 1279, - name: 'deploy', - build_path: '/root/ci-folders/builds/1279', - retry_path: '/root/ci-folders/builds/1279/retry', - created_at: '2016-11-29T18:11:58.430Z', - updated_at: '2016-11-29T18:11:58.430Z', - }, - manual_actions: [ - { - name: 'action', - play_path: '/play', + commit: { + id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + short_id: '500aabcb', + title: 'Update .gitlab-ci.yml', + author_name: 'Administrator', + author_email: 'admin@example.com', + created_at: '2016-11-07T18:28:13.000+00:00', + message: 'Update .gitlab-ci.yml', + author: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', }, - ], + deployable: { + id: 1279, + name: 'deploy', + build_path: '/root/ci-folders/builds/1279', + retry_path: '/root/ci-folders/builds/1279/retry', + created_at: '2016-11-29T18:11:58.430Z', + updated_at: '2016-11-29T18:11:58.430Z', + }, + manual_actions: [ + { + name: 'action', + play_path: '/play', + }, + ], + }, + 'stop_action?': true, + environment_path: 'root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-10T15:55:58.778Z', }, - 'stop_action?': true, - environment_path: 'root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-10T15:55:58.778Z', }; component = new window.gl.environmentsList.EnvironmentItem({ el: document.querySelector('tr#environment-row'), propsData: { model: environment, - toggleRow: () => {}, canCreateDeployment: true, canReadEnvironment: true, }, @@ -144,7 +125,7 @@ describe('Environment item', () => { it('should render deployment internal id', () => { expect( component.$el.querySelector('.deployment-column span').textContent, - ).toContain(environment.last_deployment.iid); + ).toContain(environment.latest.last_deployment.iid); expect( component.$el.querySelector('.deployment-column span').textContent, @@ -154,7 +135,7 @@ describe('Environment item', () => { it('should render last deployment date', () => { const timeagoInstance = new timeago(); // eslint-disable-line const formatedDate = timeagoInstance.format( - environment.last_deployment.deployable.created_at, + environment.latest.last_deployment.deployable.created_at, ); expect( @@ -166,7 +147,7 @@ describe('Environment item', () => { it('should render user avatar with link to profile', () => { expect( component.$el.querySelector('.js-deploy-user-container').getAttribute('href'), - ).toEqual(environment.last_deployment.user.web_url); + ).toEqual(environment.latest.last_deployment.user.web_url); }); }); @@ -174,13 +155,13 @@ describe('Environment item', () => { it('Should link to build url provided', () => { expect( component.$el.querySelector('.build-link').getAttribute('href'), - ).toEqual(environment.last_deployment.deployable.build_path); + ).toEqual(environment.latest.last_deployment.deployable.build_path); }); it('Should render deployable name and id', () => { expect( component.$el.querySelector('.build-link').getAttribute('href'), - ).toEqual(environment.last_deployment.deployable.build_path); + ).toEqual(environment.latest.last_deployment.deployable.build_path); }); }); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 9a8300d3832..d073e120290 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -20,50 +20,10 @@ require('./mock_data'); gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); }); - it('should count stopped environments and save the count in the state', () => { - expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(1); - }); - - it('should count available environments and save the count in the state', () => { - expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(3); - }); - - it('should store environments with same environment_type as sibilings', () => { - expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(3); - - const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments - .filter(env => env.children && env.children.length > 0); - - expect(parentFolder[0].children.length).toBe(2); - expect(parentFolder[0].children[0].environment_type).toBe('review'); - expect(parentFolder[0].children[1].environment_type).toBe('review'); - expect(parentFolder[0].children[0].name).toBe('test-environment'); - expect(parentFolder[0].children[1].name).toBe('test-environment-1'); - }); - - it('should sort the environments alphabetically', () => { - const { environments } = gl.environmentsList.EnvironmentsStore.state; - - expect(environments[0].name).toBe('production'); - expect(environments[1].name).toBe('review'); - expect(environments[1].children[0].name).toBe('test-environment'); - expect(environments[1].children[1].name).toBe('test-environment-1'); - expect(environments[2].name).toBe('review_app'); - }); - }); - - describe('toggleFolder', () => { - beforeEach(() => { - gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); - }); - - it('should toggle the open property for the given environment', () => { - gl.environmentsList.EnvironmentsStore.toggleFolder('review'); - - const { environments } = gl.environmentsList.EnvironmentsStore.state; - const environment = environments.filter(env => env['vue-isChildren'] === true && env.name === 'review'); - - expect(environment[0].isOpen).toBe(true); + it('should store environments', () => { + expect( + gl.environmentsList.EnvironmentsStore.state.environments.length + ).toBe(environmentsList.length); }); }); }); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 80e1cbc6f4d..91595c049b0 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,153 +1,59 @@ const environmentsList = [ { - id: 31, - name: 'production', - state: 'available', - external_url: 'https://www.gitlab.com', - environment_type: null, - last_deployment: { - id: 64, - iid: 5, - sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - ref: { - name: 'master', - ref_url: 'http://localhost:3000/root/ci-folders/tree/master', - }, - tag: false, - 'last?': true, - user: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit: { - id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - short_id: '500aabcb', - title: 'Update .gitlab-ci.yml', - author_name: 'Administrator', - author_email: 'admin@example.com', - created_at: '2016-11-07T18:28:13.000+00:00', - message: 'Update .gitlab-ci.yml', - author: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - }, - deployable: { - id: 1278, - name: 'build', - build_path: '/root/ci-folders/builds/1278', - retry_path: '/root/ci-folders/builds/1278/retry', - }, - manual_actions: [], + name: 'DEV', + size: 1, + latest: { + id: 7, + name: 'DEV', + state: 'available', + external_url: null, + environment_type: null, + last_deployment: null, + 'stop_action?': false, + environment_path: '/root/review-app/environments/7', + stop_path: '/root/review-app/environments/7/stop', + created_at: '2017-01-31T10:53:46.894Z', + updated_at: '2017-01-31T10:53:46.894Z', }, - 'stop_action?': true, - environment_path: '/root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-07T11:11:16.525Z', }, { - id: 32, - name: 'review_app', - state: 'stopped', - external_url: 'https://www.gitlab.com', - environment_type: null, - last_deployment: { - id: 64, - iid: 5, - sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - ref: { - name: 'master', - ref_url: 'http://localhost:3000/root/ci-folders/tree/master', - }, - tag: false, - 'last?': true, - user: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit: { - id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - short_id: '500aabcb', - title: 'Update .gitlab-ci.yml', - author_name: 'Administrator', - author_email: 'admin@example.com', - created_at: '2016-11-07T18:28:13.000+00:00', - message: 'Update .gitlab-ci.yml', - author: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - }, - deployable: { - id: 1278, - name: 'build', - build_path: '/root/ci-folders/builds/1278', - retry_path: '/root/ci-folders/builds/1278/retry', - }, - manual_actions: [], + name: 'build', + size: 5, + latest: { + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + 'stop_action?': false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', }, - 'stop_action?': false, - environment_path: '/root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-07T11:11:16.525Z', - }, - { - id: 33, - name: 'test-environment', - state: 'available', - environment_type: 'review', - last_deployment: null, - 'stop_action?': true, - environment_path: '/root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-07T11:11:16.525Z', - }, - { - id: 34, - name: 'test-environment-1', - state: 'available', - environment_type: 'review', - last_deployment: null, - 'stop_action?': true, - environment_path: '/root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-07T11:11:16.525Z', }, ]; window.environmentsList = environmentsList; const environment = { - id: 4, - name: 'production', - state: 'available', - external_url: 'http://production.', - environment_type: null, - last_deployment: {}, - 'stop_action?': false, - environment_path: '/root/review-app/environments/4', - stop_path: '/root/review-app/environments/4/stop', - created_at: '2016-12-16T11:51:04.690Z', - updated_at: '2016-12-16T12:04:51.133Z', + name: 'DEV', + size: 1, + latest: { + id: 7, + name: 'DEV', + state: 'available', + external_url: null, + environment_type: null, + last_deployment: null, + 'stop_action?': false, + environment_path: '/root/review-app/environments/7', + stop_path: '/root/review-app/environments/7/stop', + created_at: '2017-01-31T10:53:46.894Z', + updated_at: '2017-01-31T10:53:46.894Z', + }, }; window.environment = environment; -- cgit v1.2.1 From 2aeb45bdb55a634a490bf535242a6f8c10aaa938 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 4 Feb 2017 10:38:16 +0100 Subject: Add support for environment scopes in controller --- .../projects/environments_controller_spec.rb | 59 ++++++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 4ec91738b9b..84d119f1867 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -7,8 +7,7 @@ describe Projects::EnvironmentsController do let(:project) { create(:empty_project) } let(:environment) do - create(:environment, name: 'production', - project: project) + create(:environment, name: 'production', project: project) end before do @@ -28,18 +27,56 @@ describe Projects::EnvironmentsController do context 'when requesting JSON response for folders' do before do - create(:environment, project: project, name: 'staging/review-1') - create(:environment, project: project, name: 'staging/review-2') + create(:environment, project: project, + name: 'staging/review-1', + state: :available) + + create(:environment, project: project, + name: 'staging/review-2', + state: :available) + + create(:environment, project: project, + name: 'staging/review-3', + state: :stopped) + end + + let(:environments) { json_response['environments'] } + + context 'when requesting available environments scope' do + before do + get :index, environment_params(format: :json, scope: :available) + end + + it 'responds with a payload describing available environments' do + expect(environments.count).to eq 2 + expect(environments.first['name']).to eq 'production' + expect(environments.second['name']).to eq 'staging' + expect(environments.second['size']).to eq 2 + expect(environments.second['latest']['name']).to eq 'staging/review-2' + end + + it 'contains values describing environment scopes sizes' do + expect(json_response['available_count']).to eq 3 + expect(json_response['stopped_count']).to eq 1 + end end - it 'responds with correct JSON' do - get :index, environment_params(format: :json) + context 'when requesting stopped environments scope' do + before do + get :index, environment_params(format: :json, scope: :stopped) + end - expect(json_response.count).to eq 2 - expect(json_response.first['name']).to eq 'production' - expect(json_response.second['name']).to eq 'staging' - expect(json_response.second['size']).to eq 2 - expect(json_response.second['latest']['name']).to eq 'staging/review-2' + it 'responds with a payload describing stopped environments' do + expect(environments.count).to eq 1 + expect(environments.first['name']).to eq 'staging' + expect(environments.first['size']).to eq 1 + expect(environments.first['latest']['name']).to eq 'staging/review-3' + end + + it 'contains values describing environment scopes sizes' do + expect(json_response['available_count']).to eq 3 + expect(json_response['stopped_count']).to eq 1 + end end end end -- cgit v1.2.1 From 71899e10878455277b7e2ed120d9424489a9d72b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 3 Feb 2017 21:10:50 +0000 Subject: Adjustments for the new response with counters a --- spec/javascripts/environments/environments_store_spec.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index d073e120290..ef4b06dea40 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -22,7 +22,7 @@ require('./mock_data'); it('should store environments', () => { expect( - gl.environmentsList.EnvironmentsStore.state.environments.length + gl.environmentsList.EnvironmentsStore.state.environments.length, ).toBe(environmentsList.length); }); }); -- cgit v1.2.1 From 26a951b7ab272b80df1281464aaf656570fe214e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 9 Feb 2017 11:35:53 +0000 Subject: Use CJS for tests. Updates expected model in tests --- .../environments/environment_item_spec.js.es6 | 8 +++-- .../environments/environment_spec.js.es6 | 18 ++++------- .../environments/environments_store_spec.js.es6 | 37 ++++++++++++---------- spec/javascripts/environments/mock_data.js.es6 | 8 ++--- 4 files changed, 36 insertions(+), 35 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 14478f1401d..5dc7ef5ad76 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,7 +1,7 @@ window.timeago = require('vendor/timeago'); require('~/environments/components/environment_item'); -describe('Environment item', () => { +fdescribe('Environment item', () => { preloadFixtures('static/environments/table.html.raw'); beforeEach(() => { loadFixtures('static/environments/table.html.raw'); @@ -14,7 +14,11 @@ describe('Environment item', () => { beforeEach(() => { mockItem = { name: 'review', - size: 3 + size: 3, + isFolder: true, + latest: { + environment_path: 'url', + }, }; component = new window.gl.environmentsList.EnvironmentItem({ diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 index 87eda136122..8b96f4b09db 100644 --- a/spec/javascripts/environments/environment_spec.js.es6 +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -1,9 +1,8 @@ /* global Vue, environment */ require('~/flash'); -require('~/environments/stores/environments_store'); require('~/environments/components/environment'); -require('./mock_data'); +const { environment } = require('./mock_data'); describe('Environment', () => { preloadFixtures('static/environments/environments.html.raw'); @@ -35,9 +34,6 @@ describe('Environment', () => { it('should render the empty state', (done) => { component = new gl.environmentsList.EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), - propsData: { - store: gl.environmentsList.EnvironmentsStore.create(), - }, }); setTimeout(() => { @@ -56,7 +52,11 @@ describe('Environment', () => { describe('with environments', () => { const environmentsResponseInterceptor = (request, next) => { - next(request.respondWith(JSON.stringify([environment]), { + next(request.respondWith(JSON.stringify({ + environments: [environment], + stopped_count: 1, + available_count: 0, + }), { status: 200, })); }; @@ -74,9 +74,6 @@ describe('Environment', () => { it('should render a table with environments', (done) => { component = new gl.environmentsList.EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), - propsData: { - store: gl.environmentsList.EnvironmentsStore.create(), - }, }); setTimeout(() => { @@ -109,9 +106,6 @@ describe('Environment', () => { it('should render empty state', (done) => { component = new gl.environmentsList.EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), - propsData: { - store: gl.environmentsList.EnvironmentsStore.create(), - }, }); setTimeout(() => { diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index ef4b06dea40..861136c621f 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,30 +1,33 @@ -/* global environmentsList */ - -require('~/environments/stores/environments_store'); -require('./mock_data'); +const Store = require('~/environments/stores/environments_store'); +const { environmentsList } = require('./mock_data'); (() => { describe('Store', () => { + let store; + beforeEach(() => { - gl.environmentsList.EnvironmentsStore.create(); + store = new Store(); }); it('should start with a blank state', () => { - expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); - expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(0); - expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(0); + expect(store.state.environments.length).toBe(0); + expect(store.state.stoppedCounter).toBe(0); + expect(store.state.availableCounter).toBe(0); }); - describe('store environments', () => { - beforeEach(() => { - gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); - }); + it('should store environments', () => { + store.storeEnvironments(environmentsList); + expect(store.state.environments.length).toBe(environmentsList.length); + }); + + it('should store available count', () => { + store.storeAvailableCount(2); + expect(store.state.availableCounter).toBe(2); + }); - it('should store environments', () => { - expect( - gl.environmentsList.EnvironmentsStore.state.environments.length, - ).toBe(environmentsList.length); - }); + it('should store stopped count', () => { + store.storeStoppedCount(2); + expect(store.state.stoppedCounter).toBe(2); }); }); })(); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 91595c049b0..bdecc95d219 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,4 +1,3 @@ - const environmentsList = [ { name: 'DEV', @@ -36,8 +35,6 @@ const environmentsList = [ }, ]; -window.environmentsList = environmentsList; - const environment = { name: 'DEV', size: 1, @@ -56,4 +53,7 @@ const environment = { }, }; -window.environment = environment; +module.exports = { + environmentsList, + environment +}; -- cgit v1.2.1 From d6ae01da55bc8e0903c9ff13211d2e5dd29bff1f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 9 Feb 2017 11:52:22 +0000 Subject: Use CJS in all environments components --- spec/javascripts/environments/environment_actions_spec.js.es6 | 6 +++--- .../environments/environment_external_url_spec.js.es6 | 4 ++-- spec/javascripts/environments/environment_item_spec.js.es6 | 8 ++++---- .../javascripts/environments/environment_rollback_spec.js.es6 | 8 ++++---- spec/javascripts/environments/environment_spec.js.es6 | 11 +++++------ spec/javascripts/environments/environment_stop_spec.js.es6 | 4 ++-- 6 files changed, 20 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index b1838045a06..850586f9f3a 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,4 +1,4 @@ -require('~/environments/components/environment_actions'); +const ActionsComponent = require('~/environments/components/environment_actions'); describe('Actions Component', () => { preloadFixtures('static/environments/element.html.raw'); @@ -19,7 +19,7 @@ describe('Actions Component', () => { }, ]; - const component = new window.gl.environmentsList.ActionsComponent({ + const component = new ActionsComponent({ el: document.querySelector('.test-dom-element'), propsData: { actions: actionsMock, @@ -47,7 +47,7 @@ describe('Actions Component', () => { }, ]; - const component = new window.gl.environmentsList.ActionsComponent({ + const component = new ActionsComponent({ el: document.querySelector('.test-dom-element'), propsData: { actions: actionsMock, diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index a6a587e69f5..393dbb5aae0 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,4 +1,4 @@ -require('~/environments/components/environment_external_url'); +const ExternalUrlComponent = require('~/environments/components/environment_external_url'); describe('External URL Component', () => { preloadFixtures('static/environments/element.html.raw'); @@ -8,7 +8,7 @@ describe('External URL Component', () => { it('should link to the provided externalUrl prop', () => { const externalURL = 'https://gitlab.com'; - const component = new window.gl.environmentsList.ExternalUrlComponent({ + const component = new ExternalUrlComponent({ el: document.querySelector('.test-dom-element'), propsData: { externalUrl: externalURL, diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 5dc7ef5ad76..dd614e50d7f 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,7 +1,7 @@ window.timeago = require('vendor/timeago'); -require('~/environments/components/environment_item'); +const EnvironmentItem = require('~/environments/components/environment_item'); -fdescribe('Environment item', () => { +describe('Environment item', () => { preloadFixtures('static/environments/table.html.raw'); beforeEach(() => { loadFixtures('static/environments/table.html.raw'); @@ -21,7 +21,7 @@ fdescribe('Environment item', () => { }, }; - component = new window.gl.environmentsList.EnvironmentItem({ + component = new EnvironmentItem({ el: document.querySelector('tr#environment-row'), propsData: { model: mockItem, @@ -111,7 +111,7 @@ fdescribe('Environment item', () => { }, }; - component = new window.gl.environmentsList.EnvironmentItem({ + component = new EnvironmentItem({ el: document.querySelector('tr#environment-row'), propsData: { model: environment, diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 043b8708a6e..4a596baad09 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,4 +1,4 @@ -require('~/environments/components/environment_rollback'); +const RollbackComponent = require('~/environments/components/environment_rollback'); describe('Rollback Component', () => { preloadFixtures('static/environments/element.html.raw'); @@ -10,7 +10,7 @@ describe('Rollback Component', () => { }); it('Should link to the provided retryUrl', () => { - const component = new window.gl.environmentsList.RollbackComponent({ + const component = new RollbackComponent({ el: document.querySelector('.test-dom-element'), propsData: { retryUrl: retryURL, @@ -22,7 +22,7 @@ describe('Rollback Component', () => { }); it('Should render Re-deploy label when isLastDeployment is true', () => { - const component = new window.gl.environmentsList.RollbackComponent({ + const component = new RollbackComponent({ el: document.querySelector('.test-dom-element'), propsData: { retryUrl: retryURL, @@ -34,7 +34,7 @@ describe('Rollback Component', () => { }); it('Should render Rollback label when isLastDeployment is false', () => { - const component = new window.gl.environmentsList.RollbackComponent({ + const component = new RollbackComponent({ el: document.querySelector('.test-dom-element'), propsData: { retryUrl: retryURL, diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 index 8b96f4b09db..1d1a688a4a5 100644 --- a/spec/javascripts/environments/environment_spec.js.es6 +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -1,7 +1,6 @@ -/* global Vue, environment */ - +const Vue = require('vue'); require('~/flash'); -require('~/environments/components/environment'); +const EnvironmentsComponent = require('~/environments/components/environment'); const { environment } = require('./mock_data'); describe('Environment', () => { @@ -32,7 +31,7 @@ describe('Environment', () => { }); it('should render the empty state', (done) => { - component = new gl.environmentsList.EnvironmentsComponent({ + component = new EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), }); @@ -72,7 +71,7 @@ describe('Environment', () => { }); it('should render a table with environments', (done) => { - component = new gl.environmentsList.EnvironmentsComponent({ + component = new EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), }); @@ -104,7 +103,7 @@ describe('Environment', () => { }); it('should render empty state', (done) => { - component = new gl.environmentsList.EnvironmentsComponent({ + component = new EnvironmentsComponent({ el: document.querySelector('#environments-list-view'), }); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index 2dfce5ba824..5ca65b1debc 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,4 +1,4 @@ -require('~/environments/components/environment_stop'); +const StopComponent = require('~/environments/components/environment_stop'); describe('Stop Component', () => { preloadFixtures('static/environments/element.html.raw'); @@ -10,7 +10,7 @@ describe('Stop Component', () => { loadFixtures('static/environments/element.html.raw'); stopURL = '/stop'; - component = new window.gl.environmentsList.StopComponent({ + component = new StopComponent({ el: document.querySelector('.test-dom-element'), propsData: { stopUrl: stopURL, -- cgit v1.2.1 From 2bd1a229060c959a177171ddbb32d1f2202b4801 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 9 Feb 2017 15:51:49 +0000 Subject: Disables add issue button Previously was disabled until any list was present (except for done) this now takes into account the welcome blank state Closes #27931 --- spec/features/boards/boards_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'spec') diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 7225f38b7e5..1b25b51cfb2 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -28,6 +28,12 @@ describe 'Issue Boards', feature: true, js: true do expect(page).to have_content('Welcome to your Issue Board!') end + it 'disables add issues button by default' do + button = page.find('.issue-boards-search button', text: 'Add issues') + + expect(button[:disabled]).to eq true + end + it 'hides the blank state when clicking nevermind button' do page.within(find('.board-blank-state')) do click_button("Nevermind, I'll use my own") -- cgit v1.2.1 From 482e7ff01201dba89a13f5e9979ea17c202c87c7 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 9 Feb 2017 17:32:08 +0000 Subject: Fix broken test and linter error --- spec/javascripts/environments/mock_data.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index bdecc95d219..081897f5456 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -55,5 +55,5 @@ const environment = { module.exports = { environmentsList, - environment + environment, }; -- cgit v1.2.1 From 0b14b654b6e5d936f7241dcc0c249e0d4cc42728 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 23 Jan 2017 18:40:25 -0200 Subject: Gather issuable metadata to avoid n+ queries on index view --- spec/controllers/dashboard_controller_spec.rb | 19 ++++++++ .../controllers/projects/issues_controller_spec.rb | 2 + .../projects/merge_requests_controller_spec.rb | 4 ++ spec/features/issuables/issuable_list_spec.rb | 57 ++++++++++++++++++++++ .../issuables_list_metadata_shared_examples.rb | 35 +++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 spec/controllers/dashboard_controller_spec.rb create mode 100644 spec/features/issuables/issuable_list_spec.rb create mode 100644 spec/support/issuables_list_metadata_shared_examples.rb (limited to 'spec') diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb new file mode 100644 index 00000000000..566d8515198 --- /dev/null +++ b/spec/controllers/dashboard_controller_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe DashboardController do + let(:user) { create(:user) } + let(:project) { create(:project) } + + before do + project.team << [user, :master] + sign_in(user) + end + + describe 'GET issues' do + it_behaves_like 'issuables list meta-data', :issue, :issues + end + + describe 'GET merge requests' do + it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests + end +end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 4b89381eb96..e576bf9ef79 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -24,6 +24,8 @@ describe Projects::IssuesController do project.team << [user, :developer] end + it_behaves_like "issuables list meta-data", :issue + it "returns index" do get :index, namespace_id: project.namespace.path, project_id: project.path diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 63780802cfa..bfd134e406e 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -147,6 +147,8 @@ describe Projects::MergeRequestsController do end describe 'GET index' do + let!(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } + def get_merge_requests(page = nil) get :index, namespace_id: project.namespace.to_param, @@ -154,6 +156,8 @@ describe Projects::MergeRequestsController do state: 'opened', page: page.to_param end + it_behaves_like "issuables list meta-data", :merge_request + context 'when page param' do let(:last_page) { project.merge_requests.page().total_pages } let!(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb new file mode 100644 index 00000000000..e31bc40adc3 --- /dev/null +++ b/spec/features/issuables/issuable_list_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' + +describe 'issuable list', feature: true do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + + issuable_types = [:issue, :merge_request] + + before do + project.add_user(user, :developer) + login_as(user) + issuable_types.each { |type| create_issuables(type) } + end + + issuable_types.each do |issuable_type| + it "avoids N+1 database queries for #{issuable_type.to_s.humanize.pluralize}" do + control_count = ActiveRecord::QueryRecorder.new { visit_issuable_list(issuable_type) }.count + + create_issuables(issuable_type) + + expect { visit_issuable_list(issuable_type) }.not_to exceed_query_limit(control_count) + end + + it "counts upvotes, downvotes and notes count for each #{issuable_type.to_s.humanize}" do + visit_issuable_list(issuable_type) + + expect(first('.fa-thumbs-up').find(:xpath, '..')).to have_content(1) + expect(first('.fa-thumbs-down').find(:xpath, '..')).to have_content(1) + expect(first('.fa-comments').find(:xpath, '..')).to have_content(2) + end + end + + def visit_issuable_list(issuable_type) + if issuable_type == :issue + visit namespace_project_issues_path(project.namespace, project) + else + visit namespace_project_merge_requests_path(project.namespace, project) + end + end + + def create_issuables(issuable_type) + 3.times do + if issuable_type == :issue + issuable = create(:issue, project: project, author: user) + else + issuable = create(:merge_request, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) + end + + 2.times do + create(:note_on_issue, noteable: issuable, project: project, note: 'Test note') + end + + create(:award_emoji, :downvote, awardable: issuable) + create(:award_emoji, :upvote, awardable: issuable) + end + end +end diff --git a/spec/support/issuables_list_metadata_shared_examples.rb b/spec/support/issuables_list_metadata_shared_examples.rb new file mode 100644 index 00000000000..dac94dfc31e --- /dev/null +++ b/spec/support/issuables_list_metadata_shared_examples.rb @@ -0,0 +1,35 @@ +shared_examples 'issuables list meta-data' do |issuable_type, action = nil| + before do + @issuable_ids = [] + + 2.times do + if issuable_type == :issue + issuable = create(issuable_type, project: project) + else + issuable = create(issuable_type, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) + end + + @issuable_ids << issuable.id + + issuable.id.times { create(:note, noteable: issuable, project: issuable.project) } + (issuable.id + 1).times { create(:award_emoji, :downvote, awardable: issuable) } + (issuable.id + 2).times { create(:award_emoji, :upvote, awardable: issuable) } + end + end + + it "creates indexed meta-data object for issuable notes and votes count" do + if action + get action + else + get :index, namespace_id: project.namespace.path, project_id: project.path + end + + meta_data = assigns(:issuable_meta_data) + + @issuable_ids.each do |id| + expect(meta_data[id].notes_count).to eq(id) + expect(meta_data[id].downvotes).to eq(id + 1) + expect(meta_data[id].upvotes).to eq(id + 2) + end + end +end -- cgit v1.2.1 From d0d94e4f104c276ee4095a76d1204daae384c708 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 10 Feb 2017 09:36:52 +0100 Subject: Fix pagination headers in grouped environments API --- spec/serializers/environment_serializer_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'spec') diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index 1b95f1ff198..6a6df377b35 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -181,6 +181,17 @@ describe EnvironmentSerializer do expect(subject.first[:name]).to eq 'production' expect(subject.second[:name]).to eq 'staging' end + + it 'appends correct total page count header' do + expect(subject).not_to be_empty + expect(response).to have_received(:[]=).with('X-Total', '3') + end + + it 'appends correct page count headers' do + expect(subject).not_to be_empty + expect(response).to have_received(:[]=).with('X-Total-Pages', '2') + expect(response).to have_received(:[]=).with('X-Per-Page', '2') + end end end end -- cgit v1.2.1 From 88d610c60e9064f92419481a9df6453b3c8079b3 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Thu, 9 Feb 2017 13:39:39 +0100 Subject: Add member: Always return 409 when a member exists --- spec/requests/api/members_spec.rb | 4 +- spec/requests/api/v3/members_spec.rb | 342 +++++++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 spec/requests/api/v3/members_spec.rb (limited to 'spec') diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 9892e014cb9..3e9bcfd1a60 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -145,11 +145,11 @@ describe API::Members, api: true do end end - it "returns #{source_type == 'project' ? 201 : 409} if member already exists" do + it "returns 409 if member already exists" do post api("/#{source_type.pluralize}/#{source.id}/members", master), user_id: master.id, access_level: Member::MASTER - expect(response).to have_http_status(source_type == 'project' ? 201 : 409) + expect(response).to have_http_status(409) end it 'returns 400 when user_id is not given' do diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb new file mode 100644 index 00000000000..28c3ca03960 --- /dev/null +++ b/spec/requests/api/v3/members_spec.rb @@ -0,0 +1,342 @@ +require 'spec_helper' + +describe API::Members, api: true do + include ApiHelpers + + let(:master) { create(:user) } + let(:developer) { create(:user) } + let(:access_requester) { create(:user) } + let(:stranger) { create(:user) } + + let(:project) do + create(:empty_project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + project.team << [developer, :developer] + project.team << [master, :master] + project.request_access(access_requester) + end + end + + let!(:group) do + create(:group, :public, :access_requestable) do |group| + group.add_developer(developer) + group.add_owner(master) + group.request_access(access_requester) + end + end + + shared_examples 'GET /:sources/:id/members' do |source_type| + context "with :sources == #{source_type.pluralize}" do + it_behaves_like 'a 404 response when source is private' do + let(:route) { get v3_api("/#{source_type.pluralize}/#{source.id}/members", stranger) } + end + + %i[master developer access_requester stranger].each do |type| + context "when authenticated as a #{type}" do + it 'returns 200' do + user = public_send(type) + get v3_api("/#{source_type.pluralize}/#{source.id}/members", user) + + expect(response).to have_http_status(200) + expect(json_response.size).to eq(2) + expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id] + end + end + end + + it 'does not return invitees' do + create(:"#{source_type}_member", invite_token: '123', invite_email: 'test@abc.com', source: source, user: nil) + + get v3_api("/#{source_type.pluralize}/#{source.id}/members", developer) + + expect(response).to have_http_status(200) + expect(json_response.size).to eq(2) + expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id] + end + + it 'finds members with query string' do + get v3_api("/#{source_type.pluralize}/#{source.id}/members", developer), query: master.username + + expect(response).to have_http_status(200) + expect(json_response.count).to eq(1) + expect(json_response.first['username']).to eq(master.username) + end + end + end + + shared_examples 'GET /:sources/:id/members/:user_id' do |source_type| + context "with :sources == #{source_type.pluralize}" do + it_behaves_like 'a 404 response when source is private' do + let(:route) { get v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger) } + end + + context 'when authenticated as a non-member' do + %i[access_requester stranger].each do |type| + context "as a #{type}" do + it 'returns 200' do + user = public_send(type) + get v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user) + + expect(response).to have_http_status(200) + # User attributes + expect(json_response['id']).to eq(developer.id) + expect(json_response['name']).to eq(developer.name) + expect(json_response['username']).to eq(developer.username) + expect(json_response['state']).to eq(developer.state) + expect(json_response['avatar_url']).to eq(developer.avatar_url) + expect(json_response['web_url']).to eq(Gitlab::Routing.url_helpers.user_url(developer)) + + # Member attributes + expect(json_response['access_level']).to eq(Member::DEVELOPER) + end + end + end + end + end + end + + shared_examples 'POST /:sources/:id/members' do |source_type| + context "with :sources == #{source_type.pluralize}" do + it_behaves_like 'a 404 response when source is private' do + let(:route) do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", stranger), + user_id: access_requester.id, access_level: Member::MASTER + end + end + + context 'when authenticated as a non-member or member with insufficient rights' do + %i[access_requester stranger developer].each do |type| + context "as a #{type}" do + it 'returns 403' do + user = public_send(type) + post v3_api("/#{source_type.pluralize}/#{source.id}/members", user), + user_id: access_requester.id, access_level: Member::MASTER + + expect(response).to have_http_status(403) + end + end + end + end + + context 'when authenticated as a master/owner' do + context 'and new member is already a requester' do + it 'transforms the requester into a proper member' do + expect do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + user_id: access_requester.id, access_level: Member::MASTER + + expect(response).to have_http_status(201) + end.to change { source.members.count }.by(1) + expect(source.requesters.count).to eq(0) + expect(json_response['id']).to eq(access_requester.id) + expect(json_response['access_level']).to eq(Member::MASTER) + end + end + + it 'creates a new member' do + expect do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + user_id: stranger.id, access_level: Member::DEVELOPER, expires_at: '2016-08-05' + + expect(response).to have_http_status(201) + end.to change { source.members.count }.by(1) + expect(json_response['id']).to eq(stranger.id) + expect(json_response['access_level']).to eq(Member::DEVELOPER) + expect(json_response['expires_at']).to eq('2016-08-05') + end + end + + it "returns #{source_type == 'project' ? 201 : 409} if member already exists" do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + user_id: master.id, access_level: Member::MASTER + + expect(response).to have_http_status(source_type == 'project' ? 201 : 409) + end + + it 'returns 400 when user_id is not given' do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + access_level: Member::MASTER + + expect(response).to have_http_status(400) + end + + it 'returns 400 when access_level is not given' do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + user_id: stranger.id + + expect(response).to have_http_status(400) + end + + it 'returns 422 when access_level is not valid' do + post v3_api("/#{source_type.pluralize}/#{source.id}/members", master), + user_id: stranger.id, access_level: 1234 + + expect(response).to have_http_status(422) + end + end + end + + shared_examples 'PUT /:sources/:id/members/:user_id' do |source_type| + context "with :sources == #{source_type.pluralize}" do + it_behaves_like 'a 404 response when source is private' do + let(:route) do + put v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger), + access_level: Member::MASTER + end + end + + context 'when authenticated as a non-member or member with insufficient rights' do + %i[access_requester stranger developer].each do |type| + context "as a #{type}" do + it 'returns 403' do + user = public_send(type) + put v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user), + access_level: Member::MASTER + + expect(response).to have_http_status(403) + end + end + end + end + + context 'when authenticated as a master/owner' do + it 'updates the member' do + put v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master), + access_level: Member::MASTER, expires_at: '2016-08-05' + + expect(response).to have_http_status(200) + expect(json_response['id']).to eq(developer.id) + expect(json_response['access_level']).to eq(Member::MASTER) + expect(json_response['expires_at']).to eq('2016-08-05') + end + end + + it 'returns 409 if member does not exist' do + put v3_api("/#{source_type.pluralize}/#{source.id}/members/123", master), + access_level: Member::MASTER + + expect(response).to have_http_status(404) + end + + it 'returns 400 when access_level is not given' do + put v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) + + expect(response).to have_http_status(400) + end + + it 'returns 422 when access level is not valid' do + put v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master), + access_level: 1234 + + expect(response).to have_http_status(422) + end + end + end + + shared_examples 'DELETE /:sources/:id/members/:user_id' do |source_type| + context "with :sources == #{source_type.pluralize}" do + it_behaves_like 'a 404 response when source is private' do + let(:route) { delete v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger) } + end + + context 'when authenticated as a non-member or member with insufficient rights' do + %i[access_requester stranger].each do |type| + context "as a #{type}" do + it 'returns 403' do + user = public_send(type) + delete v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user) + + expect(response).to have_http_status(403) + end + end + end + end + + context 'when authenticated as a member and deleting themself' do + it 'deletes the member' do + expect do + delete v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", developer) + + expect(response).to have_http_status(200) + end.to change { source.members.count }.by(-1) + end + end + + context 'when authenticated as a master/owner' do + context 'and member is a requester' do + it "returns #{source_type == 'project' ? 200 : 404}" do + expect do + delete v3_api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master) + + expect(response).to have_http_status(source_type == 'project' ? 200 : 404) + end.not_to change { source.requesters.count } + end + end + + it 'deletes the member' do + expect do + delete v3_api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) + + expect(response).to have_http_status(200) + end.to change { source.members.count }.by(-1) + end + end + + it "returns #{source_type == 'project' ? 200 : 404} if member does not exist" do + delete v3_api("/#{source_type.pluralize}/#{source.id}/members/123", master) + + expect(response).to have_http_status(source_type == 'project' ? 200 : 404) + end + end + end + + it_behaves_like 'GET /:sources/:id/members', 'project' do + let(:source) { project } + end + + it_behaves_like 'GET /:sources/:id/members', 'group' do + let(:source) { group } + end + + it_behaves_like 'GET /:sources/:id/members/:user_id', 'project' do + let(:source) { project } + end + + it_behaves_like 'GET /:sources/:id/members/:user_id', 'group' do + let(:source) { group } + end + + it_behaves_like 'POST /:sources/:id/members', 'project' do + let(:source) { project } + end + + it_behaves_like 'POST /:sources/:id/members', 'group' do + let(:source) { group } + end + + it_behaves_like 'PUT /:sources/:id/members/:user_id', 'project' do + let(:source) { project } + end + + it_behaves_like 'PUT /:sources/:id/members/:user_id', 'group' do + let(:source) { group } + end + + it_behaves_like 'DELETE /:sources/:id/members/:user_id', 'project' do + let(:source) { project } + end + + it_behaves_like 'DELETE /:sources/:id/members/:user_id', 'group' do + let(:source) { group } + end + + context 'Adding owner to project' do + it 'returns 403' do + expect do + post v3_api("/projects/#{project.id}/members", master), + user_id: stranger.id, access_level: Member::OWNER + + expect(response).to have_http_status(422) + end.to change { project.members.count }.by(0) + end + end +end -- cgit v1.2.1 From 86558d53ddcf008fff396d25c38c9462fb77f615 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 10 Feb 2017 19:41:15 +0000 Subject: Adds verification in case the endpoint already has `.json` --- spec/features/merge_requests/create_new_mr_spec.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'spec') diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index e853fb7e016..0832a3656a8 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Create New Merge Request', feature: true, js: true do + include WaitForVueResource + let(:user) { create(:user) } let(:project) { create(:project, :public) } @@ -99,6 +101,7 @@ feature 'Create New Merge Request', feature: true, js: true do page.within('.merge-request') do click_link 'Pipelines' + wait_for_vue_resource expect(page).to have_content "##{pipeline.id}" end -- cgit v1.2.1 From a97dcc077c68f4f320cd7a5686b9056adfef6c09 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 8 Feb 2017 18:15:47 +0100 Subject: Add method for creating foreign keys concurrently This method allows one to create foreign keys without blocking access to the source table, but only on PostgreSQL. When creating a regular foreign key the "ALTER TABLE" statement used for this won't return until all data has been validated. This statement in turn will acquire a lock on the source table. As a result this lock can be held for quite a long amount of time, depending on the number of rows and system load. By breaking up the foreign key creation process in two steps (creation, and validation) we can reduce the amount of locking to a minimum. Locking is still necessary for the "ALTER TABLE" statement that adds the constraint, but this is a fast process and so will only block access for a few milliseconds. --- spec/lib/gitlab/database/migration_helpers_spec.rb | 76 ++++++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 7fd25b9e5bf..e94ca4fcfd2 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -12,15 +12,14 @@ describe Gitlab::Database::MigrationHelpers, lib: true do describe '#add_concurrent_index' do context 'outside a transaction' do before do - expect(model).to receive(:transaction_open?).and_return(false) - - unless Gitlab::Database.postgresql? - allow_any_instance_of(Gitlab::Database::MigrationHelpers).to receive(:disable_statement_timeout) - end + allow(model).to receive(:transaction_open?).and_return(false) end context 'using PostgreSQL' do - before { expect(Gitlab::Database).to receive(:postgresql?).and_return(true) } + before do + allow(Gitlab::Database).to receive(:postgresql?).and_return(true) + allow(model).to receive(:disable_statement_timeout) + end it 'creates the index concurrently' do expect(model).to receive(:add_index). @@ -59,6 +58,71 @@ describe Gitlab::Database::MigrationHelpers, lib: true do end end + describe '#add_concurrent_foreign_key' do + context 'inside a transaction' do + it 'raises an error' do + expect(model).to receive(:transaction_open?).and_return(true) + + expect do + model.add_concurrent_foreign_key(:projects, :users, column: :user_id) + end.to raise_error(RuntimeError) + end + end + + context 'outside a transaction' do + before do + allow(model).to receive(:transaction_open?).and_return(false) + end + + context 'using MySQL' do + it 'creates a regular foreign key' do + allow(Gitlab::Database).to receive(:mysql?).and_return(true) + + expect(model).to receive(:add_foreign_key). + with(:projects, :users, column: :user_id, on_delete: :cascade) + + model.add_concurrent_foreign_key(:projects, :users, column: :user_id) + end + end + + context 'using PostgreSQL' do + before do + allow(Gitlab::Database).to receive(:mysql?).and_return(false) + end + + it 'creates a concurrent foreign key' do + expect(model).to receive(:disable_statement_timeout) + expect(model).to receive(:execute).ordered.with(/NOT VALID/) + expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/) + + model.add_concurrent_foreign_key(:projects, :users, column: :user_id) + end + end + end + end + + describe '#disable_statement_timeout' do + context 'using PostgreSQL' do + it 'disables statement timeouts' do + expect(Gitlab::Database).to receive(:postgresql?).and_return(true) + + expect(model).to receive(:execute).with('SET statement_timeout TO 0') + + model.disable_statement_timeout + end + end + + context 'using MySQL' do + it 'does nothing' do + expect(Gitlab::Database).to receive(:postgresql?).and_return(false) + + expect(model).not_to receive(:execute) + + model.disable_statement_timeout + end + end + end + describe '#update_column_in_batches' do before do create_list(:empty_project, 5) -- cgit v1.2.1 From 766060bcdf3ff7c37f471b58e5d13721b263e37b Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 9 Feb 2017 16:52:43 +0100 Subject: Enforce use of add_concurrent_foreign_key This adds a Rubocop rule to enforce the use of add_concurrent_foreign_key instead of the regular add_foreign_key method. This cop has been disabled for existing migrations so we don't need to change those. --- .../migration/add_concurrent_foreign_key_spec.rb | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb (limited to 'spec') diff --git a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb new file mode 100644 index 00000000000..7cb24dc5646 --- /dev/null +++ b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../../rubocop/cop/migration/add_concurrent_foreign_key' + +describe RuboCop::Cop::Migration::AddConcurrentForeignKey do + include CopHelper + + let(:cop) { described_class.new } + + context 'outside of a migration' do + it 'does not register any offenses' do + inspect_source(cop, 'def up; add_foreign_key(:projects, :users, column: :user_id); end') + + expect(cop.offenses).to be_empty + end + end + + context 'in a migration' do + before do + allow(cop).to receive(:in_migration?).and_return(true) + end + + it 'registers an offense when using add_foreign_key' do + inspect_source(cop, 'def up; add_foreign_key(:projects, :users, column: :user_id); end') + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + end + end + end +end -- cgit v1.2.1 From 92cbc1e4ad8d874428089c4c65293fa218f67206 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 30 Nov 2016 15:13:42 +0800 Subject: Enable the `RSpec/ExpectActual` cop and correct offenses --- .../issues/filtered_search/filter_issues_spec.rb | 33 ++++------ spec/lib/gitlab/regex_spec.rb | 71 ++++++++++++---------- 2 files changed, 49 insertions(+), 55 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 6f7046c8461..64f448a83b7 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -113,13 +113,11 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by invalid author' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end it 'filters issues by multiple authors' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end @@ -158,8 +156,7 @@ describe 'Filter issues', js: true, feature: true do end it 'sorting' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end @@ -182,13 +179,11 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by invalid assignee' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end it 'filters issues by multiple assignees' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end @@ -228,8 +223,7 @@ describe 'Filter issues', js: true, feature: true do context 'sorting' do it 'sorts' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end end @@ -253,8 +247,7 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by invalid label' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end it 'filters issues by multiple labels' do @@ -429,8 +422,7 @@ describe 'Filter issues', js: true, feature: true do context 'sorting' do it 'sorts' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end end @@ -456,13 +448,11 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by invalid milestones' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end it 'filters issues by multiple milestones' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end it 'filters issues by milestone containing special characters' do @@ -523,8 +513,7 @@ describe 'Filter issues', js: true, feature: true do context 'sorting' do it 'sorts' do - pending('to be tested, issue #26546') - expect(true).to be(false) + skip('to be tested, issue #26546') end end end diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index c78cd30157e..1dbc2f6eb13 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -2,47 +2,52 @@ require 'spec_helper' describe Gitlab::Regex, lib: true do - describe 'project path regex' do - it { expect('gitlab-ce').to match(Gitlab::Regex.project_path_regex) } - it { expect('gitlab_git').to match(Gitlab::Regex.project_path_regex) } - it { expect('_underscore.js').to match(Gitlab::Regex.project_path_regex) } - it { expect('100px.com').to match(Gitlab::Regex.project_path_regex) } - it { expect('?gitlab').not_to match(Gitlab::Regex.project_path_regex) } - it { expect('git lab').not_to match(Gitlab::Regex.project_path_regex) } - it { expect('gitlab.git').not_to match(Gitlab::Regex.project_path_regex) } - end + describe '.project_path_regex' do + subject { described_class.project_path_regex } - describe 'project name regex' do - it { expect('gitlab-ce').to match(Gitlab::Regex.project_name_regex) } - it { expect('GitLab CE').to match(Gitlab::Regex.project_name_regex) } - it { expect('100 lines').to match(Gitlab::Regex.project_name_regex) } - it { expect('gitlab.git').to match(Gitlab::Regex.project_name_regex) } - it { expect('Český název').to match(Gitlab::Regex.project_name_regex) } - it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) } - it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) } + it { is_expected.to match('gitlab-ce') } + it { is_expected.to match('gitlab_git') } + it { is_expected.to match('_underscore.js') } + it { is_expected.to match('100px.com') } + it { is_expected.not_to match('?gitlab') } + it { is_expected.not_to match('git lab') } + it { is_expected.not_to match('gitlab.git') } end - describe 'file name regex' do - it { expect('foo@bar').to match(Gitlab::Regex.file_name_regex) } + describe '.project_name_regex' do + subject { described_class.project_name_regex } + + it { is_expected.to match('gitlab-ce') } + it { is_expected.to match('GitLab CE') } + it { is_expected.to match('100 lines') } + it { is_expected.to match('gitlab.git') } + it { is_expected.to match('Český název') } + it { is_expected.to match('Dash – is this') } + it { is_expected.not_to match('?gitlab') } end - describe 'file path regex' do - it { expect('foo@/bar').to match(Gitlab::Regex.file_path_regex) } + describe '.file_name_regex' do + subject { described_class.file_name_regex } + + it { is_expected.to match('foo@bar') } end - describe 'environment slug regex' do - def be_matched - match(Gitlab::Regex.environment_slug_regex) - end + describe '.file_path_regex' do + subject { described_class.file_path_regex } + + it { is_expected.to match('foo@/bar') } + end - it { expect('foo').to be_matched } - it { expect('foo-1').to be_matched } + describe '.environment_slug_regex' do + subject { described_class.environment_slug_regex } - it { expect('FOO').not_to be_matched } - it { expect('foo/1').not_to be_matched } - it { expect('foo.1').not_to be_matched } - it { expect('foo*1').not_to be_matched } - it { expect('9foo').not_to be_matched } - it { expect('foo-').not_to be_matched } + it { is_expected.to match('foo') } + it { is_expected.to match('foo-1') } + it { is_expected.not_to match('FOO') } + it { is_expected.not_to match('foo/1') } + it { is_expected.not_to match('foo.1') } + it { is_expected.not_to match('foo*1') } + it { is_expected.not_to match('9foo') } + it { is_expected.not_to match('foo-') } end end -- cgit v1.2.1 From d4317e4d22b33d0bfe07b231ddeb4dd774aa0bb7 Mon Sep 17 00:00:00 2001 From: winniehell Date: Thu, 9 Feb 2017 12:03:41 +0100 Subject: Use textarea for quick submit spec --- spec/javascripts/behaviors/quick_submit_spec.js | 28 ++++++++++++---------- .../fixtures/behaviors/quick_submit.html.haml | 1 - 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 1541037888f..8113b16b74a 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -12,31 +12,33 @@ require('~/behaviors/quick_submit'); // Prevent a form submit from moving us off the testing page return e.preventDefault(); }); - return this.spies = { + this.spies = { submit: spyOnEvent('form', 'submit') }; + + this.textarea = $('.js-quick-submit textarea').first(); }); it('does not respond to other keyCodes', function() { - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ keyCode: 32 })); return expect(this.spies.submit).not.toHaveBeenTriggered(); }); it('does not respond to Enter alone', function() { - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ ctrlKey: false, metaKey: false })); return expect(this.spies.submit).not.toHaveBeenTriggered(); }); it('does not respond to repeated events', function() { - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ repeat: true })); return expect(this.spies.submit).not.toHaveBeenTriggered(); }); it('disables submit buttons', function() { - $('textarea').trigger(keydownEvent()); + this.textarea.trigger(keydownEvent()); expect($('input[type=submit]')).toBeDisabled(); return expect($('button[type=submit]')).toBeDisabled(); }); @@ -44,34 +46,34 @@ require('~/behaviors/quick_submit'); // only run the tests that apply to the current platform if (navigator.userAgent.match(/Macintosh/)) { it('responds to Meta+Enter', function() { - $('input.quick-submit-input').trigger(keydownEvent()); + this.textarea.trigger(keydownEvent()); return expect(this.spies.submit).toHaveBeenTriggered(); }); it('excludes other modifier keys', function() { - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ altKey: true })); - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ ctrlKey: true })); - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ shiftKey: true })); return expect(this.spies.submit).not.toHaveBeenTriggered(); }); } else { it('responds to Ctrl+Enter', function() { - $('input.quick-submit-input').trigger(keydownEvent()); + this.textarea.trigger(keydownEvent()); return expect(this.spies.submit).toHaveBeenTriggered(); }); it('excludes other modifier keys', function() { - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ altKey: true })); - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ metaKey: true })); - $('input.quick-submit-input').trigger(keydownEvent({ + this.textarea.trigger(keydownEvent({ shiftKey: true })); return expect(this.spies.submit).not.toHaveBeenTriggered(); diff --git a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml index dc2ceed42f4..6dd53931a42 100644 --- a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml +++ b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml @@ -1,5 +1,4 @@ %form.js-quick-submit{ action: '/foo' } - %input{ type: 'text', class: 'quick-submit-input'} %textarea %input{ type: 'submit'} Submit -- cgit v1.2.1 From 128d8b61180845e0465a3fe4e5f64d417f4f819a Mon Sep 17 00:00:00 2001 From: winniehell Date: Thu, 9 Feb 2017 12:47:55 +0100 Subject: Replace static fixture for behaviors/quick_submit_spec.js (!9086) --- spec/javascripts/behaviors/quick_submit_spec.js | 18 +++++++++++++----- .../fixtures/behaviors/quick_submit.html.haml | 5 ----- 2 files changed, 13 insertions(+), 10 deletions(-) delete mode 100644 spec/javascripts/fixtures/behaviors/quick_submit.html.haml (limited to 'spec') diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 8113b16b74a..0e4c2c560cc 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -5,9 +5,9 @@ require('~/behaviors/quick_submit'); (function() { describe('Quick Submit behavior', function() { var keydownEvent; - preloadFixtures('static/behaviors/quick_submit.html.raw'); + preloadFixtures('issues/open-issue.html.raw'); beforeEach(function() { - loadFixtures('static/behaviors/quick_submit.html.raw'); + loadFixtures('issues/open-issue.html.raw'); $('form').submit(function(e) { // Prevent a form submit from moving us off the testing page return e.preventDefault(); @@ -37,10 +37,18 @@ require('~/behaviors/quick_submit'); })); return expect(this.spies.submit).not.toHaveBeenTriggered(); }); - it('disables submit buttons', function() { + it('disables input of type submit', function() { + const submitButton = $('.js-quick-submit input[type=submit]'); this.textarea.trigger(keydownEvent()); - expect($('input[type=submit]')).toBeDisabled(); - return expect($('button[type=submit]')).toBeDisabled(); + expect(submitButton).toBeDisabled(); + }); + it('disables button of type submit', function() { + // button doesn't exist in fixture, add it manually + const submitButton = $(''); + submitButton.insertAfter(this.textarea); + + this.textarea.trigger(keydownEvent()); + expect(submitButton).toBeDisabled(); }); // We cannot stub `navigator.userAgent` for CI's `rake karma` task, so we'll // only run the tests that apply to the current platform diff --git a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml deleted file mode 100644 index 6dd53931a42..00000000000 --- a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -%form.js-quick-submit{ action: '/foo' } - %textarea - - %input{ type: 'submit'} Submit - %button.btn{ type: 'submit' } Submit -- cgit v1.2.1 From dd5f32c1996e91a5ca6f699b093624bff7ddc5b3 Mon Sep 17 00:00:00 2001 From: winniehell Date: Thu, 9 Feb 2017 22:39:04 +0100 Subject: Replace static fixture for new_branch_spec.js (!9131) --- spec/javascripts/fixtures/branches.rb | 28 ++++++++++++++++++++++++++ spec/javascripts/fixtures/new_branch.html.haml | 4 ---- spec/javascripts/new_branch_spec.js | 4 ++-- 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 spec/javascripts/fixtures/branches.rb delete mode 100644 spec/javascripts/fixtures/new_branch.html.haml (limited to 'spec') diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb new file mode 100644 index 00000000000..0e7c2351b66 --- /dev/null +++ b/spec/javascripts/fixtures/branches.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Projects::BranchesController, '(JavaScript fixtures)', type: :controller do + include JavaScriptFixturesHelpers + + let(:admin) { create(:admin) } + let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} + let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') } + + render_views + + before(:all) do + clean_frontend_fixtures('branches/') + end + + before(:each) do + sign_in(admin) + end + + it 'branches/new_branch.html.raw' do |example| + get :new, + namespace_id: project.namespace.to_param, + project_id: project.to_param + + expect(response).to be_success + store_frontend_fixture(response, example.description) + end +end diff --git a/spec/javascripts/fixtures/new_branch.html.haml b/spec/javascripts/fixtures/new_branch.html.haml deleted file mode 100644 index f06629e5ecc..00000000000 --- a/spec/javascripts/fixtures/new_branch.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -%form.js-create-branch-form - %input.js-branch-name - .js-branch-name-error - %input{id: "ref"} diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 9b657868523..1d014502c2a 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -8,7 +8,7 @@ require('~/new_branch_form'); describe('Branch', function() { return describe('create a new branch', function() { var expectToHaveError, fillNameWith; - preloadFixtures('static/new_branch.html.raw'); + preloadFixtures('branches/new_branch.html.raw'); fillNameWith = function(value) { return $('.js-branch-name').val(value).trigger('blur'); }; @@ -16,7 +16,7 @@ require('~/new_branch_form'); return expect($('.js-branch-name-error span').text()).toEqual(error); }; beforeEach(function() { - loadFixtures('static/new_branch.html.raw'); + loadFixtures('branches/new_branch.html.raw'); $('form').on('submit', function(e) { return e.preventDefault(); }); -- cgit v1.2.1 From bfb82f8a0d4d837a0472342c05de18c60037a2ea Mon Sep 17 00:00:00 2001 From: winniehell Date: Sat, 11 Feb 2017 00:45:54 +0100 Subject: Include all files with 0% coverage in report --- spec/javascripts/test_bundle.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index 030d2de090a..ca707d872a4 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -42,3 +42,38 @@ testsContext.keys().forEach(function (path) { }); } }); + +// workaround: include all source files to find files with 0% coverage +// see also https://github.com/deepsweet/istanbul-instrumenter-loader/issues/15 +describe('Uncovered files', function () { + // the following files throw errors because of undefined variables + const troubleMakers = [ + './blob_edit/blob_edit_bundle.js', + './cycle_analytics/components/stage_plan_component.js', + './cycle_analytics/components/stage_staging_component.js', + './cycle_analytics/components/stage_test_component.js', + './diff_notes/components/jump_to_discussion.js', + './diff_notes/components/resolve_count.js', + './merge_conflicts/components/inline_conflict_lines.js', + './merge_conflicts/components/parallel_conflict_lines.js', + './network/branch_graph.js', + ]; + + const sourceFiles = require.context('~', true, /^\.\/(?!application\.js).*\.(js|es6)$/); + sourceFiles.keys().forEach(function (path) { + // ignore if there is a matching spec file + if (testsContext.keys().indexOf(`${path.replace(/\.js(\.es6)?$/, '')}_spec`) > -1) { + return; + } + + it(`includes '${path}'`, function () { + try { + sourceFiles(path); + } catch (err) { + if (troubleMakers.indexOf(path) === -1) { + expect(err).toBeNull(); + } + } + }); + }); +}); -- cgit v1.2.1 From 9a24db121c6eda400ee531bf0253038d9fb28a52 Mon Sep 17 00:00:00 2001 From: wendy0402 Date: Sun, 29 Jan 2017 07:14:56 +0700 Subject: fix issue creation from milestone doesn't assign the milestone --- spec/services/issues/build_service_spec.rb | 11 ++++++++++- spec/services/issues/create_service_spec.rb | 1 + .../issuable_create_service_slash_commands_shared_examples.rb | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb index 4cfba35c830..09807e5d35b 100644 --- a/spec/services/issues/build_service_spec.rb +++ b/spec/services/issues/build_service_spec.rb @@ -120,11 +120,20 @@ describe Issues::BuildService, services: true do end describe '#execute' do + let(:milestone) { create(:milestone, project: project) } + it 'builds a new issues with given params' do - issue = described_class.new(project, user, title: 'Issue #1', description: 'Issue description').execute + issue = described_class.new( + project, + user, + title: 'Issue #1', + description: 'Issue description', + milestone_id: milestone.id, + ).execute expect(issue.title).to eq('Issue #1') expect(issue.description).to eq('Issue description') + expect(issue.milestone).to eq(milestone) end end end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index 30578ee4c7d..e1feeed8a67 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -46,6 +46,7 @@ describe Issues::CreateService, services: true do expect(issue).to be_persisted expect(issue.title).to eq('Awesome issue') + expect(issue.description).to eq('please fix') expect(issue.assignee).to be_nil expect(issue.labels).to be_empty expect(issue.milestone).to be_nil diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb index dd54b0addda..c64574679b6 100644 --- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb +++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb @@ -58,7 +58,7 @@ shared_examples 'new issuable record that supports slash commands' do let(:example_params) do { assignee: create(:user), - milestone_id: double(:milestone), + milestone_id: 1, description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}") } end -- cgit v1.2.1 From b8dbebce1d7e0ad4edf2ab09135457ade69c240c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Sun, 12 Feb 2017 13:43:46 +0000 Subject: Fix typo --- spec/features/projects/builds_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb index f7e0115643e..80ba5ff1a63 100644 --- a/spec/features/projects/builds_spec.rb +++ b/spec/features/projects/builds_spec.rb @@ -271,7 +271,7 @@ feature 'Builds', :feature do let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) } let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } - it 'shows a link to lastest deployment' do + it 'shows a link to latest deployment' do visit namespace_project_build_path(project.namespace, project, build) expect(page).to have_link('latest deployment') -- cgit v1.2.1 From 595afed2e3de93d1685b2f77dd8e72df2781a57b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 9 Feb 2017 15:10:16 +0000 Subject: Integrates pagination component with API Adds pagination tests Remove misplaced comment Fix broken store test --- .../environments/environment_spec.js.es6 | 28 ++++++++++++++--- .../environments/environments_store_spec.js.es6 | 36 ++++++++++++++++++---- 2 files changed, 53 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 index 1d1a688a4a5..f557dcee91f 100644 --- a/spec/javascripts/environments/environment_spec.js.es6 +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -49,7 +49,7 @@ describe('Environment', () => { }); }); - describe('with environments', () => { + describe('with paginated environments', () => { const environmentsResponseInterceptor = (request, next) => { next(request.respondWith(JSON.stringify({ environments: [environment], @@ -57,11 +57,22 @@ describe('Environment', () => { available_count: 0, }), { status: 200, + headers: { + 'X-Next-Page': '2', + 'X-Page': '1', + 'X-Per-Page': '1', + 'X-Prev-Page': '', + 'X-Total': '37', + 'X-Total-Pages': '2', + }, })); }; beforeEach(() => { Vue.http.interceptors.push(environmentsResponseInterceptor); + component = new EnvironmentsComponent({ + el: document.querySelector('#environments-list-view'), + }); }); afterEach(() => { @@ -71,10 +82,6 @@ describe('Environment', () => { }); it('should render a table with environments', (done) => { - component = new EnvironmentsComponent({ - el: document.querySelector('#environments-list-view'), - }); - setTimeout(() => { expect( component.$el.querySelectorAll('table tbody tr').length, @@ -82,6 +89,17 @@ describe('Environment', () => { done(); }, 0); }); + + describe('pagination', () => { + it('should render pagination', (done) => { + setTimeout(() => { + expect( + component.$el.querySelectorAll('.gl-pagination li').length, + ).toEqual(5); + done(); + }, 0); + }); + }); }); }); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 861136c621f..8fd660c3edb 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -10,24 +10,48 @@ const { environmentsList } = require('./mock_data'); }); it('should start with a blank state', () => { - expect(store.state.environments.length).toBe(0); - expect(store.state.stoppedCounter).toBe(0); - expect(store.state.availableCounter).toBe(0); + expect(store.state.environments.length).toEqual(0); + expect(store.state.stoppedCounter).toEqual(0); + expect(store.state.availableCounter).toEqual(0); + expect(store.state.paginationInformation).toEqual({}); }); it('should store environments', () => { store.storeEnvironments(environmentsList); - expect(store.state.environments.length).toBe(environmentsList.length); + expect(store.state.environments.length).toEqual(environmentsList.length); }); it('should store available count', () => { store.storeAvailableCount(2); - expect(store.state.availableCounter).toBe(2); + expect(store.state.availableCounter).toEqual(2); }); it('should store stopped count', () => { store.storeStoppedCount(2); - expect(store.state.stoppedCounter).toBe(2); + expect(store.state.stoppedCounter).toEqual(2); + }); + + it('should store pagination information', () => { + const pagination = { + 'X-nExt-pAge': '2', + 'X-page': '1', + 'X-Per-Page': '1', + 'X-Prev-Page': '2', + 'X-TOTAL': '37', + 'X-Total-Pages': '2', + }; + + const expectedResult = { + perPage: 1, + page: 1, + total: 37, + totalPages: 2, + nextPage: 2, + previousPage: 2, + }; + + store.storePagination(pagination); + expect(store.state.paginationInformation).toEqual(expectedResult); }); }); })(); -- cgit v1.2.1 From 27d7ec70b1efcaac73095e6ea3894b0eb9ba8473 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 10 Feb 2017 17:26:48 +0000 Subject: Remove spec checking for scope 'all' since it's no longer part of component Changes after review Fix typo --- spec/javascripts/environments/environment_spec.js.es6 | 6 +++--- .../vue_shared/components/table_pagination_spec.js.es6 | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 index f557dcee91f..657d8d2ab02 100644 --- a/spec/javascripts/environments/environment_spec.js.es6 +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -58,11 +58,11 @@ describe('Environment', () => { }), { status: 200, headers: { - 'X-Next-Page': '2', - 'X-Page': '1', + 'X-nExt-pAge': '2', + 'x-page': '1', 'X-Per-Page': '1', 'X-Prev-Page': '', - 'X-Total': '37', + 'X-TOTAL': '37', 'X-Total-Pages': '2', }, })); diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 b/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 index e84f0dcfe67..dd495cb43bc 100644 --- a/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 +++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js.es6 @@ -34,7 +34,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '1' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); it('should go to the previous page', () => { @@ -55,7 +55,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Prev' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); it('should go to the next page', () => { @@ -76,7 +76,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Next' } }); expect(changeChanges.one).toEqual(5); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); it('should go to the last page', () => { @@ -97,7 +97,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: 'Last >>' } }); expect(changeChanges.one).toEqual(10); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); it('should go to the first page', () => { @@ -118,7 +118,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '<< First' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); it('should do nothing', () => { @@ -139,7 +139,7 @@ describe('Pagination component', () => { component.changePage({ target: { innerText: '...' } }); expect(changeChanges.one).toEqual(1); - expect(changeChanges.two).toEqual('all'); + expect(changeChanges.two).toEqual(null); }); }); -- cgit v1.2.1 From c2fe699ac801fd2440cc4b57083a60a334cffa06 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Sun, 12 Feb 2017 13:04:00 +0000 Subject: Add pagination tests for environments table Remove fdescribe statement Fix conflict --- .../environments/environment_spec.js.es6 | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 index 657d8d2ab02..edd0cad32d0 100644 --- a/spec/javascripts/environments/environment_spec.js.es6 +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -99,6 +99,48 @@ describe('Environment', () => { done(); }, 0); }); + + it('should update url when no search params are present', (done) => { + spyOn(gl.utils, 'visitUrl'); + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2'); + done(); + }, 0); + }); + + it('should update url when page is already present', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?page=1'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2'); + done(); + }, 0); + }); + + it('should update url when page and scope are already present', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?scope=all&page=1'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?scope=all&page=2'); + done(); + }, 0); + }); + + it('should update url when page and scope are already present and page is first param', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?page=1&scope=all'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2&scope=all'); + done(); + }, 0); + }); }); }); }); -- cgit v1.2.1 From fc7d2a88f4256a68eb884981fcc2dd99febaa668 Mon Sep 17 00:00:00 2001 From: winniehell Date: Sun, 12 Feb 2017 23:49:29 +0100 Subject: Replace static fixture for merge_request_tabs_spec.js (!9172) --- .../fixtures/merge_request_tabs.html.haml | 22 ------------- spec/javascripts/fixtures/merge_requests.rb | 36 ++++++++++++++++++++++ spec/javascripts/merge_request_tabs_spec.js | 4 +-- 3 files changed, 38 insertions(+), 24 deletions(-) delete mode 100644 spec/javascripts/fixtures/merge_request_tabs.html.haml create mode 100644 spec/javascripts/fixtures/merge_requests.rb (limited to 'spec') diff --git a/spec/javascripts/fixtures/merge_request_tabs.html.haml b/spec/javascripts/fixtures/merge_request_tabs.html.haml deleted file mode 100644 index 68678c3d7e3..00000000000 --- a/spec/javascripts/fixtures/merge_request_tabs.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -%ul.nav.nav-tabs.merge-request-tabs - %li.notes-tab - %a{href: '/foo/bar/merge_requests/1', data: {target: 'div#notes', action: 'notes', toggle: 'tab'}} - Discussion - %li.commits-tab - %a{href: '/foo/bar/merge_requests/1/commits', data: {target: 'div#commits', action: 'commits', toggle: 'tab'}} - Commits - %li.diffs-tab - %a{href: '/foo/bar/merge_requests/1/diffs', data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'}} - Diffs - -.tab-content - #notes.notes.tab-pane - Notes Content - #commits.commits.tab-pane - Commits Content - #diffs.diffs.tab-pane - Diffs Content - -.mr-loading-status - .loading - Loading Animation diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb new file mode 100644 index 00000000000..62984097099 --- /dev/null +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :controller do + include JavaScriptFixturesHelpers + + let(:admin) { create(:admin) } + let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} + let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + + render_views + + before(:all) do + clean_frontend_fixtures('merge_requests/') + end + + before(:each) do + sign_in(admin) + end + + it 'merge_requests/merge_request_with_task_list.html.raw' do |example| + merge_request = create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') + render_merge_request(example.description, merge_request) + end + + private + + def render_merge_request(fixture_file_name, merge_request) + get :show, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: merge_request.to_param + + expect(response).to be_success + store_frontend_fixture(response, fixture_file_name) + end +end diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 92a0f1c05f7..3810991f104 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -25,7 +25,7 @@ require('vendor/jquery.scrollTo'); }; $.extend(stubLocation, defaults, stubs || {}); }; - preloadFixtures('static/merge_request_tabs.html.raw'); + preloadFixtures('merge_requests/merge_request_with_task_list.html.raw'); beforeEach(function () { this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation }); @@ -41,7 +41,7 @@ require('vendor/jquery.scrollTo'); describe('#activateTab', function () { beforeEach(function () { spyOn($, 'ajax').and.callFake(function () {}); - loadFixtures('static/merge_request_tabs.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); this.subject = this.class.activateTab; }); it('shows the first tab when action is show', function () { -- cgit v1.2.1 From 0f06d2646afc1bd5b445910829d3d13f04de9c94 Mon Sep 17 00:00:00 2001 From: winniehell Date: Mon, 13 Feb 2017 01:06:54 +0100 Subject: Replace static fixture for header_spec.js (!9174) --- spec/javascripts/fixtures/header.html.haml | 35 ------------------------------ spec/javascripts/header_spec.js | 2 +- 2 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 spec/javascripts/fixtures/header.html.haml (limited to 'spec') diff --git a/spec/javascripts/fixtures/header.html.haml b/spec/javascripts/fixtures/header.html.haml deleted file mode 100644 index f397f69e753..00000000000 --- a/spec/javascripts/fixtures/header.html.haml +++ /dev/null @@ -1,35 +0,0 @@ -%header.navbar.navbar-gitlab.nav_header_class - .container-fluid - .header-content - %button.side-nav-toggle - %span.sr-only - Toggle navigation - %i.fa.fa-bars - %button.navbar-toggle - %span.sr-only - Toggle navigation - %i.fa.fa-ellipsis-v - .navbar-collapse.collapse - %ui.nav.navbar-nav - %li.hidden-sm.hidden-xs - %li.visible-sm.visible-xs - %li - %a - %i.fa.fa-bell.fa-fw - %span.badge.todos-pending-count - %li - %a - %i.fa.fa-plus.fa-fw - %li.header-user.dropdown - %a - %img - %span.caret - .dropdown-menu-nav - .dropdown-menu-align-right - %ul - %li - %a.profile-link - %li - %a - %li.divider - %li.sign-out-link diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index cecebb0b038..2b263b71b7d 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -6,7 +6,7 @@ require('~/lib/utils/text_utility'); (function() { describe('Header', function() { var todosPendingCount = '.todos-pending-count'; - var fixtureTemplate = 'static/header.html.raw'; + var fixtureTemplate = 'issues/open-issue.html.raw'; function isTodosCountHidden() { return $(todosPendingCount).hasClass('hidden'); -- cgit v1.2.1 From f2aa9b463086697771e2bf936a7d272307bcbd67 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 10 Feb 2017 16:14:18 -0600 Subject: Fix current build arrow Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/27939 --- spec/features/projects/builds_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb index f7e0115643e..f1036b275f7 100644 --- a/spec/features/projects/builds_spec.rb +++ b/spec/features/projects/builds_spec.rb @@ -109,6 +109,10 @@ feature 'Builds', :feature do expect(page).to have_content pipeline.git_commit_message expect(page).to have_content pipeline.git_author_name end + + it 'shows active build' do + expect(page).to have_selector('.build-job.active') + end end context "Job from other project" do -- cgit v1.2.1 From c7b425a3e50a3b348c17e8df2d44e8019d6afe3c Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Thu, 9 Feb 2017 11:34:02 +0100 Subject: Mark as WIP based on MR commits only --- .../merge_requests/refresh_service_spec.rb | 41 +++++++++++++++++----- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 2cc21acab7b..983dac6efdb 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -287,41 +287,64 @@ describe MergeRequests::RefreshService, services: true do it 'references the commit that caused the Work in Progress status' do refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') - allow(refresh_service).to receive(:find_new_commits) refresh_service.instance_variable_set("@commits", [ - instance_double( - Commit, + double( id: 'aaaaaaa', + sha: '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e', short_id: 'aaaaaaa', title: 'Fix issue', work_in_progress?: false ), - instance_double( - Commit, + double( id: 'bbbbbbb', + sha: '498214de67004b1da3d820901307bed2a68a8ef6', short_id: 'bbbbbbb', title: 'fixup! Fix issue', work_in_progress?: true, to_reference: 'bbbbbbb' ), - instance_double( - Commit, + double( id: 'ccccccc', + sha: '1b12f15a11fc6e62177bef08f47bc7b5ce50b141', short_id: 'ccccccc', title: 'fixup! Fix issue', work_in_progress?: true, to_reference: 'ccccccc' ), ]) - refresh_service.execute(@oldrev, @newrev, 'refs/heads/wip') reload_mrs - expect(@merge_request.notes.last.note).to eq( "marked as a **Work In Progress** from bbbbbbb" ) end + + it 'does not mark as WIP based on commits that do not belong to an MR' do + allow(refresh_service).to receive(:find_new_commits) + refresh_service.instance_variable_set("@commits", [ + double( + id: 'aaaaaaa', + sha: 'aaaaaaa', + short_id: 'aaaaaaa', + title: 'Fix issue', + work_in_progress?: false + ), + double( + id: 'bbbbbbb', + sha: 'bbbbbbbb', + short_id: 'bbbbbbb', + title: 'fixup! Fix issue', + work_in_progress?: true, + to_reference: 'bbbbbbb' + ) + ]) + + refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') + reload_mrs + + expect(@merge_request.work_in_progress?).to be_falsey + end end def reload_mrs -- cgit v1.2.1 From 1f94b952b5209180d4ee6cd38256258ac177e7df Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 13 Feb 2017 09:38:26 +0100 Subject: Show notifications settings when repository is disabled --- spec/views/projects/_home_panel.html.haml_spec.rb | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 spec/views/projects/_home_panel.html.haml_spec.rb (limited to 'spec') diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb new file mode 100644 index 00000000000..0abd7c524a1 --- /dev/null +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe 'projects/_home_panel', :view do + let(:project) { create(:empty_project, :public) } + + let(:notification_settings) do + user.notification_settings_for(project) if user + end + + before do + assign(:project, project) + assign(:notification_setting, notification_settings) + + allow(view).to receive(:current_user).and_return(user) + allow(view).to receive(:can?).and_return(false) + end + + context 'user is signed in' do + let(:user) { create(:user) } + + it 'makes it possible to set notification level' do + render + + expect(view).to render_template('shared/notifications/_button') + expect(rendered).to have_selector('.notification-dropdown') + end + end + + context 'user is signed out' do + let(:user) { nil } + + it 'is not possible to set notification level' do + render + + expect(rendered).not_to have_selector('.notification_dropdown') + end + end +end -- cgit v1.2.1 From d1d5e2388d692160078647150c3fa134a205a835 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 13 Feb 2017 09:45:10 +0100 Subject: Improve home panel partial code and view specs --- spec/views/projects/_home_panel.html.haml_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb index 0abd7c524a1..5af57cdf3b7 100644 --- a/spec/views/projects/_home_panel.html.haml_spec.rb +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -15,7 +15,7 @@ describe 'projects/_home_panel', :view do allow(view).to receive(:can?).and_return(false) end - context 'user is signed in' do + context 'when user is signed in' do let(:user) { create(:user) } it 'makes it possible to set notification level' do @@ -26,7 +26,7 @@ describe 'projects/_home_panel', :view do end end - context 'user is signed out' do + context 'when user is signed out' do let(:user) { nil } it 'is not possible to set notification level' do -- cgit v1.2.1 From 188c231304845ff29506dc152aaea6ec42373015 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 13 Feb 2017 21:01:35 +0800 Subject: Add a test to make sure the queue ticks when updating runners --- spec/requests/api/runners_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index f2d81a28cb8..daef9062e7d 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -183,6 +183,7 @@ describe API::Runners, api: true do it 'updates runner' do description = shared_runner.description active = shared_runner.active + runner_queue_value = shared_runner.ensure_runner_queue_value update_runner(shared_runner.id, admin, description: "#{description}_updated", active: !active, @@ -197,18 +198,24 @@ describe API::Runners, api: true do expect(shared_runner.tag_list).to include('ruby2.1', 'pgsql', 'mysql') expect(shared_runner.run_untagged?).to be(false) expect(shared_runner.locked?).to be(true) + expect(shared_runner.ensure_runner_queue_value) + .not_to eq(runner_queue_value) end end context 'when runner is not shared' do it 'updates runner' do description = specific_runner.description + runner_queue_value = specific_runner.ensure_runner_queue_value + update_runner(specific_runner.id, admin, description: 'test') specific_runner.reload expect(response).to have_http_status(200) expect(specific_runner.description).to eq('test') expect(specific_runner.description).not_to eq(description) + expect(specific_runner.ensure_runner_queue_value) + .not_to eq(runner_queue_value) end end -- cgit v1.2.1 From 950e2986656e17948ef227985d786ee22fb92fb2 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Mon, 13 Feb 2017 08:36:24 -0600 Subject: Change wording of MR comment box --- spec/views/projects/notes/_form.html.haml_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/views/projects/notes/_form.html.haml_spec.rb b/spec/views/projects/notes/_form.html.haml_spec.rb index b14b1ece2d0..b61f016967f 100644 --- a/spec/views/projects/notes/_form.html.haml_spec.rb +++ b/spec/views/projects/notes/_form.html.haml_spec.rb @@ -21,7 +21,7 @@ describe 'projects/notes/_form' do let(:note) { build(:"note_on_#{noteable}", project: project) } it 'says that only markdown is supported, not slash commands' do - expect(rendered).to have_content('Styling with Markdown and slash commands are supported') + expect(rendered).to have_content('Markdown and slash commands are supported') end end end @@ -30,7 +30,7 @@ describe 'projects/notes/_form' do let(:note) { build(:note_on_commit, project: project) } it 'says that only markdown is supported, not slash commands' do - expect(rendered).to have_content('Styling with Markdown is supported') + expect(rendered).to have_content('Markdown is supported') end end end -- cgit v1.2.1 From e31b982a13413151dd7317ee15aadcbde0f72edb Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 7 Feb 2017 13:56:50 +0100 Subject: Make deploy key not show in User's keys list --- spec/controllers/profiles/keys_controller_spec.rb | 19 +++++++-------- spec/factories/keys.rb | 7 ++++-- spec/models/user_spec.rb | 29 +++++++++++++++++++++++ 3 files changed, 43 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/controllers/profiles/keys_controller_spec.rb b/spec/controllers/profiles/keys_controller_spec.rb index 6bcfae0fc13..f7219690722 100644 --- a/spec/controllers/profiles/keys_controller_spec.rb +++ b/spec/controllers/profiles/keys_controller_spec.rb @@ -42,10 +42,9 @@ describe Profiles::KeysController do end describe "user with keys" do - before do - user.keys << create(:key) - user.keys << create(:another_key) - end + let!(:key) { create(:key, user: user) } + let!(:another_key) { create(:another_key, user: user) } + let!(:deploy_key) { create(:deploy_key, user: user) } it "does generally work" do get :get_keys, username: user.username @@ -53,16 +52,16 @@ describe Profiles::KeysController do expect(response).to be_success end - it "renders all keys separated with a new line" do + it "renders all non deploy keys separated with a new line" do get :get_keys, username: user.username - expect(response.body).not_to eq("") + expect(response.body).not_to eq('') expect(response.body).to eq(user.all_ssh_keys.join("\n")) - # Unique part of key 1 - expect(response.body).to match(/PWx6WM4lhHNedGfBpPJNPpZ/) - # Key 2 - expect(response.body).to match(/AQDmTillFzNTrrGgwaCKaSj/) + expect(response.body).to include(key.key.sub(' dummy@gitlab.com', '')) + expect(response.body).to include(another_key.key) + + expect(response.body).not_to include(deploy_key.key) end it "does not render the comment of the key" do diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb index d69c5b38d0a..dd93b439b2b 100644 --- a/spec/factories/keys.rb +++ b/spec/factories/keys.rb @@ -2,10 +2,13 @@ FactoryGirl.define do factory :key do title key do - "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= dummy@gitlab.com" + 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= dummy@gitlab.com' end factory :deploy_key, class: 'DeployKey' do + key do + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O96x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5/jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaCrzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy05qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz' + end end factory :personal_key do @@ -14,7 +17,7 @@ FactoryGirl.define do factory :another_key do key do - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ" + 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ' end factory :another_deploy_key, class: 'DeployKey' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7fd49c73b37..89cef7ab978 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -19,6 +19,7 @@ describe User, models: true do it { is_expected.to have_many(:project_members).dependent(:destroy) } it { is_expected.to have_many(:groups) } it { is_expected.to have_many(:keys).dependent(:destroy) } + it { is_expected.to have_many(:deploy_keys).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) } it { is_expected.to have_many(:recent_events).class_name('Event') } it { is_expected.to have_many(:issues).dependent(:destroy) } @@ -303,6 +304,34 @@ describe User, models: true do end end + shared_context 'user keys' do + let(:user) { create(:user) } + let!(:key) { create(:key, user: user) } + let!(:deploy_key) { create(:deploy_key, user: user) } + end + + describe '#keys' do + include_context 'user keys' + + context 'with key and deploy key stored' do + it 'returns stored key, but not deploy_key' do + expect(user.keys).to include key + expect(user.keys).not_to include deploy_key + end + end + end + + describe '#deploy_keys' do + include_context 'user keys' + + context 'with key and deploy key stored' do + it 'returns stored deploy key, but not normal key' do + expect(user.deploy_keys).to include deploy_key + expect(user.deploy_keys).not_to include key + end + end + end + describe '#confirm' do before do allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true) -- cgit v1.2.1 From 217937e5699326e2897a8919f421b401d077225c Mon Sep 17 00:00:00 2001 From: Jan Christophersen Date: Mon, 13 Feb 2017 16:04:06 +0100 Subject: Show mentioned/issues being closed from a Merge Requests title --- spec/features/merge_requests/closes_issues_spec.rb | 32 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb index c73065cdce1..eafcab6a0d7 100644 --- a/spec/features/merge_requests/closes_issues_spec.rb +++ b/spec/features/merge_requests/closes_issues_spec.rb @@ -10,10 +10,12 @@ feature 'Merge Request closing issues message', feature: true do :merge_request, :simple, source_project: project, - description: merge_request_description + description: merge_request_description, + title: merge_request_title ) end let(:merge_request_description) { 'Merge Request Description' } + let(:merge_request_title) { 'Merge Request Title' } before do project.team << [user, :master] @@ -45,8 +47,32 @@ feature 'Merge Request closing issues message', feature: true do end end - context 'closing some issues and mentioning, but not closing, others' do - let(:merge_request_description) { "Description\n\ncloses #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" } + context 'closing some issues in title and mentioning, but not closing, others' do + let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" } + + it 'does not display closing issue message' do + expect(page).to have_content("Accepting this merge request will close issue #{issue_1.to_reference}. Issue #{issue_2.to_reference} is mentioned but will not be closed.") + end + end + + context 'closing issues using title but not mentioning any other issue' do + let(:merge_request_title) { "closing #{issue_1.to_reference}, #{issue_2.to_reference}" } + + it 'does not display closing issue message' do + expect(page).to have_content("Accepting this merge request will close issues #{issue_1.to_reference} and #{issue_2.to_reference}") + end + end + + context 'mentioning issues using title but not closing them' do + let(:merge_request_title) { "Refers to #{issue_1.to_reference} and #{issue_2.to_reference}" } + + it 'does not display closing issue message' do + expect(page).to have_content("Issues #{issue_1.to_reference} and #{issue_2.to_reference} are mentioned but will not be closed.") + end + end + + context 'closing some issues using title and mentioning, but not closing, others' do + let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" } it 'does not display closing issue message' do expect(page).to have_content("Accepting this merge request will close issue #{issue_1.to_reference}. Issue #{issue_2.to_reference} is mentioned but will not be closed.") -- cgit v1.2.1 From 8adc356902624960647f932a8c701dc6ba4c3bb9 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Fri, 27 Jan 2017 16:53:27 -0200 Subject: Remove deprecated templates endpoints in V4 --- spec/requests/api/templates_spec.rb | 58 +++------- spec/requests/api/v3/templates_spec.rb | 203 +++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 40 deletions(-) create mode 100644 spec/requests/api/v3/templates_spec.rb (limited to 'spec') diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb index d32ba60fc4c..c0a8c0832bb 100644 --- a/spec/requests/api/templates_spec.rb +++ b/spec/requests/api/templates_spec.rb @@ -3,23 +3,23 @@ require 'spec_helper' describe API::Templates, api: true do include ApiHelpers - shared_examples_for 'the Template Entity' do |path| - before { get api(path) } + context 'the Template Entity' do + before { get api('/templates/gitignores/Ruby') } it { expect(json_response['name']).to eq('Ruby') } it { expect(json_response['content']).to include('*.gem') } end - - shared_examples_for 'the TemplateList Entity' do |path| - before { get api(path) } + + context 'the TemplateList Entity' do + before { get api('/templates/gitignores') } it { expect(json_response.first['name']).not_to be_nil } it { expect(json_response.first['content']).to be_nil } end - shared_examples_for 'requesting gitignores' do |path| + context 'requesting gitignores' do it 'returns a list of available gitignore templates' do - get api(path) + get api('/templates/gitignores') expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -27,9 +27,9 @@ describe API::Templates, api: true do end end - shared_examples_for 'requesting gitlab-ci-ymls' do |path| + context 'requesting gitlab-ci-ymls' do it 'returns a list of available gitlab_ci_ymls' do - get api(path) + get api('/templates/gitlab_ci_ymls') expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -37,17 +37,17 @@ describe API::Templates, api: true do end end - shared_examples_for 'requesting gitlab-ci-yml for Ruby' do |path| + context 'requesting gitlab-ci-yml for Ruby' do it 'adds a disclaimer on the top' do - get api(path) + get api('/templates/gitlab_ci_ymls/Ruby') expect(response).to have_http_status(200) expect(json_response['content']).to start_with("# This file is a template,") end end - shared_examples_for 'the License Template Entity' do |path| - before { get api(path) } + context 'the License Template Entity' do + before { get api('/templates/licenses/mit') } it 'returns a license template' do expect(json_response['key']).to eq('mit') @@ -64,9 +64,9 @@ describe API::Templates, api: true do end end - shared_examples_for 'GET licenses' do |path| + context 'GET templates/licenses' do it 'returns a list of available license templates' do - get api(path) + get api('/templates/licenses') expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -77,7 +77,7 @@ describe API::Templates, api: true do describe 'the popular parameter' do context 'with popular=1' do it 'returns a list of available popular license templates' do - get api("#{path}?popular=1") + get api('/templates/licenses?popular=1') expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -88,10 +88,10 @@ describe API::Templates, api: true do end end - shared_examples_for 'GET licenses/:name' do |path| + context 'GET templates/licenses/:name' do context 'with :project and :fullname given' do before do - get api("#{path}/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}") + get api("/templates/licenses/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}") end context 'for the mit license' do @@ -178,26 +178,4 @@ describe API::Templates, api: true do end end end - - describe 'with /templates namespace' do - it_behaves_like 'the Template Entity', '/templates/gitignores/Ruby' - it_behaves_like 'the TemplateList Entity', '/templates/gitignores' - it_behaves_like 'requesting gitignores', '/templates/gitignores' - it_behaves_like 'requesting gitlab-ci-ymls', '/templates/gitlab_ci_ymls' - it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/templates/gitlab_ci_ymls/Ruby' - it_behaves_like 'the License Template Entity', '/templates/licenses/mit' - it_behaves_like 'GET licenses', '/templates/licenses' - it_behaves_like 'GET licenses/:name', '/templates/licenses' - end - - describe 'without /templates namespace' do - it_behaves_like 'the Template Entity', '/gitignores/Ruby' - it_behaves_like 'the TemplateList Entity', '/gitignores' - it_behaves_like 'requesting gitignores', '/gitignores' - it_behaves_like 'requesting gitlab-ci-ymls', '/gitlab_ci_ymls' - it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/gitlab_ci_ymls/Ruby' - it_behaves_like 'the License Template Entity', '/licenses/mit' - it_behaves_like 'GET licenses', '/licenses' - it_behaves_like 'GET licenses/:name', '/licenses' - end end diff --git a/spec/requests/api/v3/templates_spec.rb b/spec/requests/api/v3/templates_spec.rb new file mode 100644 index 00000000000..4fd4e70bedd --- /dev/null +++ b/spec/requests/api/v3/templates_spec.rb @@ -0,0 +1,203 @@ +require 'spec_helper' + +describe API::V3::Templates, api: true do + include ApiHelpers + + shared_examples_for 'the Template Entity' do |path| + before { get v3_api(path) } + + it { expect(json_response['name']).to eq('Ruby') } + it { expect(json_response['content']).to include('*.gem') } + end + + shared_examples_for 'the TemplateList Entity' do |path| + before { get v3_api(path) } + + it { expect(json_response.first['name']).not_to be_nil } + it { expect(json_response.first['content']).to be_nil } + end + + shared_examples_for 'requesting gitignores' do |path| + it 'returns a list of available gitignore templates' do + get v3_api(path) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to be > 15 + end + end + + shared_examples_for 'requesting gitlab-ci-ymls' do |path| + it 'returns a list of available gitlab_ci_ymls' do + get v3_api(path) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['name']).not_to be_nil + end + end + + shared_examples_for 'requesting gitlab-ci-yml for Ruby' do |path| + it 'adds a disclaimer on the top' do + get v3_api(path) + + expect(response).to have_http_status(200) + expect(json_response['content']).to start_with("# This file is a template,") + end + end + + shared_examples_for 'the License Template Entity' do |path| + before { get v3_api(path) } + + it 'returns a license template' do + expect(json_response['key']).to eq('mit') + expect(json_response['name']).to eq('MIT License') + expect(json_response['nickname']).to be_nil + expect(json_response['popular']).to be true + expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/') + expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT') + expect(json_response['description']).to include('A permissive license that is short and to the point.') + expect(json_response['conditions']).to eq(%w[include-copyright]) + expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use]) + expect(json_response['limitations']).to eq(%w[no-liability]) + expect(json_response['content']).to include('The MIT License (MIT)') + end + end + + shared_examples_for 'GET licenses' do |path| + it 'returns a list of available license templates' do + get v3_api(path) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(15) + expect(json_response.map { |l| l['key'] }).to include('agpl-3.0') + end + + describe 'the popular parameter' do + context 'with popular=1' do + it 'returns a list of available popular license templates' do + get v3_api("#{path}?popular=1") + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(3) + expect(json_response.map { |l| l['key'] }).to include('apache-2.0') + end + end + end + end + + shared_examples_for 'GET licenses/:name' do |path| + context 'with :project and :fullname given' do + before do + get v3_api("#{path}/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}") + end + + context 'for the mit license' do + let(:license_type) { 'mit' } + + it 'returns the license text' do + expect(json_response['content']).to include('The MIT License (MIT)') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton") + end + end + + context 'for the agpl-3.0 license' do + let(:license_type) { 'agpl-3.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU AFFERO GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the gpl-3.0 license' do + let(:license_type) { 'gpl-3.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the gpl-2.0 license' do + let(:license_type) { 'gpl-2.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the apache-2.0 license' do + let(:license_type) { 'apache-2.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('Apache License') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include("Copyright #{Time.now.year} Anton") + end + end + + context 'for an uknown license' do + let(:license_type) { 'muth-over9000' } + + it 'returns a 404' do + expect(response).to have_http_status(404) + end + end + end + + context 'with no :fullname given' do + context 'with an authenticated user' do + let(:user) { create(:user) } + + it 'replaces the copyright owner placeholder with the name of the current user' do + get v3_api('/templates/licenses/mit', user) + + expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}") + end + end + end + end + + describe 'with /templates namespace' do + it_behaves_like 'the Template Entity', '/templates/gitignores/Ruby' + it_behaves_like 'the TemplateList Entity', '/templates/gitignores' + it_behaves_like 'requesting gitignores', '/templates/gitignores' + it_behaves_like 'requesting gitlab-ci-ymls', '/templates/gitlab_ci_ymls' + it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/templates/gitlab_ci_ymls/Ruby' + it_behaves_like 'the License Template Entity', '/templates/licenses/mit' + it_behaves_like 'GET licenses', '/templates/licenses' + it_behaves_like 'GET licenses/:name', '/templates/licenses' + end + + describe 'without /templates namespace' do + it_behaves_like 'the Template Entity', '/gitignores/Ruby' + it_behaves_like 'the TemplateList Entity', '/gitignores' + it_behaves_like 'requesting gitignores', '/gitignores' + it_behaves_like 'requesting gitlab-ci-ymls', '/gitlab_ci_ymls' + it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/gitlab_ci_ymls/Ruby' + it_behaves_like 'the License Template Entity', '/licenses/mit' + it_behaves_like 'GET licenses', '/licenses' + it_behaves_like 'GET licenses/:name', '/licenses' + end +end -- cgit v1.2.1 From 581cfbae24d629433e2e4eb6f6a2bb2a2938cada Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 13 Feb 2017 17:11:50 +0100 Subject: Don't connect in Gitlab::Database.adapter_name We don't need to connect when requesting the name of the database adapter. This in turn should prevent us from requesting/leaking connections just by asking whether we're using PostgreSQL or MySQL. --- spec/lib/gitlab/database_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index b142b3a2781..41252f31997 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -5,6 +5,12 @@ class MigrationTest end describe Gitlab::Database, lib: true do + describe '.adapter_name' do + it 'returns the name of the adapter' do + expect(described_class.adapter_name).to be_an_instance_of(String) + end + end + # These are just simple smoke tests to check if the methods work (regardless # of what they may return). describe '.mysql?' do -- cgit v1.2.1 From 948e1b845cd93c6450794379282712ec3b4a9caf Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 13 Feb 2017 10:35:25 -0600 Subject: Respect autocrlf setting when creating/updating file through web UI --- spec/models/repository_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'spec') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 9bfa6409607..838fd3754b2 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -351,6 +351,17 @@ describe Repository, models: true do expect(blob.data).to eq('Changelog!') end + it 'respects the autocrlf setting' do + repository.commit_file(user, 'hello.txt', "Hello,\r\nWorld", + message: 'Add hello world', + branch_name: 'master', + update: true) + + blob = repository.blob_at('master', 'hello.txt') + + expect(blob.data).to eq("Hello,\nWorld") + end + context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do -- cgit v1.2.1 From 136dc79433295aded9ecabb15aae2dc1e228b903 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 13 Feb 2017 21:45:26 +0800 Subject: Have some simple way to create connection pool --- spec/lib/gitlab/database_spec.rb | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index b142b3a2781..c9be832b1a0 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -71,6 +71,54 @@ describe Gitlab::Database, lib: true do end end + describe '.with_connection_pool' do + it 'creates a new connection pool and disconnect it after used' do + closed_pool = nil + + described_class.with_connection_pool(1) do |pool| + pool.with_connection do |connection| + connection.execute('SELECT 1 AS value') + end + + expect(pool).to be_connected + + closed_pool = pool + end + + expect(closed_pool).not_to be_connected + end + + it 'disconnects the pool even an exception was raised' do + error = Class.new(RuntimeError) + closed_pool = nil + + begin + described_class.with_connection_pool(1) do |pool| + pool.with_connection do |connection| + connection.execute('SELECT 1 AS value') + end + + closed_pool = pool + + raise error.new('boom') + end + rescue error + end + + expect(closed_pool).not_to be_connected + end + end + + describe '.create_connection_pool' do + it 'creates a new connection pool with specific pool size' do + pool = described_class.create_connection_pool(5) + + expect(pool) + .to be_kind_of(ActiveRecord::ConnectionAdapters::ConnectionPool) + expect(pool.spec.config[:pool]).to eq(5) + end + end + describe '#true_value' do it 'returns correct value for PostgreSQL' do expect(described_class).to receive(:postgresql?).and_return(true) -- cgit v1.2.1 From 17f5a34bfd7d122d1bdc8e11632ff072a89e9cbd Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Fri, 10 Feb 2017 10:44:42 -0600 Subject: Display loading indicator when filtering ref switcher dropdown --- spec/features/projects/ref_switcher_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb index 38fe2d92885..4eafac1acd8 100644 --- a/spec/features/projects/ref_switcher_spec.rb +++ b/spec/features/projects/ref_switcher_spec.rb @@ -20,9 +20,9 @@ feature 'Ref switcher', feature: true, js: true do input.set 'binary' wait_for_ajax - input.native.send_keys :down - input.native.send_keys :down - input.native.send_keys :enter + page.within '.dropdown-content ul' do + input.native.send_keys :enter + end end expect(page).to have_title 'binary-encoding' -- cgit v1.2.1 From 4f51e1fad0609c0cd50468243a83970728186a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 26 Jan 2017 18:59:50 +0100 Subject: Add comment events to contributions calendar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/features/calendar_spec.rb | 222 +++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 97 deletions(-) (limited to 'spec') diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index 3e0b6364e0d..35d090c4b7f 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -1,9 +1,11 @@ require 'spec_helper' -feature 'Contributions Calendar', js: true, feature: true do +feature 'Contributions Calendar', :feature, :js do include WaitForAjax + let(:user) { create(:user) } let(:contributed_project) { create(:project, :public) } + let(:issue_note) { create(:note, project: contributed_project) } # Ex/ Sunday Jan 1, 2016 date_format = '%A %b %-d, %Y' @@ -12,31 +14,31 @@ feature 'Contributions Calendar', js: true, feature: true do issue_params = { title: issue_title } def get_cell_color_selector(contributions) - contribution_cell = '.user-contrib-cell' - activity_colors = Array['#ededed', '#acd5f2', '#7fa8c9', '#527ba0', '#254e77'] - activity_colors_index = 0 - - if contributions > 0 && contributions < 10 - activity_colors_index = 1 - elsif contributions >= 10 && contributions < 20 - activity_colors_index = 2 - elsif contributions >= 20 && contributions < 30 - activity_colors_index = 3 - elsif contributions >= 30 - activity_colors_index = 4 - end + activity_colors = %w[#ededed #acd5f2 #7fa8c9 #527ba0 #254e77] + # We currently don't actually test the cases with contributions >= 20 + activity_colors_index = + if contributions > 0 && contributions < 10 + 1 + elsif contributions >= 10 && contributions < 20 + 2 + elsif contributions >= 20 && contributions < 30 + 3 + elsif contributions >= 30 + 4 + else + 0 + end - "#{contribution_cell}[fill='#{activity_colors[activity_colors_index]}']" + ".user-contrib-cell[fill='#{activity_colors[activity_colors_index]}']" end def get_cell_date_selector(contributions, date) - contribution_text = 'No contributions' - - if contributions === 1 - contribution_text = '1 contribution' - elsif contributions > 1 - contribution_text = "#{contributions} contributions" - end + contribution_text = + if contributions.zero? + 'No contributions' + else + "#{contributions} #{'contribution'.pluralize(contributions)}" + end "#{get_cell_color_selector(contributions)}[data-original-title='#{contribution_text}
#{date}']" end @@ -45,129 +47,155 @@ feature 'Contributions Calendar', js: true, feature: true do push_params = { project: contributed_project, action: Event::PUSHED, - author_id: @user.id, + author_id: user.id, data: { commit_count: 3 } } Event.create(push_params) end - def get_first_cell_content - find('.user-calendar-activities').text - end + def note_comment_contribution + note_comment_params = { + project: contributed_project, + action: Event::COMMENTED, + target: issue_note, + author_id: user.id + } - before do - login_as :user - visit @user.username - wait_for_ajax + Event.create(note_comment_params) end - it 'displays calendar', js: true do - expect(page).to have_css('.js-contrib-calendar') + def selected_day_activities + find('.user-calendar-activities').text end - describe 'select calendar day', js: true do - let(:cells) { page.all('.user-contrib-cell') } - let(:first_cell_content_before) { get_first_cell_content } + before do + login_as user + end + describe 'calendar day selection' do before do - cells[0].click + visit user.username wait_for_ajax - first_cell_content_before end - it 'displays calendar day activities', js: true do - expect(get_first_cell_content).not_to eq('') + it 'displays calendar' do + expect(page).to have_css('.js-contrib-calendar') end - describe 'select another calendar day', js: true do + describe 'select calendar day' do + let(:cells) { page.all('.user-contrib-cell') } + before do - cells[1].click + cells[0].click wait_for_ajax + @first_day_activities = selected_day_activities end - it 'displays different calendar day activities', js: true do - expect(get_first_cell_content).not_to eq(first_cell_content_before) + it 'displays calendar day activities' do + expect(selected_day_activities).not_to be_empty end - end - describe 'deselect calendar day', js: true do - before do - cells[0].click - wait_for_ajax + describe 'select another calendar day' do + before do + cells[1].click + wait_for_ajax + end + + it 'displays different calendar day activities' do + expect(selected_day_activities).not_to eq(@first_day_activities) + end end - it 'hides calendar day activities', js: true do - expect(get_first_cell_content).to eq('') + describe 'deselect calendar day' do + before do + cells[0].click + wait_for_ajax + end + + it 'hides calendar day activities' do + expect(selected_day_activities).to be_empty + end end end end - describe '1 calendar activity' do - before do - Issues::CreateService.new(contributed_project, @user, issue_params).execute - visit @user.username - wait_for_ajax + describe 'calendar daily activities' do + shared_context 'visit user page' do + before do + visit user.username + wait_for_ajax + end end - it 'displays calendar activity log', js: true do - expect(find('.content_list .event-note')).to have_content issue_title - end + shared_examples 'a day with activity' do |contribution_count:| + include_context 'visit user page' - it 'displays calendar activity square color for 1 contribution', js: true do - expect(page).to have_selector(get_cell_color_selector(1), count: 1) - end + it 'displays calendar activity square color for 1 contribution' do + expect(page).to have_selector(get_cell_color_selector(contribution_count), count: 1) + end - it 'displays calendar activity square on the correct date', js: true do - today = Date.today.strftime(date_format) - expect(page).to have_selector(get_cell_date_selector(1, today), count: 1) + it 'displays calendar activity square on the correct date' do + today = Date.today.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) + end end - end - describe '10 calendar activities' do - before do - (0..9).each do |i| - push_code_contribution() + describe '1 issue creation calendar activity' do + before do + Issues::CreateService.new(contributed_project, user, issue_params).execute end - visit @user.username - wait_for_ajax - end + it_behaves_like 'a day with activity', contribution_count: 1 - it 'displays calendar activity square color for 10 contributions', js: true do - expect(page).to have_selector(get_cell_color_selector(10), count: 1) - end + describe 'issue title is shown on activity page' do + include_context 'visit user page' - it 'displays calendar activity square on the correct date', js: true do - today = Date.today.strftime(date_format) - expect(page).to have_selector(get_cell_date_selector(10, today), count: 1) + it 'displays calendar activity log' do + expect(find('.content_list .event-note')).to have_content issue_title + end + end end - end - describe 'calendar activity on two days' do - before do - push_code_contribution() - - Timecop.freeze(Date.yesterday) - Issues::CreateService.new(contributed_project, @user, issue_params).execute - Timecop.return + describe '1 comment calendar activity' do + before do + note_comment_contribution + end - visit @user.username - wait_for_ajax + it_behaves_like 'a day with activity', contribution_count: 1 end - it 'displays calendar activity squares for both days', js: true do - expect(page).to have_selector(get_cell_color_selector(1), count: 2) - end + describe '10 calendar activities' do + before do + 10.times { push_code_contribution } + end - it 'displays calendar activity square for yesterday', js: true do - yesterday = Date.yesterday.strftime(date_format) - expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1) + it_behaves_like 'a day with activity', contribution_count: 10 end - it 'displays calendar activity square for today', js: true do - today = Date.today.strftime(date_format) - expect(page).to have_selector(get_cell_date_selector(1, today), count: 1) + describe 'calendar activity on two days' do + before do + push_code_contribution + + Timecop.freeze(Date.yesterday) do + Issues::CreateService.new(contributed_project, user, issue_params).execute + end + end + include_context 'visit user page' + + it 'displays calendar activity squares for both days' do + expect(page).to have_selector(get_cell_color_selector(1), count: 2) + end + + it 'displays calendar activity square for yesterday' do + yesterday = Date.yesterday.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1) + end + + it 'displays calendar activity square for today' do + today = Date.today.strftime(date_format) + expect(page).to have_selector(get_cell_date_selector(1, today), count: 1) + end end end end -- cgit v1.2.1 From 1536109ccd297924474da3e46019b191013c55d4 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 9 Feb 2017 22:35:32 -0500 Subject: Retrigger at.js for slash commands with autocomplete suffix --- spec/features/issues/gfm_autocomplete_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 93139dc9e94..7135565294b 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -182,6 +182,20 @@ feature 'GFM autocomplete', feature: true, js: true do expect(page).not_to have_selector('.atwho-view') end + it 'triggers autocomplete after selecting a slash command' do + note = find('#note_note') + page.within '.timeline-content-form' do + note.native.send_keys('') + note.native.send_keys('/as') + note.click + end + + find('.atwho-view li', text: '/assign').native.send_keys(:tab) + + user_item = find('.atwho-view li', text: user.username) + expect(user_item).to have_content(user.username) + end + def expect_to_wrap(should_wrap, item, note, value) expect(item).to have_content(value) expect(item).not_to have_content("\"#{value}\"") -- cgit v1.2.1 From c2102e6e3bf4fa5220d5fa4d3a4c1549f7385162 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Thu, 2 Feb 2017 15:57:34 -0200 Subject: Move /projects/fork/:id to /projects/:id/fork --- spec/requests/api/fork_spec.rb | 134 ------------------------------------- spec/requests/api/projects_spec.rb | 126 ++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 134 deletions(-) delete mode 100644 spec/requests/api/fork_spec.rb (limited to 'spec') diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb deleted file mode 100644 index 92ac4fd334d..00000000000 --- a/spec/requests/api/fork_spec.rb +++ /dev/null @@ -1,134 +0,0 @@ -require 'spec_helper' - -describe API::Projects, api: true do - include ApiHelpers - let(:user) { create(:user) } - let(:user2) { create(:user) } - let(:admin) { create(:admin) } - let(:group) { create(:group) } - let(:group2) do - group = create(:group, name: 'group2_name') - group.add_owner(user2) - group - end - - describe 'POST /projects/fork/:id' do - let(:project) do - create(:project, :repository, creator: user, namespace: user.namespace) - end - - before do - project.add_reporter(user2) - end - - context 'when authenticated' do - it 'forks if user has sufficient access to project' do - post api("/projects/fork/#{project.id}", user2) - - expect(response).to have_http_status(201) - expect(json_response['name']).to eq(project.name) - expect(json_response['path']).to eq(project.path) - expect(json_response['owner']['id']).to eq(user2.id) - expect(json_response['namespace']['id']).to eq(user2.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - end - - it 'forks if user is admin' do - post api("/projects/fork/#{project.id}", admin) - - expect(response).to have_http_status(201) - expect(json_response['name']).to eq(project.name) - expect(json_response['path']).to eq(project.path) - expect(json_response['owner']['id']).to eq(admin.id) - expect(json_response['namespace']['id']).to eq(admin.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - end - - it 'fails on missing project access for the project to fork' do - new_user = create(:user) - post api("/projects/fork/#{project.id}", new_user) - - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') - end - - it 'fails if forked project exists in the user namespace' do - post api("/projects/fork/#{project.id}", user) - - expect(response).to have_http_status(409) - expect(json_response['message']['name']).to eq(['has already been taken']) - expect(json_response['message']['path']).to eq(['has already been taken']) - end - - it 'fails if project to fork from does not exist' do - post api('/projects/fork/424242', user) - - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') - end - - it 'forks with explicit own user namespace id' do - post api("/projects/fork/#{project.id}", user2), namespace: user2.namespace.id - - expect(response).to have_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) - end - - it 'forks with explicit own user name as namespace' do - post api("/projects/fork/#{project.id}", user2), namespace: user2.username - - expect(response).to have_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) - end - - it 'forks to another user when admin' do - post api("/projects/fork/#{project.id}", admin), namespace: user2.username - - expect(response).to have_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) - end - - it 'fails if trying to fork to another user when not admin' do - post api("/projects/fork/#{project.id}", user2), namespace: admin.namespace.id - - expect(response).to have_http_status(404) - end - - it 'fails if trying to fork to non-existent namespace' do - post api("/projects/fork/#{project.id}", user2), namespace: 42424242 - - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('404 Target Namespace Not Found') - end - - it 'forks to owned group' do - post api("/projects/fork/#{project.id}", user2), namespace: group2.name - - expect(response).to have_http_status(201) - expect(json_response['namespace']['name']).to eq(group2.name) - end - - it 'fails to fork to not owned group' do - post api("/projects/fork/#{project.id}", user2), namespace: group.name - - expect(response).to have_http_status(404) - end - - it 'forks to not owned group when admin' do - post api("/projects/fork/#{project.id}", admin), namespace: group.name - - expect(response).to have_http_status(201) - expect(json_response['namespace']['name']).to eq(group.name) - end - end - - context 'when unauthenticated' do - it 'returns authentication error' do - post api("/projects/fork/#{project.id}") - - expect(response).to have_http_status(401) - expect(json_response['message']).to eq('401 Unauthorized') - end - end - end -end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index ac0bbec44e0..17b5e372bdc 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1332,4 +1332,130 @@ describe API::Projects, api: true do end end end + + describe 'POST /projects/:id/fork' do + let(:project) do + create(:project, :repository, creator: user, namespace: user.namespace) + end + let(:group) { create(:group) } + let(:group2) do + group = create(:group, name: 'group2_name') + group.add_owner(user2) + group + end + + before do + project.add_reporter(user2) + end + + context 'when authenticated' do + it 'forks if user has sufficient access to project' do + post api("/projects/#{project.id}/fork", user2) + + expect(response).to have_http_status(201) + expect(json_response['name']).to eq(project.name) + expect(json_response['path']).to eq(project.path) + expect(json_response['owner']['id']).to eq(user2.id) + expect(json_response['namespace']['id']).to eq(user2.namespace.id) + expect(json_response['forked_from_project']['id']).to eq(project.id) + end + + it 'forks if user is admin' do + post api("/projects/#{project.id}/fork", admin) + + expect(response).to have_http_status(201) + expect(json_response['name']).to eq(project.name) + expect(json_response['path']).to eq(project.path) + expect(json_response['owner']['id']).to eq(admin.id) + expect(json_response['namespace']['id']).to eq(admin.namespace.id) + expect(json_response['forked_from_project']['id']).to eq(project.id) + end + + it 'fails on missing project access for the project to fork' do + new_user = create(:user) + post api("/projects/#{project.id}/fork", new_user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Project Not Found') + end + + it 'fails if forked project exists in the user namespace' do + post api("/projects/#{project.id}/fork", user) + + expect(response).to have_http_status(409) + expect(json_response['message']['name']).to eq(['has already been taken']) + expect(json_response['message']['path']).to eq(['has already been taken']) + end + + it 'fails if project to fork from does not exist' do + post api('/projects/424242/fork', user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Project Not Found') + end + + it 'forks with explicit own user namespace id' do + post api("/projects/#{project.id}/fork", user2), namespace: user2.namespace.id + + expect(response).to have_http_status(201) + expect(json_response['owner']['id']).to eq(user2.id) + end + + it 'forks with explicit own user name as namespace' do + post api("/projects/#{project.id}/fork", user2), namespace: user2.username + + expect(response).to have_http_status(201) + expect(json_response['owner']['id']).to eq(user2.id) + end + + it 'forks to another user when admin' do + post api("/projects/#{project.id}/fork", admin), namespace: user2.username + + expect(response).to have_http_status(201) + expect(json_response['owner']['id']).to eq(user2.id) + end + + it 'fails if trying to fork to another user when not admin' do + post api("/projects/#{project.id}/fork", user2), namespace: admin.namespace.id + + expect(response).to have_http_status(404) + end + + it 'fails if trying to fork to non-existent namespace' do + post api("/projects/#{project.id}/fork", user2), namespace: 42424242 + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Target Namespace Not Found') + end + + it 'forks to owned group' do + post api("/projects/#{project.id}/fork", user2), namespace: group2.name + + expect(response).to have_http_status(201) + expect(json_response['namespace']['name']).to eq(group2.name) + end + + it 'fails to fork to not owned group' do + post api("/projects/#{project.id}/fork", user2), namespace: group.name + + expect(response).to have_http_status(404) + end + + it 'forks to not owned group when admin' do + post api("/projects/#{project.id}/fork", admin), namespace: group.name + + expect(response).to have_http_status(201) + expect(json_response['namespace']['name']).to eq(group.name) + end + end + + context 'when unauthenticated' do + it 'returns authentication error' do + post api("/projects/#{project.id}/fork") + + expect(response).to have_http_status(401) + expect(json_response['message']).to eq('401 Unauthorized') + end + end + end end -- cgit v1.2.1 From 2c55fd0019ea9ac33e310151a61892fada42d5a2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 13 Feb 2017 13:26:33 +0200 Subject: Add GFM support to nested groups Signed-off-by: Dmitriy Zaporozhets --- spec/lib/banzai/filter/user_reference_filter_spec.rb | 13 +++++++++++++ spec/lib/gitlab/regex_spec.rb | 12 ++++++++++++ 2 files changed, 25 insertions(+) (limited to 'spec') diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 3e1ac9fb2b2..d5d128c1907 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -112,6 +112,19 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do end end + context 'mentioning a nested group' do + it_behaves_like 'a reference containing an element node' + + let(:group) { create(:group, :nested) } + let(:reference) { group.to_reference } + + it 'links to the nested group' do + doc = reference_filter("Hey #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls.group_url(group) + end + end + it 'links with adjacent text' do doc = reference_filter("Mention me (#{reference}.)") expect(doc.to_html).to match(/\(#{reference}<\/a>\.\)/) diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 1dbc2f6eb13..089ec4e2737 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -50,4 +50,16 @@ describe Gitlab::Regex, lib: true do it { is_expected.not_to match('9foo') } it { is_expected.not_to match('foo-') } end + + describe 'NAMESPACE_REF_REGEX_STR' do + subject { %r{\A#{Gitlab::Regex::NAMESPACE_REF_REGEX_STR}\z} } + + it { is_expected.to match('gitlab.org') } + it { is_expected.to match('gitlab.org/gitlab-git') } + it { is_expected.not_to match('gitlab.org.') } + it { is_expected.not_to match('gitlab.org/') } + it { is_expected.not_to match('/gitlab.org') } + it { is_expected.not_to match('gitlab.git') } + it { is_expected.not_to match('gitlab git') } + end end -- cgit v1.2.1 From 010c9337b5e024d5af586fcc8d73fe72a52fd9f1 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Mon, 13 Feb 2017 15:55:12 -0600 Subject: Add tests --- spec/javascripts/gl_dropdown_spec.js.es6 | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index 317f38c5888..c207fb00a47 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -139,6 +139,14 @@ require('~/lib/utils/url_utility'); this.dropdownButtonElement.click(); }); + it('should show loading indicator while search results are being fetched by backend', () => { + const dropdownMenu = document.querySelector('.dropdown-menu'); + + expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(true); + remoteCallback(); + expect(dropdownMenu.className.indexOf('is-loading') !== -1).toEqual(false); + }); + it('should not focus search input while remote task is not complete', () => { expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR)); remoteCallback(); -- cgit v1.2.1 From 79ce7579bb7dad3dba344893fb20c2f1346c84a0 Mon Sep 17 00:00:00 2001 From: wendy0402 Date: Tue, 14 Feb 2017 09:28:45 +0700 Subject: Make it possible to pass coverage value to commit status API --- spec/requests/api/commit_statuses_spec.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index 88361def3cf..eb53fd71872 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -156,6 +156,7 @@ describe API::CommitStatuses, api: true do context: 'coverage', ref: 'develop', description: 'test', + coverage: 80.0, target_url: 'http://gitlab.com/status' } post api(post_url, developer), optional_params @@ -167,6 +168,7 @@ describe API::CommitStatuses, api: true do expect(json_response['status']).to eq('success') expect(json_response['name']).to eq('coverage') expect(json_response['ref']).to eq('develop') + expect(json_response['coverage']).to eq(80.0) expect(json_response['description']).to eq('test') expect(json_response['target_url']).to eq('http://gitlab.com/status') end -- cgit v1.2.1 From 109e8ef4485fb45f0a50690e732ee2b9c6e910b0 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Fri, 30 Dec 2016 13:26:30 +0000 Subject: Make WikiPage comparable according to StaticModel interface * Add WikiPage#id method returning associated SHA for wiki page commit --- spec/models/wiki_page_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'spec') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 579ebac7afb..753dc938c52 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -318,6 +318,19 @@ describe WikiPage, models: true do end end + describe '#==' do + let(:original_wiki_page) { create(:wiki_page) } + + it 'returns true for identical wiki page' do + expect(original_wiki_page).to eq(original_wiki_page) + end + + it 'returns false for updated wiki page' do + updated_wiki_page = original_wiki_page.update("Updated content") + expect(original_wiki_page).not_to eq(updated_wiki_page) + end + end + private def remove_temp_repo(path) -- cgit v1.2.1 From a616b475b16fa2689ab09fee9bb9c79c24f8bb27 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Tue, 20 Dec 2016 13:31:21 +0000 Subject: Add tests for WikiPages services * Alter wiki_pages factory with custom creation operation --- spec/factories/wiki_pages.rb | 18 ++++++++++++ spec/services/wiki_pages/create_service_spec.rb | 36 ++++++++++++++++++++++++ spec/services/wiki_pages/update_service_spec.rb | 37 +++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 spec/services/wiki_pages/create_service_spec.rb create mode 100644 spec/services/wiki_pages/update_service_spec.rb (limited to 'spec') diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb index efa6cbe5bb1..4105f59e289 100644 --- a/spec/factories/wiki_pages.rb +++ b/spec/factories/wiki_pages.rb @@ -2,8 +2,26 @@ require 'ostruct' FactoryGirl.define do factory :wiki_page do + transient do + attrs do + { + title: 'Title', + content: 'Content for wiki page', + format: 'markdown' + } + end + end + page { OpenStruct.new(url_path: 'some-name') } association :wiki, factory: :project_wiki, strategy: :build initialize_with { new(wiki, page, true) } + + before(:create) do |page, evaluator| + page.attributes = evaluator.attrs + end + + to_create do |page| + page.create + end end end diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb new file mode 100644 index 00000000000..5341ba3d261 --- /dev/null +++ b/spec/services/wiki_pages/create_service_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe WikiPages::CreateService, services: true do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:opts) do + { + title: 'Title', + content: 'Content for wiki page', + format: 'markdown' + } + end + let(:service) { described_class.new(project, user, opts) } + + describe '#execute' do + context "valid params" do + before do + allow(service).to receive(:execute_hooks) + project.add_master(user) + end + + subject { service.execute } + + it 'creates a valid wiki page' do + is_expected.to be_valid + expect(subject.title).to eq(opts[:title]) + expect(subject.content).to eq(opts[:content]) + expect(subject.format).to eq(opts[:format].to_sym) + end + + it 'executes webhooks' do + expect(service).to have_received(:execute_hooks).once.with(subject, 'create') + end + end + end +end diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb new file mode 100644 index 00000000000..2bccca764d7 --- /dev/null +++ b/spec/services/wiki_pages/update_service_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe WikiPages::UpdateService, services: true do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:wiki_page) { create(:wiki_page) } + let(:opts) do + { + content: 'New content for wiki page', + format: 'markdown', + message: 'New wiki message' + } + end + let(:service) { described_class.new(project, user, opts) } + + describe '#execute' do + context "valid params" do + before do + allow(service).to receive(:execute_hooks) + project.add_master(user) + end + + subject { service.execute(wiki_page) } + + it 'updates the wiki page' do + is_expected.to be_valid + expect(subject.content).to eq(opts[:content]) + expect(subject.format).to eq(opts[:format].to_sym) + expect(subject.message).to eq(opts[:message]) + end + + it 'executes webhooks' do + expect(service).to have_received(:execute_hooks).once.with(subject, 'update') + end + end + end +end -- cgit v1.2.1 From 142432ce5ae78cc873b9748f41e54257adc56dcc Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Tue, 14 Feb 2017 17:27:29 +1100 Subject: update issue count when closing/reopening an issue --- spec/javascripts/issue_spec.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 5b0b7aa7903..beb544468ef 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -105,6 +105,7 @@ require('~/issue'); expectIssueState(false); expect($btnClose).toHaveProp('disabled', false); + expect($('.issue_counter')).toHaveText(0); }); it('fails to close an issue with success:false', function() { @@ -121,6 +122,7 @@ require('~/issue'); expectIssueState(true); expect($btnClose).toHaveProp('disabled', false); expectErrorMessage(); + expect($('.issue_counter')).toHaveText(1); }); it('fails to closes an issue with HTTP error', function() { @@ -135,6 +137,7 @@ require('~/issue'); expectIssueState(true); expect($btnClose).toHaveProp('disabled', true); expectErrorMessage(); + expect($('.issue_counter')).toHaveText(1); }); }); @@ -159,6 +162,7 @@ require('~/issue'); expectIssueState(true); expect($btnReopen).toHaveProp('disabled', false); + expect($('.issue_counter')).toHaveText(1); }); }); }).call(this); -- cgit v1.2.1 From 1fc6f6cc7101a9c4dee694682a3533a5e4ba3447 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Tue, 20 Dec 2016 13:32:43 +0000 Subject: Execute web hooks for WikiPage delete operation * Add a new DestroyService for Wiki Pages * Alter WikiPagesController to use the new service --- spec/services/wiki_pages/destroy_service_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/services/wiki_pages/destroy_service_spec.rb (limited to 'spec') diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb new file mode 100644 index 00000000000..a4b9a390fe2 --- /dev/null +++ b/spec/services/wiki_pages/destroy_service_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe WikiPages::DestroyService, services: true do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:wiki_page) { create(:wiki_page) } + let(:service) { described_class.new(project, user) } + + describe '#execute' do + before do + allow(service).to receive(:execute_hooks) + project.add_master(user) + end + + it 'executes webhooks' do + service.execute(wiki_page) + + expect(service).to have_received(:execute_hooks).once.with(wiki_page, 'delete') + end + end +end -- cgit v1.2.1 From b06ac70ab5fec093bf189e8d0efb6ddb22796051 Mon Sep 17 00:00:00 2001 From: winniehell Date: Mon, 13 Feb 2017 23:35:08 +0100 Subject: Add dynamic fixture for todos --- spec/javascripts/fixtures/todos.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 spec/javascripts/fixtures/todos.rb (limited to 'spec') diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb new file mode 100644 index 00000000000..30ccf49e7e8 --- /dev/null +++ b/spec/javascripts/fixtures/todos.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe Dashboard::TodosController, '(JavaScript fixtures)', type: :controller do + include JavaScriptFixturesHelpers + + let(:admin) { create(:admin) } + let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} + let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') } + let(:issue_1) { create(:issue, title: 'issue_1', project: project) } + let!(:todo_1) { create(:todo, user: admin, project: project, target: issue_1, created_at: 5.hours.ago) } + let(:issue_2) { create(:issue, title: 'issue_2', project: project) } + let!(:todo_2) { create(:todo, :done, user: admin, project: project, target: issue_2, created_at: 50.hours.ago) } + + render_views + + before(:all) do + clean_frontend_fixtures('todos/') + end + + before(:each) do + sign_in(admin) + end + + it 'todos/todos.html.raw' do |example| + get :index + + expect(response).to be_success + store_frontend_fixture(response, example.description) + end +end -- cgit v1.2.1 From d8517fd457995927f8a2196e9dba1b6d68d027ad Mon Sep 17 00:00:00 2001 From: winniehell Date: Tue, 14 Feb 2017 01:09:57 +0100 Subject: Replace static fixture for right_sidebar_spec.js (!9211) --- spec/javascripts/fixtures/.gitignore | 1 + spec/javascripts/fixtures/todos.json | 4 ---- spec/javascripts/fixtures/todos.rb | 40 ++++++++++++++++++++++++++-------- spec/javascripts/right_sidebar_spec.js | 4 ++-- 4 files changed, 34 insertions(+), 15 deletions(-) delete mode 100644 spec/javascripts/fixtures/todos.json (limited to 'spec') diff --git a/spec/javascripts/fixtures/.gitignore b/spec/javascripts/fixtures/.gitignore index 009b68d5d1c..0c35cdd778e 100644 --- a/spec/javascripts/fixtures/.gitignore +++ b/spec/javascripts/fixtures/.gitignore @@ -1 +1,2 @@ *.html.raw +*.json diff --git a/spec/javascripts/fixtures/todos.json b/spec/javascripts/fixtures/todos.json deleted file mode 100644 index 62c2387d515..00000000000 --- a/spec/javascripts/fixtures/todos.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "count": 1, - "delete_path": "/dashboard/todos/1" -} \ No newline at end of file diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index 30ccf49e7e8..2c08b06ea9e 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Dashboard::TodosController, '(JavaScript fixtures)', type: :controller do +describe 'Todos (JavaScript fixtures)' do include JavaScriptFixturesHelpers let(:admin) { create(:admin) } @@ -11,20 +11,42 @@ describe Dashboard::TodosController, '(JavaScript fixtures)', type: :controller let(:issue_2) { create(:issue, title: 'issue_2', project: project) } let!(:todo_2) { create(:todo, :done, user: admin, project: project, target: issue_2, created_at: 50.hours.ago) } - render_views - before(:all) do clean_frontend_fixtures('todos/') end - before(:each) do - sign_in(admin) + describe Dashboard::TodosController, '(JavaScript fixtures)', type: :controller do + render_views + + before(:each) do + sign_in(admin) + end + + it 'todos/todos.html.raw' do |example| + get :index + + expect(response).to be_success + store_frontend_fixture(response, example.description) + end end - it 'todos/todos.html.raw' do |example| - get :index + describe Projects::TodosController, '(JavaScript fixtures)', type: :controller do + render_views + + before(:each) do + sign_in(admin) + end + + it 'todos/todos.json' do |example| + post :create, + namespace_id: namespace.path, + project_id: project.path, + issuable_type: 'issue', + issuable_id: issue_2.id, + format: 'json' - expect(response).to be_success - store_frontend_fixture(response, example.description) + expect(response).to be_success + store_frontend_fixture(response, example.description) + end end end diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index f7636865aa1..9284af8a8d9 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -34,7 +34,7 @@ require('~/extensions/jquery.js'); describe('RightSidebar', function() { var fixtureName = 'issues/open-issue.html.raw'; preloadFixtures(fixtureName); - loadJSONFixtures('todos.json'); + loadJSONFixtures('todos/todos.json'); beforeEach(function() { loadFixtures(fixtureName); @@ -64,7 +64,7 @@ require('~/extensions/jquery.js'); }); it('should broadcast todo:toggle event when add todo clicked', function() { - var todos = getJSONFixture('todos.json'); + var todos = getJSONFixture('todos/todos.json'); spyOn(jQuery, 'ajax').and.callFake(function() { var d = $.Deferred(); var response = todos; -- cgit v1.2.1 From c48539463ff2250058fbfa9d1811977f01313b7c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 14 Feb 2017 15:34:36 +0200 Subject: Expose Namespace#full_path in namespaces API Signed-off-by: Dmitriy Zaporozhets --- spec/requests/api/namespaces_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb index c1edf384d5c..a945d56f529 100644 --- a/spec/requests/api/namespaces_spec.rb +++ b/spec/requests/api/namespaces_spec.rb @@ -5,7 +5,7 @@ describe API::Namespaces, api: true do let(:admin) { create(:admin) } let(:user) { create(:user) } let!(:group1) { create(:group) } - let!(:group2) { create(:group) } + let!(:group2) { create(:group, :nested) } describe "GET /namespaces" do context "when unauthenticated" do @@ -25,11 +25,13 @@ describe API::Namespaces, api: true do end it "admin: returns an array of matched namespaces" do - get api("/namespaces?search=#{group1.name}", admin) + get api("/namespaces?search=#{group2.name}", admin) expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) + expect(json_response.last['path']).to eq(group2.path) + expect(json_response.last['full_path']).to eq(group2.full_path) end end -- cgit v1.2.1 From 4e9e29d295fe2f8cd258cde4b65e244eb74a1ae6 Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Wed, 1 Feb 2017 11:23:57 +0100 Subject: API: Consolidate /projects endpoint It consolidates these endpoints: - /projects - /projects/owned - /projects/visible - /projects/starred - /projects/all Into the /projects endpoint using query parameters. --- spec/requests/api/groups_spec.rb | 20 +++ spec/requests/api/projects_spec.rb | 258 +++++++++++++++---------------------- 2 files changed, 122 insertions(+), 156 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index f78bde6f53a..ccd7898586c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -338,6 +338,26 @@ describe API::Groups, api: true do expect(json_response.length).to eq(1) expect(json_response.first['name']).to eq(project3.name) end + + it 'only returns the projects owned by user' do + project2.group.add_owner(user3) + + get api("/groups/#{project2.group.id}/projects", user3), owned: true + + expect(response).to have_http_status(200) + expect(json_response.length).to eq(1) + expect(json_response.first['name']).to eq(project2.name) + end + + it 'only returns the projects starred by user' do + user1.starred_projects = [project1] + + get api("/groups/#{group1.id}/projects", user1), starred: true + + expect(response).to have_http_status(200) + expect(json_response.length).to eq(1) + expect(json_response.first['name']).to eq(project1.name) + end end context "when authenticated as admin" do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 17b5e372bdc..bca7642b6fc 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -41,26 +41,40 @@ describe API::Projects, api: true do end describe 'GET /projects' do - before { project } + shared_examples_for 'projects response' do + it 'returns an array of projects' do + get api('/projects', current_user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.map { |p| p['id'] }).to contain_exactly(*projects.map(&:id)) + end + end + + let!(:public_project) { create(:empty_project, :public, name: 'public_project') } + before do + project + project2 + project3 + project4 + end context 'when unauthenticated' do - it 'returns authentication error' do - get api('/projects') - expect(response).to have_http_status(401) + it_behaves_like 'projects response' do + let(:current_user) { nil } + let(:projects) { [public_project] } end end context 'when authenticated as regular user' do - it 'returns an array of projects' do - get api('/projects', user) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(project.name) - expect(json_response.first['owner']['username']).to eq(user.username) + it_behaves_like 'projects response' do + let(:current_user) { user } + let(:projects) { [public_project, project, project2, project3] } end it 'includes the project labels as the tag_list' do get api('/projects', user) + expect(response.status).to eq 200 expect(json_response).to be_an Array expect(json_response.first.keys).to include('tag_list') @@ -68,21 +82,39 @@ describe API::Projects, api: true do it 'includes open_issues_count' do get api('/projects', user) + expect(response.status).to eq 200 expect(json_response).to be_an Array expect(json_response.first.keys).to include('open_issues_count') end - it 'does not include open_issues_count' do + it 'does not include open_issues_count if issues are disabled' do project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) get api('/projects', user) + expect(response.status).to eq 200 expect(json_response).to be_an Array - expect(json_response.first.keys).not_to include('open_issues_count') + expect(json_response.find { |hash| hash['id'] == project.id }.keys).not_to include('open_issues_count') + end + + it "does not include statistics by default" do + get api('/projects', user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).not_to include('statistics') end - context 'GET /projects?simple=true' do + it "includes statistics if requested" do + get api('/projects', user), statistics: true + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).to include 'statistics' + end + + context 'and with simple=true' do it 'returns a simplified version of all the projects' do expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"] @@ -97,6 +129,7 @@ describe API::Projects, api: true do context 'and using search' do it 'returns searched project' do get api('/projects', user), { search: project.name } + expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -106,196 +139,109 @@ describe API::Projects, api: true do context 'and using the visibility filter' do it 'filters based on private visibility param' do get api('/projects', user), { visibility: 'private' } + expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).count) + expect(json_response.map { |p| p['id'] }).to contain_exactly(project.id, project2.id, project3.id) end it 'filters based on internal visibility param' do + project2.update_attribute(:visibility_level, Gitlab::VisibilityLevel::INTERNAL) + get api('/projects', user), { visibility: 'internal' } + expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).count) + expect(json_response.map { |p| p['id'] }).to contain_exactly(project2.id) end it 'filters based on public visibility param' do get api('/projects', user), { visibility: 'public' } + expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).count) + expect(json_response.map { |p| p['id'] }).to contain_exactly(public_project.id) end end context 'and using sorting' do - before do - project2 - project3 - end - it 'returns the correct order when sorted by id' do get api('/projects', user), { order_by: 'id', sort: 'desc' } + expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.first['id']).to eq(project3.id) end end - end - end - describe 'GET /projects/all' do - before { project } + context 'and with owned=true' do + it 'returns an array of projects the user owns' do + get api('/projects', user4), owned: true - context 'when unauthenticated' do - it 'returns authentication error' do - get api('/projects/all') - expect(response).to have_http_status(401) - end - end - - context 'when authenticated as regular user' do - it 'returns authentication error' do - get api('/projects/all', user) - expect(response).to have_http_status(403) - end - end - - context 'when authenticated as admin' do - it 'returns an array of all projects' do - get api('/projects/all', admin) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - - expect(json_response).to satisfy do |response| - response.one? do |entry| - entry.has_key?('permissions') && - entry['name'] == project.name && - entry['owner']['username'] == user.username - end + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['name']).to eq(project4.name) + expect(json_response.first['owner']['username']).to eq(user4.username) end end - it "does not include statistics by default" do - get api('/projects/all', admin) + context 'and with starred=true' do + let(:public_project) { create(:empty_project, :public) } - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first).not_to include('statistics') - end - - it "includes statistics if requested" do - get api('/projects/all', admin), statistics: true - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first).to include 'statistics' - end - end - end - - describe 'GET /projects/owned' do - before do - project3 - project4 - end - - context 'when unauthenticated' do - it 'returns authentication error' do - get api('/projects/owned') - expect(response).to have_http_status(401) - end - end - - context 'when authenticated as project owner' do - it 'returns an array of projects the user owns' do - get api('/projects/owned', user4) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(project4.name) - expect(json_response.first['owner']['username']).to eq(user4.username) - end - - it "does not include statistics by default" do - get api('/projects/owned', user4) - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first).not_to include('statistics') - end - - it "includes statistics if requested" do - attributes = { - commit_count: 23, - storage_size: 702, - repository_size: 123, - lfs_objects_size: 234, - build_artifacts_size: 345, - } - - project4.statistics.update!(attributes) + before do + project_member2 + user3.update_attributes(starred_projects: [project, project2, project3, public_project]) + end - get api('/projects/owned', user4), statistics: true + it 'returns the starred projects viewable by the user' do + get api('/projects', user3), starred: true - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first['statistics']).to eq attributes.stringify_keys + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id) + end end - end - end - describe 'GET /projects/visible' do - shared_examples_for 'visible projects response' do - it 'returns the visible projects' do - get api('/projects/visible', current_user) + context 'and with all query parameters' do + # | | project5 | project6 | project7 | project8 | project9 | + # |---------+----------+----------+----------+----------+----------| + # | search | x | | x | x | x | + # | starred | x | x | | x | x | + # | public | x | x | x | | x | + # | owned | x | x | x | x | | + let!(:project5) { create(:empty_project, :public, path: 'gitlab5', namespace: user.namespace) } + let!(:project6) { create(:empty_project, :public, path: 'project6', namespace: user.namespace) } + let!(:project7) { create(:empty_project, :public, path: 'gitlab7', namespace: user.namespace) } + let!(:project8) { create(:empty_project, path: 'gitlab8', namespace: user.namespace) } + let!(:project9) { create(:empty_project, :public, path: 'gitlab9') } - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(*projects.map(&:id)) - end - end + before do + user.update_attributes(starred_projects: [project5, project6, project8, project9]) + end - let!(:public_project) { create(:empty_project, :public) } - before do - project - project2 - project3 - project4 - end + it 'returns only projects that satify all query parameters' do + get api('/projects', user), { visibility: 'public', owned: true, starred: true, search: 'gitlab' } - context 'when unauthenticated' do - it_behaves_like 'visible projects response' do - let(:current_user) { nil } - let(:projects) { [public_project] } - end - end - - context 'when authenticated' do - it_behaves_like 'visible projects response' do - let(:current_user) { user } - let(:projects) { [public_project, project, project2, project3] } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.first['id']).to eq(project5.id) + end end end context 'when authenticated as a different user' do - it_behaves_like 'visible projects response' do + it_behaves_like 'projects response' do let(:current_user) { user2 } let(:projects) { [public_project] } end end - end - - describe 'GET /projects/starred' do - let(:public_project) { create(:empty_project, :public) } - - before do - project_member2 - user3.update_attributes(starred_projects: [project, project2, project3, public_project]) - end - it 'returns the starred projects viewable by the user' do - get api('/projects/starred', user3) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id) + context 'when authenticated as admin' do + it_behaves_like 'projects response' do + let(:current_user) { admin } + let(:projects) { Project.all } + end end end -- cgit v1.2.1 From 613856face7f2ea58c229682a3acbba3e64be01b Mon Sep 17 00:00:00 2001 From: dixpac Date: Tue, 14 Feb 2017 16:33:50 +0100 Subject: Move tag services to `Tags` namespace CreateTagService and DeleteTagService where in root namespace, by following service code organization I moved them in Tags::CreateService and Tags::DestroyService --- spec/services/create_tag_service_spec.rb | 53 ------------------------------ spec/services/delete_tag_service_spec.rb | 17 ---------- spec/services/tags/create_service_spec.rb | 53 ++++++++++++++++++++++++++++++ spec/services/tags/destroy_service_spec.rb | 17 ++++++++++ 4 files changed, 70 insertions(+), 70 deletions(-) delete mode 100644 spec/services/create_tag_service_spec.rb delete mode 100644 spec/services/delete_tag_service_spec.rb create mode 100644 spec/services/tags/create_service_spec.rb create mode 100644 spec/services/tags/destroy_service_spec.rb (limited to 'spec') diff --git a/spec/services/create_tag_service_spec.rb b/spec/services/create_tag_service_spec.rb deleted file mode 100644 index 7dc43c50b0d..00000000000 --- a/spec/services/create_tag_service_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'spec_helper' - -describe CreateTagService, services: true do - let(:project) { create(:project) } - let(:repository) { project.repository } - let(:user) { create(:user) } - let(:service) { described_class.new(project, user) } - - describe '#execute' do - it 'creates the tag and returns success' do - response = service.execute('v42.42.42', 'master', 'Foo') - - expect(response[:status]).to eq(:success) - expect(response[:tag]).to be_a Gitlab::Git::Tag - expect(response[:tag].name).to eq('v42.42.42') - end - - context 'when target is invalid' do - it 'returns an error' do - response = service.execute('v1.1.0', 'foo', 'Foo') - - expect(response).to eq(status: :error, - message: 'Target foo is invalid') - end - end - - context 'when tag already exists' do - it 'returns an error' do - expect(repository).to receive(:add_tag). - with(user, 'v1.1.0', 'master', 'Foo'). - and_raise(Rugged::TagError) - - response = service.execute('v1.1.0', 'master', 'Foo') - - expect(response).to eq(status: :error, - message: 'Tag v1.1.0 already exists') - end - end - - context 'when pre-receive hook fails' do - it 'returns an error' do - expect(repository).to receive(:add_tag). - with(user, 'v1.1.0', 'master', 'Foo'). - and_raise(GitHooksService::PreReceiveError, 'something went wrong') - - response = service.execute('v1.1.0', 'master', 'Foo') - - expect(response).to eq(status: :error, - message: 'something went wrong') - end - end - end -end diff --git a/spec/services/delete_tag_service_spec.rb b/spec/services/delete_tag_service_spec.rb deleted file mode 100644 index 477551f5036..00000000000 --- a/spec/services/delete_tag_service_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'spec_helper' - -describe DeleteTagService, services: true do - let(:project) { create(:project) } - let(:repository) { project.repository } - let(:user) { create(:user) } - let(:service) { described_class.new(project, user) } - - describe '#execute' do - it 'removes the tag' do - expect(repository).to receive(:before_remove_tag) - expect(service).to receive(:success) - - service.execute('v1.1.0') - end - end -end diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb new file mode 100644 index 00000000000..5478b8c9ec0 --- /dev/null +++ b/spec/services/tags/create_service_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Tags::CreateService, services: true do + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:user) { create(:user) } + let(:service) { described_class.new(project, user) } + + describe '#execute' do + it 'creates the tag and returns success' do + response = service.execute('v42.42.42', 'master', 'Foo') + + expect(response[:status]).to eq(:success) + expect(response[:tag]).to be_a Gitlab::Git::Tag + expect(response[:tag].name).to eq('v42.42.42') + end + + context 'when target is invalid' do + it 'returns an error' do + response = service.execute('v1.1.0', 'foo', 'Foo') + + expect(response).to eq(status: :error, + message: 'Target foo is invalid') + end + end + + context 'when tag already exists' do + it 'returns an error' do + expect(repository).to receive(:add_tag). + with(user, 'v1.1.0', 'master', 'Foo'). + and_raise(Rugged::TagError) + + response = service.execute('v1.1.0', 'master', 'Foo') + + expect(response).to eq(status: :error, + message: 'Tag v1.1.0 already exists') + end + end + + context 'when pre-receive hook fails' do + it 'returns an error' do + expect(repository).to receive(:add_tag). + with(user, 'v1.1.0', 'master', 'Foo'). + and_raise(GitHooksService::PreReceiveError, 'something went wrong') + + response = service.execute('v1.1.0', 'master', 'Foo') + + expect(response).to eq(status: :error, + message: 'something went wrong') + end + end + end +end diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb new file mode 100644 index 00000000000..a388c93379a --- /dev/null +++ b/spec/services/tags/destroy_service_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Tags::DestroyService, services: true do + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:user) { create(:user) } + let(:service) { described_class.new(project, user) } + + describe '#execute' do + it 'removes the tag' do + expect(repository).to receive(:before_remove_tag) + expect(service).to receive(:success) + + service.execute('v1.1.0') + end + end +end -- cgit v1.2.1 From 6676b4f0dd05ffb6071a3329cca4459e7cddcdc3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 14 Feb 2017 16:03:24 +0200 Subject: Use Namespace#full_path instead of Namespace#path Signed-off-by: Dmitriy Zaporozhets --- .../lib/gitlab/import_export/import_export_spec.rb | 5 +-- spec/models/project_spec.rb | 39 ++++++++++++++++------ spec/requests/api/projects_spec.rb | 1 + spec/requests/api/v3/projects_spec.rb | 1 + 4 files changed, 34 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb index 53f7d244d88..20743811dab 100644 --- a/spec/lib/gitlab/import_export/import_export_spec.rb +++ b/spec/lib/gitlab/import_export/import_export_spec.rb @@ -2,14 +2,15 @@ require 'spec_helper' describe Gitlab::ImportExport, services: true do describe 'export filename' do - let(:project) { create(:empty_project, :public, path: 'project-path') } + let(:group) { create(:group, :nested) } + let(:project) { create(:empty_project, :public, path: 'project-path', namespace: group) } it 'contains the project path' do expect(described_class.export_filename(project: project)).to include(project.path) end it 'contains the namespace path' do - expect(described_class.export_filename(project: project)).to include(project.namespace.path) + expect(described_class.export_filename(project: project)).to include(project.namespace.full_path) end it 'does not go over a certain length' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 35f3dd00870..b0087a9e15d 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1852,8 +1852,8 @@ describe Project, models: true do end describe '#pages_url' do - let(:group) { create :group, name: group_name } - let(:project) { create :empty_project, namespace: group, name: project_name } + let(:group) { create :group, name: 'Group' } + let(:nested_group) { create :group, parent: group } let(:domain) { 'Example.com' } subject { project.pages_url } @@ -1863,18 +1863,37 @@ describe Project, models: true do allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com') end - context 'group page' do - let(:group_name) { 'Group' } - let(:project_name) { 'group.example.com' } + context 'top-level group' do + let(:project) { create :empty_project, namespace: group, name: project_name } - it { is_expected.to eq("http://group.example.com") } + context 'group page' do + let(:project_name) { 'group.example.com' } + + it { is_expected.to eq("http://group.example.com") } + end + + context 'project page' do + let(:project_name) { 'Project' } + + it { is_expected.to eq("http://group.example.com/project") } + end end - context 'project page' do - let(:group_name) { 'Group' } - let(:project_name) { 'Project' } + context 'nested group' do + let(:project) { create :empty_project, namespace: nested_group, name: project_name } + let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" } - it { is_expected.to eq("http://group.example.com/project") } + context 'group page' do + let(:project_name) { 'group.example.com' } + + it { is_expected.to eq(expected_url) } + end + + context 'project page' do + let(:project_name) { 'Project' } + + it { is_expected.to eq(expected_url) } + end end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index ac0bbec44e0..5ea89c7e27c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -639,6 +639,7 @@ describe API::Projects, api: true do 'name' => user.namespace.name, 'path' => user.namespace.path, 'kind' => user.namespace.kind, + 'full_path' => user.namespace.full_path, }) end diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index a495122bba7..36d99d80e79 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -682,6 +682,7 @@ describe API::V3::Projects, api: true do 'name' => user.namespace.name, 'path' => user.namespace.path, 'kind' => user.namespace.kind, + 'full_path' => user.namespace.full_path, }) end -- cgit v1.2.1 From 409a3250438981331a6f97422d53bc1095ff13d4 Mon Sep 17 00:00:00 2001 From: winniehell Date: Fri, 10 Feb 2017 00:12:51 +0100 Subject: Replace static fixture for behaviors/requires_input_spec.js (!9162) --- spec/javascripts/behaviors/requires_input_spec.js | 13 +++++++------ .../fixtures/behaviors/requires_input.html.haml | 18 ------------------ 2 files changed, 7 insertions(+), 24 deletions(-) delete mode 100644 spec/javascripts/fixtures/behaviors/requires_input.html.haml (limited to 'spec') diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index a958ac76e66..631fca06514 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -4,18 +4,19 @@ require('~/behaviors/requires_input'); (function() { describe('requiresInput', function() { - preloadFixtures('static/behaviors/requires_input.html.raw'); + preloadFixtures('branches/new_branch.html.raw'); beforeEach(function() { - return loadFixtures('static/behaviors/requires_input.html.raw'); + loadFixtures('branches/new_branch.html.raw'); + this.submitButton = $('button[type="submit"]'); }); it('disables submit when any field is required', function() { $('.js-requires-input').requiresInput(); - return expect($('.submit')).toBeDisabled(); + return expect(this.submitButton).toBeDisabled(); }); it('enables submit when no field is required', function() { $('*[required=required]').removeAttr('required'); $('.js-requires-input').requiresInput(); - return expect($('.submit')).not.toBeDisabled(); + return expect(this.submitButton).not.toBeDisabled(); }); it('enables submit when all required fields are pre-filled', function() { $('*[required=required]').remove(); @@ -25,9 +26,9 @@ require('~/behaviors/requires_input'); it('enables submit when all required fields receive input', function() { $('.js-requires-input').requiresInput(); $('#required1').val('input1').change(); - expect($('.submit')).toBeDisabled(); + expect(this.submitButton).toBeDisabled(); $('#optional1').val('input1').change(); - expect($('.submit')).toBeDisabled(); + expect(this.submitButton).toBeDisabled(); $('#required2').val('input2').change(); $('#required3').val('input3').change(); $('#required4').val('input4').change(); diff --git a/spec/javascripts/fixtures/behaviors/requires_input.html.haml b/spec/javascripts/fixtures/behaviors/requires_input.html.haml deleted file mode 100644 index c3f905e912e..00000000000 --- a/spec/javascripts/fixtures/behaviors/requires_input.html.haml +++ /dev/null @@ -1,18 +0,0 @@ -%form.js-requires-input - %input{type: 'text', id: 'required1', required: 'required'} - %input{type: 'text', id: 'required2', required: 'required'} - %input{type: 'text', id: 'required3', required: 'required', value: 'Pre-filled'} - %input{type: 'text', id: 'optional1'} - - %textarea{id: 'required4', required: 'required'} - %textarea{id: 'optional2'} - - %select{id: 'required5', required: 'required'} - %option Zero - %option{value: '1'} One - %select{id: 'optional3', required: 'required'} - %option Zero - %option{value: '1'} One - - %button.submit{type: 'submit', value: 'Submit'} - %input.submit{type: 'submit', value: 'Submit'} -- cgit v1.2.1 From 309aee45b69888f9b51aaa0ce393a3f13b08c255 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 27 Oct 2016 09:26:58 -0400 Subject: entities: use the RepoCommit entity for branch commits Fixes #23895. --- spec/requests/api/branches_spec.rb | 13 ++++++++++++- spec/requests/api/commits_spec.rb | 20 +++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 5a3ffc284f2..3e66236f6ae 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -31,7 +31,18 @@ describe API::Branches, api: true do expect(response).to have_http_status(200) expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) + json_commit = json_response['commit'] + expect(json_commit['id']).to eq(branch_sha) + expect(json_commit).to have_key('short_id') + expect(json_commit).to have_key('title') + expect(json_commit).to have_key('message') + expect(json_commit).to have_key('author_name') + expect(json_commit).to have_key('author_email') + expect(json_commit).to have_key('authored_date') + expect(json_commit).to have_key('committer_name') + expect(json_commit).to have_key('committer_email') + expect(json_commit).to have_key('committed_date') + expect(json_commit).to have_key('parent_ids') expect(json_response['merged']).to eq(false) expect(json_response['protected']).to eq(false) expect(json_response['developers_can_push']).to eq(false) diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index af9028a8978..3d0d6735359 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -367,11 +367,21 @@ describe API::Commits, api: true do get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) expect(response).to have_http_status(200) - expect(json_response['id']).to eq(project.repository.commit.id) - expect(json_response['title']).to eq(project.repository.commit.title) - expect(json_response['stats']['additions']).to eq(project.repository.commit.stats.additions) - expect(json_response['stats']['deletions']).to eq(project.repository.commit.stats.deletions) - expect(json_response['stats']['total']).to eq(project.repository.commit.stats.total) + commit = project.repository.commit + expect(json_response['id']).to eq(commit.id) + expect(json_response['short_id']).to eq(commit.short_id) + expect(json_response['title']).to eq(commit.title) + expect(json_response['message']).to eq(commit.safe_message) + expect(json_response['author_name']).to eq(commit.author_name) + expect(json_response['author_email']).to eq(commit.author_email) + expect(json_response['authored_date']).to eq(commit.authored_date.iso8601(3)) + expect(json_response['committer_name']).to eq(commit.committer_name) + expect(json_response['committer_email']).to eq(commit.committer_email) + expect(json_response['committed_date']).to eq(commit.committed_date.iso8601(3)) + expect(json_response['parent_ids']).to eq(commit.parent_ids) + expect(json_response['stats']['additions']).to eq(commit.stats.additions) + expect(json_response['stats']['deletions']).to eq(commit.stats.deletions) + expect(json_response['stats']['total']).to eq(commit.stats.total) end it "returns a 404 error if not found" do -- cgit v1.2.1 From 0dfccd995aa9bf560e59299f3a4f1705d6981115 Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Sun, 12 Feb 2017 13:02:26 +0500 Subject: Add active_when helper Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/24036 --- spec/helpers/application_helper_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'spec') diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 8b201f348f1..fd40fe99941 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -265,4 +265,9 @@ describe ApplicationHelper do expect(helper.render_markup('foo.adoc', content)).to eq('NOEL') end end + + describe '#active_when' do + it { expect(helper.active_when(true)).to eq('active') } + it { expect(helper.active_when(false)).to eq(nil) } + end end -- cgit v1.2.1 From 3856a3daa14bdfc2abed28d355a5244e32a81d6a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 15 Feb 2017 19:16:12 +0800 Subject: Add some tests for admin/project runners page --- spec/controllers/admin/runners_controller_spec.rb | 85 ++++++++++++++++++++++ .../projects/runners_controller_spec.rb | 75 +++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 spec/controllers/admin/runners_controller_spec.rb create mode 100644 spec/controllers/projects/runners_controller_spec.rb (limited to 'spec') diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb new file mode 100644 index 00000000000..ae55ce87f0b --- /dev/null +++ b/spec/controllers/admin/runners_controller_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe Admin::RunnersController do + let(:runner) { create(:ci_runner) } + + before do + sign_in(create(:admin)) + end + + describe '#index' do + it 'lists all runners' do + get :index + + expect(response).to have_http_status(200) + end + end + + describe '#show' do + it 'shows a particular runner' do + get :show, id: runner.id + + expect(response).to have_http_status(200) + end + + it 'shows 404 for unknown runner' do + get :show, id: 0 + + expect(response).to have_http_status(404) + end + end + + describe '#update' do + it 'updates the runner and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + new_desc = runner.description.swapcase + + post :update, id: runner.id, runner: { description: new_desc } + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.description).to eq(new_desc) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end + + describe '#destroy' do + it 'destroys the runner' do + delete :destroy, id: runner.id + + expect(response).to have_http_status(302) + expect(Ci::Runner.find_by(id: runner.id)).to be_nil + end + end + + describe '#resume' do + it 'marks the runner as active and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + runner.update(active: false) + + post :resume, id: runner.id + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.active).to eq(true) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end + + describe '#pause' do + it 'marks the runner as inactive and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + runner.update(active: true) + + post :pause, id: runner.id + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.active).to eq(false) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end +end diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb new file mode 100644 index 00000000000..6dec12f1815 --- /dev/null +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe Projects::RunnersController do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let(:runner) { create(:ci_runner) } + + let(:params) do + { + namespace_id: project.namespace, + project_id: project, + id: runner + } + end + + before do + sign_in(user) + project.add_master(user) + project.runners << runner + end + + describe '#update' do + it 'updates the runner and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + new_desc = runner.description.swapcase + + post :update, params.merge(runner: { description: new_desc } ) + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.description).to eq(new_desc) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end + + describe '#destroy' do + it 'destroys the runner' do + delete :destroy, params + + expect(response).to have_http_status(302) + expect(Ci::Runner.find_by(id: runner.id)).to be_nil + end + end + + describe '#resume' do + it 'marks the runner as active and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + runner.update(active: false) + + post :resume, params + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.active).to eq(true) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end + + describe '#pause' do + it 'marks the runner as inactive and ticks the queue' do + old_tick = runner.ensure_runner_queue_value + runner.update(active: true) + + post :pause, params + + runner.reload + + expect(response).to have_http_status(302) + expect(runner.active).to eq(false) + expect(runner.ensure_runner_queue_value).not_to eq(old_tick) + end + end +end -- cgit v1.2.1 From 60288d6c62d7e65ed5a93a72ba047ccaa2daa22b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 15 Feb 2017 20:21:51 +0800 Subject: Use expect { }.to change { } Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8664#note_23427575 --- spec/controllers/admin/runners_controller_spec.rb | 18 +++++++++--------- spec/controllers/projects/runners_controller_spec.rb | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb index ae55ce87f0b..b5fe40d0510 100644 --- a/spec/controllers/admin/runners_controller_spec.rb +++ b/spec/controllers/admin/runners_controller_spec.rb @@ -31,16 +31,16 @@ describe Admin::RunnersController do describe '#update' do it 'updates the runner and ticks the queue' do - old_tick = runner.ensure_runner_queue_value new_desc = runner.description.swapcase - post :update, id: runner.id, runner: { description: new_desc } + expect do + post :update, id: runner.id, runner: { description: new_desc } + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.description).to eq(new_desc) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end @@ -55,31 +55,31 @@ describe Admin::RunnersController do describe '#resume' do it 'marks the runner as active and ticks the queue' do - old_tick = runner.ensure_runner_queue_value runner.update(active: false) - post :resume, id: runner.id + expect do + post :resume, id: runner.id + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.active).to eq(true) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end describe '#pause' do it 'marks the runner as inactive and ticks the queue' do - old_tick = runner.ensure_runner_queue_value runner.update(active: true) - post :pause, id: runner.id + expect do + post :pause, id: runner.id + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.active).to eq(false) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end end diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 6dec12f1815..0fa249e4405 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -21,16 +21,16 @@ describe Projects::RunnersController do describe '#update' do it 'updates the runner and ticks the queue' do - old_tick = runner.ensure_runner_queue_value new_desc = runner.description.swapcase - post :update, params.merge(runner: { description: new_desc } ) + expect do + post :update, params.merge(runner: { description: new_desc } ) + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.description).to eq(new_desc) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end @@ -45,31 +45,31 @@ describe Projects::RunnersController do describe '#resume' do it 'marks the runner as active and ticks the queue' do - old_tick = runner.ensure_runner_queue_value runner.update(active: false) - post :resume, params + expect do + post :resume, params + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.active).to eq(true) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end describe '#pause' do it 'marks the runner as inactive and ticks the queue' do - old_tick = runner.ensure_runner_queue_value runner.update(active: true) - post :pause, params + expect do + post :pause, params + end.to change { runner.ensure_runner_queue_value } runner.reload expect(response).to have_http_status(302) expect(runner.active).to eq(false) - expect(runner.ensure_runner_queue_value).not_to eq(old_tick) end end end -- cgit v1.2.1 From 7a8d0aab61fa5d59a4bde5330948f1adcfbb542c Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 15 Feb 2017 18:54:18 +0530 Subject: Ensure only commit comments relevant to target project are returned --- spec/requests/api/commits_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index af9028a8978..cb11cf98bf4 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -464,6 +464,20 @@ describe API::Commits, api: true do expect(response).to have_http_status(401) end end + + context 'when the commit is present on two projects' do + let(:forked_project) { create(:project, :repository, creator: user2, namespace: user2.namespace) } + let!(:forked_project_note) { create(:note_on_commit, author: user2, project: forked_project, commit_id: forked_project.repository.commit.id, note: 'a comment on a commit for fork') } + + it 'returns the comments for the target project' do + get api("/projects/#{forked_project.id}/repository/commits/#{forked_project.repository.commit.id}/comments", user2) + + expect(response).to have_http_status(200) + expect(json_response.length).to eq(1) + expect(json_response.first['note']).to eq('a comment on a commit for fork') + expect(json_response.first['author']['id']).to eq(user2.id) + end + end end describe 'POST :id/repository/commits/:sha/cherry_pick' do -- cgit v1.2.1 From e15032eded3b35097409817ddb1844164173ce1a Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Thu, 16 Feb 2017 01:07:29 +1100 Subject: override favicon for development to find tabs more easily --- spec/helpers/page_layout_helper_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index dc07657e101..872679a6ce3 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -40,6 +40,18 @@ describe PageLayoutHelper do end end + describe 'favicon' do + it 'defaults to favicon.ico' do + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + expect(helper.favicon).to eq 'favicon.ico' + end + + it 'has purple favicon for development' do + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) + expect(helper.favicon).to eq 'favicon-purple.ico' + end + end + describe 'page_image' do it 'defaults to the GitLab logo' do expect(helper.page_image).to end_with 'assets/gitlab_logo.png' -- cgit v1.2.1 From 33c8d413d2b42bd7b823228a2739eddcd4dfbe51 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 8 Feb 2017 20:33:29 +0000 Subject: Merge branch 'asciidoctor-xss-patch' into 'security' Add sanitization filter to asciidocs output to prevent XSS See https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/2057 --- spec/lib/gitlab/asciidoc_spec.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index ba199917f5c..bca57105d1d 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -41,6 +41,29 @@ module Gitlab render(input, context, asciidoc_opts) end end + + context "XSS" do + links = { + 'links' => { + input: 'link:mylink"onmouseover="alert(1)[Click Here]', + output: "" + }, + 'images' => { + input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]', + output: "
\n

\"Alt

\n
" + }, + 'pre' => { + input: '```mypre">', + output: "
\n
\n
\">
\n
\n
" + } + } + + links.each do |name, data| + it "does not convert dangerous #{name} into HTML" do + expect(render(data[:input], context)).to eql data[:output] + end + end + end end def render(*args) -- cgit v1.2.1 From 7e1f7a02dbe3ebb6688005a4d966670bea12beb1 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 9 Feb 2017 17:30:06 +0000 Subject: Merge branch 'fix-rdoc-xss' into 'security' Fix XSS in rdoc and other markups See https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/2058 --- spec/lib/gitlab/other_markup.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 spec/lib/gitlab/other_markup.rb (limited to 'spec') diff --git a/spec/lib/gitlab/other_markup.rb b/spec/lib/gitlab/other_markup.rb new file mode 100644 index 00000000000..8f5a353b381 --- /dev/null +++ b/spec/lib/gitlab/other_markup.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Gitlab::OtherMarkup, lib: true do + context "XSS Checks" do + links = { + 'links' => { + file: 'file.rdoc', + input: 'XSS[JaVaScriPt:alert(1)]', + output: '

XSS

' + } + } + links.each do |name, data| + it "does not convert dangerous #{name} into HTML" do + expect(render(data[:file], data[:input], context)).to eql data[:output] + end + end + end + + def render(*args) + described_class.render(*args) + end +end -- cgit v1.2.1 From dd944bf14f4a0fd555db32d5833325fa459d9565 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 13 Feb 2017 22:42:46 +0000 Subject: Merge branch 'svg-xss-fix' into 'security' Fix for XSS vulnerability in SVG attachments See https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/2059 --- spec/controllers/uploads_controller_spec.rb | 22 ++++++++++++++++++++++ spec/factories/notes.rb | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 570d9fa43f8..c9584ddf18c 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -4,6 +4,28 @@ describe UploadsController do let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } describe "GET show" do + context 'Content-Disposition security measures' do + let(:project) { create(:empty_project, :public) } + + context 'for PNG files' do + it 'returns Content-Disposition: inline' do + note = create(:note, :with_attachment, project: project) + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.png' + + expect(response['Content-Disposition']).to start_with('inline;') + end + end + + context 'for SVG files' do + it 'returns Content-Disposition: attachment' do + note = create(:note, :with_svg_attachment, project: project) + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.svg' + + expect(response['Content-Disposition']).to start_with('attachment;') + end + end + end + context "when viewing a user avatar" do context "when signed in" do before do diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index a21da7074f9..5c50cd7f4ad 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -97,7 +97,11 @@ FactoryGirl.define do end trait :with_attachment do - attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") } + attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") } + end + + trait :with_svg_attachment do + attachment { fixture_file_upload(Rails.root + "spec/fixtures/unsanitized.svg", "image/svg+xml") } end end end -- cgit v1.2.1 From cec1e3ebc8fe03955c3c1c27f10a7d924f2917ed Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 15 Feb 2017 16:45:41 +0100 Subject: create lighter version of JSON and reuse initial restore in spec to speed up run --- spec/lib/gitlab/import_export/project.light.json | 48 ++++++ .../import_export/project_tree_restorer_spec.rb | 164 +++++++++------------ 2 files changed, 121 insertions(+), 91 deletions(-) create mode 100644 spec/lib/gitlab/import_export/project.light.json (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json new file mode 100644 index 00000000000..a78836c3c34 --- /dev/null +++ b/spec/lib/gitlab/import_export/project.light.json @@ -0,0 +1,48 @@ +{ + "description": "Nisi et repellendus ut enim quo accusamus vel magnam.", + "visibility_level": 10, + "archived": false, + "labels": [ + { + "id": 2, + "title": "test2", + "color": "#428bca", + "project_id": 8, + "created_at": "2016-07-22T08:55:44.161Z", + "updated_at": "2016-07-22T08:55:44.161Z", + "template": false, + "description": "", + "type": "ProjectLabel", + "priorities": [ + ] + }, + { + "id": 3, + "title": "test3", + "color": "#428bca", + "group_id": 8, + "created_at": "2016-07-22T08:55:44.161Z", + "updated_at": "2016-07-22T08:55:44.161Z", + "template": false, + "description": "", + "project_id": null, + "type": "GroupLabel", + "priorities": [ + { + "id": 1, + "project_id": 5, + "label_id": 1, + "priority": 1, + "created_at": "2016-10-18T09:35:43.338Z", + "updated_at": "2016-10-18T09:35:43.338Z" + } + ] + } + ], + "snippets": [ + + ], + "hooks": [ + + ] +} \ No newline at end of file diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 0af13ba8e47..0eefb450f37 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -3,24 +3,27 @@ include ImportExport::CommonUtil describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do describe 'restore project tree' do - let(:user) { create(:user) } - let(:namespace) { create(:namespace, owner: user) } - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') } - let!(:project) { create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } - let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } - let(:restored_project_json) { project_tree_restorer.restore } + before(:all) do + user = create(:user) + + RSpec::Mocks.with_temporary_scope do + @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') + allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') + project = create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') + project_tree_restorer = described_class.new(user: user, shared: @shared, project: project) + @restored_project_json = project_tree_restorer.restore + end + end before do - allow(shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') end context 'JSON' do it 'restores models based on JSON' do - expect(restored_project_json).to be true + expect(@restored_project_json).to be true end it 'restore correct project features' do - restored_project_json project = Project.find_by_path('project') expect(project.project_feature.issues_access_level).to eq(ProjectFeature::DISABLED) @@ -31,62 +34,42 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do end it 'has the same label associated to two issues' do - restored_project_json - expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2) end it 'has milestones associated to two separate issues' do - restored_project_json - expect(Milestone.find_by_description('test milestone').issues.count).to eq(2) end it 'creates a valid pipeline note' do - restored_project_json - expect(Ci::Pipeline.first.notes).not_to be_empty end it 'restores pipelines with missing ref' do - restored_project_json - expect(Ci::Pipeline.where(ref: nil)).not_to be_empty end it 'restores the correct event with symbolised data' do - restored_project_json - expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty end it 'preserves updated_at on issues' do - restored_project_json - issue = Issue.where(description: 'Aliquam enim illo et possimus.').first expect(issue.reload.updated_at.to_s).to eq('2016-06-14 15:02:47 UTC') end it 'contains the merge access levels on a protected branch' do - restored_project_json - expect(ProtectedBranch.first.merge_access_levels).not_to be_empty end it 'contains the push access levels on a protected branch' do - restored_project_json - expect(ProtectedBranch.first.push_access_levels).not_to be_empty end context 'event at forth level of the tree' do let(:event) { Event.where(title: 'test levels').first } - before do - restored_project_json - end - it 'restores the event' do expect(event).not_to be_nil end @@ -99,77 +82,44 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do it 'has the correct data for merge request st_diffs' do # makes sure we are renaming the custom method +utf8_st_diffs+ into +st_diffs+ - expect { restored_project_json }.to change(MergeRequestDiff.where.not(st_diffs: nil), :count).by(9) + expect(MergeRequestDiff.where.not(st_diffs: nil).count).to eq(9) end it 'has labels associated to label links, associated to issues' do - restored_project_json - expect(Label.first.label_links.first.target).not_to be_nil end it 'has project labels' do - restored_project_json - expect(ProjectLabel.count).to eq(2) end it 'has no group labels' do - restored_project_json - expect(GroupLabel.count).to eq(0) end - context 'with group' do - let!(:project) do - create(:empty_project, - :builds_disabled, - :issues_disabled, - name: 'project', - path: 'project', - group: create(:group)) - end - - it 'has group labels' do - restored_project_json - - expect(GroupLabel.count).to eq(1) - end - - it 'has label priorities' do - restored_project_json - - expect(GroupLabel.first.priorities).not_to be_empty - end - end - it 'has a project feature' do - restored_project_json - - expect(project.project_feature).not_to be_nil + expect(Project.first.project_feature).not_to be_nil end it 'restores the correct service' do - restored_project_json - expect(CustomIssueTrackerService.first).not_to be_nil end context 'Merge requests' do before do - restored_project_json + @restored_project_json end it 'always has the new project as a target' do - expect(MergeRequest.find_by_title('MR1').target_project).to eq(project) + expect(MergeRequest.find_by_title('MR1').target_project).to eq(Project.first) end it 'has the same source project as originally if source/target are the same' do - expect(MergeRequest.find_by_title('MR1').source_project).to eq(project) + expect(MergeRequest.find_by_title('MR1').source_project).to eq(Project.first) end it 'has the new project as target if source/target differ' do - expect(MergeRequest.find_by_title('MR2').target_project).to eq(project) + expect(MergeRequest.find_by_title('MR2').target_project).to eq(Project.first) end it 'has no source if source/target differ' do @@ -177,39 +127,71 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do end end - context 'project.json file access check' do - it 'does not read a symlink' do - Dir.mktmpdir do |tmpdir| - setup_symlink(tmpdir, 'project.json') - allow(shared).to receive(:export_path).and_call_original - - restored_project_json + context 'tokens are regenerated' do + it 'has a new CI trigger token' do + expect(Ci::Trigger.where(token: 'cdbfasdf44a5958c83654733449e585')).to be_empty + end - expect(shared.errors.first).not_to include('test') - end + it 'has a new CI build token' do + expect(Ci::Build.where(token: 'abcd')).to be_empty end end + end + end - context 'when there is an existing build with build token' do - it 'restores project json correctly' do - create(:ci_build, token: 'abcd') + context 'Light JSON' do + let(:user) { create(:user) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') } + let!(:project) { create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } + let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } + let(:restored_project_json) { project_tree_restorer.restore } - expect(restored_project_json).to be true - end - end + before do + allow(ImportExport).to receive(:project_filename).and_return('project.light.json') + allow(shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') + end + + context 'project.json file access check' do + it 'does not read a symlink' do + Dir.mktmpdir do |tmpdir| + setup_symlink(tmpdir, 'project.json') + allow(shared).to receive(:export_path).and_call_original - context 'tokens are regenerated' do - before do restored_project_json - end - it 'has a new CI trigger token' do - expect(Ci::Trigger.where(token: 'cdbfasdf44a5958c83654733449e585')).to be_empty + expect(shared.errors.first).not_to include('test') end + end + end - it 'has a new CI build token' do - expect(Ci::Build.where(token: 'abcd')).to be_empty - end + context 'when there is an existing build with build token' do + it 'restores project json correctly' do + create(:ci_build, token: 'abcd') + + expect(restored_project_json).to be true + end + end + + context 'with group' do + let!(:project) do + create(:empty_project, + :builds_disabled, + :issues_disabled, + name: 'project', + path: 'project', + group: create(:group)) + end + + before do + restored_project_json + end + + it 'has group labels' do + expect(GroupLabel.count).to eq(1) + end + + it 'has label priorities' do + expect(GroupLabel.first.priorities).not_to be_empty end end end -- cgit v1.2.1 From 25fec0f882300ab4f917a71a5650ab0d29c7b939 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 9 Feb 2017 16:19:12 -0600 Subject: Fix regression where cmd-click stopped working for todos and merge request tabs --- spec/javascripts/merge_request_tabs_spec.js | 40 +++++++++++++++--- spec/javascripts/todos_spec.js | 63 +++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 spec/javascripts/todos_spec.js (limited to 'spec') diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 3810991f104..5b0c124962c 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -62,19 +62,47 @@ require('vendor/jquery.scrollTo'); }); }); describe('#opensInNewTab', function () { - var commitsLink; var tabUrl; + var windowTarget = '_blank'; beforeEach(function () { - commitsLink = '.commits-tab li a'; - tabUrl = $(commitsLink).attr('href'); + loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + + tabUrl = $('.commits-tab a').attr('href'); spyOn($.fn, 'attr').and.returnValue(tabUrl); }); + + describe('meta click', () => { + beforeEach(function () { + spyOn(gl.utils, 'isMetaClick').and.returnValue(true); + }); + + it('opens page when commits link is clicked', function () { + spyOn(window, 'open').and.callFake(function (url, name) { + expect(url).toEqual(tabUrl); + expect(name).toEqual(windowTarget); + }); + + this.class.bindEvents(); + document.querySelector('.merge-request-tabs .commits-tab a').click(); + }); + + it('opens page when commits badge is clicked', function () { + spyOn(window, 'open').and.callFake(function (url, name) { + expect(url).toEqual(tabUrl); + expect(name).toEqual(windowTarget); + }); + + this.class.bindEvents(); + document.querySelector('.merge-request-tabs .commits-tab a .badge').click(); + }); + }); + it('opens page tab in a new browser tab with Ctrl+Click - Windows/Linux', function () { spyOn(window, 'open').and.callFake(function (url, name) { expect(url).toEqual(tabUrl); - expect(name).toEqual('_blank'); + expect(name).toEqual(windowTarget); }); this.class.clickTab({ @@ -87,7 +115,7 @@ require('vendor/jquery.scrollTo'); it('opens page tab in a new browser tab with Cmd+Click - Mac', function () { spyOn(window, 'open').and.callFake(function (url, name) { expect(url).toEqual(tabUrl); - expect(name).toEqual('_blank'); + expect(name).toEqual(windowTarget); }); this.class.clickTab({ @@ -100,7 +128,7 @@ require('vendor/jquery.scrollTo'); it('opens page tab in a new browser tab with Middle-click - Mac/PC', function () { spyOn(window, 'open').and.callFake(function (url, name) { expect(url).toEqual(tabUrl); - expect(name).toEqual('_blank'); + expect(name).toEqual(windowTarget); }); this.class.clickTab({ diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js new file mode 100644 index 00000000000..66e4fbd6304 --- /dev/null +++ b/spec/javascripts/todos_spec.js @@ -0,0 +1,63 @@ +require('~/todos'); +require('~/lib/utils/common_utils'); + +describe('Todos', () => { + preloadFixtures('todos/todos.html.raw'); + let todoItem; + + beforeEach(() => { + loadFixtures('todos/todos.html.raw'); + todoItem = document.querySelector('.todos-list .todo'); + + return new gl.Todos(); + }); + + describe('goToTodoUrl', () => { + it('opens the todo url', (done) => { + const todoLink = todoItem.dataset.url; + + spyOn(gl.utils, 'visitUrl').and.callFake((url) => { + expect(url).toEqual(todoLink); + done(); + }); + + todoItem.click(); + }); + + describe('meta click', () => { + let visitUrlSpy; + + beforeEach(() => { + spyOn(gl.utils, 'isMetaClick').and.returnValue(true); + visitUrlSpy = spyOn(gl.utils, 'visitUrl').and.callFake(() => {}); + }); + + it('opens the todo url in another tab', (done) => { + const todoLink = todoItem.dataset.url; + + spyOn(window, 'open').and.callFake((url, target) => { + expect(todoLink).toEqual(url); + expect(target).toEqual('_blank'); + done(); + }); + + todoItem.click(); + expect(visitUrlSpy).not.toHaveBeenCalled(); + }); + + it('opens the avatar\'s url in another tab when the avatar is clicked', (done) => { + const avatarImage = todoItem.querySelector('img'); + const avatarUrl = avatarImage.parentElement.getAttribute('href'); + + spyOn(window, 'open').and.callFake((url, target) => { + expect(avatarUrl).toEqual(url); + expect(target).toEqual('_blank'); + done(); + }); + + avatarImage.click(); + expect(visitUrlSpy).not.toHaveBeenCalled(); + }); + }); + }); +}); -- cgit v1.2.1 From 79ef221e4e4998809a3fa1ac888c39868baa589e Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Wed, 15 Feb 2017 12:55:41 -0500 Subject: Fix Rubocop offense --- spec/views/projects/_home_panel.html.haml_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb index 5af57cdf3b7..f5381a48207 100644 --- a/spec/views/projects/_home_panel.html.haml_spec.rb +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'projects/_home_panel', :view do let(:project) { create(:empty_project, :public) } let(:notification_settings) do - user.notification_settings_for(project) if user + user&.notification_settings_for(project) end before do -- cgit v1.2.1 From a89e9736266cbf9ccde3a49eccd8ab04f72bf38f Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Sat, 11 Feb 2017 22:30:15 +0500 Subject: Set `Auto-Submitted: auto-generated` header to emails Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/20305 --- spec/lib/additional_email_headers_interceptor_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 spec/lib/additional_email_headers_interceptor_spec.rb (limited to 'spec') diff --git a/spec/lib/additional_email_headers_interceptor_spec.rb b/spec/lib/additional_email_headers_interceptor_spec.rb new file mode 100644 index 00000000000..580450eef1e --- /dev/null +++ b/spec/lib/additional_email_headers_interceptor_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe AdditionalEmailHeadersInterceptor do + it 'adds Auto-Submitted header' do + mail = ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', body: 'hello').deliver + + expect(mail.header['To'].value).to eq('test@mail.com') + expect(mail.header['From'].value).to eq('info@mail.com') + expect(mail.header['Auto-Submitted'].value).to eq('auto-generated') + expect(mail.header['X-Auto-Response-Suppress'].value).to eq('All') + end +end -- cgit v1.2.1 From b29f6c5176b699de2f6efb012f9646e0d3243727 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 15 Feb 2017 16:36:13 +0000 Subject: Use `page` query parameter instead of `p` to keep consistency with all URLs Fix rubocop error --- spec/features/projects/pipelines/pipelines_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 6555b2fc6c1..5c896a051a4 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -277,6 +277,28 @@ describe 'Pipelines', :feature, :js do end end end + + context 'with pagination' do + before do + create_list(:ci_empty_pipeline, 40, project: project) + end + + it 'should render pagination' do + visit namespace_project_pipelines_path(project.namespace, project) + wait_for_vue_resource + + expect(page).to have_css('.gl-pagination') + expect(page.find_all('tbody tr').length).to eq(20) + end + + it "should render second page of pipelines" do + visit namespace_project_pipelines_path(project.namespace, project, page: '2') + wait_for_vue_resource + + expect(page).to have_css('.gl-pagination') + expect(page.find_all('tbody tr').length).to eq(20) + end + end end describe 'POST /:project/pipelines' do -- cgit v1.2.1 From 4b7f0b327cceedf7b107db5fcfa7af75e4eb9e34 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Mon, 13 Feb 2017 09:56:27 -0600 Subject: Remove all gitlab theme related code --- spec/features/profiles/preferences_spec.rb | 29 ------------------ spec/helpers/preferences_helper_spec.rb | 26 ---------------- spec/lib/gitlab/themes_spec.rb | 48 ------------------------------ 3 files changed, 103 deletions(-) delete mode 100644 spec/lib/gitlab/themes_spec.rb (limited to 'spec') diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb index a6b841c0210..15c8677fcd3 100644 --- a/spec/features/profiles/preferences_spec.rb +++ b/spec/features/profiles/preferences_spec.rb @@ -8,35 +8,6 @@ describe 'Profile > Preferences', feature: true do visit profile_preferences_path end - describe 'User changes their application theme', js: true do - let(:default) { Gitlab::Themes.default } - let(:theme) { Gitlab::Themes.by_id(5) } - - it 'creates a flash message' do - choose "user_theme_id_#{theme.id}" - - expect_preferences_saved_message - end - - it 'updates their preference' do - choose "user_theme_id_#{theme.id}" - - allowing_for_delay do - visit page.current_path - expect(page).to have_checked_field("user_theme_id_#{theme.id}") - end - end - - it 'reflects the changes immediately' do - expect(page).to have_selector("body.#{default.css_class}") - - choose "user_theme_id_#{theme.id}" - - expect(page).not_to have_selector("body.#{default.css_class}") - expect(page).to have_selector("body.#{theme.css_class}") - end - end - describe 'User changes their syntax highlighting theme', js: true do it 'creates a flash message' do choose 'user_color_scheme_id_5' diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 1f02e06e312..f3e79cc7290 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -26,32 +26,6 @@ describe PreferencesHelper do end end - describe 'user_application_theme' do - context 'with a user' do - it "returns user's theme's css_class" do - stub_user(theme_id: 3) - - expect(helper.user_application_theme).to eq 'ui_green' - end - - it 'returns the default when id is invalid' do - stub_user(theme_id: Gitlab::Themes.count + 5) - - allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(2) - - expect(helper.user_application_theme).to eq 'ui_charcoal' - end - end - - context 'without a user' do - it 'returns the default theme' do - stub_user - - expect(helper.user_application_theme).to eq Gitlab::Themes.default.css_class - end - end - end - describe 'user_color_scheme' do context 'with a user' do it "returns user's scheme's css_class" do diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb deleted file mode 100644 index 7a140518dd2..00000000000 --- a/spec/lib/gitlab/themes_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Themes, lib: true do - describe '.body_classes' do - it 'returns a space-separated list of class names' do - css = described_class.body_classes - - expect(css).to include('ui_graphite') - expect(css).to include(' ui_charcoal ') - expect(css).to include(' ui_blue') - end - end - - describe '.by_id' do - it 'returns a Theme by its ID' do - expect(described_class.by_id(1).name).to eq 'Graphite' - expect(described_class.by_id(6).name).to eq 'Blue' - end - end - - describe '.default' do - it 'returns the default application theme' do - allow(described_class).to receive(:default_id).and_return(2) - expect(described_class.default.id).to eq 2 - end - - it 'prevents an infinite loop when configuration default is invalid' do - default = described_class::APPLICATION_DEFAULT - themes = described_class::THEMES - - config = double(default_theme: 0).as_null_object - allow(Gitlab).to receive(:config).and_return(config) - expect(described_class.default.id).to eq default - - config = double(default_theme: themes.size + 5).as_null_object - allow(Gitlab).to receive(:config).and_return(config) - expect(described_class.default.id).to eq default - end - end - - describe '.each' do - it 'passes the block to the THEMES Array' do - ids = [] - described_class.each { |theme| ids << theme.id } - expect(ids).not_to be_empty - end - end -end -- cgit v1.2.1 From 0667d1aa7f251f5bf11dd121fe2f696107d8103e Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Mon, 13 Feb 2017 11:38:53 -0600 Subject: Drop theme ID from users table --- spec/models/user_spec.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'spec') diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 89cef7ab978..546efcfce97 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -582,7 +582,6 @@ describe User, models: true do it "applies defaults to user" do expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit) expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group) - expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme) expect(user.external).to be_falsey end end -- cgit v1.2.1 From c780ad0e926f15ed47acd744df99f89081c8a340 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Mon, 13 Feb 2017 11:50:13 -0600 Subject: Remove all instances of theme_id; require downtime --- spec/controllers/profiles/preferences_controller_spec.rb | 6 ++---- spec/fixtures/api/schemas/user/login.json | 1 - spec/fixtures/api/schemas/user/public.json | 16 +++++++--------- spec/models/user_spec.rb | 3 +-- spec/support/gitlab_stubs/session.json | 4 ++-- spec/support/gitlab_stubs/user.json | 4 ++-- 6 files changed, 14 insertions(+), 20 deletions(-) (limited to 'spec') diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb index 8f02003992a..7b3aa0491c7 100644 --- a/spec/controllers/profiles/preferences_controller_spec.rb +++ b/spec/controllers/profiles/preferences_controller_spec.rb @@ -25,8 +25,7 @@ describe Profiles::PreferencesController do def go(params: {}, format: :js) params.reverse_merge!( color_scheme_id: '1', - dashboard: 'stars', - theme_id: '1' + dashboard: 'stars' ) patch :update, user: params, format: format @@ -41,8 +40,7 @@ describe Profiles::PreferencesController do it "changes the user's preferences" do prefs = { color_scheme_id: '1', - dashboard: 'stars', - theme_id: '2' + dashboard: 'stars' }.with_indifferent_access expect(user).to receive(:update_attributes).with(prefs) diff --git a/spec/fixtures/api/schemas/user/login.json b/spec/fixtures/api/schemas/user/login.json index e6c1d9c9d84..6181b3ccc86 100644 --- a/spec/fixtures/api/schemas/user/login.json +++ b/spec/fixtures/api/schemas/user/login.json @@ -19,7 +19,6 @@ "organization", "last_sign_in_at", "confirmed_at", - "theme_id", "color_scheme_id", "projects_limit", "current_sign_in_at", diff --git a/spec/fixtures/api/schemas/user/public.json b/spec/fixtures/api/schemas/user/public.json index dbd5d32e89c..5587cfec61a 100644 --- a/spec/fixtures/api/schemas/user/public.json +++ b/spec/fixtures/api/schemas/user/public.json @@ -19,7 +19,6 @@ "organization", "last_sign_in_at", "confirmed_at", - "theme_id", "color_scheme_id", "projects_limit", "current_sign_in_at", @@ -32,14 +31,14 @@ "properties": { "id": { "type": "integer" }, "username": { "type": "string" }, - "email": { + "email": { "type": "string", "pattern": "^[^@]+@[^@]+$" }, "name": { "type": "string" }, - "state": { + "state": { "type": "string", - "enum": ["active", "blocked"] + "enum": ["active", "blocked"] }, "avatar_url": { "type": "string" }, "web_url": { "type": "string" }, @@ -54,18 +53,17 @@ "organization": { "type": ["string", "null"] }, "last_sign_in_at": { "type": "date" }, "confirmed_at": { "type": ["date", "null"] }, - "theme_id": { "type": "integer" }, "color_scheme_id": { "type": "integer" }, "projects_limit": { "type": "integer" }, "current_sign_in_at": { "type": "date" }, - "identities": { + "identities": { "type": "array", "items": { "type": "object", "properties": { - "provider": { + "provider": { "type": "string", - "enum": ["github", "bitbucket", "google_oauth2"] + "enum": ["github", "bitbucket", "google_oauth2"] }, "extern_uid": { "type": ["number", "string"] } } @@ -74,6 +72,6 @@ "can_create_group": { "type": "boolean" }, "can_create_project": { "type": "boolean" }, "two_factor_enabled": { "type": "boolean" }, - "external": { "type": "boolean" } + "external": { "type": "boolean" } } } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 546efcfce97..584a4facd94 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -587,12 +587,11 @@ describe User, models: true do end describe 'with default overrides' do - let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true, theme_id: 1) } + let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true) } it "applies defaults to user" do expect(user.projects_limit).to eq(123) expect(user.can_create_group).to be_falsey - expect(user.theme_id).to eq(1) end end diff --git a/spec/support/gitlab_stubs/session.json b/spec/support/gitlab_stubs/session.json index ce8dfe5ae75..cd55d63125e 100644 --- a/spec/support/gitlab_stubs/session.json +++ b/spec/support/gitlab_stubs/session.json @@ -7,7 +7,7 @@ "skype":"aertert", "linkedin":"", "twitter":"", - "theme_id":2,"color_scheme_id":2, + "color_scheme_id":2, "state":"active", "created_at":"2012-12-21T13:02:20Z", "extern_uid":null, @@ -17,4 +17,4 @@ "can_create_project":false, "private_token":"Wvjy2Krpb7y8xi93owUz", "access_token":"Wvjy2Krpb7y8xi93owUz" -} \ No newline at end of file +} diff --git a/spec/support/gitlab_stubs/user.json b/spec/support/gitlab_stubs/user.json index ce8dfe5ae75..cd55d63125e 100644 --- a/spec/support/gitlab_stubs/user.json +++ b/spec/support/gitlab_stubs/user.json @@ -7,7 +7,7 @@ "skype":"aertert", "linkedin":"", "twitter":"", - "theme_id":2,"color_scheme_id":2, + "color_scheme_id":2, "state":"active", "created_at":"2012-12-21T13:02:20Z", "extern_uid":null, @@ -17,4 +17,4 @@ "can_create_project":false, "private_token":"Wvjy2Krpb7y8xi93owUz", "access_token":"Wvjy2Krpb7y8xi93owUz" -} \ No newline at end of file +} -- cgit v1.2.1 From 2fc559142e00cc15a47c49c190666284221cc9b0 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Mon, 13 Feb 2017 18:37:26 -0600 Subject: Fix active_tab and issuables_counter specs --- spec/features/dashboard/active_tab_spec.rb | 7 ++++--- spec/features/dashboard/issuables_counter_spec.rb | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/features/dashboard/active_tab_spec.rb b/spec/features/dashboard/active_tab_spec.rb index 7d59fcac517..ae750be4d4a 100644 --- a/spec/features/dashboard/active_tab_spec.rb +++ b/spec/features/dashboard/active_tab_spec.rb @@ -1,14 +1,15 @@ require 'spec_helper' -RSpec.describe 'Dashboard Active Tab', feature: true do +RSpec.describe 'Dashboard Active Tab', js: true, feature: true do before do login_as :user end shared_examples 'page has active tab' do |title| it "#{title} tab" do - expect(page).to have_selector('.nav-sidebar li.active', count: 1) - expect(find('.nav-sidebar li.active')).to have_content(title) + find('.global-dropdown-toggle').trigger('click') + expect(page).to have_selector('.global-dropdown-menu li.active', count: 1) + expect(find('.global-dropdown-menu li.active')).to have_content(title) end end diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index 41dcfe439c2..603076d7d37 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -36,7 +36,8 @@ describe 'Navigation bar counter', feature: true, js: true, caching: true do def expect_counters(issuable_type, count) dashboard_count = find('li.active span.badge') - nav_count = find(".dashboard-shortcuts-#{issuable_type} span.count") + find('.global-dropdown-toggle').click + nav_count = find(".dashboard-shortcuts-#{issuable_type} span.badge") expect(nav_count).to have_content(count) expect(dashboard_count).to have_content(count) -- cgit v1.2.1 From 8c1b41f12b5ec8dd3dd2547d3ad729e71c4ebadd Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Tue, 14 Feb 2017 12:27:47 -0600 Subject: Move migration to post_migrate; fix shortcuts_spec --- spec/features/dashboard/shortcuts_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index d9be4e5dbdd..c5a0d1c6d99 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -24,6 +24,7 @@ feature 'Dashboard shortcuts', feature: true, js: true do end def ensure_active_main_tab(content) - expect(find('.nav-sidebar li.active')).to have_content(content) + find('.global-dropdown-toggle').trigger('click') + expect(find('.global-dropdown-menu li.active')).to have_content(content) end end -- cgit v1.2.1 From f1710bd131a040ef9104a1ff1a804b35c9568550 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Tue, 14 Feb 2017 17:43:03 -0600 Subject: Delete sidebar specs and fixtures; update shortcuts_spec to check page title --- spec/features/dashboard/shortcuts_spec.rb | 11 ++-- spec/javascripts/dashboard_spec.js.es6 | 37 ----------- spec/javascripts/fixtures/dashboard.html.haml | 45 -------------- spec/javascripts/project_dashboard_spec.js.es6 | 86 -------------------------- 4 files changed, 5 insertions(+), 174 deletions(-) delete mode 100644 spec/javascripts/dashboard_spec.js.es6 delete mode 100644 spec/javascripts/fixtures/dashboard.html.haml delete mode 100644 spec/javascripts/project_dashboard_spec.js.es6 (limited to 'spec') diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index c5a0d1c6d99..62a2c54c94c 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -10,21 +10,20 @@ feature 'Dashboard shortcuts', feature: true, js: true do find('body').native.send_key('g') find('body').native.send_key('p') - ensure_active_main_tab('Projects') + check_page_title('Projects') find('body').native.send_key('g') find('body').native.send_key('i') - ensure_active_main_tab('Issues') + check_page_title('Issues') find('body').native.send_key('g') find('body').native.send_key('m') - ensure_active_main_tab('Merge Requests') + check_page_title('Merge Requests') end - def ensure_active_main_tab(content) - find('.global-dropdown-toggle').trigger('click') - expect(find('.global-dropdown-menu li.active')).to have_content(content) + def check_page_title(title) + expect(find('.header-content .title')).to have_content(title) end end diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 deleted file mode 100644 index c0bdb89ed63..00000000000 --- a/spec/javascripts/dashboard_spec.js.es6 +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable no-new */ - -require('~/sidebar'); -require('~/lib/utils/text_utility'); - -((global) => { - describe('Dashboard', () => { - const fixtureTemplate = 'static/dashboard.html.raw'; - - function todosCountText() { - return $('.js-todos-count').text(); - } - - function triggerToggle(newCount) { - $(document).trigger('todo:toggle', newCount); - } - - preloadFixtures(fixtureTemplate); - beforeEach(() => { - loadFixtures(fixtureTemplate); - new global.Sidebar(); - }); - - it('should update todos-count after receiving the todo:toggle event', () => { - triggerToggle(5); - expect(todosCountText()).toEqual('5'); - }); - - it('should display todos-count with delimiter', () => { - triggerToggle(1000); - expect(todosCountText()).toEqual('1,000'); - - triggerToggle(1000000); - expect(todosCountText()).toEqual('1,000,000'); - }); - }); -})(window.gl); diff --git a/spec/javascripts/fixtures/dashboard.html.haml b/spec/javascripts/fixtures/dashboard.html.haml deleted file mode 100644 index 32446acfd60..00000000000 --- a/spec/javascripts/fixtures/dashboard.html.haml +++ /dev/null @@ -1,45 +0,0 @@ -%ul.nav.nav-sidebar - %li.home.active - %a.dashboard-shortcuts-projects - %span - Projects - %li - %a - %span - Todos - %span.count.js-todos-count - 1 - %li - %a.dashboard-shortcuts-activity - %span - Activity - %li - %a - %span - Groups - %li - %a - %span - Milestones - %li - %a.dashboard-shortcuts-issues - %span - Issues - %span - 1 - %li - %a.dashboard-shortcuts-merge_requests - %span - Merge Requests - %li - %a - %span - Snippets - %li - %a - %span - Help - %li - %a - %span - Profile Settings diff --git a/spec/javascripts/project_dashboard_spec.js.es6 b/spec/javascripts/project_dashboard_spec.js.es6 deleted file mode 100644 index 24833b4eb57..00000000000 --- a/spec/javascripts/project_dashboard_spec.js.es6 +++ /dev/null @@ -1,86 +0,0 @@ -require('~/sidebar'); - -(() => { - describe('Project dashboard page', () => { - let $pageWithSidebar = null; - let $sidebarToggle = null; - let sidebar = null; - const fixtureTemplate = 'projects/dashboard.html.raw'; - - const assertSidebarStateExpanded = (shouldBeExpanded) => { - expect(sidebar.isExpanded).toBe(shouldBeExpanded); - expect($pageWithSidebar.hasClass('page-sidebar-expanded')).toBe(shouldBeExpanded); - }; - - preloadFixtures(fixtureTemplate); - beforeEach(() => { - loadFixtures(fixtureTemplate); - - $pageWithSidebar = $('.page-with-sidebar'); - $sidebarToggle = $('.toggle-nav-collapse'); - - // otherwise instantiating the Sidebar for the second time - // won't do anything, as the Sidebar is a singleton class - gl.Sidebar.singleton = null; - sidebar = new gl.Sidebar(); - }); - - it('can show the sidebar when the toggler is clicked', () => { - assertSidebarStateExpanded(false); - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - }); - - it('should dismiss the sidebar when clone button clicked', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - const cloneButton = $('.project-clone-holder a.clone-dropdown-btn'); - cloneButton.click(); - assertSidebarStateExpanded(false); - }); - - it('should dismiss the sidebar when download button clicked', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - const downloadButton = $('.project-action-button .btn:has(i.fa-download)'); - downloadButton.click(); - assertSidebarStateExpanded(false); - }); - - it('should dismiss the sidebar when add button clicked', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - const addButton = $('.project-action-button .btn:has(i.fa-plus)'); - addButton.click(); - assertSidebarStateExpanded(false); - }); - - it('should dismiss the sidebar when notification button clicked', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - const notifButton = $('.js-notification-toggle-btns .notifications-btn'); - notifButton.click(); - assertSidebarStateExpanded(false); - }); - - it('should dismiss the sidebar when clicking on the body', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - $('body').click(); - assertSidebarStateExpanded(false); - }); - - it('should dismiss the sidebar when clicking on the project description header', () => { - $sidebarToggle.click(); - assertSidebarStateExpanded(true); - - $('.project-home-panel').click(); - assertSidebarStateExpanded(false); - }); - }); -})(); -- cgit v1.2.1 From 679ce9dbb35021bec3bc048948e471ba3989e518 Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Thu, 16 Feb 2017 06:55:52 +1100 Subject: dev favicon is blue, not purple --- spec/helpers/page_layout_helper_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 872679a6ce3..2cc0b40b2d0 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -46,9 +46,9 @@ describe PageLayoutHelper do expect(helper.favicon).to eq 'favicon.ico' end - it 'has purple favicon for development' do + it 'has blue favicon for development' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) - expect(helper.favicon).to eq 'favicon-purple.ico' + expect(helper.favicon).to eq 'favicon-blue.ico' end end -- cgit v1.2.1 From 1285d629064abce3aee8faafaa57492da6f8f163 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 13 Feb 2017 16:11:11 +0000 Subject: Move change page param to utility function Add tests Adds folder name in the top of the table --- .../environments/environment_table_spec.js.es6 | 30 +++ .../folder/environments_folder_view_spec.js.es6 | 212 +++++++++++++++++++++ .../environments_folder_view.html.haml | 7 + 3 files changed, 249 insertions(+) create mode 100644 spec/javascripts/environments/environment_table_spec.js.es6 create mode 100644 spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 create mode 100644 spec/javascripts/fixtures/environments/environments_folder_view.html.haml (limited to 'spec') diff --git a/spec/javascripts/environments/environment_table_spec.js.es6 b/spec/javascripts/environments/environment_table_spec.js.es6 new file mode 100644 index 00000000000..be4330b5012 --- /dev/null +++ b/spec/javascripts/environments/environment_table_spec.js.es6 @@ -0,0 +1,30 @@ +const EnvironmentTable = require('~/environments/components/environments_table'); + +describe('Environment item', () => { + preloadFixtures('static/environments/element.html.raw'); + beforeEach(() => { + loadFixtures('static/environments/element.html.raw'); + }); + + it('Should render a table', () => { + const mockItem = { + name: 'review', + size: 3, + isFolder: true, + latest: { + environment_path: 'url', + }, + }; + + const component = new EnvironmentTable({ + el: document.querySelector('.test-dom-element'), + propsData: { + environments: [{ mockItem }], + canCreateDeployment: false, + canReadEnvironment: true, + }, + }); + + expect(component.$el.tagName).toEqual('TABLE'); + }); +}); diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 b/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 new file mode 100644 index 00000000000..6a95fabcea5 --- /dev/null +++ b/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 @@ -0,0 +1,212 @@ +const Vue = require('vue'); +require('~/flash'); +const EnvironmentsFolderViewComponent = require('~/environments/folder/environments_folder_view'); +const { environmentsList } = require('../mock_data'); + +describe('Environments Folder View', () => { + preloadFixtures('static/environments/environments_folder_view.html.raw'); + + beforeEach(() => { + loadFixtures('static/environments/environments_folder_view.html.raw'); + window.history.pushState({}, null, 'environments/folders/51'); + }); + + let component; + + describe('successfull request', () => { + const environmentsResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify({ + environments: environmentsList, + stopped_count: 1, + available_count: 0, + }), { + status: 200, + headers: { + 'X-nExt-pAge': '2', + 'x-page': '1', + 'X-Per-Page': '1', + 'X-Prev-Page': '', + 'X-TOTAL': '37', + 'X-Total-Pages': '2', + }, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsResponseInterceptor); + component = new EnvironmentsFolderViewComponent({ + el: document.querySelector('#environments-folder-list-view'), + }); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsResponseInterceptor, + ); + }); + + it('should render a table with environments', (done) => { + setTimeout(() => { + expect( + component.$el.querySelectorAll('table tbody tr').length, + ).toEqual(2); + done(); + }, 0); + }); + + it('should render available tab with count', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-available-environments-folder-tab').textContent, + ).toContain('Available'); + + expect( + component.$el.querySelector('.js-available-environments-folder-tab .js-available-environments-count').textContent, + ).toContain('0'); + done(); + }, 0); + }); + + it('should render stopped tab with count', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-stopped-environments-folder-tab').textContent, + ).toContain('Stopped'); + + expect( + component.$el.querySelector('.js-stopped-environments-folder-tab .js-stopped-environments-count').textContent, + ).toContain('1'); + done(); + }, 0); + }); + + // FIX ME: + it('should render parent folder name', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-folder-name'), + ).toBe(null); + done(); + }, 0); + }); + + describe('pagination', () => { + it('should render pagination', (done) => { + setTimeout(() => { + expect( + component.$el.querySelectorAll('.gl-pagination li').length, + ).toEqual(5); + done(); + }, 0); + }); + + it('should update url when no search params are present', (done) => { + spyOn(gl.utils, 'visitUrl'); + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2'); + done(); + }, 0); + }); + + it('should update url when page is already present', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?page=1'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2'); + done(); + }, 0); + }); + + it('should update url when page and scope are already present', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?scope=all&page=1'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?scope=all&page=2'); + done(); + }, 0); + }); + + it('should update url when page and scope are already present and page is first param', (done) => { + spyOn(gl.utils, 'visitUrl'); + window.history.pushState({}, null, '?page=1&scope=all'); + + setTimeout(() => { + component.$el.querySelector('.gl-pagination li:nth-child(5) a').click(); + expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2&scope=all'); + done(); + }, 0); + }); + }); + }); + + describe('unsuccessfull request', () => { + const environmentsErrorResponseInterceptor = (request, next) => { + next(request.respondWith(JSON.stringify([]), { + status: 500, + })); + }; + + beforeEach(() => { + Vue.http.interceptors.push(environmentsErrorResponseInterceptor); + }); + + afterEach(() => { + Vue.http.interceptors = _.without( + Vue.http.interceptors, environmentsErrorResponseInterceptor, + ); + }); + + it('should not render a table', (done) => { + component = new EnvironmentsFolderViewComponent({ + el: document.querySelector('#environments-folder-list-view'), + }); + + setTimeout(() => { + expect( + component.$el.querySelector('table'), + ).toBe(null); + done(); + }, 0); + }); + + it('should render available tab with count 0', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-available-environments-folder-tab').textContent, + ).toContain('Available'); + + expect( + component.$el.querySelector('.js-available-environments-folder-tab .js-available-environments-count').textContent, + ).toContain('0'); + done(); + }, 0); + }); + + it('should render stopped tab with count 0', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-stopped-environments-folder-tab').textContent, + ).toContain('Stopped'); + + expect( + component.$el.querySelector('.js-stopped-environments-folder-tab .js-stopped-environments-count').textContent, + ).toContain('0'); + done(); + }, 0); + }); + + it('should not render parent folder name', (done) => { + setTimeout(() => { + expect( + component.$el.querySelector('.js-folder-name'), + ).toBe(null); + done(); + }, 0); + }); + }); +}); diff --git a/spec/javascripts/fixtures/environments/environments_folder_view.html.haml b/spec/javascripts/fixtures/environments/environments_folder_view.html.haml new file mode 100644 index 00000000000..aceec139730 --- /dev/null +++ b/spec/javascripts/fixtures/environments/environments_folder_view.html.haml @@ -0,0 +1,7 @@ +%div + #environments-folder-list-view{ data: { "can-create-deployment" => "true", + "can-read-environment" => "true", + "css-class" => "", + "commit-icon-svg" => custom_icon("icon_commit"), + "terminal-icon-svg" => custom_icon("icon_terminal"), + "play-icon-svg" => custom_icon("icon_play") } } -- cgit v1.2.1 From 1a299121f30c3b9ff48bf97052ecc25cf518452f Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Thu, 16 Feb 2017 11:47:26 +1100 Subject: don't trigger tanuki loader when downloading files --- spec/features/projects/main/download_buttons_spec.rb | 7 +++++++ spec/features/projects/pipelines/pipelines_spec.rb | 8 ++++++++ 2 files changed, 15 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/main/download_buttons_spec.rb b/spec/features/projects/main/download_buttons_spec.rb index 227ccf9459c..02198ff3e41 100644 --- a/spec/features/projects/main/download_buttons_spec.rb +++ b/spec/features/projects/main/download_buttons_spec.rb @@ -39,6 +39,13 @@ feature 'Download buttons in project main page', feature: true do expect(page).to have_link "Download '#{build.name}'", href: href end + + scenario 'download links have download attribute' do + expect(page).to have_selector('a', text: 'Download') + page.all('a', text: 'Download').each do |link| + expect(link[:download]).to eq '' + end + end end end end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 6555b2fc6c1..b56be499264 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -218,6 +218,14 @@ describe 'Pipelines', :feature, :js do expect(page).to have_link(with_artifacts.name) end + + it 'has download attribute on download links' do + find('.js-pipeline-dropdown-download').click + expect(page).to have_selector('a', text: 'Download') + page.all('.build-artifacts a', text: 'Download').each do |link| + expect(link[:download]).to eq '' + end + end end context 'with artifacts expired' do -- cgit v1.2.1 From 6606a45030ecd4035b095d33d32f1372c3562b02 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 15 Feb 2017 23:50:05 -0800 Subject: Fix a number of race conditions that can occur during namespace deletion There are two problems in the current implementation: 1. If a project is marked for deletion via the `pending_delete` flag and then the namespace was quickly deleted, it's possible that the namespace skips over that project and leaves that project in an orphaned state. 2. Before namespace deletion, the namespace attempts to clean up all the relevant storage paths. However, if all projects have been removed synchronously, then the namespace will not be able to clean anything. To prevent this, we should load the paths to be deleted before actually destroying projects. The specs were missing this second case due to a permission issue that caused project removal never to happen. --- spec/services/groups/destroy_service_spec.rb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index f86189b68e9..32c2ed8cae7 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -9,14 +9,18 @@ describe Groups::DestroyService, services: true do let!(:gitlab_shell) { Gitlab::Shell.new } let!(:remove_path) { group.path + "+#{group.id}+deleted" } + before do + group.add_user(user, Gitlab::Access::OWNER) + end + shared_examples 'group destruction' do |async| context 'database records' do before do destroy_group(group, user, async) end - it { expect(Group.all).not_to include(group) } - it { expect(Project.all).not_to include(project) } + it { expect(Group.unscoped.all).not_to include(group) } + it { expect(Project.unscoped.all).not_to include(project) } end context 'file system' do @@ -32,7 +36,7 @@ describe Groups::DestroyService, services: true do context 'Sidekiq fake' do before do - # Dont run sidekiq to check if renamed repository exists + # Don't run sidekiq to check if renamed repository exists Sidekiq::Testing.fake! { destroy_group(group, user, async) } end @@ -95,4 +99,13 @@ describe Groups::DestroyService, services: true do describe 'synchronous delete' do it_behaves_like 'group destruction', false end + + context 'projects in pending_delete' do + before do + project.pending_delete = true + project.save + end + + it_behaves_like 'group destruction', false + end end -- cgit v1.2.1 From 65427442b9866dd98b7356d7a8f94b486fef662a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 16 Feb 2017 09:14:47 +0100 Subject: refactored a couple of things --- .../import_export/project_tree_restorer_spec.rb | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 0eefb450f37..94a3b0fbba9 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -4,18 +4,19 @@ include ImportExport::CommonUtil describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do describe 'restore project tree' do before(:all) do - user = create(:user) + @user = create(:user) RSpec::Mocks.with_temporary_scope do @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') - project = create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') - project_tree_restorer = described_class.new(user: user, shared: @shared, project: project) + @project = create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') + project_tree_restorer = described_class.new(user: @user, shared: @shared, project: @project) @restored_project_json = project_tree_restorer.restore end end - before do + after(:all) do + @user.destroy! end context 'JSON' do @@ -98,7 +99,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do end it 'has a project feature' do - expect(Project.first.project_feature).not_to be_nil + expect(@project.project_feature).not_to be_nil end it 'restores the correct service' do @@ -106,20 +107,16 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do end context 'Merge requests' do - before do - @restored_project_json - end - it 'always has the new project as a target' do - expect(MergeRequest.find_by_title('MR1').target_project).to eq(Project.first) + expect(MergeRequest.find_by_title('MR1').target_project).to eq(@project) end it 'has the same source project as originally if source/target are the same' do - expect(MergeRequest.find_by_title('MR1').source_project).to eq(Project.first) + expect(MergeRequest.find_by_title('MR1').source_project).to eq(@project) end it 'has the new project as target if source/target differ' do - expect(MergeRequest.find_by_title('MR2').target_project).to eq(Project.first) + expect(MergeRequest.find_by_title('MR2').target_project).to eq(@project) end it 'has no source if source/target differ' do -- cgit v1.2.1 From b3fb5b4f26b609ad41ccb0837e599fa50c22b55f Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 13 Feb 2017 16:43:17 +0100 Subject: Use gitlab shell import instead of manually creating the webhooks Also update repo restorer to use project wiki method. --- .../lib/gitlab/import_export/repo_restorer_spec.rb | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 spec/lib/gitlab/import_export/repo_restorer_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb new file mode 100644 index 00000000000..a9feb8dd19d --- /dev/null +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Gitlab::ImportExport::RepoRestorer, services: true do + describe 'bundle a project Git repo' do + let(:user) { create(:user) } + let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project) { create(:empty_project) } + let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } + let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) } + let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) } + let(:restorer) do + described_class.new(path_to_bundle: bundle_path, + shared: shared, + project: project) + end + + before do + allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) + + bundler.save + end + + after do + FileUtils.rm_rf(export_path) + FileUtils.rm_rf(project_with_repo.repository.path_to_repo) + FileUtils.rm_rf(project.repository.path_to_repo) + end + + it 'restores the repo successfully' do + expect(restorer.restore).to be true + end + + it 'has the webhooks' do + restorer.restore + + expect(Gitlab::Git::Hook.new('post-receive', project.repository.path_to_repo)).to exist + end + end +end -- cgit v1.2.1 From 7a9d3a3c9043d391fc890befc6ed8117aa94c8ad Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 14 Feb 2017 14:13:35 +0000 Subject: Show merge errors in merge request widget There were two problems here: 1. On the JS side, the reference to $widgetBody didn't refer to the right DOM element any more. This might be because it was replaced by the `getMergeStatus` method. Even if it wasn't, ensuring we have the right element means that the content gets updated. 2. On the Ruby side, the `log_merge_error` method didn't update the `merge_error` column of the merge request. Change that to update if requested, and update in the most common cases by default. Additionally, this would sometimes return an error hash, but it doesn't look like this was ever used (the return value of `MergeService#execute` appears to be unused everywhere). --- spec/features/merge_requests/widget_spec.rb | 15 +++++++++++ spec/services/merge_requests/merge_service_spec.rb | 29 +++++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb index 957e913bf95..4ad944366c8 100644 --- a/spec/features/merge_requests/widget_spec.rb +++ b/spec/features/merge_requests/widget_spec.rb @@ -52,4 +52,19 @@ describe 'Merge request', :feature, :js do end end end + + context 'merge error' do + before do + allow_any_instance_of(Repository).to receive(:merge).and_return(false) + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + click_button 'Accept Merge Request' + wait_for_ajax + end + + it 'updates the MR widget' do + page.within('.mr-widget-body') do + expect(page).to have_content('Conflicts detected during merge') + end + end + end end diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 5a89acc96a4..d96f819e66a 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -149,35 +149,46 @@ describe MergeRequests::MergeService, services: true do context "error handling" do let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } - it 'saves error if there is an exception' do - allow(service).to receive(:repository).and_raise("error message") + before do + allow(Rails.logger).to receive(:error) + end + it 'logs and saves error if there is an exception' do + error_message = 'error message' + + allow(service).to receive(:repository).and_raise("error message") allow(service).to receive(:execute_hooks) service.execute(merge_request) - expect(merge_request.merge_error).to eq("Something went wrong during merge: error message") + expect(merge_request.merge_error).to include(error_message) + expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message)) end - it 'saves error if there is an PreReceiveError exception' do - allow(service).to receive(:repository).and_raise(GitHooksService::PreReceiveError, "error") + it 'logs and saves error if there is an PreReceiveError exception' do + error_message = 'error message' + allow(service).to receive(:repository).and_raise(GitHooksService::PreReceiveError, error_message) allow(service).to receive(:execute_hooks) service.execute(merge_request) - expect(merge_request.merge_error).to eq("error") + expect(merge_request.merge_error).to include(error_message) + expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message)) end - it 'aborts if there is a merge conflict' do + it 'logs and saves error if there is a merge conflict' do + error_message = 'Conflicts detected during merge' + allow_any_instance_of(Repository).to receive(:merge).and_return(false) allow(service).to receive(:execute_hooks) service.execute(merge_request) - expect(merge_request.open?).to be_truthy + expect(merge_request).to be_open expect(merge_request.merge_commit_sha).to be_nil - expect(merge_request.merge_error).to eq("Conflicts detected during merge") + expect(merge_request.merge_error).to include(error_message) + expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message)) end end end -- cgit v1.2.1 From 605195c26add353805bdb5b3e927ebc286f91fec Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 16 Feb 2017 10:23:59 +0000 Subject: Fix broken tests --- .../environments/environment_item_spec.js.es6 | 115 ++++++++++----------- .../environments/environments_store_spec.js.es6 | 7 +- .../folder/environments_folder_view_spec.js.es6 | 16 +-- spec/javascripts/environments/mock_data.js.es6 | 33 ++++++ 4 files changed, 96 insertions(+), 75 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 88413d9ae2b..7fea80ed799 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -14,11 +14,10 @@ describe('Environment item', () => { beforeEach(() => { mockItem = { name: 'review', + folderName: 'review', size: 3, isFolder: true, - latest: { - environment_path: 'url', - }, + environment_path: 'url', }; component = new EnvironmentItem({ @@ -49,21 +48,36 @@ describe('Environment item', () => { environment = { name: 'production', size: 1, - latest: { - state: 'stopped', - external_url: 'http://external.com', - environment_type: null, - last_deployment: { - id: 66, - iid: 6, - sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - ref: { - name: 'master', - ref_path: 'root/ci-folders/tree/master', - }, - tag: true, - 'last?': true, - user: { + state: 'stopped', + external_url: 'http://external.com', + environment_type: null, + last_deployment: { + id: 66, + iid: 6, + sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + ref: { + name: 'master', + ref_path: 'root/ci-folders/tree/master', + }, + tag: true, + 'last?': true, + user: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit: { + id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + short_id: '500aabcb', + title: 'Update .gitlab-ci.yml', + author_name: 'Administrator', + author_email: 'admin@example.com', + created_at: '2016-11-07T18:28:13.000+00:00', + message: 'Update .gitlab-ci.yml', + author: { name: 'Administrator', username: 'root', id: 1, @@ -71,44 +85,27 @@ describe('Environment item', () => { avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', web_url: 'http://localhost:3000/root', }, - commit: { - id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - short_id: '500aabcb', - title: 'Update .gitlab-ci.yml', - author_name: 'Administrator', - author_email: 'admin@example.com', - created_at: '2016-11-07T18:28:13.000+00:00', - message: 'Update .gitlab-ci.yml', - author: { - name: 'Administrator', - username: 'root', - id: 1, - state: 'active', - avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', - web_url: 'http://localhost:3000/root', - }, - commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', - }, - deployable: { - id: 1279, - name: 'deploy', - build_path: '/root/ci-folders/builds/1279', - retry_path: '/root/ci-folders/builds/1279/retry', - created_at: '2016-11-29T18:11:58.430Z', - updated_at: '2016-11-29T18:11:58.430Z', - }, - manual_actions: [ - { - name: 'action', - play_path: '/play', - }, - ], + commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', }, - 'stop_action?': true, - environment_path: 'root/ci-folders/environments/31', - created_at: '2016-11-07T11:11:16.525Z', - updated_at: '2016-11-10T15:55:58.778Z', + deployable: { + id: 1279, + name: 'deploy', + build_path: '/root/ci-folders/builds/1279', + retry_path: '/root/ci-folders/builds/1279/retry', + created_at: '2016-11-29T18:11:58.430Z', + updated_at: '2016-11-29T18:11:58.430Z', + }, + manual_actions: [ + { + name: 'action', + play_path: '/play', + }, + ], }, + 'stop_action?': true, + environment_path: 'root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-10T15:55:58.778Z', }; component = new EnvironmentItem({ @@ -129,7 +126,7 @@ describe('Environment item', () => { it('should render deployment internal id', () => { expect( component.$el.querySelector('.deployment-column span').textContent, - ).toContain(environment.latest.last_deployment.iid); + ).toContain(environment.last_deployment.iid); expect( component.$el.querySelector('.deployment-column span').textContent, @@ -139,7 +136,7 @@ describe('Environment item', () => { it('should render last deployment date', () => { const timeagoInstance = new timeago(); // eslint-disable-line const formatedDate = timeagoInstance.format( - environment.latest.last_deployment.deployable.created_at, + environment.last_deployment.deployable.created_at, ); expect( @@ -151,7 +148,7 @@ describe('Environment item', () => { it('should render user avatar with link to profile', () => { expect( component.$el.querySelector('.js-deploy-user-container').getAttribute('href'), - ).toEqual(environment.latest.last_deployment.user.web_url); + ).toEqual(environment.last_deployment.user.web_url); }); }); @@ -159,13 +156,13 @@ describe('Environment item', () => { it('Should link to build url provided', () => { expect( component.$el.querySelector('.build-link').getAttribute('href'), - ).toEqual(environment.latest.last_deployment.deployable.build_path); + ).toEqual(environment.last_deployment.deployable.build_path); }); it('Should render deployable name and id', () => { expect( component.$el.querySelector('.build-link').getAttribute('href'), - ).toEqual(environment.latest.last_deployment.deployable.build_path); + ).toEqual(environment.last_deployment.deployable.build_path); }); }); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 8fd660c3edb..49c7dc4b25c 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,5 +1,5 @@ const Store = require('~/environments/stores/environments_store'); -const { environmentsList } = require('./mock_data'); +const { environmentsList, serverData } = require('./mock_data'); (() => { describe('Store', () => { @@ -17,8 +17,9 @@ const { environmentsList } = require('./mock_data'); }); it('should store environments', () => { - store.storeEnvironments(environmentsList); - expect(store.state.environments.length).toEqual(environmentsList.length); + store.storeEnvironments(serverData); + expect(store.state.environments.length).toEqual(serverData.length); + expect(store.state.environments[0]).toEqual(environmentsList[0]); }); it('should store available count', () => { diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 b/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 index 6a95fabcea5..d1335b5b304 100644 --- a/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 +++ b/spec/javascripts/environments/folder/environments_folder_view_spec.js.es6 @@ -8,7 +8,7 @@ describe('Environments Folder View', () => { beforeEach(() => { loadFixtures('static/environments/environments_folder_view.html.raw'); - window.history.pushState({}, null, 'environments/folders/51'); + window.history.pushState({}, null, 'environments/folders/build'); }); let component; @@ -80,12 +80,11 @@ describe('Environments Folder View', () => { }, 0); }); - // FIX ME: it('should render parent folder name', (done) => { setTimeout(() => { expect( - component.$el.querySelector('.js-folder-name'), - ).toBe(null); + component.$el.querySelector('.js-folder-name').textContent, + ).toContain('Environments / build'); done(); }, 0); }); @@ -199,14 +198,5 @@ describe('Environments Folder View', () => { done(); }, 0); }); - - it('should not render parent folder name', (done) => { - setTimeout(() => { - expect( - component.$el.querySelector('.js-folder-name'), - ).toBe(null); - done(); - }, 0); - }); }); }); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 081897f5456..5c395c6b2d8 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,4 +1,36 @@ const environmentsList = [ + { + name: 'DEV', + size: 1, + id: 7, + state: 'available', + external_url: null, + environment_type: null, + last_deployment: null, + 'stop_action?': false, + environment_path: '/root/review-app/environments/7', + stop_path: '/root/review-app/environments/7/stop', + created_at: '2017-01-31T10:53:46.894Z', + updated_at: '2017-01-31T10:53:46.894Z', + }, + { + folderName: 'build', + size: 5, + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + 'stop_action?': false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', + }, +]; + +const serverData = [ { name: 'DEV', size: 1, @@ -56,4 +88,5 @@ const environment = { module.exports = { environmentsList, environment, + serverData, }; -- cgit v1.2.1 From 21aafcfc899d34f296ddd1e3380970dbe01397f6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 16 Feb 2017 11:34:08 +0100 Subject: fix tmpdir --- spec/lib/gitlab/import_export/repo_restorer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index a9feb8dd19d..168a59e5139 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::ImportExport::RepoRestorer, services: true do let(:user) { create(:user) } let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project) } - let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" } + let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) } let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) } -- cgit v1.2.1 From ac7101364293666aaf81dfaa19ab46b148d0718c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 16 Feb 2017 11:15:08 +0000 Subject: Rename storePagination to setPagination --- spec/javascripts/environments/environments_store_spec.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 8fd660c3edb..71c1abd0c91 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -50,7 +50,7 @@ const { environmentsList } = require('./mock_data'); previousPage: 2, }; - store.storePagination(pagination); + store.setPagination(pagination); expect(store.state.paginationInformation).toEqual(expectedResult); }); }); -- cgit v1.2.1 From 51f037809e207b5a28d6c3f7945801a7a13739fe Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 16 Feb 2017 12:02:55 +0000 Subject: Create util to handle pagination transformation --- .../javascripts/lib/utils/common_utils_spec.js.es6 | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 006ede21093..f4d3e77e515 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -108,6 +108,30 @@ require('~/lib/utils/common_utils'); }); }); + describe('gl.utils.parseIntPagination', () => { + it('should parse to integers all string values and return pagination object', () => { + const pagination = { + 'X-PER-PAGE': 10, + 'X-PAGE': 2, + 'X-TOTAL': 30, + 'X-TOTAL-PAGES': 3, + 'X-NEXT-PAGE': 3, + 'X-PREV-PAGE': 1, + }; + + const expectedPagination = { + perPage: 10, + page: 2, + total: 30, + totalPages: 3, + nextPage: 3, + previousPage: 1, + }; + + expect(gl.utils.parseIntPagination(pagination)).toEqual(expectedPagination); + }); + }); + describe('gl.utils.isMetaClick', () => { it('should identify meta click on Windows/Linux', () => { const e = { -- cgit v1.2.1 From d89f4d73b9422aac15ee708ca72405f399c7dfa6 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Wed, 15 Feb 2017 14:51:40 +0100 Subject: Fix error in MR widget after /merge slash command --- spec/controllers/projects/merge_requests_controller_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index bfd134e406e..f84f922ba5e 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1143,15 +1143,15 @@ describe Projects::MergeRequestsController do end end - context 'when no special status for MR' do + context 'when MR does not have special state' do let(:merge_request) { create(:merge_request, source_project: project) } it 'returns an OK response' do expect(response).to have_http_status(:ok) end - it 'sets status to nil' do - expect(assigns(:status)).to be_nil + it 'sets status to success' do + expect(assigns(:status)).to eq(:success) expect(response).to render_template('merge') end end -- cgit v1.2.1 From 78082831c1b3fa724badc6bab4fd54d9fbd0366c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 16 Feb 2017 13:28:59 +0000 Subject: Fix broken test --- spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6 b/spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6 index 789f5dc9f49..94973419979 100644 --- a/spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6 +++ b/spec/javascripts/commit/pipelines/pipelines_store_spec.js.es6 @@ -1,10 +1,10 @@ -require('~/commit/pipelines/pipelines_store'); +const PipelinesStore = require('~/commit/pipelines/pipelines_store'); describe('Store', () => { let store; beforeEach(() => { - store = new gl.commits.pipelines.PipelinesStore(); + store = new PipelinesStore(); }); // unregister intervals and event handlers -- cgit v1.2.1 From 02aad721f16a8eb4d5fd7499693614dadfa64770 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 16 Feb 2017 14:06:22 -0600 Subject: Only yield valid references in ReferenceFilter.references_in --- .../banzai/filter/issue_reference_filter_spec.rb | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 456dbac0698..11607d4fb26 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -311,7 +311,7 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end end - describe '#issues_per_Project' do + describe '#issues_per_project' do context 'using an internal issue tracker' do it 'returns a Hash containing the issues per project' do doc = Nokogiri::HTML.fragment('') @@ -346,4 +346,26 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end end end + + describe '.references_in' do + let(:merge_request) { create(:merge_request) } + + it 'yields valid references' do + expect do |b| + described_class.references_in(issue.to_reference, &b) + end.to yield_with_args(issue.to_reference, issue.iid, nil, nil, MatchData) + end + + it "doesn't yield invalid references" do + expect do |b| + described_class.references_in('#0', &b) + end.not_to yield_control + end + + it "doesn't yield unsupported references" do + expect do |b| + described_class.references_in(merge_request.to_reference, &b) + end.not_to yield_control + end + end end -- cgit v1.2.1 From 9f00c2b0d2362232b49ef260e0500b14b975e574 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 16 Feb 2017 20:17:12 +0000 Subject: Reduce number of pipelines created to test pagination stub pagination in tests --- spec/features/projects/pipelines/pipelines_spec.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 06f953a50d7..8d1214dedb4 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -288,23 +288,22 @@ describe 'Pipelines', :feature, :js do context 'with pagination' do before do - create_list(:ci_empty_pipeline, 40, project: project) + allow(Ci::Pipeline).to receive(:default_per_page).and_return(1) + create(:ci_empty_pipeline, project: project) end it 'should render pagination' do visit namespace_project_pipelines_path(project.namespace, project) wait_for_vue_resource - expect(page).to have_css('.gl-pagination') - expect(page.find_all('tbody tr').length).to eq(20) + expect(page).to have_selector('.gl-pagination') end - it "should render second page of pipelines" do + it 'should render second page of pipelines' do visit namespace_project_pipelines_path(project.namespace, project, page: '2') wait_for_vue_resource - expect(page).to have_css('.gl-pagination') - expect(page.find_all('tbody tr').length).to eq(20) + expect(page).to have_selector('.gl-pagination .page', count: 2) end end end -- cgit v1.2.1 From ae69e8764c273029ed944e98842a21a4aab0f4af Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 14 Feb 2017 10:16:24 -0600 Subject: Restore pagination to admin abuse reports --- spec/features/admin/admin_abuse_reports_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'spec') diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb index 7fcfe5a54c7..340884fc986 100644 --- a/spec/features/admin/admin_abuse_reports_spec.rb +++ b/spec/features/admin/admin_abuse_reports_spec.rb @@ -30,5 +30,24 @@ describe "Admin::AbuseReports", feature: true, js: true do end end end + + describe 'if a many users have been reported for abuse' do + let(:report_count) { AbuseReport.default_per_page + 3 } + + before do + report_count.times do + create(:abuse_report, user: create(:user)) + end + end + + describe 'in the abuse report view' do + it 'presents information about abuse report' do + visit admin_abuse_reports_path + + expect(page).to have_selector('.pagination') + expect(page).to have_selector('.pagination .page', count: (report_count.to_f / AbuseReport.default_per_page).ceil) + end + end + end end end -- cgit v1.2.1 From aa7c8be5c654000fe71a59e4f8ff22bd3a3e1219 Mon Sep 17 00:00:00 2001 From: Joren De Groof Date: Thu, 16 Feb 2017 10:08:18 +0100 Subject: Add API endpoint to get all milestone merge requests --- spec/requests/api/milestones_spec.rb | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 8beef821d6c..7bb208721a1 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -229,4 +229,40 @@ describe API::Milestones, api: true do end end end + + describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do + let(:merge_request) { create(:merge_request, source_project: project) } + before do + milestone.merge_requests << merge_request + end + + it 'returns project merge_requests for a particular milestone' do + get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq(merge_request.title) + expect(json_response.first['milestone']['title']).to eq(milestone.title) + end + + it 'returns a 404 error if milestone id not found' do + get api("/projects/#{project.id}/milestones/1234/merge_requests", user) + + expect(response).to have_http_status(404) + end + + it 'returns a 404 if the user has no access to the milestone' do + new_user = create :user + get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", new_user) + + expect(response).to have_http_status(404) + end + + it 'returns a 401 error if user not authenticated' do + get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests") + + expect(response).to have_http_status(401) + end + end end -- cgit v1.2.1 From 5a0027236bd424ec9178d846c94092dfac419ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 17 Feb 2017 10:25:34 +0100 Subject: Allow slashes in slash command arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/lib/gitlab/slash_commands/extractor_spec.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/slash_commands/extractor_spec.rb b/spec/lib/gitlab/slash_commands/extractor_spec.rb index 1e4954c4af8..d7f77486b3e 100644 --- a/spec/lib/gitlab/slash_commands/extractor_spec.rb +++ b/spec/lib/gitlab/slash_commands/extractor_spec.rb @@ -81,6 +81,14 @@ describe Gitlab::SlashCommands::Extractor 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 -- cgit v1.2.1