summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/notes/components/diff_discussion_header_spec.js141
-rw-r--r--spec/frontend/releases/detail/components/app_spec.js19
-rw-r--r--spec/frontend/repository/pages/index_spec.js42
-rw-r--r--spec/frontend/repository/pages/tree_spec.js60
-rw-r--r--spec/frontend/repository/utils/dom_spec.js20
-rw-r--r--spec/frontend/repository/utils/title_spec.js4
-rw-r--r--spec/helpers/application_settings_helper_spec.rb1
-rw-r--r--spec/helpers/releases_helper_spec.rb14
-rw-r--r--spec/javascripts/frequent_items/components/app_spec.js2
-rw-r--r--spec/javascripts/frequent_items/mock_data.js4
-rw-r--r--spec/javascripts/frequent_items/store/actions_spec.js7
-rw-r--r--spec/javascripts/notes/components/noteable_discussion_spec.js114
-rw-r--r--spec/javascripts/vue_shared/components/project_selector/project_selector_spec.js9
-rw-r--r--spec/migrations/move_limits_from_plans_spec.rb37
-rw-r--r--spec/models/application_setting_spec.rb16
-rw-r--r--spec/requests/api/settings_spec.rb48
-rw-r--r--spec/services/issues/update_service_spec.rb18
17 files changed, 371 insertions, 185 deletions
diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js
new file mode 100644
index 00000000000..f90147f9105
--- /dev/null
+++ b/spec/frontend/notes/components/diff_discussion_header_spec.js
@@ -0,0 +1,141 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+
+import createStore from '~/notes/stores';
+import diffDiscussionHeader from '~/notes/components/diff_discussion_header.vue';
+
+import { discussionMock } from '../../../javascripts/notes/mock_data';
+import mockDiffFile from '../../diffs/mock_data/diff_discussions';
+
+const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json';
+
+describe('diff_discussion_header component', () => {
+ let store;
+ let wrapper;
+
+ preloadFixtures(discussionWithTwoUnresolvedNotes);
+
+ beforeEach(() => {
+ window.mrTabs = {};
+ store = createStore();
+
+ const localVue = createLocalVue();
+ wrapper = mount(diffDiscussionHeader, {
+ store,
+ propsData: { discussion: discussionMock },
+ localVue,
+ sync: false,
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render user avatar', () => {
+ const discussion = { ...discussionMock };
+ discussion.diff_file = mockDiffFile;
+ discussion.diff_discussion = true;
+
+ wrapper.setProps({ discussion });
+
+ expect(wrapper.find('.user-avatar-link').exists()).toBe(true);
+ });
+
+ describe('action text', () => {
+ const commitId = 'razupaltuff';
+ const truncatedCommitId = commitId.substr(0, 8);
+ let commitElement;
+
+ beforeEach(done => {
+ store.state.diffs = {
+ projectPath: 'something',
+ };
+
+ wrapper.setProps({
+ discussion: {
+ ...discussionMock,
+ for_commit: true,
+ commit_id: commitId,
+ diff_discussion: true,
+ diff_file: {
+ ...mockDiffFile,
+ },
+ },
+ });
+
+ wrapper.vm
+ .$nextTick()
+ .then(() => {
+ commitElement = wrapper.find('.commit-sha');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('for diff threads without a commit id', () => {
+ it('should show started a thread on the diff text', done => {
+ Object.assign(wrapper.vm.discussion, {
+ for_commit: false,
+ commit_id: null,
+ });
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.text()).toContain('started a thread on the diff');
+
+ done();
+ });
+ });
+
+ it('should show thread on older version text', done => {
+ Object.assign(wrapper.vm.discussion, {
+ for_commit: false,
+ commit_id: null,
+ active: false,
+ });
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.text()).toContain('started a thread on an old version of the diff');
+
+ done();
+ });
+ });
+ });
+
+ describe('for commit threads', () => {
+ it('should display a monospace started a thread on commit', () => {
+ expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
+ expect(commitElement.exists()).toBe(true);
+ expect(commitElement.text()).toContain(truncatedCommitId);
+ });
+ });
+
+ describe('for diff thread with a commit id', () => {
+ it('should display started thread on commit header', done => {
+ wrapper.vm.discussion.for_commit = false;
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
+
+ expect(commitElement).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('should display outdated change on commit header', done => {
+ wrapper.vm.discussion.for_commit = false;
+ wrapper.vm.discussion.active = false;
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.text()).toContain(
+ `started a thread on an outdated change in commit ${truncatedCommitId}`,
+ );
+
+ expect(commitElement).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/releases/detail/components/app_spec.js b/spec/frontend/releases/detail/components/app_spec.js
index f8eb33a69a8..4726f18c8fa 100644
--- a/spec/frontend/releases/detail/components/app_spec.js
+++ b/spec/frontend/releases/detail/components/app_spec.js
@@ -8,15 +8,17 @@ describe('Release detail component', () => {
let wrapper;
let releaseClone;
let actions;
+ let state;
beforeEach(() => {
gon.api_version = 'v4';
releaseClone = JSON.parse(JSON.stringify(convertObjectPropsToCamelCase(release)));
- const state = {
+ state = {
release: releaseClone,
markdownDocsPath: 'path/to/markdown/docs',
+ updateReleaseApiDocsPath: 'path/to/update/release/api/docs',
};
actions = {
@@ -46,6 +48,21 @@ describe('Release detail component', () => {
expect(wrapper.find('#git-ref').element.value).toBe(releaseClone.tagName);
});
+ it('renders the correct help text under the "Tag name" field', () => {
+ const helperText = wrapper.find('#tag-name-help');
+ const helperTextLink = helperText.find('a');
+ const helperTextLinkAttrs = helperTextLink.attributes();
+
+ expect(helperText.text()).toBe(
+ 'Changing a Release tag is only supported via Releases API. More information',
+ );
+ expect(helperTextLink.text()).toBe('More information');
+ expect(helperTextLinkAttrs.href).toBe(state.updateReleaseApiDocsPath);
+ expect(helperTextLinkAttrs.rel).toContain('noopener');
+ expect(helperTextLinkAttrs.rel).toContain('noreferrer');
+ expect(helperTextLinkAttrs.target).toBe('_blank');
+ });
+
it('renders the correct release title in the "Release title" field', () => {
expect(wrapper.find('#release-title').element.value).toBe(releaseClone.name);
});
diff --git a/spec/frontend/repository/pages/index_spec.js b/spec/frontend/repository/pages/index_spec.js
new file mode 100644
index 00000000000..c0afb7931b1
--- /dev/null
+++ b/spec/frontend/repository/pages/index_spec.js
@@ -0,0 +1,42 @@
+import { shallowMount } from '@vue/test-utils';
+import IndexPage from '~/repository/pages/index.vue';
+import TreePage from '~/repository/pages/tree.vue';
+import { updateElementsVisibility } from '~/repository/utils/dom';
+
+jest.mock('~/repository/utils/dom');
+
+describe('Repository index page component', () => {
+ let wrapper;
+
+ function factory() {
+ wrapper = shallowMount(IndexPage);
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+
+ updateElementsVisibility.mockClear();
+ });
+
+ it('calls updateElementsVisibility on mounted', () => {
+ factory();
+
+ expect(updateElementsVisibility).toHaveBeenCalledWith('.js-show-on-project-root', true);
+ });
+
+ it('calls updateElementsVisibility after destroy', () => {
+ factory();
+ wrapper.destroy();
+
+ expect(updateElementsVisibility.mock.calls.pop()).toEqual(['.js-show-on-project-root', false]);
+ });
+
+ it('renders TreePage', () => {
+ factory();
+
+ const child = wrapper.find(TreePage);
+
+ expect(child.exists()).toBe(true);
+ expect(child.props()).toEqual({ path: '/' });
+ });
+});
diff --git a/spec/frontend/repository/pages/tree_spec.js b/spec/frontend/repository/pages/tree_spec.js
new file mode 100644
index 00000000000..36662696c91
--- /dev/null
+++ b/spec/frontend/repository/pages/tree_spec.js
@@ -0,0 +1,60 @@
+import { shallowMount } from '@vue/test-utils';
+import TreePage from '~/repository/pages/tree.vue';
+import { updateElementsVisibility } from '~/repository/utils/dom';
+
+jest.mock('~/repository/utils/dom');
+
+describe('Repository tree page component', () => {
+ let wrapper;
+
+ function factory(path) {
+ wrapper = shallowMount(TreePage, { propsData: { path } });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+
+ updateElementsVisibility.mockClear();
+ });
+
+ describe('when root path', () => {
+ beforeEach(() => {
+ factory('/');
+ });
+
+ it('shows root elements', () => {
+ expect(updateElementsVisibility.mock.calls).toEqual([
+ ['.js-show-on-root', true],
+ ['.js-hide-on-root', false],
+ ]);
+ });
+
+ describe('when changed', () => {
+ beforeEach(() => {
+ updateElementsVisibility.mockClear();
+
+ wrapper.setProps({ path: '/test' });
+ });
+
+ it('hides root elements', () => {
+ expect(updateElementsVisibility.mock.calls).toEqual([
+ ['.js-show-on-root', false],
+ ['.js-hide-on-root', true],
+ ]);
+ });
+ });
+ });
+
+ describe('when non-root path', () => {
+ beforeEach(() => {
+ factory('/test');
+ });
+
+ it('hides root elements', () => {
+ expect(updateElementsVisibility.mock.calls).toEqual([
+ ['.js-show-on-root', false],
+ ['.js-hide-on-root', true],
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/repository/utils/dom_spec.js b/spec/frontend/repository/utils/dom_spec.js
new file mode 100644
index 00000000000..678d444904d
--- /dev/null
+++ b/spec/frontend/repository/utils/dom_spec.js
@@ -0,0 +1,20 @@
+import { setHTMLFixture } from '../../helpers/fixtures';
+import { updateElementsVisibility } from '~/repository/utils/dom';
+
+describe('updateElementsVisibility', () => {
+ it('adds hidden class', () => {
+ setHTMLFixture('<div class="js-test"></div>');
+
+ updateElementsVisibility('.js-test', false);
+
+ expect(document.querySelector('.js-test').classList).toContain('hidden');
+ });
+
+ it('removes hidden class', () => {
+ setHTMLFixture('<div class="hidden js-test"></div>');
+
+ updateElementsVisibility('.js-test', true);
+
+ expect(document.querySelector('.js-test').classList).not.toContain('hidden');
+ });
+});
diff --git a/spec/frontend/repository/utils/title_spec.js b/spec/frontend/repository/utils/title_spec.js
index c4879716fd7..63035933424 100644
--- a/spec/frontend/repository/utils/title_spec.js
+++ b/spec/frontend/repository/utils/title_spec.js
@@ -8,8 +8,8 @@ describe('setTitle', () => {
${'app/assets'} | ${'app/assets'}
${'app/assets/javascripts'} | ${'app/assets/javascripts'}
`('sets document title as $title for $path', ({ path, title }) => {
- setTitle(path, 'master', 'GitLab');
+ setTitle(path, 'master', 'GitLab Org / GitLab');
- expect(document.title).toEqual(`${title} · master · GitLab`);
+ expect(document.title).toEqual(`${title} · master · GitLab Org / GitLab · GitLab`);
});
});
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index a5e8370a715..8303c4eafbe 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -39,7 +39,6 @@ describe ApplicationSettingsHelper do
context 'with tracking parameters' do
it { expect(visible_attributes).to include(*%i(snowplow_collector_hostname snowplow_cookie_domain snowplow_enabled snowplow_app_id)) }
- it { expect(visible_attributes).to include(*%i(pendo_enabled pendo_url)) }
end
describe '.integration_expanded?' do
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
index 3b4973677ef..3f56c189642 100644
--- a/spec/helpers/releases_helper_spec.rb
+++ b/spec/helpers/releases_helper_spec.rb
@@ -17,9 +17,11 @@ describe ReleasesHelper do
context 'url helpers' do
let(:project) { build(:project, namespace: create(:group)) }
+ let(:release) { create(:release, project: project) }
before do
helper.instance_variable_set(:@project, project)
+ helper.instance_variable_set(:@release, release)
end
describe '#data_for_releases_page' do
@@ -28,5 +30,17 @@ describe ReleasesHelper do
expect(helper.data_for_releases_page.keys).to eq(keys)
end
end
+
+ describe '#data_for_edit_release_page' do
+ it 'has the needed data to display the "edit release" page' do
+ keys = %i(project_id
+ tag_name
+ markdown_preview_path
+ markdown_docs_path
+ releases_page_path
+ update_release_api_docs_path)
+ expect(helper.data_for_edit_release_page.keys).to eq(keys)
+ end
+ end
end
end
diff --git a/spec/javascripts/frequent_items/components/app_spec.js b/spec/javascripts/frequent_items/components/app_spec.js
index 36dd8604d08..da0427d650a 100644
--- a/spec/javascripts/frequent_items/components/app_spec.js
+++ b/spec/javascripts/frequent_items/components/app_spec.js
@@ -247,7 +247,7 @@ describe('Frequent Items App Component', () => {
.then(() => {
expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(
- mockSearchedProjects.length,
+ mockSearchedProjects.data.length,
);
})
.then(done)
diff --git a/spec/javascripts/frequent_items/mock_data.js b/spec/javascripts/frequent_items/mock_data.js
index 3ca5b4c7446..7f7d7b1cdbf 100644
--- a/spec/javascripts/frequent_items/mock_data.js
+++ b/spec/javascripts/frequent_items/mock_data.js
@@ -68,7 +68,7 @@ export const mockFrequentGroups = [
},
];
-export const mockSearchedGroups = [mockRawGroup];
+export const mockSearchedGroups = { data: [mockRawGroup] };
export const mockProcessedSearchedGroups = [mockGroup];
export const mockProject = {
@@ -135,7 +135,7 @@ export const mockFrequentProjects = [
},
];
-export const mockSearchedProjects = [mockRawProject];
+export const mockSearchedProjects = { data: [mockRawProject] };
export const mockProcessedSearchedProjects = [mockProject];
export const unsortedFrequentItems = [
diff --git a/spec/javascripts/frequent_items/store/actions_spec.js b/spec/javascripts/frequent_items/store/actions_spec.js
index 0a8525e77d6..7b065b69cce 100644
--- a/spec/javascripts/frequent_items/store/actions_spec.js
+++ b/spec/javascripts/frequent_items/store/actions_spec.js
@@ -169,7 +169,7 @@ describe('Frequent Items Dropdown Store Actions', () => {
});
it('should dispatch `receiveSearchedItemsSuccess`', done => {
- mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects);
+ mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects, {});
testAction(
actions.fetchSearchedItems,
@@ -178,7 +178,10 @@ describe('Frequent Items Dropdown Store Actions', () => {
[],
[
{ type: 'requestSearchedItems' },
- { type: 'receiveSearchedItemsSuccess', payload: mockSearchedProjects },
+ {
+ type: 'receiveSearchedItemsSuccess',
+ payload: { data: mockSearchedProjects, headers: {} },
+ },
],
done,
);
diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js
index ea5c57b8a7c..ea1ed3da112 100644
--- a/spec/javascripts/notes/components/noteable_discussion_spec.js
+++ b/spec/javascripts/notes/components/noteable_discussion_spec.js
@@ -1,4 +1,4 @@
-import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { mount, createLocalVue } from '@vue/test-utils';
import createStore from '~/notes/stores';
import noteableDiscussion from '~/notes/components/noteable_discussion.vue';
import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
@@ -23,7 +23,7 @@ describe('noteable_discussion component', () => {
store.dispatch('setNotesData', notesDataMock);
const localVue = createLocalVue();
- wrapper = shallowMount(noteableDiscussion, {
+ wrapper = mount(noteableDiscussion, {
store,
propsData: { discussion: discussionMock },
localVue,
@@ -35,16 +35,6 @@ describe('noteable_discussion component', () => {
wrapper.destroy();
});
- it('should render user avatar', () => {
- const discussion = { ...discussionMock };
- discussion.diff_file = mockDiffFile;
- discussion.diff_discussion = true;
-
- wrapper.setProps({ discussion, renderDiffFile: true });
-
- expect(wrapper.find('.user-avatar-link').exists()).toBe(true);
- });
-
it('should not render thread header for non diff threads', () => {
expect(wrapper.find('.discussion-header').exists()).toBe(false);
});
@@ -134,105 +124,6 @@ describe('noteable_discussion component', () => {
});
});
- describe('action text', () => {
- const commitId = 'razupaltuff';
- const truncatedCommitId = commitId.substr(0, 8);
- let commitElement;
-
- beforeEach(done => {
- store.state.diffs = {
- projectPath: 'something',
- };
-
- wrapper.setProps({
- discussion: {
- ...discussionMock,
- for_commit: true,
- commit_id: commitId,
- diff_discussion: true,
- diff_file: {
- ...mockDiffFile,
- },
- },
- renderDiffFile: true,
- });
-
- wrapper.vm
- .$nextTick()
- .then(() => {
- commitElement = wrapper.find('.commit-sha');
- })
- .then(done)
- .catch(done.fail);
- });
-
- describe('for commit threads', () => {
- it('should display a monospace started a thread on commit', () => {
- expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
- expect(commitElement.exists()).toBe(true);
- expect(commitElement.text()).toContain(truncatedCommitId);
- });
- });
-
- describe('for diff thread with a commit id', () => {
- it('should display started thread on commit header', done => {
- wrapper.vm.discussion.for_commit = false;
-
- wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
-
- expect(commitElement).not.toBe(null);
-
- done();
- });
- });
-
- it('should display outdated change on commit header', done => {
- wrapper.vm.discussion.for_commit = false;
- wrapper.vm.discussion.active = false;
-
- wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain(
- `started a thread on an outdated change in commit ${truncatedCommitId}`,
- );
-
- expect(commitElement).not.toBe(null);
-
- done();
- });
- });
- });
-
- describe('for diff threads without a commit id', () => {
- it('should show started a thread on the diff text', done => {
- Object.assign(wrapper.vm.discussion, {
- for_commit: false,
- commit_id: null,
- });
-
- wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain('started a thread on the diff');
-
- done();
- });
- });
-
- it('should show thread on older version text', done => {
- Object.assign(wrapper.vm.discussion, {
- for_commit: false,
- commit_id: null,
- active: false,
- });
-
- wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain('started a thread on an old version of the diff');
-
- done();
- });
- });
- });
- });
-
describe('for resolved thread', () => {
beforeEach(() => {
const discussion = getJSONFixture(discussionWithTwoUnresolvedNotes)[0];
@@ -262,6 +153,7 @@ describe('noteable_discussion component', () => {
}));
wrapper.setProps({ discussion });
+
wrapper.vm
.$nextTick()
.then(done)
diff --git a/spec/javascripts/vue_shared/components/project_selector/project_selector_spec.js b/spec/javascripts/vue_shared/components/project_selector/project_selector_spec.js
index 9c2deca585b..323a0f03017 100644
--- a/spec/javascripts/vue_shared/components/project_selector/project_selector_spec.js
+++ b/spec/javascripts/vue_shared/components/project_selector/project_selector_spec.js
@@ -3,7 +3,7 @@ import _ from 'underscore';
import ProjectSelector from '~/vue_shared/components/project_selector/project_selector.vue';
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
-import { GlSearchBoxByType } from '@gitlab/ui';
+import { GlSearchBoxByType, GlInfiniteScroll } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import { trimText } from 'spec/helpers/text_helper';
@@ -91,6 +91,13 @@ describe('ProjectSelector component', () => {
expect(searchInput.attributes('placeholder')).toBe('Search your projects');
});
+ it(`triggers a "bottomReached" event when user has scrolled to the bottom of the list`, () => {
+ spyOn(vm, '$emit');
+ wrapper.find(GlInfiniteScroll).vm.$emit('bottomReached');
+
+ expect(vm.$emit).toHaveBeenCalledWith('bottomReached');
+ });
+
it(`triggers a "projectClicked" event when a project is clicked`, () => {
spyOn(vm, '$emit');
wrapper.find(ProjectListItem).vm.$emit('click', _.first(searchResults));
diff --git a/spec/migrations/move_limits_from_plans_spec.rb b/spec/migrations/move_limits_from_plans_spec.rb
new file mode 100644
index 00000000000..693d6ecb2c1
--- /dev/null
+++ b/spec/migrations/move_limits_from_plans_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20191030152934_move_limits_from_plans.rb')
+
+describe MoveLimitsFromPlans, :migration do
+ let(:plans) { table(:plans) }
+ let(:plan_limits) { table(:plan_limits) }
+
+ let!(:early_adopter_plan) { plans.create(name: 'early_adopter', title: 'Early adopter', active_pipelines_limit: 10, pipeline_size_limit: 11, active_jobs_limit: 12) }
+ let!(:gold_plan) { plans.create(name: 'gold', title: 'Gold', active_pipelines_limit: 20, pipeline_size_limit: 21, active_jobs_limit: 22) }
+ let!(:silver_plan) { plans.create(name: 'silver', title: 'Silver', active_pipelines_limit: 30, pipeline_size_limit: 31, active_jobs_limit: 32) }
+ let!(:bronze_plan) { plans.create(name: 'bronze', title: 'Bronze', active_pipelines_limit: 40, pipeline_size_limit: 41, active_jobs_limit: 42) }
+ let!(:free_plan) { plans.create(name: 'free', title: 'Free', active_pipelines_limit: 50, pipeline_size_limit: 51, active_jobs_limit: 52) }
+ let!(:other_plan) { plans.create(name: 'other', title: 'Other', active_pipelines_limit: nil, pipeline_size_limit: nil, active_jobs_limit: 0) }
+
+ describe 'migrate' do
+ it 'populates plan_limits from all the records in plans' do
+ expect { migrate! }.to change { plan_limits.count }.by 6
+ end
+
+ it 'copies plan limits and plan.id into to plan_limits table' do
+ migrate!
+
+ new_data = plan_limits.pluck(:plan_id, :ci_active_pipelines, :ci_pipeline_size, :ci_active_jobs)
+ expected_data = [
+ [early_adopter_plan.id, 10, 11, 12],
+ [gold_plan.id, 20, 21, 22],
+ [silver_plan.id, 30, 31, 32],
+ [bronze_plan.id, 40, 41, 42],
+ [free_plan.id, 50, 51, 52],
+ [other_plan.id, 0, 0, 0]
+ ]
+ expect(new_data).to contain_exactly(*expected_data)
+ end
+ end
+end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 9d3f5b4b132..4aa8f2d959d 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -82,22 +82,6 @@ describe ApplicationSetting do
it { is_expected.to allow_value(nil).for(:snowplow_iglu_registry_url) }
end
- context 'when pendo is enabled' do
- before do
- setting.pendo_enabled = true
- end
-
- it { is_expected.not_to allow_value(nil).for(:pendo_url) }
- it { is_expected.to allow_value(http).for(:pendo_url) }
- it { is_expected.to allow_value(https).for(:pendo_url) }
- it { is_expected.not_to allow_value(ftp).for(:pendo_url) }
- it { is_expected.not_to allow_value('http://127.0.0.1').for(:pendo_url) }
- end
-
- context 'when pendo is not enabled' do
- it { is_expected.to allow_value(nil).for(:pendo_url) }
- end
-
context "when user accepted let's encrypt terms of service" do
before do
setting.update(lets_encrypt_terms_of_service_accepted: true)
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 1b58fb1dab1..c50cb4a5927 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -223,54 +223,6 @@ describe API::Settings, 'Settings' do
end
end
- context "pendo tracking settings" do
- let(:settings) do
- {
- pendo_url: "https://pendo.example.com",
- pendo_enabled: true
- }
- end
-
- let(:attribute_names) { settings.keys.map(&:to_s) }
-
- it "includes the attributes in the API" do
- get api("/application/settings", admin)
-
- expect(response).to have_gitlab_http_status(200)
- attribute_names.each do |attribute|
- expect(json_response.keys).to include(attribute)
- end
- end
-
- it "allows updating the settings" do
- put api("/application/settings", admin), params: settings
-
- expect(response).to have_gitlab_http_status(200)
- settings.each do |attribute, value|
- expect(ApplicationSetting.current.public_send(attribute)).to eq(value)
- end
- end
-
- context "missing pendo_url value when pendo_enabled is true" do
- it "returns a blank parameter error message" do
- put api("/application/settings", admin), params: { pendo_enabled: true }
-
- expect(response).to have_gitlab_http_status(400)
- expect(json_response["error"]).to eq("pendo_url is missing")
- end
-
- it "handles validation errors" do
- put api("/application/settings", admin), params: settings.merge({
- pendo_url: nil
- })
-
- expect(response).to have_gitlab_http_status(400)
- message = json_response["message"]
- expect(message["pendo_url"]).to include("can't be blank")
- end
- end
- end
-
context 'EKS integration settings' do
let(:attribute_names) { settings.keys.map(&:to_s) }
let(:sensitive_attributes) { %w(eks_secret_access_key) }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 21e308e6636..604befd7225 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -606,6 +606,24 @@ describe Issues::UpdateService, :mailer do
end
end
+ context 'when same id is passed as add_label_ids and remove_label_ids' do
+ let(:params) { { add_label_ids: [label.id], remove_label_ids: [label.id] } }
+
+ context 'for a label assigned to an issue' do
+ it 'removes the label' do
+ issue.update(labels: [label])
+
+ expect(result.label_ids).to be_empty
+ end
+ end
+
+ context 'for a label not assigned to an issue' do
+ it 'does not add the label' do
+ expect(result.label_ids).to be_empty
+ end
+ end
+ end
+
context 'when duplicate label titles are given' do
let(:params) do
{ labels: [label3.title, label3.title] }