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-02-03 12:08:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-03 12:08:42 +0300
commitf14507e586a7f75f0fb71a1d8468b7361be860d4 (patch)
treea8aa547b517a7ae5626c902bfb558c1fc5386c4e /spec
parentf4d27d532e3abeecd1caffeb3a56e698ae982e5b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb10
-rw-r--r--spec/frontend/error_tracking_settings/store/getters_spec.js2
-rw-r--r--spec/frontend/ide/components/ide_status_list_spec.js2
-rw-r--r--spec/frontend/mr_popover/mr_popover_spec.js2
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js2
-rw-r--r--spec/frontend/registry/settings/components/settings_form_spec.js217
-rw-r--r--spec/frontend/registry/settings/store/actions_spec.js13
-rw-r--r--spec/frontend/registry/settings/store/getters_spec.js4
-rw-r--r--spec/frontend/registry/settings/store/mutations_spec.js4
-rw-r--r--spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap (renamed from spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap)10
-rw-r--r--spec/frontend/registry/shared/components/expiration_policy_form_spec.js237
-rw-r--r--spec/frontend/registry/shared/mock_data.js (renamed from spec/frontend/registry/settings/mock_data.js)0
-rw-r--r--spec/frontend/releases/detail/components/app_spec.js2
-rw-r--r--spec/frontend/sidebar/confidential_issue_sidebar_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/recaptcha_modal_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/slot_switch_spec.js2
-rw-r--r--spec/helpers/button_helper_spec.rb2
-rw-r--r--spec/models/concerns/delete_with_limit_spec.rb15
-rw-r--r--spec/models/project_services/emails_on_push_service_spec.rb16
-rw-r--r--spec/requests/api/services_spec.rb15
21 files changed, 319 insertions, 242 deletions
diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb
index 9bbeb0eb260..72e2865dd6a 100644
--- a/spec/features/projects/settings/operations_settings_spec.rb
+++ b/spec/features/projects/settings/operations_settings_spec.rb
@@ -61,7 +61,7 @@ describe 'Projects > Settings > For a forked project', :js do
within('div#project-dropdown') do
click_button('Select project')
- click_button('Sentry | Internal')
+ click_button('Sentry | internal')
end
click_button('Save changes')
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 1a1940f6efb..4c5bc290402 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -26,11 +26,11 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
it 'saves expiration policy submit the form' do
within '#js-registry-policies' do
within '.card-body' do
- find('#expiration-policy-toggle button:not(.is-disabled)').click
- select('7 days until tags are automatically removed', from: 'expiration-policy-interval')
- select('Every day', from: 'expiration-policy-schedule')
- select('50 tags per image name', from: 'expiration-policy-latest')
- fill_in('expiration-policy-name-matching', with: '*-production')
+ find('.gl-toggle-wrapper button:not(.is-disabled)').click
+ 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('Docker tags with names matching this regex pattern will expire:', with: '*-production')
end
submit_button = find('.card-footer .btn.btn-success')
expect(submit_button).not_to be_disabled
diff --git a/spec/frontend/error_tracking_settings/store/getters_spec.js b/spec/frontend/error_tracking_settings/store/getters_spec.js
index 2c5ff084b8a..b135fdee40b 100644
--- a/spec/frontend/error_tracking_settings/store/getters_spec.js
+++ b/spec/frontend/error_tracking_settings/store/getters_spec.js
@@ -47,7 +47,7 @@ describe('Error Tracking Settings - Getters', () => {
it('should display correctly when a project is selected', () => {
[state.selectedProject] = projectList;
- expect(getters.dropdownLabel(state, mockGetters)).toEqual('organizationName | name');
+ expect(getters.dropdownLabel(state, mockGetters)).toEqual('organizationName | slug');
});
it('should display correctly when no project is selected', () => {
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js
index 2762adfb57d..99c27ca30fb 100644
--- a/spec/frontend/ide/components/ide_status_list_spec.js
+++ b/spec/frontend/ide/components/ide_status_list_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
-import IdeStatusList from '~/ide/components/ide_status_list';
+import IdeStatusList from '~/ide/components/ide_status_list.vue';
const TEST_FILE = {
name: 'lorem.md',
diff --git a/spec/frontend/mr_popover/mr_popover_spec.js b/spec/frontend/mr_popover/mr_popover_spec.js
index 0c0d4c73d91..3f62dca4a57 100644
--- a/spec/frontend/mr_popover/mr_popover_spec.js
+++ b/spec/frontend/mr_popover/mr_popover_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import MRPopover from '~/mr_popover/components/mr_popover';
+import MRPopover from '~/mr_popover/components/mr_popover.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
describe('MR Popover', () => {
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 8a5c5d84198..e9ba65e4387 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -4,7 +4,7 @@ import component from '~/registry/settings/components/registry_settings_app.vue'
import SettingsForm from '~/registry/settings/components/settings_form.vue';
import { createStore } from '~/registry/settings/store/';
import { SET_IS_DISABLED } from '~/registry/settings/store/mutation_types';
-import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/settings/constants';
+import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/shared/constants';
describe('Registry Settings App', () => {
let wrapper;
diff --git a/spec/frontend/registry/settings/components/settings_form_spec.js b/spec/frontend/registry/settings/components/settings_form_spec.js
index 89dd161ec3e..eefb0313a0b 100644
--- a/spec/frontend/registry/settings/components/settings_form_spec.js
+++ b/spec/frontend/registry/settings/components/settings_form_spec.js
@@ -1,49 +1,33 @@
-import { mount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import Tracking from '~/tracking';
-import stubChildren from 'helpers/stub_children';
import component from '~/registry/settings/components/settings_form.vue';
+import expirationPolicyForm from '~/registry/shared/components/expiration_policy_form.vue';
import { createStore } from '~/registry/settings/store/';
import {
- NAME_REGEX_LENGTH,
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
-} from '~/registry/settings/constants';
-import { stringifiedFormOptions } from '../mock_data';
+} from '~/registry/shared/constants';
+import { stringifiedFormOptions } from '../../shared/mock_data';
describe('Settings Form', () => {
let wrapper;
let store;
let dispatchSpy;
- const FORM_ELEMENTS_ID_PREFIX = '#expiration-policy';
const trackingPayload = {
label: 'docker_container_retention_and_expiration_policies',
};
- const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
+ const findForm = () => wrapper.find(expirationPolicyForm);
- const findFormGroup = name => wrapper.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}-group`);
- const findFormElements = (name, parent = wrapper) =>
- parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`);
- const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
- const findSaveButton = () => wrapper.find({ ref: 'save-button' });
- const findForm = () => wrapper.find({ ref: 'form-element' });
- const findLoadingIcon = (parent = wrapper) => parent.find(GlLoadingIcon);
-
- const mountComponent = (options = {}) => {
- wrapper = mount(component, {
- stubs: {
- ...stubChildren(component),
- GlCard: false,
- GlLoadingIcon,
- },
+ const mountComponent = () => {
+ wrapper = shallowMount(component, {
mocks: {
$toast: {
show: jest.fn(),
},
},
store,
- ...options,
});
};
@@ -59,170 +43,50 @@ describe('Settings Form', () => {
wrapper.destroy();
});
- it('renders', () => {
- expect(wrapper.element).toMatchSnapshot();
- });
-
- describe.each`
- elementName | modelName | value | disabledByToggle
- ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
- ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'}
- ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
- ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
- ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
- `(
- `${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`,
- ({ elementName, modelName, value, disabledByToggle }) => {
- let formGroup;
- beforeEach(() => {
- formGroup = findFormGroup(elementName);
- });
- it(`${elementName} form group exist in the dom`, () => {
- expect(formGroup.exists()).toBe(true);
- });
-
- it(`${elementName} form group has a label-for property`, () => {
- expect(formGroup.attributes('label-for')).toBe(`expiration-policy-${elementName}`);
- });
-
- it(`${elementName} form group has a label-cols property`, () => {
- expect(formGroup.attributes('label-cols')).toBe(`${wrapper.vm.$options.labelsConfig.cols}`);
- });
-
- it(`${elementName} form group has a label-align property`, () => {
- expect(formGroup.attributes('label-align')).toBe(
- `${wrapper.vm.$options.labelsConfig.align}`,
- );
- });
-
- it(`${elementName} form group contains an input element`, () => {
- expect(findFormElements(elementName, formGroup).exists()).toBe(true);
- });
-
- it(`${elementName} form element change updated ${modelName} with ${value}`, () => {
- const element = findFormElements(elementName, formGroup);
- const modelUpdateEvent = element.vm.$options.model
- ? element.vm.$options.model.event
- : 'input';
- element.vm.$emit(modelUpdateEvent, value);
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm[modelName]).toBe(value);
- });
- });
-
- it(`${elementName} is ${disabledByToggle} by enabled set to false`, () => {
- store.dispatch('updateSettings', { enabled: false });
- const expectation = disabledByToggle === 'disabled' ? 'true' : undefined;
- expect(findFormElements(elementName, formGroup).attributes('disabled')).toBe(expectation);
- });
- },
- );
-
- describe('form actions', () => {
+ describe('form', () => {
let form;
beforeEach(() => {
form = findForm();
});
- describe('cancel button', () => {
- it('has type reset', () => {
- expect(findCancelButton().attributes('type')).toBe('reset');
- });
-
- it('is disabled the form was not changed from his original value', () => {
- store.dispatch('receiveSettingsSuccess', { foo: 'bar' });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- });
- });
-
- it('is disabled when the form data is loading', () => {
- store.dispatch('toggleLoading');
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- });
- });
-
- it('is enabled when the user changed something in the form and the data is not being loaded', () => {
- store.dispatch('receiveSettingsSuccess', { foo: 'bar' });
- store.dispatch('updateSettings', { foo: 'baz' });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe(undefined);
- });
+ describe('data binding', () => {
+ it('v-model change update the settings property', () => {
+ dispatchSpy.mockReturnValue();
+ form.vm.$emit('input', 'foo');
+ expect(dispatchSpy).toHaveBeenCalledWith('updateSettings', { settings: 'foo' });
});
});
- describe('form cancel event', () => {
+ describe('form reset event', () => {
it('calls the appropriate function', () => {
dispatchSpy.mockReturnValue();
- form.trigger('reset');
+ form.vm.$emit('reset');
expect(dispatchSpy).toHaveBeenCalledWith('resetSettings');
});
it('tracks the reset event', () => {
dispatchSpy.mockReturnValue();
- form.trigger('reset');
+ form.vm.$emit('reset');
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'reset_form', trackingPayload);
});
});
- it('save has type submit', () => {
- expect(findSaveButton().attributes('type')).toBe('submit');
- });
-
- describe('when isLoading is true', () => {
- beforeEach(() => {
- store.dispatch('toggleLoading');
- });
-
- afterEach(() => {
- store.dispatch('toggleLoading');
- });
-
- it.each`
- elementName
- ${'toggle'}
- ${'interval'}
- ${'schedule'}
- ${'latest'}
- ${'name-matching'}
- `(`${FORM_ELEMENTS_ID_PREFIX}-$elementName is disabled`, ({ elementName }) => {
- expect(findFormElements(elementName).attributes('disabled')).toBe('true');
- });
-
- it('submit button is disabled and shows a spinner', () => {
- const button = findSaveButton();
- expect(button.attributes('disabled')).toBeTruthy();
- expect(findLoadingIcon(button)).toExist();
- });
-
- it('cancel button is disabled', () => {
- expect(findCancelButton().attributes('disabled')).toBeTruthy();
- });
- });
-
describe('form submit event ', () => {
- it('calls the appropriate function', () => {
- dispatchSpy.mockResolvedValue();
- form.trigger('submit');
- expect(dispatchSpy).toHaveBeenCalled();
- });
-
it('dispatches the saveSettings action', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
expect(dispatchSpy).toHaveBeenCalledWith('saveSettings');
});
it('tracks the submit event', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'submit_form', trackingPayload);
});
it('show a success toast when submit succeed', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE, {
type: 'success',
@@ -232,7 +96,7 @@ describe('Settings Form', () => {
it('show an error toast when submit fails', () => {
dispatchSpy.mockRejectedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE, {
type: 'error',
@@ -241,45 +105,4 @@ describe('Settings Form', () => {
});
});
});
-
- describe('form validation', () => {
- describe(`when name regex is longer than ${NAME_REGEX_LENGTH}`, () => {
- const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(',');
- beforeEach(() => {
- store.dispatch('updateSettings', { name_regex: invalidString });
- });
-
- it('save btn is disabled', () => {
- expect(findSaveButton().attributes('disabled')).toBeTruthy();
- });
-
- it('nameRegexState is false', () => {
- expect(wrapper.vm.nameRegexState).toBe(false);
- });
- });
-
- it('if the user did not type validation is null', () => {
- store.dispatch('updateSettings', { name_regex: null });
- expect(wrapper.vm.nameRegexState).toBe(null);
- return wrapper.vm.$nextTick().then(() => {
- expect(findSaveButton().attributes('disabled')).toBeFalsy();
- });
- });
-
- it(`if the user typed and is less than ${NAME_REGEX_LENGTH} state is true`, () => {
- store.dispatch('updateSettings', { name_regex: 'abc' });
- expect(wrapper.vm.nameRegexState).toBe(true);
- });
- });
-
- describe('help text', () => {
- it('toggleDescriptionText text reflects enabled property', () => {
- const toggleHelpText = findFormGroup('toggle').find('span');
- expect(toggleHelpText.html()).toContain('disabled');
- wrapper.setData({ enabled: true });
- return wrapper.vm.$nextTick().then(() => {
- expect(toggleHelpText.html()).toContain('enabled');
- });
- });
- });
});
diff --git a/spec/frontend/registry/settings/store/actions_spec.js b/spec/frontend/registry/settings/store/actions_spec.js
index f904d0b660a..5038dc82416 100644
--- a/spec/frontend/registry/settings/store/actions_spec.js
+++ b/spec/frontend/registry/settings/store/actions_spec.js
@@ -10,11 +10,14 @@ describe('Actions Registry Store', () => {
${'updateSettings'} | ${types.UPDATE_SETTINGS} | ${'foo'}
${'toggleLoading'} | ${types.TOGGLE_LOADING} | ${undefined}
${'resetSettings'} | ${types.RESET_SETTINGS} | ${undefined}
- `('%s action invokes %s mutation with payload %s', ({ actionName, mutationName, payload }) => {
- it('should set the initial state', done => {
- testAction(actions[actionName], payload, {}, [{ type: mutationName, payload }], [], done);
- });
- });
+ `(
+ '$actionName invokes $mutationName with payload $payload',
+ ({ actionName, mutationName, payload }) => {
+ it('should set state', done => {
+ testAction(actions[actionName], payload, {}, [{ type: mutationName, payload }], [], done);
+ });
+ },
+ );
describe('receiveSettingsSuccess', () => {
it('calls SET_SETTINGS when data is present', () => {
diff --git a/spec/frontend/registry/settings/store/getters_spec.js b/spec/frontend/registry/settings/store/getters_spec.js
index d9ee53766d6..44631b97a39 100644
--- a/spec/frontend/registry/settings/store/getters_spec.js
+++ b/spec/frontend/registry/settings/store/getters_spec.js
@@ -1,6 +1,6 @@
import * as getters from '~/registry/settings/store/getters';
-import * as utils from '~/registry/settings/utils';
-import { formOptions } from '../mock_data';
+import * as utils from '~/registry/shared/utils';
+import { formOptions } from '../../shared/mock_data';
describe('Getters registry settings store', () => {
const settings = {
diff --git a/spec/frontend/registry/settings/store/mutations_spec.js b/spec/frontend/registry/settings/store/mutations_spec.js
index deb59089d60..8ab0196fd4d 100644
--- a/spec/frontend/registry/settings/store/mutations_spec.js
+++ b/spec/frontend/registry/settings/store/mutations_spec.js
@@ -1,7 +1,7 @@
import mutations from '~/registry/settings/store/mutations';
import * as types from '~/registry/settings/store/mutation_types';
import createState from '~/registry/settings/store/state';
-import { formOptions, stringifiedFormOptions } from '../mock_data';
+import { formOptions, stringifiedFormOptions } from '../../shared/mock_data';
describe('Mutations Registry Store', () => {
let mockState;
@@ -28,7 +28,7 @@ describe('Mutations Registry Store', () => {
mockState.settings = { foo: 'bar' };
const payload = { foo: 'baz' };
const expectedState = { ...mockState, settings: payload };
- mutations[types.UPDATE_SETTINGS](mockState, payload);
+ mutations[types.UPDATE_SETTINGS](mockState, { settings: payload });
expect(mockState.settings).toEqual(expectedState.settings);
});
});
diff --git a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap
index 06f73c8f456..b53736951e1 100644
--- a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
+++ b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap
@@ -1,7 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Settings Form renders 1`] = `
-<form>
+exports[`Expiration Policy Form renders 1`] = `
+<form
+ class="lh-2"
+>
<div
class="card"
>
@@ -56,7 +58,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-interval"
- value="bar"
>
<option
value="foo"
@@ -85,7 +86,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-schedule"
- value="bar"
>
<option
value="foo"
@@ -114,7 +114,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-latest"
- value="bar"
>
<option
value="foo"
@@ -159,7 +158,6 @@ exports[`Settings Form renders 1`] = `
>
<glbutton-stub
class="mr-2 d-block"
- disabled="true"
size="md"
type="reset"
variant="secondary"
diff --git a/spec/frontend/registry/shared/components/expiration_policy_form_spec.js b/spec/frontend/registry/shared/components/expiration_policy_form_spec.js
new file mode 100644
index 00000000000..b51519925f1
--- /dev/null
+++ b/spec/frontend/registry/shared/components/expiration_policy_form_spec.js
@@ -0,0 +1,237 @@
+import { mount } from '@vue/test-utils';
+import stubChildren from 'helpers/stub_children';
+import component from '~/registry/shared/components/expiration_policy_form.vue';
+
+import { NAME_REGEX_LENGTH } from '~/registry/shared/constants';
+import { formOptions } from '../mock_data';
+
+describe('Expiration Policy Form', () => {
+ let wrapper;
+
+ const FORM_ELEMENTS_ID_PREFIX = '#expiration-policy';
+
+ const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
+
+ const findFormGroup = name => wrapper.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}-group`);
+ const findFormElements = (name, parent = wrapper) =>
+ parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`);
+ const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
+ const findSaveButton = () => wrapper.find({ ref: 'save-button' });
+ const findForm = () => wrapper.find({ ref: 'form-element' });
+ const findLoadingIcon = (parent = wrapper) => parent.find(GlLoadingIcon);
+
+ const mountComponent = props => {
+ wrapper = mount(component, {
+ stubs: {
+ ...stubChildren(component),
+ GlCard: false,
+ GlLoadingIcon,
+ },
+ propsData: {
+ formOptions,
+ ...props,
+ },
+ methods: {
+ // override idGenerator to avoid having to test with dynamic uid
+ idGenerator: value => value,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders', () => {
+ mountComponent();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe.each`
+ elementName | modelName | value | disabledByToggle
+ ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
+ ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'}
+ ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
+ ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
+ ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
+ `(
+ `${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`,
+ ({ elementName, modelName, value, disabledByToggle }) => {
+ it(`${elementName} form group exist in the dom`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(formGroup.exists()).toBe(true);
+ });
+
+ it(`${elementName} form group has a label-for property`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(formGroup.attributes('label-for')).toBe(`expiration-policy-${elementName}`);
+ });
+
+ it(`${elementName} form group has a label-cols property`, () => {
+ mountComponent({ labelCols: '1' });
+ const formGroup = findFormGroup(elementName);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(formGroup.attributes('label-cols')).toBe('1');
+ });
+ });
+
+ it(`${elementName} form group has a label-align property`, () => {
+ mountComponent({ labelAlign: 'foo' });
+ const formGroup = findFormGroup(elementName);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(formGroup.attributes('label-align')).toBe('foo');
+ });
+ });
+
+ it(`${elementName} form group contains an input element`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(findFormElements(elementName, formGroup).exists()).toBe(true);
+ });
+
+ it(`${elementName} form element change updated ${modelName} with ${value}`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ const element = findFormElements(elementName, formGroup);
+
+ const modelUpdateEvent = element.vm.$options.model
+ ? element.vm.$options.model.event
+ : 'input';
+ element.vm.$emit(modelUpdateEvent, value);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('input')).toEqual([[{ [modelName]: value }]]);
+ });
+ });
+
+ it(`${elementName} is ${disabledByToggle} by enabled set to false`, () => {
+ mountComponent({ settings: { enabled: false } });
+ const formGroup = findFormGroup(elementName);
+ const expectation = disabledByToggle === 'disabled' ? 'true' : undefined;
+ expect(findFormElements(elementName, formGroup).attributes('disabled')).toBe(expectation);
+ });
+ },
+ );
+
+ describe('form actions', () => {
+ describe('cancel button', () => {
+ it('has type reset', () => {
+ mountComponent();
+ expect(findCancelButton().attributes('type')).toBe('reset');
+ });
+
+ it('is disabled when disableCancelButton is true', () => {
+ mountComponent({ disableCancelButton: true });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe('true');
+ });
+ });
+
+ it('is disabled isLoading is true', () => {
+ mountComponent({ isLoading: true });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe('true');
+ });
+ });
+
+ it('is enabled when isLoading and disableCancelButton are false', () => {
+ mountComponent({ disableCancelButton: false, isLoading: false });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe(undefined);
+ });
+ });
+ });
+
+ describe('form cancel event', () => {
+ it('calls the appropriate function', () => {
+ mountComponent();
+ findForm().trigger('reset');
+ expect(wrapper.emitted('reset')).toBeTruthy();
+ });
+ });
+
+ it('save has type submit', () => {
+ mountComponent();
+ expect(findSaveButton().attributes('type')).toBe('submit');
+ });
+
+ describe('when isLoading is true', () => {
+ beforeEach(() => {
+ mountComponent({ isLoading: true });
+ });
+
+ it.each`
+ elementName
+ ${'toggle'}
+ ${'interval'}
+ ${'schedule'}
+ ${'latest'}
+ ${'name-matching'}
+ `(`${FORM_ELEMENTS_ID_PREFIX}-$elementName is disabled`, ({ elementName }) => {
+ expect(findFormElements(elementName).attributes('disabled')).toBe('true');
+ });
+
+ it('submit button is disabled and shows a spinner', () => {
+ const button = findSaveButton();
+ expect(button.attributes('disabled')).toBeTruthy();
+ expect(findLoadingIcon(button)).toExist();
+ });
+ });
+
+ describe('form submit event ', () => {
+ it('calls the appropriate function', () => {
+ mountComponent();
+ findForm().trigger('submit');
+ expect(wrapper.emitted('submit')).toBeTruthy();
+ });
+ });
+ });
+
+ describe('form validation', () => {
+ describe(`when name regex is longer than ${NAME_REGEX_LENGTH}`, () => {
+ const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(',');
+
+ beforeEach(() => {
+ mountComponent({ value: { name_regex: invalidString } });
+ });
+
+ it('save btn is disabled', () => {
+ expect(findSaveButton().attributes('disabled')).toBeTruthy();
+ });
+
+ it('nameRegexState is false', () => {
+ expect(wrapper.vm.nameRegexState).toBe(false);
+ });
+ });
+
+ it('if the user did not type validation is null', () => {
+ mountComponent({ value: { name_regex: '' } });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.nameRegexState).toBe(null);
+ expect(findSaveButton().attributes('disabled')).toBeFalsy();
+ });
+ });
+
+ it(`if the user typed and is less than ${NAME_REGEX_LENGTH} state is true`, () => {
+ mountComponent({ value: { name_regex: 'foo' } });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.nameRegexState).toBe(true);
+ });
+ });
+ });
+
+ describe('help text', () => {
+ it('toggleDescriptionText show disabled when settings.enabled is false', () => {
+ mountComponent();
+ const toggleHelpText = findFormGroup('toggle').find('span');
+ expect(toggleHelpText.html()).toContain('disabled');
+ });
+
+ it('toggleDescriptionText show enabled when settings.enabled is true', () => {
+ mountComponent({ value: { enabled: true } });
+ const toggleHelpText = findFormGroup('toggle').find('span');
+ expect(toggleHelpText.html()).toContain('enabled');
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/mock_data.js b/spec/frontend/registry/shared/mock_data.js
index 411363c2c95..411363c2c95 100644
--- a/spec/frontend/registry/settings/mock_data.js
+++ b/spec/frontend/registry/shared/mock_data.js
diff --git a/spec/frontend/releases/detail/components/app_spec.js b/spec/frontend/releases/detail/components/app_spec.js
index fd5239ad44e..894cd3a8f14 100644
--- a/spec/frontend/releases/detail/components/app_spec.js
+++ b/spec/frontend/releases/detail/components/app_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { mount } from '@vue/test-utils';
-import ReleaseDetailApp from '~/releases/detail/components/app';
+import ReleaseDetailApp from '~/releases/detail/components/app.vue';
import { release } from '../../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
diff --git a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
index 13b7c426366..4853d9795b1 100644
--- a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
+++ b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
@@ -4,7 +4,7 @@ import ConfidentialIssueSidebar from '~/sidebar/components/confidential/confiden
import EditForm from '~/sidebar/components/confidential/edit_form.vue';
import SidebarService from '~/sidebar/services/sidebar_service';
import createFlash from '~/flash';
-import RecaptchaModal from '~/vue_shared/components/recaptcha_modal';
+import RecaptchaModal from '~/vue_shared/components/recaptcha_modal.vue';
jest.mock('~/flash');
jest.mock('~/sidebar/services/sidebar_service');
diff --git a/spec/frontend/vue_shared/components/recaptcha_modal_spec.js b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
index 223e7187d99..8ab65efd388 100644
--- a/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
+++ b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { eventHub } from '~/vue_shared/components/recaptcha_eventhub';
-import RecaptchaModal from '~/vue_shared/components/recaptcha_modal';
+import RecaptchaModal from '~/vue_shared/components/recaptcha_modal.vue';
describe('RecaptchaModal', () => {
const recaptchaFormId = 'recaptcha-form';
diff --git a/spec/frontend/vue_shared/components/slot_switch_spec.js b/spec/frontend/vue_shared/components/slot_switch_spec.js
index 71e6087c272..73307b5573f 100644
--- a/spec/frontend/vue_shared/components/slot_switch_spec.js
+++ b/spec/frontend/vue_shared/components/slot_switch_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import SlotSwitch from '~/vue_shared/components/slot_switch';
+import SlotSwitch from '~/vue_shared/components/slot_switch.vue';
describe('SlotSwitch', () => {
const slots = {
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index e918c34ffef..cf8887f9731 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -173,7 +173,7 @@ describe ButtonHelper do
expect(element.attr('data-clipboard-text')).to eq(nil)
expect(element.inner_text).to eq("")
- expect(element.to_html).to include sprite_icon('duplicate')
+ expect(element.to_html).to include sprite_icon('copy-to-clipboard')
end
end
diff --git a/spec/models/concerns/delete_with_limit_spec.rb b/spec/models/concerns/delete_with_limit_spec.rb
new file mode 100644
index 00000000000..52085f970f3
--- /dev/null
+++ b/spec/models/concerns/delete_with_limit_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe DeleteWithLimit do
+ describe '.delete_with_limit' do
+ it 'deletes a limited amount of rows' do
+ create_list(:web_hook_log, 4)
+
+ expect do
+ WebHookLog.delete_with_limit(2)
+ end.to change { WebHookLog.count }.by(-2)
+ end
+ end
+end
diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb
index 56f094ecb48..ce1952b503f 100644
--- a/spec/models/project_services/emails_on_push_service_spec.rb
+++ b/spec/models/project_services/emails_on_push_service_spec.rb
@@ -21,6 +21,22 @@ describe EmailsOnPushService do
end
end
+ context 'when properties is missing branches_to_be_notified' do
+ subject { described_class.new(properties: {}) }
+
+ it 'sets the default value to all' do
+ expect(subject.branches_to_be_notified).to eq('all')
+ end
+ end
+
+ context 'when branches_to_be_notified is already set' do
+ subject { described_class.new(properties: { branches_to_be_notified: 'protected' }) }
+
+ it 'does not overwrite it with the default value' do
+ expect(subject.branches_to_be_notified).to eq('protected')
+ end
+ end
+
context 'project emails' do
let(:push_data) { { object_kind: 'push' } }
let(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 5dc7de0ab8b..628d5533366 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -127,21 +127,6 @@ describe API::Services do
expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
end
- it "returns empty hash or nil values if properties and data fields are empty" do
- # deprecated services are not valid for update
- initialized_service.update_attribute(:properties, {})
-
- if initialized_service.data_fields_present?
- initialized_service.data_fields.destroy
- initialized_service.reload
- end
-
- get api("/projects/#{project.id}/services/#{dashed_service}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['properties'].values.compact).to be_empty
- end
-
it "returns error when authenticated but not a project owner" do
project.add_developer(user2)
get api("/projects/#{project.id}/services/#{dashed_service}", user2)