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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-09-24 00:06:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-09-24 00:06:29 +0300
commitb9254657872c4db441ab268154686f5476fb4bc6 (patch)
treeab045c623296a049d1246ba2d66800456a1077aa /spec
parentc792263edfaf826c58f4aa41d26904464a17a3e7 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/boards/lists_controller_spec.rb4
-rw-r--r--spec/frontend/ide/components/error_message_spec.js122
-rw-r--r--spec/frontend/lib/utils/datetime_utility_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/recaptcha_eventhub_spec.js21
-rw-r--r--spec/frontend/vue_shared/components/recaptcha_modal_spec.js36
-rw-r--r--spec/javascripts/ide/components/error_message_spec.js106
-rw-r--r--spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js14
-rw-r--r--spec/routing/project_routing_spec.rb5
-rw-r--r--spec/services/boards/lists/update_service_spec.rb66
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb4
10 files changed, 241 insertions, 151 deletions
diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb
index 802fc1770a4..77b5872fcb3 100644
--- a/spec/controllers/boards/lists_controller_spec.rb
+++ b/spec/controllers/boards/lists_controller_spec.rb
@@ -162,10 +162,10 @@ describe Boards::ListsController do
end
context 'with unauthorized user' do
- it 'returns a forbidden 403 response' do
+ it 'returns a 422 unprocessable entity response' do
move user: guest, board: board, list: planning, position: 6
- expect(response).to have_gitlab_http_status(403)
+ expect(response).to have_gitlab_http_status(422)
end
end
diff --git a/spec/frontend/ide/components/error_message_spec.js b/spec/frontend/ide/components/error_message_spec.js
new file mode 100644
index 00000000000..fd6d1a494d4
--- /dev/null
+++ b/spec/frontend/ide/components/error_message_spec.js
@@ -0,0 +1,122 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlLoadingIcon } from '@gitlab/ui';
+import ErrorMessage from '~/ide/components/error_message.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('IDE error message component', () => {
+ let wrapper;
+
+ const setErrorMessageMock = jest.fn();
+ const createComponent = messageProps => {
+ const fakeStore = new Vuex.Store({
+ actions: { setErrorMessage: setErrorMessageMock },
+ });
+
+ wrapper = shallowMount(ErrorMessage, {
+ propsData: {
+ message: {
+ text: 'some text',
+ actionText: 'test action',
+ actionPayload: 'testActionPayload',
+ ...messageProps,
+ },
+ },
+ store: fakeStore,
+ localVue,
+ sync: false,
+ });
+ };
+
+ beforeEach(() => {
+ setErrorMessageMock.mockReset();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('renders error message', () => {
+ const text = 'error message';
+ createComponent({ text });
+ expect(wrapper.text()).toContain(text);
+ });
+
+ it('clears error message on click', () => {
+ createComponent();
+ wrapper.trigger('click');
+
+ expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null, undefined);
+ });
+
+ describe('with action', () => {
+ let actionMock;
+
+ const message = {
+ actionText: 'test action',
+ actionPayload: 'testActionPayload',
+ };
+
+ beforeEach(() => {
+ actionMock = jest.fn().mockResolvedValue();
+ createComponent({
+ ...message,
+ action: actionMock,
+ });
+ });
+
+ it('renders action button', () => {
+ const button = wrapper.find('button');
+
+ expect(button.exists()).toBe(true);
+ expect(button.text()).toContain(message.actionText);
+ });
+
+ it('does not clear error message on click', () => {
+ wrapper.trigger('click');
+
+ expect(setErrorMessageMock).not.toHaveBeenCalled();
+ });
+
+ it('dispatches action', () => {
+ wrapper.find('button').trigger('click');
+
+ expect(actionMock).toHaveBeenCalledWith(message.actionPayload);
+ });
+
+ it('does not dispatch action when already loading', () => {
+ wrapper.find('button').trigger('click');
+ actionMock.mockReset();
+ wrapper.find('button').trigger('click');
+ expect(actionMock).not.toHaveBeenCalled();
+ });
+
+ it('shows loading icon when loading', () => {
+ let resolve;
+ actionMock.mockImplementation(
+ () =>
+ new Promise(ok => {
+ resolve = ok;
+ }),
+ );
+ wrapper.find('button').trigger('click');
+
+ return wrapper.vm.$nextTick(() => {
+ expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
+ resolve();
+ });
+ });
+
+ it('hides loading icon when operation finishes', () => {
+ wrapper.find('button').trigger('click');
+ return actionMock()
+ .then(() => wrapper.vm.$nextTick())
+ .then(() => {
+ expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js
index 9f1700bb243..8cbf170b3e6 100644
--- a/spec/frontend/lib/utils/datetime_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime_utility_spec.js
@@ -388,20 +388,6 @@ describe('prettyTime methods', () => {
expect(datetimeUtility.stringifyTime(timeObject, true)).toEqual('1 week 1 hour');
});
});
-
- describe('abbreviateTime', () => {
- it('should abbreviate stringified times for weeks', () => {
- const fullTimeString = '1w 3d 4h 5m';
-
- expect(datetimeUtility.abbreviateTime(fullTimeString)).toBe('1w');
- });
-
- it('should abbreviate stringified times for non-weeks', () => {
- const fullTimeString = '0w 3d 4h 5m';
-
- expect(datetimeUtility.abbreviateTime(fullTimeString)).toBe('3d');
- });
- });
});
describe('calculateRemainingMilliseconds', () => {
diff --git a/spec/frontend/vue_shared/components/recaptcha_eventhub_spec.js b/spec/frontend/vue_shared/components/recaptcha_eventhub_spec.js
new file mode 100644
index 00000000000..d86d627886f
--- /dev/null
+++ b/spec/frontend/vue_shared/components/recaptcha_eventhub_spec.js
@@ -0,0 +1,21 @@
+import { eventHub, callbackName } from '~/vue_shared/components/recaptcha_eventhub';
+
+describe('reCAPTCHA event hub', () => {
+ // the following test case currently crashes
+ // see https://gitlab.com/gitlab-org/gitlab/issues/29192#note_217840035
+ // eslint-disable-next-line jest/no-disabled-tests
+ it.skip('throws an error for overriding the callback', () => {
+ expect(() => {
+ window[callbackName] = 'something';
+ }).toThrow();
+ });
+
+ it('triggering callback emits a submit event', () => {
+ const eventHandler = jest.fn();
+ eventHub.$once('submit', eventHandler);
+
+ window[callbackName]();
+
+ expect(eventHandler).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/recaptcha_modal_spec.js b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
new file mode 100644
index 00000000000..e509fe09d94
--- /dev/null
+++ b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
@@ -0,0 +1,36 @@
+import { shallowMount } from '@vue/test-utils';
+
+import { eventHub } from '~/vue_shared/components/recaptcha_eventhub';
+
+import RecaptchaModal from '~/vue_shared/components/recaptcha_modal';
+
+describe('RecaptchaModal', () => {
+ const recaptchaFormId = 'recaptcha-form';
+ const recaptchaHtml = `<form id="${recaptchaFormId}"></form>`;
+
+ let wrapper;
+
+ const findRecaptchaForm = () => wrapper.find(`#${recaptchaFormId}`).element;
+
+ beforeEach(() => {
+ wrapper = shallowMount(RecaptchaModal, {
+ sync: false,
+ propsData: {
+ html: recaptchaHtml,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('submits the form if event hub emits submit event', () => {
+ const form = findRecaptchaForm();
+ jest.spyOn(form, 'submit').mockImplementation();
+
+ eventHub.$emit('submit');
+
+ expect(form.submit).toHaveBeenCalled();
+ });
+});
diff --git a/spec/javascripts/ide/components/error_message_spec.js b/spec/javascripts/ide/components/error_message_spec.js
deleted file mode 100644
index 80d6c7fd564..00000000000
--- a/spec/javascripts/ide/components/error_message_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import Vue from 'vue';
-import store from '~/ide/stores';
-import ErrorMessage from '~/ide/components/error_message.vue';
-import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
-import { resetStore } from '../helpers';
-
-describe('IDE error message component', () => {
- const Component = Vue.extend(ErrorMessage);
- let vm;
-
- beforeEach(() => {
- vm = createComponentWithStore(Component, store, {
- message: {
- text: 'error message',
- action: null,
- actionText: null,
- },
- }).$mount();
- });
-
- afterEach(() => {
- vm.$destroy();
- resetStore(vm.$store);
- });
-
- it('renders error message', () => {
- expect(vm.$el.textContent).toContain('error message');
- });
-
- it('clears error message on click', () => {
- spyOn(vm, 'setErrorMessage');
-
- vm.$el.click();
-
- expect(vm.setErrorMessage).toHaveBeenCalledWith(null);
- });
-
- describe('with action', () => {
- let actionSpy;
-
- beforeEach(done => {
- actionSpy = jasmine.createSpy('action').and.returnValue(Promise.resolve());
-
- vm.message.action = actionSpy;
- vm.message.actionText = 'test action';
- vm.message.actionPayload = 'testActionPayload';
-
- vm.$nextTick(done);
- });
-
- it('renders action button', () => {
- expect(vm.$el.querySelector('.flash-action')).not.toBe(null);
- expect(vm.$el.textContent).toContain('test action');
- });
-
- it('does not clear error message on click', () => {
- spyOn(vm, 'setErrorMessage');
-
- vm.$el.click();
-
- expect(vm.setErrorMessage).not.toHaveBeenCalled();
- });
-
- it('dispatches action', done => {
- vm.$el.querySelector('.flash-action').click();
-
- vm.$nextTick(() => {
- expect(actionSpy).toHaveBeenCalledWith('testActionPayload');
-
- done();
- });
- });
-
- it('does not dispatch action when already loading', () => {
- vm.isLoading = true;
-
- vm.$el.querySelector('.flash-action').click();
-
- expect(actionSpy).not.toHaveBeenCalledWith();
- });
-
- it('resets isLoading after click', done => {
- vm.$el.querySelector('.flash-action').click();
-
- expect(vm.isLoading).toBe(true);
-
- setTimeout(() => {
- expect(vm.isLoading).toBe(false);
-
- done();
- });
- });
-
- it('shows loading icon when isLoading is true', done => {
- expect(vm.$el.querySelector('.loading-container').style.display).not.toBe('');
-
- vm.isLoading = true;
-
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.loading-container').style.display).toBe('');
-
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
index 2e1863cff86..ab28190ae64 100644
--- a/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
+++ b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
@@ -83,8 +83,8 @@ describe('Issuable Time Tracker', () => {
initTimeTrackingComponent({
timeEstimate: 100000, // 1d 3h
timeSpent: 5000, // 1h 23m
- timeEstimateHumanReadable: '',
- timeSpentHumanReadable: '',
+ timeEstimateHumanReadable: '1d 3h',
+ timeSpentHumanReadable: '1h 23m',
});
});
@@ -98,6 +98,16 @@ describe('Issuable Time Tracker', () => {
});
});
+ it('should show full times when the sidebar is collapsed', done => {
+ Vue.nextTick(() => {
+ const timeTrackingText = vm.$el.querySelector('.time-tracking-collapsed-summary span')
+ .innerText;
+
+ expect(timeTrackingText).toBe('1h 23m / 1d 3h');
+ done();
+ });
+ });
+
describe('Remaining meter', () => {
it('should display the remaining meter with the correct width', done => {
Vue.nextTick(() => {
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 7e2d70d6eb5..acdbf064a73 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -276,6 +276,11 @@ describe 'project routing' do
expect(get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45', path: 'foo/bar/baz')
expect(get('/gitlab/gitlabhq/refs/feature@45/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45', path: 'foo/bar/baz')
expect(get('/gitlab/gitlabhq/refs/stable/logs_tree/files.scss')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'stable', path: 'files.scss')
+ assert_routing({ path: "/gitlab/gitlabhq/refs/stable/logs_tree/new%0A%0Aline.txt",
+ method: :get },
+ { controller: 'projects/refs', action: 'logs_tree',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "stable", path: "new\n\nline.txt" })
end
end
diff --git a/spec/services/boards/lists/update_service_spec.rb b/spec/services/boards/lists/update_service_spec.rb
index f28bbab941a..a5411a2fb3a 100644
--- a/spec/services/boards/lists/update_service_spec.rb
+++ b/spec/services/boards/lists/update_service_spec.rb
@@ -10,9 +10,8 @@ describe Boards::Lists::UpdateService do
context 'when user can admin list' do
it 'calls Lists::MoveService to update list position' do
board.parent.add_developer(user)
- service = described_class.new(board.parent, user, position: 1)
- expect(Boards::Lists::MoveService).to receive(:new).with(board.parent, user, { position: 1 }).and_call_original
+ expect(Boards::Lists::MoveService).to receive(:new).with(board.parent, user, params).and_call_original
expect_any_instance_of(Boards::Lists::MoveService).to receive(:execute).with(list)
service.execute(list)
@@ -21,8 +20,6 @@ describe Boards::Lists::UpdateService do
context 'when user cannot admin list' do
it 'does not call Lists::MoveService to update list position' do
- service = described_class.new(board.parent, user, position: 1)
-
expect(Boards::Lists::MoveService).not_to receive(:new)
service.execute(list)
@@ -34,7 +31,6 @@ describe Boards::Lists::UpdateService do
context 'when user can read list' do
it 'updates list preference for user' do
board.parent.add_guest(user)
- service = described_class.new(board.parent, user, collapsed: true)
service.execute(list)
@@ -44,8 +40,6 @@ describe Boards::Lists::UpdateService do
context 'when user cannot read list' do
it 'does not update list preference for user' do
- service = described_class.new(board.parent, user, collapsed: true)
-
service.execute(list)
expect(list.preferences_for(user).collapsed).to be_nil
@@ -54,35 +48,61 @@ describe Boards::Lists::UpdateService do
end
describe '#execute' do
+ let(:service) { described_class.new(board.parent, user, params) }
+
context 'when position parameter is present' do
+ let(:params) { { position: 1 } }
+
context 'for projects' do
- it_behaves_like 'moving list' do
- let(:project) { create(:project, :private) }
- let(:board) { create(:board, project: project) }
- end
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+
+ it_behaves_like 'moving list'
end
context 'for groups' do
- it_behaves_like 'moving list' do
- let(:group) { create(:group, :private) }
- let(:board) { create(:board, group: group) }
- end
+ let(:group) { create(:group, :private) }
+ let(:board) { create(:board, group: group) }
+
+ it_behaves_like 'moving list'
end
end
context 'when collapsed parameter is present' do
+ let(:params) { { collapsed: true } }
+
context 'for projects' do
- it_behaves_like 'updating list preferences' do
- let(:project) { create(:project, :private) }
- let(:board) { create(:board, project: project) }
- end
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+
+ it_behaves_like 'updating list preferences'
end
context 'for groups' do
- it_behaves_like 'updating list preferences' do
- let(:group) { create(:group, :private) }
- let(:board) { create(:board, group: group) }
- end
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+
+ it_behaves_like 'updating list preferences'
+ end
+ end
+
+ context 'when position and collapsed are both present' do
+ let(:params) { { collapsed: true, position: 1 } }
+
+ context 'for projects' do
+ let(:project) { create(:project, :private) }
+ let(:board) { create(:board, project: project) }
+
+ it_behaves_like 'moving list'
+ it_behaves_like 'updating list preferences'
+ end
+
+ context 'for groups' do
+ let(:group) { create(:group, :private) }
+ let(:board) { create(:board, group: group) }
+
+ it_behaves_like 'moving list'
+ it_behaves_like 'updating list preferences'
end
end
end
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
index 07c541ec189..f2f31e1b7f2 100644
--- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -11,10 +11,6 @@ shared_examples_for 'multiple issue boards' do
wait_for_requests
end
- it 'shows board switcher' do
- expect(page).to have_css('.boards-switcher')
- end
-
it 'shows current board name' do
page.within('.boards-switcher') do
expect(page).to have_content(board.name)