diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-03 09:08:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-03 09:08:42 +0000 |
commit | f14507e586a7f75f0fb71a1d8468b7361be860d4 (patch) | |
tree | a8aa547b517a7ae5626c902bfb558c1fc5386c4e /spec | |
parent | f4d27d532e3abeecd1caffeb3a56e698ae982e5b (diff) | |
download | gitlab-ce-f14507e586a7f75f0fb71a1d8468b7361be860d4.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
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) |