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>2020-12-03 00:09:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-03 00:09:44 +0300
commitf96f2720d1b21b76eadedc54fdea67cb70e98d94 (patch)
tree527d27d5ceb816969e315b6223b3ddb2ca128dae /spec
parentad05e1db038a2e983d25555144fa29063e060c50 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb25
-rw-r--r--spec/frontend/diffs/components/app_spec.js57
-rw-r--r--spec/frontend/diffs/components/settings_dropdown_spec.js95
-rw-r--r--spec/frontend/diffs/store/actions_spec.js17
-rw-r--r--spec/frontend/diffs/store/mutations_spec.js14
-rw-r--r--spec/frontend/diffs/utils/preferences_spec.js40
-rw-r--r--spec/frontend/pipeline_new/components/pipeline_new_form_spec.js125
-rw-r--r--spec/frontend/pipeline_new/mock_data.js16
-rw-r--r--spec/frontend/pipeline_new/utils/format_refs_spec.js21
-rw-r--r--spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap64
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js29
-rw-r--r--spec/frontend/registry/settings/components/settings_form_spec.js189
-rw-r--r--spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap8
-rw-r--r--spec/frontend/registry/shared/utils_spec.js5
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/custom_emoji_spec.rb9
-rw-r--r--spec/models/project_spec.rb28
-rw-r--r--spec/spec_helper.rb4
18 files changed, 596 insertions, 151 deletions
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index cb333bdb428..120c5b56e03 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -26,20 +26,20 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
subject
settings_block = find('#js-registry-policies')
- expect(settings_block).to have_text 'Cleanup policy for tags'
+ expect(settings_block).to have_text 'Clean up image tags'
end
it 'saves cleanup policy submit the form' do
subject
within '#js-registry-policies' do
- within '.gl-card-body' do
- select('7 days until tags are automatically removed', from: 'Expiration interval:')
- select('Every day', from: 'Expiration schedule:')
- select('50 tags per image name', from: 'Number of tags to retain:')
- fill_in('Tags with names matching this regex pattern will expire:', with: '.*-production')
- end
- submit_button = find('.gl-card-footer .btn.btn-success')
+ select('Every day', from: 'Run cleanup')
+ select('50 tags per image name', from: 'Keep the most recent:')
+ fill_in('Keep tags matching:', with: 'stable')
+ select('7 days', from: 'Remove tags older than:')
+ fill_in('Remove tags matching:', with: '.*-production')
+
+ submit_button = find('.btn.btn-success')
expect(submit_button).not_to be_disabled
submit_button.click
end
@@ -51,10 +51,9 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
subject
within '#js-registry-policies' do
- within '.gl-card-body' do
- fill_in('Tags with names matching this regex pattern will expire:', with: '*-production')
- end
- submit_button = find('.gl-card-footer .btn.btn-success')
+ fill_in('Remove tags matching:', with: '*-production')
+
+ submit_button = find('.btn.btn-success')
expect(submit_button).not_to be_disabled
submit_button.click
end
@@ -85,7 +84,7 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
within '#js-registry-policies' do
case result
when :available_section
- expect(find('.gl-card-header')).to have_content('Tag expiration policy')
+ expect(find('[data-testid="enable-toggle"]')).to have_content('Tags that match the rules on this page are automatically scheduled for deletion.')
when :disabled_message
expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled')
end
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index 01c789270da..416564b72c3 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -17,10 +17,14 @@ import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import diffsMockData from '../mock_data/merge_request_diffs';
+import { EVT_VIEW_FILE_BY_FILE } from '~/diffs/constants';
+
+import eventHub from '~/diffs/event_hub';
+
const mergeRequestDiff = { version_index: 1 };
const TEST_ENDPOINT = `${TEST_HOST}/diff/endpoint`;
-const COMMIT_URL = '[BASE URL]/OLD';
-const UPDATED_COMMIT_URL = '[BASE URL]/NEW';
+const COMMIT_URL = `${TEST_HOST}/COMMIT/OLD`;
+const UPDATED_COMMIT_URL = `${TEST_HOST}/COMMIT/NEW`;
function getCollapsedFilesWarning(wrapper) {
return wrapper.find(CollapsedFilesWarning);
@@ -61,7 +65,7 @@ describe('diffs/components/app', () => {
changesEmptyStateIllustration: '',
dismissEndpoint: '',
showSuggestPopover: true,
- viewDiffsFileByFile: false,
+ fileByFileUserPreference: false,
...props,
},
provide,
@@ -700,12 +704,14 @@ describe('diffs/components/app', () => {
});
describe('file-by-file', () => {
- it('renders a single diff', () => {
- createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ it('renders a single diff', async () => {
+ createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' });
state.diffs.diffFiles.push({ file_hash: '312' });
});
+ await wrapper.vm.$nextTick();
+
expect(wrapper.findAll(DiffFile).length).toBe(1);
});
@@ -713,31 +719,37 @@ describe('diffs/components/app', () => {
const fileByFileNav = () => wrapper.find('[data-testid="file-by-file-navigation"]');
const paginator = () => fileByFileNav().find(GlPagination);
- it('sets previous button as disabled', () => {
- createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ it('sets previous button as disabled', async () => {
+ createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
});
+ await wrapper.vm.$nextTick();
+
expect(paginator().attributes('prevpage')).toBe(undefined);
expect(paginator().attributes('nextpage')).toBe('2');
});
- it('sets next button as disabled', () => {
- createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ it('sets next button as disabled', async () => {
+ createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
state.diffs.currentDiffFileId = '312';
});
+ await wrapper.vm.$nextTick();
+
expect(paginator().attributes('prevpage')).toBe('1');
expect(paginator().attributes('nextpage')).toBe(undefined);
});
- it("doesn't display when there's fewer than 2 files", () => {
- createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ it("doesn't display when there's fewer than 2 files", async () => {
+ createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' });
state.diffs.currentDiffFileId = '123';
});
+ await wrapper.vm.$nextTick();
+
expect(fileByFileNav().exists()).toBe(false);
});
@@ -748,11 +760,13 @@ describe('diffs/components/app', () => {
`(
'it calls navigateToDiffFileIndex with $index when $link is clicked',
async ({ currentDiffFileId, targetFile }) => {
- createComponent({ viewDiffsFileByFile: true }, ({ state }) => {
+ createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });
state.diffs.currentDiffFileId = currentDiffFileId;
});
+ await wrapper.vm.$nextTick();
+
jest.spyOn(wrapper.vm, 'navigateToDiffFileIndex');
paginator().vm.$emit('input', targetFile);
@@ -763,5 +777,24 @@ describe('diffs/components/app', () => {
},
);
});
+
+ describe('control via event stream', () => {
+ it.each`
+ setting
+ ${true}
+ ${false}
+ `(
+ 'triggers the action with the new fileByFile setting - $setting - when the event with that setting is received',
+ async ({ setting }) => {
+ createComponent();
+ await wrapper.vm.$nextTick();
+
+ eventHub.$emit(EVT_VIEW_FILE_BY_FILE, { setting });
+ await wrapper.vm.$nextTick();
+
+ expect(store.state.diffs.viewDiffsFileByFile).toBe(setting);
+ },
+ );
+ });
});
});
diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js
index 72330d8efba..a9b1c81d00e 100644
--- a/spec/frontend/diffs/components/settings_dropdown_spec.js
+++ b/spec/frontend/diffs/components/settings_dropdown_spec.js
@@ -2,12 +2,18 @@ import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import diffModule from '~/diffs/store/modules';
import SettingsDropdown from '~/diffs/components/settings_dropdown.vue';
-import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
+import {
+ EVT_VIEW_FILE_BY_FILE,
+ PARALLEL_DIFF_VIEW_TYPE,
+ INLINE_DIFF_VIEW_TYPE,
+} from '~/diffs/constants';
+import eventHub from '~/diffs/event_hub';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Diff settings dropdown component', () => {
+ let wrapper;
let vm;
let actions;
@@ -25,10 +31,15 @@ describe('Diff settings dropdown component', () => {
extendStore(store);
- vm = mount(SettingsDropdown, {
+ wrapper = mount(SettingsDropdown, {
localVue,
store,
});
+ vm = wrapper.vm;
+ }
+
+ function getFileByFileCheckbox(vueWrapper) {
+ return vueWrapper.find('[data-testid="file-by-file"]');
}
beforeEach(() => {
@@ -41,14 +52,14 @@ describe('Diff settings dropdown component', () => {
});
afterEach(() => {
- vm.destroy();
+ wrapper.destroy();
});
describe('tree view buttons', () => {
it('list view button dispatches setRenderTreeList with false', () => {
createComponent();
- vm.find('.js-list-view').trigger('click');
+ wrapper.find('.js-list-view').trigger('click');
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false);
});
@@ -56,7 +67,7 @@ describe('Diff settings dropdown component', () => {
it('tree view button dispatches setRenderTreeList with true', () => {
createComponent();
- vm.find('.js-tree-view').trigger('click');
+ wrapper.find('.js-tree-view').trigger('click');
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true);
});
@@ -68,8 +79,8 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('.js-list-view').classes('selected')).toBe(true);
- expect(vm.find('.js-tree-view').classes('selected')).toBe(false);
+ expect(wrapper.find('.js-list-view').classes('selected')).toBe(true);
+ expect(wrapper.find('.js-tree-view').classes('selected')).toBe(false);
});
it('sets tree button as selected when renderTreeList is true', () => {
@@ -79,8 +90,8 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('.js-list-view').classes('selected')).toBe(false);
- expect(vm.find('.js-tree-view').classes('selected')).toBe(true);
+ expect(wrapper.find('.js-list-view').classes('selected')).toBe(false);
+ expect(wrapper.find('.js-tree-view').classes('selected')).toBe(true);
});
});
@@ -92,8 +103,8 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('.js-inline-diff-button').classes('selected')).toBe(true);
- expect(vm.find('.js-parallel-diff-button').classes('selected')).toBe(false);
+ expect(wrapper.find('.js-inline-diff-button').classes('selected')).toBe(true);
+ expect(wrapper.find('.js-parallel-diff-button').classes('selected')).toBe(false);
});
it('sets parallel button as selected', () => {
@@ -103,14 +114,14 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('.js-inline-diff-button').classes('selected')).toBe(false);
- expect(vm.find('.js-parallel-diff-button').classes('selected')).toBe(true);
+ expect(wrapper.find('.js-inline-diff-button').classes('selected')).toBe(false);
+ expect(wrapper.find('.js-parallel-diff-button').classes('selected')).toBe(true);
});
it('calls setInlineDiffViewType when clicking inline button', () => {
createComponent();
- vm.find('.js-inline-diff-button').trigger('click');
+ wrapper.find('.js-inline-diff-button').trigger('click');
expect(actions.setInlineDiffViewType).toHaveBeenCalled();
});
@@ -118,7 +129,7 @@ describe('Diff settings dropdown component', () => {
it('calls setParallelDiffViewType when clicking parallel button', () => {
createComponent();
- vm.find('.js-parallel-diff-button').trigger('click');
+ wrapper.find('.js-parallel-diff-button').trigger('click');
expect(actions.setParallelDiffViewType).toHaveBeenCalled();
});
@@ -132,7 +143,7 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('#show-whitespace').element.checked).toBe(false);
+ expect(wrapper.find('#show-whitespace').element.checked).toBe(false);
});
it('sets as checked when showWhitespace is true', () => {
@@ -142,13 +153,13 @@ describe('Diff settings dropdown component', () => {
});
});
- expect(vm.find('#show-whitespace').element.checked).toBe(true);
+ expect(wrapper.find('#show-whitespace').element.checked).toBe(true);
});
it('calls setShowWhitespace on change', () => {
createComponent();
- const checkbox = vm.find('#show-whitespace');
+ const checkbox = wrapper.find('#show-whitespace');
checkbox.element.checked = true;
checkbox.trigger('change');
@@ -159,4 +170,52 @@ describe('Diff settings dropdown component', () => {
});
});
});
+
+ describe('file-by-file toggle', () => {
+ beforeEach(() => {
+ jest.spyOn(eventHub, '$emit');
+ });
+
+ it.each`
+ fileByFile | checked
+ ${true} | ${true}
+ ${false} | ${false}
+ `(
+ 'sets { checked: $checked } if the fileByFile setting is $fileByFile',
+ async ({ fileByFile, checked }) => {
+ createComponent(store => {
+ Object.assign(store.state.diffs, {
+ viewDiffsFileByFile: fileByFile,
+ });
+ });
+
+ await vm.$nextTick();
+
+ expect(vm.checked).toBe(checked);
+ },
+ );
+
+ it.each`
+ start | emit
+ ${true} | ${false}
+ ${false} | ${true}
+ `(
+ 'when the file by file setting starts as $start, toggling the checkbox should emit an event set to $emit',
+ async ({ start, emit }) => {
+ createComponent(store => {
+ Object.assign(store.state.diffs, {
+ viewDiffsFileByFile: start,
+ });
+ });
+
+ await vm.$nextTick();
+
+ getFileByFileCheckbox(wrapper).trigger('click');
+
+ await vm.$nextTick();
+
+ expect(eventHub.$emit).toHaveBeenCalledWith(EVT_VIEW_FILE_BY_FILE, { setting: emit });
+ },
+ );
+ });
});
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index 0032fe926d0..c1a7844d301 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -48,6 +48,7 @@ import {
moveToNeighboringCommit,
setCurrentDiffFileIdFromNote,
navigateToDiffFileIndex,
+ setFileByFile,
} from '~/diffs/store/actions';
import eventHub from '~/notes/event_hub';
import * as types from '~/diffs/store/mutation_types';
@@ -1455,4 +1456,20 @@ describe('DiffsStoreActions', () => {
);
});
});
+
+ describe('setFileByFile', () => {
+ it.each`
+ value
+ ${true}
+ ${false}
+ `('commits SET_FILE_BY_FILE with the new value $value', ({ value }) => {
+ return testAction(
+ setFileByFile,
+ { fileByFile: value },
+ { viewDiffsFileByFile: null },
+ [{ type: types.SET_FILE_BY_FILE, payload: value }],
+ [],
+ );
+ });
+ });
});
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js
index 2dda9a0ad71..c061c5c2590 100644
--- a/spec/frontend/diffs/store/mutations_spec.js
+++ b/spec/frontend/diffs/store/mutations_spec.js
@@ -892,4 +892,18 @@ describe('DiffsStoreMutations', () => {
expect(state.showSuggestPopover).toBe(false);
});
});
+
+ describe('SET_FILE_BY_FILE', () => {
+ it.each`
+ value | opposite
+ ${true} | ${false}
+ ${false} | ${true}
+ `('sets viewDiffsFileByFile to $value', ({ value, opposite }) => {
+ const state = { viewDiffsFileByFile: opposite };
+
+ mutations[types.SET_FILE_BY_FILE](state, value);
+
+ expect(state.viewDiffsFileByFile).toBe(value);
+ });
+ });
});
diff --git a/spec/frontend/diffs/utils/preferences_spec.js b/spec/frontend/diffs/utils/preferences_spec.js
new file mode 100644
index 00000000000..a48db1d7512
--- /dev/null
+++ b/spec/frontend/diffs/utils/preferences_spec.js
@@ -0,0 +1,40 @@
+import Cookies from 'js-cookie';
+import { getParameterValues } from '~/lib/utils/url_utility';
+
+import { fileByFile } from '~/diffs/utils/preferences';
+import {
+ DIFF_FILE_BY_FILE_COOKIE_NAME,
+ DIFF_VIEW_FILE_BY_FILE,
+ DIFF_VIEW_ALL_FILES,
+} from '~/diffs/constants';
+
+jest.mock('~/lib/utils/url_utility');
+
+describe('diffs preferences', () => {
+ describe('fileByFile', () => {
+ it.each`
+ result | preference | cookie | searchParam
+ ${false} | ${false} | ${undefined} | ${undefined}
+ ${true} | ${true} | ${undefined} | ${undefined}
+ ${true} | ${false} | ${DIFF_VIEW_FILE_BY_FILE} | ${undefined}
+ ${false} | ${true} | ${DIFF_VIEW_ALL_FILES} | ${undefined}
+ ${true} | ${false} | ${undefined} | ${[DIFF_VIEW_FILE_BY_FILE]}
+ ${false} | ${true} | ${undefined} | ${[DIFF_VIEW_ALL_FILES]}
+ ${true} | ${false} | ${DIFF_VIEW_FILE_BY_FILE} | ${[DIFF_VIEW_FILE_BY_FILE]}
+ ${true} | ${true} | ${DIFF_VIEW_ALL_FILES} | ${[DIFF_VIEW_FILE_BY_FILE]}
+ ${false} | ${false} | ${DIFF_VIEW_ALL_FILES} | ${[DIFF_VIEW_ALL_FILES]}
+ ${false} | ${true} | ${DIFF_VIEW_FILE_BY_FILE} | ${[DIFF_VIEW_ALL_FILES]}
+ `(
+ 'should return $result when { preference: $preference, cookie: $cookie, search: $searchParam }',
+ ({ result, preference, cookie, searchParam }) => {
+ if (cookie) {
+ Cookies.set(DIFF_FILE_BY_FILE_COOKIE_NAME, cookie);
+ }
+
+ getParameterValues.mockReturnValue(searchParam);
+
+ expect(fileByFile(preference)).toBe(result);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
index 197f646a22e..b42339f626e 100644
--- a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
+++ b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
@@ -5,7 +5,14 @@ import waitForPromises from 'helpers/wait_for_promises';
import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue';
-import { mockRefs, mockParams, mockPostParams, mockProjectId, mockError } from '../mock_data';
+import {
+ mockBranches,
+ mockTags,
+ mockParams,
+ mockPostParams,
+ mockProjectId,
+ mockError,
+} from '../mock_data';
import { redirectTo } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
@@ -37,6 +44,10 @@ describe('Pipeline New Form', () => {
const findWarnings = () => wrapper.findAll('[data-testid="run-pipeline-warning"]');
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const getExpectedPostParams = () => JSON.parse(mock.history.post[0].data);
+ const changeRef = i =>
+ findDropdownItems()
+ .at(i)
+ .vm.$emit('click');
const createComponent = (term = '', props = {}, method = shallowMount) => {
wrapper = method(PipelineNewForm, {
@@ -44,7 +55,8 @@ describe('Pipeline New Form', () => {
projectId: mockProjectId,
pipelinesPath,
configVariablesPath,
- refs: mockRefs,
+ branches: mockBranches,
+ tags: mockTags,
defaultBranch: 'master',
settingsLink: '',
maxWarnings: 25,
@@ -76,8 +88,11 @@ describe('Pipeline New Form', () => {
});
it('displays dropdown with all branches and tags', () => {
+ const refLength = mockBranches.length + mockTags.length;
+
createComponent();
- expect(findDropdownItems()).toHaveLength(mockRefs.length);
+
+ expect(findDropdownItems()).toHaveLength(refLength);
});
it('when user enters search term the list is filtered', () => {
@@ -130,15 +145,6 @@ describe('Pipeline New Form', () => {
expect(findVariableRows()).toHaveLength(2);
});
- it('creates a pipeline on submit', async () => {
- findForm().vm.$emit('submit', dummySubmitEvent);
-
- await waitForPromises();
-
- expect(getExpectedPostParams()).toEqual(mockPostParams);
- expect(redirectTo).toHaveBeenCalledWith(`${pipelinesPath}/${postResponse.id}`);
- });
-
it('creates blank variable on input change event', async () => {
const input = findKeyInputs().at(2);
input.element.value = 'test_var_2';
@@ -150,45 +156,81 @@ describe('Pipeline New Form', () => {
expect(findKeyInputs().at(3).element.value).toBe('');
expect(findValueInputs().at(3).element.value).toBe('');
});
+ });
- describe('when the form has been modified', () => {
- const selectRef = i =>
- findDropdownItems()
- .at(i)
- .vm.$emit('click');
+ describe('Pipeline creation', () => {
+ beforeEach(async () => {
+ mock.onPost(pipelinesPath).reply(httpStatusCodes.OK, postResponse);
- beforeEach(async () => {
- const input = findKeyInputs().at(0);
- input.element.value = 'test_var_2';
- input.trigger('change');
+ await waitForPromises();
+ });
+ it('creates pipeline with full ref and variables', async () => {
+ createComponent();
- findRemoveIcons()
- .at(1)
- .trigger('click');
+ changeRef(0);
- await wrapper.vm.$nextTick();
- });
+ findForm().vm.$emit('submit', dummySubmitEvent);
- it('form values are restored when the ref changes', async () => {
- expect(findVariableRows()).toHaveLength(2);
+ await waitForPromises();
- selectRef(1);
- await waitForPromises();
+ expect(getExpectedPostParams().ref).toEqual(wrapper.vm.$data.refValue.fullName);
+ expect(redirectTo).toHaveBeenCalledWith(`${pipelinesPath}/${postResponse.id}`);
+ });
+ it('creates a pipeline with short ref and variables', async () => {
+ // query params are used
+ createComponent('', mockParams);
- expect(findVariableRows()).toHaveLength(3);
- expect(findKeyInputs().at(0).element.value).toBe('test_var');
- });
+ await waitForPromises();
- it('form values are restored again when the ref is reverted', async () => {
- selectRef(1);
- await waitForPromises();
+ findForm().vm.$emit('submit', dummySubmitEvent);
- selectRef(2);
- await waitForPromises();
+ await waitForPromises();
- expect(findVariableRows()).toHaveLength(2);
- expect(findKeyInputs().at(0).element.value).toBe('test_var_2');
- });
+ expect(getExpectedPostParams()).toEqual(mockPostParams);
+ expect(redirectTo).toHaveBeenCalledWith(`${pipelinesPath}/${postResponse.id}`);
+ });
+ });
+
+ describe('When the ref has been changed', () => {
+ beforeEach(async () => {
+ createComponent('', {}, mount);
+
+ await waitForPromises();
+ });
+ it('variables persist between ref changes', async () => {
+ changeRef(0); // change to master
+
+ await waitForPromises();
+
+ const masterInput = findKeyInputs().at(0);
+ masterInput.element.value = 'build_var';
+ masterInput.trigger('change');
+
+ await wrapper.vm.$nextTick();
+
+ changeRef(1); // change to branch-1
+
+ await waitForPromises();
+
+ const branchOneInput = findKeyInputs().at(0);
+ branchOneInput.element.value = 'deploy_var';
+ branchOneInput.trigger('change');
+
+ await wrapper.vm.$nextTick();
+
+ changeRef(0); // change back to master
+
+ await waitForPromises();
+
+ expect(findKeyInputs().at(0).element.value).toBe('build_var');
+ expect(findVariableRows().length).toBe(2);
+
+ changeRef(1); // change back to branch-1
+
+ await waitForPromises();
+
+ expect(findKeyInputs().at(0).element.value).toBe('deploy_var');
+ expect(findVariableRows().length).toBe(2);
});
});
@@ -321,6 +363,7 @@ describe('Pipeline New Form', () => {
it('shows the correct warning title', () => {
const { length } = mockError.warnings;
+
expect(findWarningAlertSummary().attributes('message')).toBe(`${length} warnings found:`);
});
diff --git a/spec/frontend/pipeline_new/mock_data.js b/spec/frontend/pipeline_new/mock_data.js
index cdbd6d4437e..feb24ec602d 100644
--- a/spec/frontend/pipeline_new/mock_data.js
+++ b/spec/frontend/pipeline_new/mock_data.js
@@ -1,4 +1,14 @@
-export const mockRefs = ['master', 'branch-1', 'tag-1'];
+export const mockBranches = [
+ { shortName: 'master', fullName: 'refs/heads/master' },
+ { shortName: 'branch-1', fullName: 'refs/heads/branch-1' },
+ { shortName: 'branch-2', fullName: 'refs/heads/branch-2' },
+];
+
+export const mockTags = [
+ { shortName: '1.0.0', fullName: 'refs/tags/1.0.0' },
+ { shortName: '1.1.0', fullName: 'refs/tags/1.1.0' },
+ { shortName: '1.2.0', fullName: 'refs/tags/1.2.0' },
+];
export const mockParams = {
refParam: 'tag-1',
@@ -31,3 +41,7 @@ export const mockError = {
],
total_warnings: 7,
};
+
+export const mockBranchRefs = ['master', 'dev', 'release'];
+
+export const mockTagRefs = ['1.0.0', '1.1.0', '1.2.0'];
diff --git a/spec/frontend/pipeline_new/utils/format_refs_spec.js b/spec/frontend/pipeline_new/utils/format_refs_spec.js
new file mode 100644
index 00000000000..1fda6a8af83
--- /dev/null
+++ b/spec/frontend/pipeline_new/utils/format_refs_spec.js
@@ -0,0 +1,21 @@
+import formatRefs from '~/pipeline_new/utils/format_refs';
+import { BRANCH_REF_TYPE, TAG_REF_TYPE } from '~/pipeline_new/constants';
+import { mockBranchRefs, mockTagRefs } from '../mock_data';
+
+describe('Format refs util', () => {
+ it('formats branch ref correctly', () => {
+ expect(formatRefs(mockBranchRefs, BRANCH_REF_TYPE)).toEqual([
+ { fullName: 'refs/heads/master', shortName: 'master' },
+ { fullName: 'refs/heads/dev', shortName: 'dev' },
+ { fullName: 'refs/heads/release', shortName: 'release' },
+ ]);
+ });
+
+ it('formats tag ref correctly', () => {
+ expect(formatRefs(mockTagRefs, TAG_REF_TYPE)).toEqual([
+ { fullName: 'refs/tags/1.0.0', shortName: '1.0.0' },
+ { fullName: 'refs/tags/1.1.0', shortName: '1.1.0' },
+ { fullName: 'refs/tags/1.2.0', shortName: '1.2.0' },
+ ]);
+ });
+});
diff --git a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
new file mode 100644
index 00000000000..86895341f2c
--- /dev/null
+++ b/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Settings Form Cadence matches snapshot 1`] = `
+<expiration-dropdown-stub
+ class="gl-mr-7 gl-mb-0!"
+ data-testid="cadence-dropdown"
+ formoptions="[object Object],[object Object],[object Object],[object Object],[object Object]"
+ label="Run cleanup:"
+ name="cadence"
+ value="EVERY_DAY"
+/>
+`;
+
+exports[`Settings Form Enable matches snapshot 1`] = `
+<expiration-toggle-stub
+ class="gl-mb-0!"
+ data-testid="enable-toggle"
+ value="true"
+/>
+`;
+
+exports[`Settings Form Keep N matches snapshot 1`] = `
+<expiration-dropdown-stub
+ data-testid="keep-n-dropdown"
+ formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"
+ label="Keep the most recent:"
+ name="keep-n"
+ value="TEN_TAGS"
+/>
+`;
+
+exports[`Settings Form Keep Regex matches snapshot 1`] = `
+<expiration-textarea-stub
+ data-testid="keep-regex-textarea"
+ description="Tags with names that match this regex pattern are kept. %{linkStart}More information%{linkEnd}"
+ error=""
+ label="Keep tags matching:"
+ name="keep-regex"
+ placeholder=""
+ value="sss"
+/>
+`;
+
+exports[`Settings Form OlderThan matches snapshot 1`] = `
+<expiration-dropdown-stub
+ data-testid="older-than-dropdown"
+ formoptions="[object Object],[object Object],[object Object],[object Object]"
+ label="Remove tags older than:"
+ name="older-than"
+ value="FOURTEEN_DAYS"
+/>
+`;
+
+exports[`Settings Form Remove regex matches snapshot 1`] = `
+<expiration-textarea-stub
+ data-testid="remove-regex-textarea"
+ description="Tags with names that match this regex pattern are removed. %{linkStart}More information%{linkEnd}"
+ error=""
+ label="Remove tags matching:"
+ name="remove-regex"
+ placeholder=".*"
+ value="asdasdssssdfdf"
+/>
+`;
diff --git a/spec/frontend/registry/settings/components/registry_settings_app_spec.js b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
index a784396f47a..6be24b81ac1 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -11,7 +11,11 @@ import {
UNAVAILABLE_USER_FEATURE_TEXT,
} from '~/registry/settings/constants';
-import { expirationPolicyPayload, emptyExpirationPolicyPayload } from '../mock_data';
+import {
+ expirationPolicyPayload,
+ emptyExpirationPolicyPayload,
+ containerExpirationPolicyData,
+} from '../mock_data';
const localVue = createLocalVue();
@@ -62,6 +66,29 @@ describe('Registry Settings App', () => {
wrapper.destroy();
});
+ describe('isEdited status', () => {
+ it.each`
+ description | apiResponse | workingCopy | result
+ ${'empty response and no changes from user'} | ${emptyExpirationPolicyPayload()} | ${{}} | ${false}
+ ${'empty response and changes from user'} | ${emptyExpirationPolicyPayload()} | ${{ enabled: true }} | ${true}
+ ${'response and no changes'} | ${expirationPolicyPayload()} | ${containerExpirationPolicyData()} | ${false}
+ ${'response and changes'} | ${expirationPolicyPayload()} | ${{ ...containerExpirationPolicyData(), nameRegex: '12345' }} | ${true}
+ ${'response and empty'} | ${expirationPolicyPayload()} | ${{}} | ${true}
+ `('$description', async ({ apiResponse, workingCopy, result }) => {
+ const requests = mountComponentWithApollo({
+ provide: { ...defaultProvidedValues, enableHistoricEntries: true },
+ resolver: jest.fn().mockResolvedValue(apiResponse),
+ });
+ await Promise.all(requests);
+
+ findSettingsComponent().vm.$emit('input', workingCopy);
+
+ await wrapper.vm.$nextTick();
+
+ expect(findSettingsComponent().props('isEdited')).toBe(result);
+ });
+ });
+
it('renders the setting form', async () => {
const requests = mountComponentWithApollo({
resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()),
diff --git a/spec/frontend/registry/settings/components/settings_form_spec.js b/spec/frontend/registry/settings/components/settings_form_spec.js
index 4346cfadcc8..3744faa0d80 100644
--- a/spec/frontend/registry/settings/components/settings_form_spec.js
+++ b/spec/frontend/registry/settings/components/settings_form_spec.js
@@ -4,7 +4,6 @@ import createMockApollo from 'jest/helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Tracking from '~/tracking';
import component from '~/registry/settings/components/settings_form.vue';
-import expirationPolicyFields from '~/registry/shared/components/expiration_policy_fields.vue';
import updateContainerExpirationPolicyMutation from '~/registry/settings/graphql/mutations/update_container_expiration_policy.graphql';
import expirationPolicyQuery from '~/registry/settings/graphql/queries/get_expiration_policy.graphql';
import {
@@ -39,9 +38,15 @@ describe('Settings Form', () => {
};
const findForm = () => wrapper.find({ ref: 'form-element' });
- const findFields = () => wrapper.find(expirationPolicyFields);
- const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
- const findSaveButton = () => wrapper.find({ ref: 'save-button' });
+
+ const findCancelButton = () => wrapper.find('[data-testid="cancel-button"');
+ const findSaveButton = () => wrapper.find('[data-testid="save-button"');
+ const findEnableToggle = () => wrapper.find('[data-testid="enable-toggle"]');
+ const findCadenceDropdown = () => wrapper.find('[data-testid="cadence-dropdown"]');
+ const findKeepNDropdown = () => wrapper.find('[data-testid="keep-n-dropdown"]');
+ const findKeepRegexTextarea = () => wrapper.find('[data-testid="keep-regex-textarea"]');
+ const findOlderThanDropdown = () => wrapper.find('[data-testid="older-than-dropdown"]');
+ const findRemoveRegexTextarea = () => wrapper.find('[data-testid="remove-regex-textarea"]');
const mountComponent = ({
props = defaultProps,
@@ -109,45 +114,136 @@ describe('Settings Form', () => {
wrapper.destroy();
});
- describe('data binding', () => {
- it('v-model change update the settings property', () => {
+ describe.each`
+ model | finder | fieldName | type | defaultValue
+ ${'enabled'} | ${findEnableToggle} | ${'Enable'} | ${'toggle'} | ${false}
+ ${'cadence'} | ${findCadenceDropdown} | ${'Cadence'} | ${'dropdown'} | ${'EVERY_DAY'}
+ ${'keepN'} | ${findKeepNDropdown} | ${'Keep N'} | ${'dropdown'} | ${'TEN_TAGS'}
+ ${'nameRegexKeep'} | ${findKeepRegexTextarea} | ${'Keep Regex'} | ${'textarea'} | ${''}
+ ${'olderThan'} | ${findOlderThanDropdown} | ${'OlderThan'} | ${'dropdown'} | ${'NINETY_DAYS'}
+ ${'nameRegex'} | ${findRemoveRegexTextarea} | ${'Remove regex'} | ${'textarea'} | ${''}
+ `('$fieldName', ({ model, finder, type, defaultValue }) => {
+ it('matches snapshot', () => {
mountComponent();
- findFields().vm.$emit('input', { newValue: 'foo' });
- expect(wrapper.emitted('input')).toEqual([['foo']]);
+
+ expect(finder().element).toMatchSnapshot();
});
- it('v-model change update the api error property', () => {
- const apiErrors = { baz: 'bar' };
- mountComponent({ data: { apiErrors } });
- expect(findFields().props('apiErrors')).toEqual(apiErrors);
- findFields().vm.$emit('input', { newValue: 'foo', modified: 'baz' });
- expect(findFields().props('apiErrors')).toEqual({});
+ it('input event triggers a model update', () => {
+ mountComponent();
+
+ finder().vm.$emit('input', 'foo');
+ expect(wrapper.emitted('input')[0][0]).toMatchObject({
+ [model]: 'foo',
+ });
});
it('shows the default option when none are selected', () => {
mountComponent({ props: { value: {} } });
- expect(findFields().props('value')).toEqual({
- cadence: 'EVERY_DAY',
- keepN: 'TEN_TAGS',
- olderThan: 'NINETY_DAYS',
- });
+ expect(finder().props('value')).toEqual(defaultValue);
});
+
+ if (type !== 'toggle') {
+ it.each`
+ isLoading | mutationLoading | enabledValue
+ ${false} | ${false} | ${false}
+ ${true} | ${false} | ${false}
+ ${true} | ${true} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${false}
+ `(
+ 'is disabled when is loading is $isLoading, mutationLoading is $mutationLoading and enabled is $enabledValue',
+ ({ isLoading, mutationLoading, enabledValue }) => {
+ mountComponent({
+ props: { isLoading, value: { enabled: enabledValue } },
+ data: { mutationLoading },
+ });
+ expect(finder().props('disabled')).toEqual(true);
+ },
+ );
+ } else {
+ it.each`
+ isLoading | mutationLoading
+ ${true} | ${false}
+ ${true} | ${true}
+ ${false} | ${true}
+ `(
+ 'is disabled when is loading is $isLoading and mutationLoading is $mutationLoading',
+ ({ isLoading, mutationLoading }) => {
+ mountComponent({
+ props: { isLoading, value: {} },
+ data: { mutationLoading },
+ });
+ expect(finder().props('disabled')).toEqual(true);
+ },
+ );
+ }
+
+ if (type === 'textarea') {
+ it('input event updates the api error property', async () => {
+ const apiErrors = { [model]: 'bar' };
+ mountComponent({ data: { apiErrors } });
+
+ finder().vm.$emit('input', 'foo');
+ expect(finder().props('error')).toEqual('bar');
+
+ await wrapper.vm.$nextTick();
+
+ expect(finder().props('error')).toEqual('');
+ });
+
+ it('validation event updates buttons disabled state', async () => {
+ mountComponent();
+
+ expect(findSaveButton().props('disabled')).toBe(false);
+
+ finder().vm.$emit('validation', false);
+
+ await wrapper.vm.$nextTick();
+
+ expect(findSaveButton().props('disabled')).toBe(true);
+ });
+ }
+
+ if (type === 'dropdown') {
+ it('has the correct formOptions', () => {
+ mountComponent();
+ expect(finder().props('formOptions')).toEqual(wrapper.vm.$options.formOptions[model]);
+ });
+ }
});
describe('form', () => {
describe('form reset event', () => {
- beforeEach(() => {
+ it('calls the appropriate function', () => {
mountComponent();
findForm().trigger('reset');
- });
- it('calls the appropriate function', () => {
+
expect(wrapper.emitted('reset')).toEqual([[]]);
});
it('tracks the reset event', () => {
+ mountComponent();
+
+ findForm().trigger('reset');
+
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'reset_form', trackingPayload);
});
+
+ it('resets the errors objects', async () => {
+ mountComponent({
+ data: { apiErrors: { nameRegex: 'bar' }, localErrors: { nameRegexKeep: false } },
+ });
+
+ findForm().trigger('reset');
+
+ await wrapper.vm.$nextTick();
+
+ expect(findKeepRegexTextarea().props('error')).toBe('');
+ expect(findRemoveRegexTextarea().props('error')).toBe('');
+ expect(findSaveButton().props('disabled')).toBe(false);
+ });
});
describe('form submit event ', () => {
@@ -209,6 +305,7 @@ describe('Settings Form', () => {
});
});
});
+
describe('global errors', () => {
it('shows an error', async () => {
const handlers = mountComponentWithApollo({
@@ -230,7 +327,7 @@ describe('Settings Form', () => {
graphQLErrors: [
{
extensions: {
- problems: [{ path: ['name'], message: 'baz' }],
+ problems: [{ path: ['nameRegexKeep'], message: 'baz' }],
},
},
],
@@ -241,7 +338,7 @@ describe('Settings Form', () => {
await waitForPromises();
await wrapper.vm.$nextTick();
- expect(findFields().props('apiErrors')).toEqual({ name: 'baz' });
+ expect(findKeepRegexTextarea().props('error')).toEqual('baz');
});
});
});
@@ -257,23 +354,21 @@ describe('Settings Form', () => {
});
it.each`
- isLoading | isEdited | mutationLoading | isDisabled
- ${true} | ${true} | ${true} | ${true}
- ${false} | ${true} | ${true} | ${true}
- ${false} | ${false} | ${true} | ${true}
- ${true} | ${false} | ${false} | ${true}
- ${false} | ${false} | ${false} | ${true}
- ${false} | ${true} | ${false} | ${false}
+ isLoading | isEdited | mutationLoading
+ ${true} | ${true} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${true}
+ ${true} | ${false} | ${false}
+ ${false} | ${false} | ${false}
`(
- 'when isLoading is $isLoading and isEdited is $isEdited and mutationLoading is $mutationLoading is $isDisabled that the is disabled',
- ({ isEdited, isLoading, mutationLoading, isDisabled }) => {
+ 'when isLoading is $isLoading, isEdited is $isEdited and mutationLoading is $mutationLoading is disabled',
+ ({ isEdited, isLoading, mutationLoading }) => {
mountComponent({
props: { ...defaultProps, isEdited, isLoading },
data: { mutationLoading },
});
- const expectation = isDisabled ? 'true' : undefined;
- expect(findCancelButton().attributes('disabled')).toBe(expectation);
+ expect(findCancelButton().props('disabled')).toBe(true);
},
);
});
@@ -284,24 +379,24 @@ describe('Settings Form', () => {
expect(findSaveButton().attributes('type')).toBe('submit');
});
+
it.each`
- isLoading | fieldsAreValid | mutationLoading | isDisabled
- ${true} | ${true} | ${true} | ${true}
- ${false} | ${true} | ${true} | ${true}
- ${false} | ${false} | ${true} | ${true}
- ${true} | ${false} | ${false} | ${true}
- ${false} | ${false} | ${false} | ${true}
- ${false} | ${true} | ${false} | ${false}
+ isLoading | localErrors | mutationLoading
+ ${true} | ${{}} | ${true}
+ ${true} | ${{}} | ${false}
+ ${false} | ${{}} | ${true}
+ ${false} | ${{ foo: false }} | ${true}
+ ${true} | ${{ foo: false }} | ${false}
+ ${false} | ${{ foo: false }} | ${false}
`(
- 'when isLoading is $isLoading and fieldsAreValid is $fieldsAreValid and mutationLoading is $mutationLoading is $isDisabled that the is disabled',
- ({ fieldsAreValid, isLoading, mutationLoading, isDisabled }) => {
+ 'when isLoading is $isLoading, localErrors is $localErrors and mutationLoading is $mutationLoading is disabled',
+ ({ localErrors, isLoading, mutationLoading }) => {
mountComponent({
props: { ...defaultProps, isLoading },
- data: { mutationLoading, fieldsAreValid },
+ data: { mutationLoading, localErrors },
});
- const expectation = isDisabled ? 'true' : undefined;
- expect(findSaveButton().attributes('disabled')).toBe(expectation);
+ expect(findSaveButton().props('disabled')).toBe(true);
},
);
diff --git a/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
index 032007bba51..7062773b46b 100644
--- a/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
+++ b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
@@ -76,25 +76,25 @@ Array [
Object {
"default": false,
"key": "SEVEN_DAYS",
- "label": "7 days until tags are automatically removed",
+ "label": "7 days",
"variable": 7,
},
Object {
"default": false,
"key": "FOURTEEN_DAYS",
- "label": "14 days until tags are automatically removed",
+ "label": "14 days",
"variable": 14,
},
Object {
"default": false,
"key": "THIRTY_DAYS",
- "label": "30 days until tags are automatically removed",
+ "label": "30 days",
"variable": 30,
},
Object {
"default": true,
"key": "NINETY_DAYS",
- "label": "90 days until tags are automatically removed",
+ "label": "90 days",
"variable": 90,
},
]
diff --git a/spec/frontend/registry/shared/utils_spec.js b/spec/frontend/registry/shared/utils_spec.js
index edb0c3261be..1ba832f67ea 100644
--- a/spec/frontend/registry/shared/utils_spec.js
+++ b/spec/frontend/registry/shared/utils_spec.js
@@ -11,10 +11,7 @@ describe('Utils', () => {
[{ variable: 1 }, { variable: 2 }],
olderThanTranslationGenerator,
);
- expect(result).toEqual([
- { variable: 1, label: '1 day until tags are automatically removed' },
- { variable: 2, label: '2 days until tags are automatically removed' },
- ]);
+ expect(result).toEqual([{ variable: 1, label: '1 day' }, { variable: 2, label: '2 days' }]);
});
});
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 412f45739b1..9117fc9006d 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -86,6 +86,7 @@ label:
- issues
- merge_requests
- priorities
+- epic_board_labels
milestone:
- group
- project
diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb
index 62380299ea0..41ce480b02f 100644
--- a/spec/models/custom_emoji_spec.rb
+++ b/spec/models/custom_emoji_spec.rb
@@ -22,6 +22,15 @@ RSpec.describe CustomEmoji do
expect(new_emoji.errors.messages).to eq(name: ["#{emoji_name} is already being used for another emoji"])
end
+ it 'disallows very long invalid emoji name without regular expression backtracking issues' do
+ new_emoji = build(:custom_emoji, name: 'a' * 10000 + '!', group: group)
+
+ Timeout.timeout(1) do
+ expect(new_emoji).not_to be_valid
+ expect(new_emoji.errors.messages).to eq(name: ["is too long (maximum is 36 characters)", "is invalid"])
+ end
+ end
+
it 'disallows duplicate custom emoji names within namespace' do
old_emoji = create(:custom_emoji, group: group)
new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace, group: group)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 0ca35476233..3bcb21bc828 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -5071,11 +5071,11 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe "#default_branch" do
- context "with an empty repository" do
+ describe '#default_branch' do
+ context 'with an empty repository' do
let_it_be(:project) { create(:project_empty_repo) }
- context "group.default_branch_name is available" do
+ context 'group.default_branch_name is available' do
let(:project_group) { create(:group) }
let(:project) { create(:project, path: 'avatar', namespace: project_group) }
@@ -5088,19 +5088,19 @@ RSpec.describe Project, factory_default: :keep do
.and_return('example_branch')
end
- it "returns the group default value" do
- expect(project.default_branch).to eq("example_branch")
+ it 'returns the group default value' do
+ expect(project.default_branch).to eq('example_branch')
end
end
- context "Gitlab::CurrentSettings.default_branch_name is available" do
+ context 'Gitlab::CurrentSettings.default_branch_name is available' do
before do
expect(Gitlab::CurrentSettings)
.to receive(:default_branch_name)
.and_return(example_branch_name)
end
- context "is missing or nil" do
+ context 'is missing or nil' do
let(:example_branch_name) { nil }
it "returns nil" do
@@ -5108,10 +5108,18 @@ RSpec.describe Project, factory_default: :keep do
end
end
- context "is present" do
- let(:example_branch_name) { "example_branch_name" }
+ context 'is blank' do
+ let(:example_branch_name) { '' }
- it "returns the expected branch name" do
+ it 'returns nil' do
+ expect(project.default_branch).to be_nil
+ end
+ end
+
+ context 'is present' do
+ let(:example_branch_name) { 'example_branch_name' }
+
+ it 'returns the expected branch name' do
expect(project.default_branch).to eq(example_branch_name)
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e8405934f62..55ee846090f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -8,6 +8,10 @@ if $".include?(File.expand_path('fast_spec_helper.rb', __dir__))
abort 'Aborting...'
end
+# Enable deprecation warnings by default and make them more visible
+# to developers to ease upgrading to newer Ruby versions.
+Warning[:deprecated] = true unless ENV.key?('SILENCE_DEPRECATIONS')
+
require './spec/deprecation_toolkit_env'
require './spec/simplecov_env'