summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorTim Zallmann <tzallmann@gitlab.com>2017-06-21 09:39:30 +0200
committerTim Zallmann <tzallmann@gitlab.com>2017-06-21 09:39:30 +0200
commit1578ee93475c0ebb62399403d971e99aa45e7276 (patch)
tree9664baf0f488e2f6dcf2e6d20305331c5efd3966 /spec
parent278bf413bf4e395e268aa6bacade828e9f58d064 (diff)
parent6d859009efb4c9c865b63f074d07461d0558fd2a (diff)
downloadgitlab-ce-1578ee93475c0ebb62399403d971e99aa45e7276.tar.gz
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce
Diffstat (limited to 'spec')
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb19
-rw-r--r--spec/features/reportable_note/snippets_spec.rb11
-rw-r--r--spec/fixtures/emails/html_empty_link.eml26
-rw-r--r--spec/helpers/application_helper_spec.rb91
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js27
-rw-r--r--spec/javascripts/fixtures/merge_requests.rb13
-rw-r--r--spec/javascripts/fixtures/pipelines_table.html.haml1
-rw-r--r--spec/javascripts/issue_show/components/description_spec.js12
-rw-r--r--spec/javascripts/merge_request_notes_spec.js96
-rw-r--r--spec/javascripts/pipelines/async_button_spec.js44
-rw-r--r--spec/javascripts/pipelines/pipelines_actions_spec.js31
-rw-r--r--spec/javascripts/pipelines/pipelines_table_row_spec.js (renamed from spec/javascripts/vue_shared/components/pipelines_table_row_spec.js)2
-rw-r--r--spec/javascripts/pipelines/pipelines_table_spec.js (renamed from spec/javascripts/vue_shared/components/pipelines_table_spec.js)6
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb4
-rw-r--r--spec/lib/gitlab/metrics_spec.rb30
-rw-r--r--spec/lib/gitlab/visibility_level_spec.rb31
-rw-r--r--spec/models/project_feature_spec.rb12
-rw-r--r--spec/models/project_services/chat_message/pipeline_message_spec.rb10
-rw-r--r--spec/models/project_services/chat_message/push_message_spec.rb16
-rw-r--r--spec/models/project_spec.rb32
-rw-r--r--spec/requests/api/users_spec.rb9
-rw-r--r--spec/requests/api/v3/users_spec.rb32
-rw-r--r--spec/services/projects/transfer_service_spec.rb61
-rw-r--r--spec/support/features/reportable_note_shared_examples.rb13
-rw-r--r--spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb41
25 files changed, 490 insertions, 180 deletions
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index 2eb04df3cb3..a99c19cb787 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -16,6 +16,21 @@ feature 'Issues > Labels bulk assignment', feature: true do
gitlab_sign_in user
end
+ context 'sidebar' do
+ before do
+ enable_bulk_update
+ end
+
+ it 'is present when bulk edit is enabled' do
+ expect(page).to have_css('.issuable-sidebar')
+ end
+
+ it 'is not present when bulk edit is disabled' do
+ disable_bulk_update
+ expect(page).not_to have_css('.issuable-sidebar')
+ end
+ end
+
context 'can bulk assign' do
before do
enable_bulk_update
@@ -398,4 +413,8 @@ feature 'Issues > Labels bulk assignment', feature: true do
visit namespace_project_issues_path(project.namespace, project)
click_button 'Edit Issues'
end
+
+ def disable_bulk_update
+ click_button 'Cancel'
+ end
end
diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb
index a88990eada0..5bee4a31379 100644
--- a/spec/features/reportable_note/snippets_spec.rb
+++ b/spec/features/reportable_note/snippets_spec.rb
@@ -19,15 +19,4 @@ describe 'Reportable note on snippets', :feature, :js do
it_behaves_like 'reportable note'
end
-
- describe 'on personal snippet' do
- let(:snippet) { create(:personal_snippet, :public, author: user) }
- let!(:note) { create(:note_on_personal_snippet, noteable: snippet, author: user) }
-
- before do
- visit snippet_path(snippet)
- end
-
- it_behaves_like 'reportable note'
- end
end
diff --git a/spec/fixtures/emails/html_empty_link.eml b/spec/fixtures/emails/html_empty_link.eml
new file mode 100644
index 00000000000..1672b98b925
--- /dev/null
+++ b/spec/fixtures/emails/html_empty_link.eml
@@ -0,0 +1,26 @@
+
+MIME-Version: 1.0
+Received: by 10.25.161.144 with HTTP; Tue, 7 Oct 2014 22:17:17 -0700 (PDT)
+X-Originating-IP: [117.207.85.84]
+In-Reply-To: <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
+References: <topic/35@discourse.techapj.com>
+ <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
+Date: Wed, 8 Oct 2014 10:47:17 +0530
+Delivered-To: arpit@techapj.com
+Message-ID: <CAOJeqne=SJ_LwN4sb-0Y95ejc2OpreVhdmcPn0TnmwSvTCYzzQ@mail.gmail.com>
+Subject: Re: [Discourse] [Meta] Welcome to techAPJ's Discourse!
+From: Arpit Jalan <arpit@techapj.com>
+To: Discourse <mail+e1c7f2a380e33840aeb654f075490bad@arpitjalan.com>Accept-Language: en-US
+Content-Language: en-US
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+x-originating-ip: [134.68.31.227]
+Content-Type: multipart/alternative;
+ boundary="_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_"
+MIME-Version: 1.0
+
+--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_
+Content-Type: text/html; charset="utf-8"
+
+<a name="_MailEndCompose">no brackets!</a>
+--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_--
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index cc7f889b927..c1966c273db 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -82,42 +82,71 @@ describe ApplicationHelper do
end
describe 'avatar_icon' do
- it 'returns an url for the avatar' do
- user = create(:user, avatar: File.open(uploaded_image_temp_path))
-
- avatar_url = "/uploads/system/user/avatar/#{user.id}/banana_sample.gif"
-
- expect(helper.avatar_icon(user.email).to_s).to match(avatar_url)
-
- allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)
- avatar_url = "#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif"
-
- expect(helper.avatar_icon(user.email).to_s).to match(avatar_url)
- end
-
- it 'returns an url for the avatar with relative url' do
- stub_config_setting(relative_url_root: '/gitlab')
- # Must be stubbed after the stub above, and separately
- stub_config_setting(url: Settings.send(:build_gitlab_url))
-
- user = create(:user, avatar: File.open(uploaded_image_temp_path))
-
- expect(helper.avatar_icon(user.email).to_s).
- to match("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
- end
+ let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
+
+ context 'using an email' do
+ context 'when there is a matching user' do
+ it 'returns a relative URL for the avatar' do
+ expect(helper.avatar_icon(user.email).to_s).
+ to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
+
+ context 'when an asset_host is set in the config' do
+ let(:asset_host) { 'http://assets' }
+
+ before do
+ allow(ActionController::Base).to receive(:asset_host).and_return(asset_host)
+ end
+
+ it 'returns an absolute URL on that asset host' do
+ expect(helper.avatar_icon(user.email, only_path: false).to_s).
+ to eq("#{asset_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
+ end
+
+ context 'when only_path is set to false' do
+ it 'returns an absolute URL for the avatar' do
+ expect(helper.avatar_icon(user.email, only_path: false).to_s).
+ to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
+ end
+
+ context 'when the GitLab instance is at a relative URL' do
+ before do
+ stub_config_setting(relative_url_root: '/gitlab')
+ # Must be stubbed after the stub above, and separately
+ stub_config_setting(url: Settings.send(:build_gitlab_url))
+ end
+
+ it 'returns a relative URL with the correct prefix' do
+ expect(helper.avatar_icon(user.email).to_s).
+ to eq("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
+ end
+ end
- it 'calls gravatar_icon when no User exists with the given email' do
- expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
+ context 'when no user exists for the email' do
+ it 'calls gravatar_icon' do
+ expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
- helper.avatar_icon('foo@example.com', 20, 2)
+ helper.avatar_icon('foo@example.com', 20, 2)
+ end
+ end
end
- describe 'using a User' do
- it 'returns an URL for the avatar' do
- user = create(:user, avatar: File.open(uploaded_image_temp_path))
+ describe 'using a user' do
+ context 'when only_path is true' do
+ it 'returns a relative URL for the avatar' do
+ expect(helper.avatar_icon(user, only_path: true).to_s).
+ to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
+ end
- expect(helper.avatar_icon(user).to_s).
- to match("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ context 'when only_path is false' do
+ it 'returns an absolute URL for the avatar' do
+ expect(helper.avatar_icon(user, only_path: false).to_s).
+ to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ end
end
end
end
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index ebfd60198b2..694f94efcff 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -1,15 +1,15 @@
import Vue from 'vue';
-import PipelinesTable from '~/commit/pipelines/pipelines_table';
+import pipelinesTable from '~/commit/pipelines/pipelines_table.vue';
describe('Pipelines table in Commits and Merge requests', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
let pipeline;
+ let PipelinesTable;
- preloadFixtures('static/pipelines_table.html.raw');
preloadFixtures(jsonFixtureName);
beforeEach(() => {
- loadFixtures('static/pipelines_table.html.raw');
+ PipelinesTable = Vue.extend(pipelinesTable);
const pipelines = getJSONFixture(jsonFixtureName).pipelines;
pipeline = pipelines.find(p => p.id === 1);
});
@@ -26,8 +26,11 @@ describe('Pipelines table in Commits and Merge requests', () => {
Vue.http.interceptors.push(pipelinesEmptyResponse);
this.component = new PipelinesTable({
- el: document.querySelector('#commit-pipeline-table-view'),
- });
+ propsData: {
+ endpoint: 'endpoint',
+ helpPagePath: 'foo',
+ },
+ }).$mount();
});
afterEach(function () {
@@ -58,8 +61,11 @@ describe('Pipelines table in Commits and Merge requests', () => {
Vue.http.interceptors.push(pipelinesResponse);
this.component = new PipelinesTable({
- el: document.querySelector('#commit-pipeline-table-view'),
- });
+ propsData: {
+ endpoint: 'endpoint',
+ helpPagePath: 'foo',
+ },
+ }).$mount();
});
afterEach(() => {
@@ -92,8 +98,11 @@ describe('Pipelines table in Commits and Merge requests', () => {
Vue.http.interceptors.push(pipelinesErrorResponse);
this.component = new PipelinesTable({
- el: document.querySelector('#commit-pipeline-table-view'),
- });
+ propsData: {
+ endpoint: 'endpoint',
+ helpPagePath: 'foo',
+ },
+ }).$mount();
});
afterEach(function () {
diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb
index a746a776548..0715f4d5f6b 100644
--- a/spec/javascripts/fixtures/merge_requests.rb
+++ b/spec/javascripts/fixtures/merge_requests.rb
@@ -55,13 +55,20 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
render_merge_request(example.description, merge_request)
end
+ it 'merge_requests/changes_tab_with_comments.json' do |example|
+ create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
+ create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
+ render_merge_request(example.description, merge_request, action: :diffs, format: :json)
+ end
+
private
- def render_merge_request(fixture_file_name, merge_request)
- get :show,
+ def render_merge_request(fixture_file_name, merge_request, action: :show, format: :html)
+ get action,
namespace_id: project.namespace.to_param,
project_id: project,
- id: merge_request.to_param
+ id: merge_request.to_param,
+ format: format
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/fixtures/pipelines_table.html.haml b/spec/javascripts/fixtures/pipelines_table.html.haml
deleted file mode 100644
index ad1682704bb..00000000000
--- a/spec/javascripts/fixtures/pipelines_table.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-#commit-pipeline-table-view{ data: { endpoint: "endpoint", "help-page-path": "foo" } }
diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js
index 886462c4b9a..f3fdbff01a6 100644
--- a/spec/javascripts/issue_show/components/description_spec.js
+++ b/spec/javascripts/issue_show/components/description_spec.js
@@ -95,6 +95,18 @@ describe('Description component', () => {
done();
});
});
+
+ it('clears task status text when no tasks are present', (done) => {
+ vm.taskStatus = '0 of 0';
+
+ setTimeout(() => {
+ expect(
+ document.querySelector('.issuable-meta #task_status').textContent.trim(),
+ ).toBe('');
+
+ done();
+ });
+ });
});
it('applies syntax highlighting and math when description changed', (done) => {
diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js
index e54acfa8e44..b6d0ce02c4f 100644
--- a/spec/javascripts/merge_request_notes_spec.js
+++ b/spec/javascripts/merge_request_notes_spec.js
@@ -7,54 +7,92 @@ import '~/render_gfm';
import '~/render_math';
import '~/notes';
+const upArrowKeyCode = 38;
+
describe('Merge request notes', () => {
window.gon = window.gon || {};
window.gl = window.gl || {};
gl.utils = gl.utils || {};
- const fixture = 'merge_requests/diff_comment.html.raw';
- preloadFixtures(fixture);
+ const discussionTabFixture = 'merge_requests/diff_comment.html.raw';
+ const changesTabJsonFixture = 'merge_requests/changes_tab_with_comments.json';
+ preloadFixtures(discussionTabFixture, changesTabJsonFixture);
- beforeEach(() => {
- loadFixtures(fixture);
- gl.utils.disableButtonIfEmptyField = _.noop;
- window.project_uploads_path = 'http://test.host/uploads';
- $('body').data('page', 'projects:merge_requests:show');
- window.gon.current_user_id = $('.note:last').data('author-id');
+ describe('Discussion tab with diff comments', () => {
+ beforeEach(() => {
+ loadFixtures(discussionTabFixture);
+ gl.utils.disableButtonIfEmptyField = _.noop;
+ window.project_uploads_path = 'http://test.host/uploads';
+ $('body').data('page', 'projects:merge_requests:show');
+ window.gon.current_user_id = $('.note:last').data('author-id');
- return new Notes('', []);
- });
+ return new Notes('', []);
+ });
+
+ describe('up arrow', () => {
+ it('edits last comment when triggered in main form', () => {
+ const upArrowEvent = $.Event('keydown');
+ upArrowEvent.which = upArrowKeyCode;
+
+ spyOnEvent('.note:last .js-note-edit', 'click');
+
+ $('.js-note-text').trigger(upArrowEvent);
+
+ expect('click').toHaveBeenTriggeredOn('.note:last .js-note-edit');
+ });
+
+ it('edits last comment in discussion when triggered in discussion form', (done) => {
+ const upArrowEvent = $.Event('keydown');
+ upArrowEvent.which = upArrowKeyCode;
+
+ spyOnEvent('.note-discussion .js-note-edit', 'click');
+
+ $('.js-discussion-reply-button').click();
- describe('up arrow', () => {
- it('edits last comment when triggered in main form', () => {
- const upArrowEvent = $.Event('keydown');
- upArrowEvent.which = 38;
+ setTimeout(() => {
+ expect(
+ $('.note-discussion .js-note-text'),
+ ).toExist();
- spyOnEvent('.note:last .js-note-edit', 'click');
+ $('.note-discussion .js-note-text').trigger(upArrowEvent);
- $('.js-note-text').trigger(upArrowEvent);
+ expect('click').toHaveBeenTriggeredOn('.note-discussion .js-note-edit');
- expect('click').toHaveBeenTriggeredOn('.note:last .js-note-edit');
+ done();
+ });
+ });
});
+ });
- it('edits last comment in discussion when triggered in discussion form', (done) => {
- const upArrowEvent = $.Event('keydown');
- upArrowEvent.which = 38;
+ describe('Changes tab with diff comments', () => {
+ beforeEach(() => {
+ const diffsResponse = getJSONFixture(changesTabJsonFixture);
+ const noteFormHtml = `<form class="js-new-note-form">
+ <textarea class="js-note-text"></textarea>
+ </form>`;
+ setFixtures(diffsResponse.html + noteFormHtml);
+ $('body').data('page', 'projects:merge_requests:show');
+ window.gon.current_user_id = $('.note:last').data('author-id');
+
+ return new Notes('', []);
+ });
- spyOnEvent('.note-discussion .js-note-edit', 'click');
+ describe('up arrow', () => {
+ it('edits last comment in discussion when triggered in discussion form', (done) => {
+ const upArrowEvent = $.Event('keydown');
+ upArrowEvent.which = upArrowKeyCode;
- $('.js-discussion-reply-button').click();
+ spyOnEvent('.note:last .js-note-edit', 'click');
- setTimeout(() => {
- expect(
- $('.note-discussion .js-note-text'),
- ).toExist();
+ $('.js-discussion-reply-button').trigger('click');
- $('.note-discussion .js-note-text').trigger(upArrowEvent);
+ setTimeout(() => {
+ $('.js-note-text').trigger(upArrowEvent);
- expect('click').toHaveBeenTriggeredOn('.note-discussion .js-note-edit');
+ expect('click').toHaveBeenTriggeredOn('.note:last .js-note-edit');
- done();
+ done();
+ });
});
});
});
diff --git a/spec/javascripts/pipelines/async_button_spec.js b/spec/javascripts/pipelines/async_button_spec.js
index 28c9c7ab282..48620898357 100644
--- a/spec/javascripts/pipelines/async_button_spec.js
+++ b/spec/javascripts/pipelines/async_button_spec.js
@@ -1,25 +1,20 @@
import Vue from 'vue';
import asyncButtonComp from '~/pipelines/components/async_button.vue';
+import eventHub from '~/pipelines/event_hub';
describe('Pipelines Async Button', () => {
let component;
- let spy;
let AsyncButtonComponent;
beforeEach(() => {
AsyncButtonComponent = Vue.extend(asyncButtonComp);
- spy = jasmine.createSpy('spy').and.returnValue(Promise.resolve());
-
component = new AsyncButtonComponent({
propsData: {
endpoint: '/foo',
title: 'Foo',
icon: 'fa fa-foo',
cssClass: 'bar',
- service: {
- postAction: spy,
- },
},
}).$mount();
});
@@ -33,7 +28,7 @@ describe('Pipelines Async Button', () => {
});
it('should render the provided title', () => {
- expect(component.$el.getAttribute('title')).toContain('Foo');
+ expect(component.$el.getAttribute('data-original-title')).toContain('Foo');
expect(component.$el.getAttribute('aria-label')).toContain('Foo');
});
@@ -41,37 +36,12 @@ describe('Pipelines Async Button', () => {
expect(component.$el.getAttribute('class')).toContain('bar');
});
- it('should call the service when it is clicked with the provided endpoint', () => {
- component.$el.click();
- expect(spy).toHaveBeenCalledWith('/foo');
- });
-
- it('should hide loading if request fails', () => {
- spy = jasmine.createSpy('spy').and.returnValue(Promise.reject());
-
- component = new AsyncButtonComponent({
- propsData: {
- endpoint: '/foo',
- title: 'Foo',
- icon: 'fa fa-foo',
- cssClass: 'bar',
- dataAttributes: {
- 'data-foo': 'foo',
- },
- service: {
- postAction: spy,
- },
- },
- }).$mount();
-
- component.$el.click();
- expect(component.$el.querySelector('.fa-spinner')).toBe(null);
- });
-
describe('With confirm dialog', () => {
it('should call the service when confimation is positive', () => {
spyOn(window, 'confirm').and.returnValue(true);
- spy = jasmine.createSpy('spy').and.returnValue(Promise.resolve());
+ eventHub.$on('postAction', (endpoint) => {
+ expect(endpoint).toEqual('/foo');
+ });
component = new AsyncButtonComponent({
propsData: {
@@ -79,15 +49,11 @@ describe('Pipelines Async Button', () => {
title: 'Foo',
icon: 'fa fa-foo',
cssClass: 'bar',
- service: {
- postAction: spy,
- },
confirmActionMessage: 'bar',
},
}).$mount();
component.$el.click();
- expect(spy).toHaveBeenCalledWith('/foo');
});
});
});
diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js
index 8a58b77f1e3..72fb0a8f9ef 100644
--- a/spec/javascripts/pipelines/pipelines_actions_spec.js
+++ b/spec/javascripts/pipelines/pipelines_actions_spec.js
@@ -3,7 +3,6 @@ import pipelinesActionsComp from '~/pipelines/components/pipelines_actions.vue';
describe('Pipelines Actions dropdown', () => {
let component;
- let spy;
let actions;
let ActionsComponent;
@@ -22,14 +21,9 @@ describe('Pipelines Actions dropdown', () => {
},
];
- spy = jasmine.createSpy('spy').and.returnValue(Promise.resolve());
-
component = new ActionsComponent({
propsData: {
actions,
- service: {
- postAction: spy,
- },
},
}).$mount();
});
@@ -40,31 +34,6 @@ describe('Pipelines Actions dropdown', () => {
).toEqual(actions.length);
});
- it('should call the service when an action is clicked', () => {
- component.$el.querySelector('.js-pipeline-dropdown-manual-actions').click();
- component.$el.querySelector('.js-pipeline-action-link').click();
-
- expect(spy).toHaveBeenCalledWith(actions[0].path);
- });
-
- it('should hide loading if request fails', () => {
- spy = jasmine.createSpy('spy').and.returnValue(Promise.reject());
-
- component = new ActionsComponent({
- propsData: {
- actions,
- service: {
- postAction: spy,
- },
- },
- }).$mount();
-
- component.$el.querySelector('.js-pipeline-dropdown-manual-actions').click();
- component.$el.querySelector('.js-pipeline-action-link').click();
-
- expect(component.$el.querySelector('.fa-spinner')).toEqual(null);
- });
-
it('should render a disabled action when it\'s not playable', () => {
expect(
component.$el.querySelector('.dropdown-menu li:last-child button').getAttribute('disabled'),
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js b/spec/javascripts/pipelines/pipelines_table_row_spec.js
index 9475ee28a03..7ce39dca112 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_row_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import tableRowComp from '~/vue_shared/components/pipelines_table_row.vue';
+import tableRowComp from '~/pipelines/components/pipelines_table_row.vue';
describe('Pipelines Table Row', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_spec.js b/spec/javascripts/pipelines/pipelines_table_spec.js
index 4c35d702004..3afe89c8db4 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import pipelinesTableComp from '~/vue_shared/components/pipelines_table.vue';
+import pipelinesTableComp from '~/pipelines/components/pipelines_table.vue';
import '~/lib/utils/datetime_utility';
describe('Pipelines Table', () => {
@@ -22,7 +22,6 @@ describe('Pipelines Table', () => {
component = new PipelinesTableComponent({
propsData: {
pipelines: [],
- service: {},
},
}).$mount();
});
@@ -48,7 +47,6 @@ describe('Pipelines Table', () => {
const component = new PipelinesTableComponent({
propsData: {
pipelines: [],
- service: {},
},
}).$mount();
expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(0);
@@ -58,10 +56,8 @@ describe('Pipelines Table', () => {
describe('with data', () => {
it('should render rows', () => {
const component = new PipelinesTableComponent({
- el: document.querySelector('.test-dom-element'),
propsData: {
pipelines: [pipeline],
- service: {},
},
}).$mount();
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index 28698e89c33..71659d5e8b0 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -208,5 +208,9 @@ describe Gitlab::Email::ReplyParser, lib: true do
it "properly renders html-only email from MS Outlook" do
expect(test_parse_body(fixture_file("emails/outlook_html.eml"))).to eq("Microsoft Outlook 2010")
end
+
+ it "does not wrap links with no href in unnecessary brackets" do
+ expect(test_parse_body(fixture_file("emails/html_empty_link.eml"))).to eq("no brackets!")
+ end
end
end
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index 5a87b906609..58a84cd3fe1 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -15,6 +15,36 @@ describe Gitlab::Metrics do
end
end
+ describe '.prometheus_metrics_enabled_unmemoized' do
+ subject { described_class.send(:prometheus_metrics_enabled_unmemoized) }
+
+ context 'prometheus metrics enabled in config' do
+ before do
+ allow(described_class).to receive(:current_application_settings).and_return(prometheus_metrics_enabled: true)
+ end
+
+ context 'when metrics folder is present' do
+ before do
+ allow(described_class).to receive(:metrics_folder_present?).and_return(true)
+ end
+
+ it 'metrics are enabled' do
+ expect(subject).to eq(true)
+ end
+ end
+
+ context 'when metrics folder is missing' do
+ before do
+ allow(described_class).to receive(:metrics_folder_present?).and_return(false)
+ end
+
+ it 'metrics are disabled' do
+ expect(subject).to eq(false)
+ end
+ end
+ end
+ end
+
describe '.prometheus_metrics_enabled?' do
it 'returns a boolean' do
expect(described_class.prometheus_metrics_enabled?).to be_in([true, false])
diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb
index 3255c6f1ef7..a8f21803ec7 100644
--- a/spec/lib/gitlab/visibility_level_spec.rb
+++ b/spec/lib/gitlab/visibility_level_spec.rb
@@ -18,4 +18,35 @@ describe Gitlab::VisibilityLevel, lib: true do
expect(described_class.level_value(100)).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
end
+
+ describe '.levels_for_user' do
+ it 'returns all levels for an admin' do
+ user = double(:user, admin?: true)
+
+ expect(described_class.levels_for_user(user)).
+ to eq([Gitlab::VisibilityLevel::PRIVATE,
+ Gitlab::VisibilityLevel::INTERNAL,
+ Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'returns INTERNAL and PUBLIC for internal users' do
+ user = double(:user, admin?: false, external?: false)
+
+ expect(described_class.levels_for_user(user)).
+ to eq([Gitlab::VisibilityLevel::INTERNAL,
+ Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'returns PUBLIC for external users' do
+ user = double(:user, admin?: false, external?: true)
+
+ expect(described_class.levels_for_user(user)).
+ to eq([Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'returns PUBLIC when no user is given' do
+ expect(described_class.levels_for_user).
+ to eq([Gitlab::VisibilityLevel::PUBLIC])
+ end
+ end
end
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index 09a4448d387..580c83c12c0 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -4,6 +4,18 @@ describe ProjectFeature do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
+ describe '.quoted_access_level_column' do
+ it 'returns the table name and quoted column name for a feature' do
+ expected = if Gitlab::Database.postgresql?
+ '"project_features"."issues_access_level"'
+ else
+ '`project_features`.`issues_access_level`'
+ end
+
+ expect(described_class.quoted_access_level_column(:issues)).to eq(expected)
+ end
+ end
+
describe '#feature_available?' do
let(:features) { %w(issues wiki builds merge_requests snippets repository) }
diff --git a/spec/models/project_services/chat_message/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb
index 7d2599dc703..43b02568cb9 100644
--- a/spec/models/project_services/chat_message/pipeline_message_spec.rb
+++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb
@@ -62,7 +62,7 @@ describe ChatMessage::PipelineMessage do
def build_message(status_text = status, name = user[:name])
"<http://example.gitlab.com|project_name>:" \
" Pipeline <http://example.gitlab.com/pipelines/123|#123>" \
- " of branch `<http://example.gitlab.com/commits/develop|develop>`" \
+ " of branch <http://example.gitlab.com/commits/develop|develop>" \
" by #{name} #{status_text} in 02:00:10"
end
end
@@ -81,7 +81,7 @@ describe ChatMessage::PipelineMessage do
expect(subject.pretext).to be_empty
expect(subject.attachments).to eq(message)
expect(subject.activity).to eq({
- title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch `[develop](http://example.gitlab.com/commits/develop)` by hacker passed',
+ title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by hacker passed',
subtitle: 'in [project_name](http://example.gitlab.com)',
text: 'in 02:00:10',
image: ''
@@ -98,7 +98,7 @@ describe ChatMessage::PipelineMessage do
expect(subject.pretext).to be_empty
expect(subject.attachments).to eq(message)
expect(subject.activity).to eq({
- title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch `[develop](http://example.gitlab.com/commits/develop)` by hacker failed',
+ title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by hacker failed',
subtitle: 'in [project_name](http://example.gitlab.com)',
text: 'in 02:00:10',
image: ''
@@ -113,7 +113,7 @@ describe ChatMessage::PipelineMessage do
expect(subject.pretext).to be_empty
expect(subject.attachments).to eq(message)
expect(subject.activity).to eq({
- title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch `[develop](http://example.gitlab.com/commits/develop)` by API failed',
+ title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by API failed',
subtitle: 'in [project_name](http://example.gitlab.com)',
text: 'in 02:00:10',
image: ''
@@ -125,7 +125,7 @@ describe ChatMessage::PipelineMessage do
def build_markdown_message(status_text = status, name = user[:name])
"[project_name](http://example.gitlab.com):" \
" Pipeline [#123](http://example.gitlab.com/pipelines/123)" \
- " of branch `[develop](http://example.gitlab.com/commits/develop)`" \
+ " of branch [develop](http://example.gitlab.com/commits/develop)" \
" by #{name} #{status_text} in 02:00:10"
end
end
diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb
index e38117b75f6..c794f659c41 100644
--- a/spec/models/project_services/chat_message/push_message_spec.rb
+++ b/spec/models/project_services/chat_message/push_message_spec.rb
@@ -28,7 +28,7 @@ describe ChatMessage::PushMessage, models: true do
context 'without markdown' do
it 'returns a message regarding pushes' do
expect(subject.pretext).to eq(
- 'test.user pushed to branch `<http://url.com/commits/master|master>` of '\
+ 'test.user pushed to branch <http://url.com/commits/master|master> of '\
'<http://url.com|project_name> (<http://url.com/compare/before...after|Compare changes>)')
expect(subject.attachments).to eq([{
text: "<http://url1.com|abcdefgh>: message1 - author1\n\n"\
@@ -45,7 +45,7 @@ describe ChatMessage::PushMessage, models: true do
it 'returns a message regarding pushes' do
expect(subject.pretext).to eq(
- 'test.user pushed to branch `[master](http://url.com/commits/master)` of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))')
+ 'test.user pushed to branch [master](http://url.com/commits/master) of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))')
expect(subject.attachments).to eq(
"[abcdefgh](http://url1.com): message1 - author1\n\n[12345678](http://url2.com): message2 - author2")
expect(subject.activity).to eq({
@@ -74,7 +74,7 @@ describe ChatMessage::PushMessage, models: true do
context 'without markdown' do
it 'returns a message regarding pushes' do
expect(subject.pretext).to eq('test.user pushed new tag ' \
- '`<http://url.com/commits/new_tag|new_tag>` to ' \
+ '<http://url.com/commits/new_tag|new_tag> to ' \
'<http://url.com|project_name>')
expect(subject.attachments).to be_empty
end
@@ -87,7 +87,7 @@ describe ChatMessage::PushMessage, models: true do
it 'returns a message regarding pushes' do
expect(subject.pretext).to eq(
- 'test.user pushed new tag `[new_tag](http://url.com/commits/new_tag)` to [project_name](http://url.com)')
+ 'test.user pushed new tag [new_tag](http://url.com/commits/new_tag) to [project_name](http://url.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
title: 'test.user created tag',
@@ -107,7 +107,7 @@ describe ChatMessage::PushMessage, models: true do
context 'without markdown' do
it 'returns a message regarding a new branch' do
expect(subject.pretext).to eq(
- 'test.user pushed new branch `<http://url.com/commits/master|master>` to '\
+ 'test.user pushed new branch <http://url.com/commits/master|master> to '\
'<http://url.com|project_name>')
expect(subject.attachments).to be_empty
end
@@ -120,7 +120,7 @@ describe ChatMessage::PushMessage, models: true do
it 'returns a message regarding a new branch' do
expect(subject.pretext).to eq(
- 'test.user pushed new branch `[master](http://url.com/commits/master)` to [project_name](http://url.com)')
+ 'test.user pushed new branch [master](http://url.com/commits/master) to [project_name](http://url.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
title: 'test.user created branch',
@@ -140,7 +140,7 @@ describe ChatMessage::PushMessage, models: true do
context 'without markdown' do
it 'returns a message regarding a removed branch' do
expect(subject.pretext).to eq(
- 'test.user removed branch `master` from <http://url.com|project_name>')
+ 'test.user removed branch master from <http://url.com|project_name>')
expect(subject.attachments).to be_empty
end
end
@@ -152,7 +152,7 @@ describe ChatMessage::PushMessage, models: true do
it 'returns a message regarding a removed branch' do
expect(subject.pretext).to eq(
- 'test.user removed branch `master` from [project_name](http://url.com)')
+ 'test.user removed branch master from [project_name](http://url.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
title: 'test.user removed branch',
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 63333b7af1f..c7ba3ae903d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2060,4 +2060,36 @@ describe Project, models: true do
expect(project.last_repository_updated_at.to_i).to eq(project.created_at.to_i)
end
end
+
+ describe '.public_or_visible_to_user' do
+ let!(:user) { create(:user) }
+
+ let!(:private_project) do
+ create(:empty_project, :private, creator: user, namespace: user.namespace)
+ end
+
+ let!(:public_project) { create(:empty_project, :public) }
+
+ context 'with a user' do
+ let(:projects) do
+ Project.all.public_or_visible_to_user(user)
+ end
+
+ it 'includes projects the user has access to' do
+ expect(projects).to include(private_project)
+ end
+
+ it 'includes projects the user can see' do
+ expect(projects).to include(public_project)
+ end
+ end
+
+ context 'without a user' do
+ it 'only includes public projects' do
+ projects = Project.all.public_or_visible_to_user
+
+ expect(projects).to eq([public_project])
+ end
+ end
+ end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index bc869ea1108..750682bde52 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -11,7 +11,7 @@ describe API::Users do
let(:not_existing_user_id) { (User.maximum('id') || 0 ) + 10 }
let(:not_existing_pat_id) { (PersonalAccessToken.maximum('id') || 0 ) + 10 }
- describe "GET /users" do
+ describe 'GET /users' do
context "when unauthenticated" do
it "returns authentication error" do
get api("/users")
@@ -76,6 +76,12 @@ describe API::Users do
expect(response).to have_http_status(403)
end
+
+ it 'does not reveal the `is_admin` flag of the user' do
+ get api('/users', user)
+
+ expect(json_response.first.keys).not_to include 'is_admin'
+ end
end
context "when admin" do
@@ -92,6 +98,7 @@ describe API::Users do
expect(json_response.first.keys).to include 'two_factor_enabled'
expect(json_response.first.keys).to include 'last_sign_in_at'
expect(json_response.first.keys).to include 'confirmed_at'
+ expect(json_response.first.keys).to include 'is_admin'
end
it "returns an array of external users" do
diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb
index e9c57f7c6c3..6d7401f9764 100644
--- a/spec/requests/api/v3/users_spec.rb
+++ b/spec/requests/api/v3/users_spec.rb
@@ -7,6 +7,38 @@ describe API::V3::Users do
let(:email) { create(:email, user: user) }
let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
+ describe 'GET /users' do
+ context 'when authenticated' do
+ it 'returns an array of users' do
+ get v3_api('/users', user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ username = user.username
+ expect(json_response.detect do |user|
+ user['username'] == username
+ end['username']).to eq(username)
+ end
+ end
+
+ context 'when authenticated as user' do
+ it 'does not reveal the `is_admin` flag of the user' do
+ get v3_api('/users', user)
+
+ expect(json_response.first.keys).not_to include 'is_admin'
+ end
+ end
+
+ context 'when authenticated as admin' do
+ it 'reveals the `is_admin` flag of the user' do
+ get v3_api('/users', admin)
+
+ expect(json_response.first.keys).to include 'is_admin'
+ end
+ end
+ end
+
describe 'GET /user/:id/keys' do
before { admin }
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 5d2f4cf17fb..63bd0353d50 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -19,6 +19,67 @@ describe Projects::TransferService, services: true do
it { expect(project.namespace).to eq(group) }
end
+ context 'when transfer succeeds' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'sends notifications' do
+ expect_any_instance_of(NotificationService).to receive(:project_was_moved)
+
+ transfer_project(project, user, group)
+ end
+
+ it 'executes system hooks' do
+ expect_any_instance_of(Projects::TransferService).to receive(:execute_system_hooks)
+
+ transfer_project(project, user, group)
+ end
+ end
+
+ context 'when transfer fails' do
+ let!(:original_path) { project_path(project) }
+
+ def attempt_project_transfer
+ expect do
+ transfer_project(project, user, group)
+ end.to raise_error(ActiveRecord::ActiveRecordError)
+ end
+
+ before do
+ group.add_owner(user)
+
+ expect_any_instance_of(Labels::TransferService).to receive(:execute).and_raise(ActiveRecord::StatementInvalid, "PG ERROR")
+ end
+
+ def project_path(project)
+ File.join(project.repository_storage_path, "#{project.path_with_namespace}.git")
+ end
+
+ def current_path
+ project_path(project)
+ end
+
+ it 'rolls back repo location' do
+ attempt_project_transfer
+
+ expect(Dir.exist?(original_path)).to be_truthy
+ expect(original_path).to eq current_path
+ end
+
+ it "doesn't send move notifications" do
+ expect_any_instance_of(NotificationService).not_to receive(:project_was_moved)
+
+ attempt_project_transfer
+ end
+
+ it "doesn't run system hooks" do
+ expect_any_instance_of(Projects::TransferService).not_to receive(:execute_system_hooks)
+
+ attempt_project_transfer
+ end
+ end
+
context 'namespace -> no namespace' do
before do
@result = transfer_project(project, user, nil)
diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb
index 0d80c95e826..27e079c01dd 100644
--- a/spec/support/features/reportable_note_shared_examples.rb
+++ b/spec/support/features/reportable_note_shared_examples.rb
@@ -13,9 +13,7 @@ shared_examples 'reportable note' do
it 'dropdown has Edit, Report and Delete links' do
dropdown = comment.find(more_actions_selector)
-
- dropdown.click
- dropdown.find('.dropdown-menu li', match: :first)
+ open_dropdown(dropdown)
expect(dropdown).to have_button('Edit comment')
expect(dropdown).to have_link('Report as abuse', href: abuse_report_path)
@@ -24,13 +22,16 @@ shared_examples 'reportable note' do
it 'Report button links to a report page' do
dropdown = comment.find(more_actions_selector)
-
- dropdown.click
- dropdown.find('.dropdown-menu li', match: :first)
+ open_dropdown(dropdown)
dropdown.click_link('Report as abuse')
expect(find('#user_name')['value']).to match(note.author.username)
expect(find('#abuse_report_message')['value']).to match(noteable_note_url(note))
end
+
+ def open_dropdown(dropdown)
+ dropdown.click
+ dropdown.find('.dropdown-menu li', match: :first)
+ end
end
diff --git a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
new file mode 100644
index 00000000000..e56c0f6be03
--- /dev/null
+++ b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe 'projects/notes/_more_actions_dropdown', :view do
+ let(:author_user) { create(:user) }
+ let(:not_author_user) { create(:user) }
+
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let!(:note) { create(:note_on_issue, author: author_user, noteable: issue, project: project) }
+
+ before do
+ assign(:project, project)
+ end
+
+ it 'shows Report as abuse button if not editable and not current users comment' do
+ render 'projects/notes/more_actions_dropdown', current_user: not_author_user, note_editable: false, note: note
+
+ expect(rendered).to have_link('Report as abuse')
+ end
+
+ it 'does not show the More actions button if not editable and current users comment' do
+ render 'projects/notes/more_actions_dropdown', current_user: author_user, note_editable: false, note: note
+
+ expect(rendered).not_to have_selector('.dropdown.more-actions')
+ end
+
+ it 'shows Report as abuse, Edit and Delete buttons if editable and not current users comment' do
+ render 'projects/notes/more_actions_dropdown', current_user: not_author_user, note_editable: true, note: note
+
+ expect(rendered).to have_link('Report as abuse')
+ expect(rendered).to have_button('Edit comment')
+ expect(rendered).to have_link('Delete comment')
+ end
+
+ it 'shows Edit and Delete buttons if editable and current users comment' do
+ render 'projects/notes/more_actions_dropdown', current_user: author_user, note_editable: true, note: note
+
+ expect(rendered).to have_button('Edit comment')
+ expect(rendered).to have_link('Delete comment')
+ end
+end