Skip to content
Snippets Groups Projects
Commit d91f5211 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent c859c3bf
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -17,10 +17,10 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
expect(settings_block).to have_text 'Container Registry tag expiration policy'
end
 
it 'Save expiration policy submit the form', :js do
it 'Save expiration policy submit the form' do
within '#js-registry-policies' do
within '.card-body' do
click_button(class: 'gl-toggle')
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')
Loading
Loading
@@ -30,8 +30,8 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
expect(submit_button).not_to be_disabled
submit_button.click
end
flash_text = find('.flash-text')
expect(flash_text).to have_content('Expiration policy successfully saved.')
toast = find('.gl-toast')
expect(toast).to have_content('Expiration policy successfully saved.')
end
end
end
Loading
Loading
@@ -161,17 +161,20 @@ exports[`Settings Form renders 1`] = `
class="mr-2 d-block"
type="reset"
>
Cancel
</glbutton-stub>
<glbutton-stub
class="d-block"
class="d-flex justify-content-center align-items-center js-no-auto-disable"
type="submit"
variant="success"
>
Save expiration policy
<!---->
</glbutton-stub>
</div>
</div>
Loading
Loading
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import component from '~/registry/settings/components/registry_settings_app.vue';
import { createStore } from '~/registry/settings/store/';
const localVue = createLocalVue();
localVue.use(Vuex);
import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/settings/constants';
 
describe('Registry Settings App', () => {
let wrapper;
let store;
let fetchSpy;
 
const findSettingsComponent = () => wrapper.find({ ref: 'settings-form' });
const findLoadingComponent = () => wrapper.find({ ref: 'loading-icon' });
 
const mountComponent = (options = {}) => {
fetchSpy = jest.fn();
const mountComponent = ({ dispatchMock } = {}) => {
store = createStore();
const dispatchSpy = jest.spyOn(store, 'dispatch');
if (dispatchMock) {
dispatchSpy[dispatchMock]();
}
wrapper = shallowMount(component, {
store,
methods: {
fetchSettings: fetchSpy,
mocks: {
$toast: {
show: jest.fn(),
},
},
...options,
store,
});
};
 
beforeEach(() => {
store = createStore();
mountComponent();
});
afterEach(() => {
wrapper.destroy();
});
 
it('renders', () => {
mountComponent({ dispatchMock: 'mockResolvedValue' });
expect(wrapper.element).toMatchSnapshot();
});
 
it('call the store function to load the data on mount', () => {
expect(fetchSpy).toHaveBeenCalled();
mountComponent({ dispatchMock: 'mockResolvedValue' });
expect(store.dispatch).toHaveBeenCalledWith('fetchSettings');
});
 
it('renders a loader if isLoading is true', () => {
store.dispatch('toggleLoading');
return wrapper.vm.$nextTick().then(() => {
expect(findLoadingComponent().exists()).toBe(true);
expect(findSettingsComponent().exists()).toBe(false);
});
it('show a toast if fetchSettings fails', () => {
mountComponent({ dispatchMock: 'mockRejectedValue' });
return wrapper.vm.$nextTick().then(() =>
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(FETCH_SETTINGS_ERROR_MESSAGE, {
type: 'error',
}),
);
});
it('renders the setting form', () => {
mountComponent({ dispatchMock: 'mockResolvedValue' });
expect(findSettingsComponent().exists()).toBe(true);
});
});
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import stubChildren from 'helpers/stub_children';
import component from '~/registry/settings/components/settings_form.vue';
import { createStore } from '~/registry/settings/store/';
import { NAME_REGEX_LENGTH } from '~/registry/settings/constants';
import {
NAME_REGEX_LENGTH,
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
} from '~/registry/settings/constants';
import { stringifiedFormOptions } from '../mock_data';
 
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Settings Form', () => {
let wrapper;
let store;
let saveSpy;
let resetSpy;
let dispatchSpy;
const FORM_ELEMENTS_ID_PREFIX = '#expiration-policy';
const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
 
const findFormGroup = name => wrapper.find(`#expiration-policy-${name}-group`);
const findFormElements = (name, father = wrapper) => father.find(`#expiration-policy-${name}`);
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 = {}) => {
saveSpy = jest.fn();
resetSpy = jest.fn();
wrapper = mount(component, {
stubs: {
...stubChildren(component),
GlCard: false,
GlLoadingIcon,
},
store,
methods: {
saveSettings: saveSpy,
resetSettings: resetSpy,
mocks: {
$toast: {
show: jest.fn(),
},
},
store,
...options,
});
};
Loading
Loading
@@ -41,6 +46,7 @@ describe('Settings Form', () => {
beforeEach(() => {
store = createStore();
store.dispatch('setInitialState', stringifiedFormOptions);
dispatchSpy = jest.spyOn(store, 'dispatch');
mountComponent();
});
 
Loading
Loading
@@ -59,48 +65,53 @@ describe('Settings Form', () => {
${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
`('$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);
});
`(
`${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-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-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 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 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} 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);
});
});
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', () => {
let form;
Loading
Loading
@@ -112,17 +123,79 @@ describe('Settings Form', () => {
});
 
it('form reset event call the appropriate function', () => {
dispatchSpy.mockReturnValue();
form.trigger('reset');
expect(resetSpy).toHaveBeenCalled();
// expect.any(Object) is necessary because the event payload is passed to the function
expect(dispatchSpy).toHaveBeenCalledWith('resetSettings', expect.any(Object));
});
 
it('save has type submit', () => {
expect(findSaveButton().attributes('type')).toBe('submit');
});
 
it('form submit event call the appropriate function', () => {
form.trigger('submit');
expect(saveSpy).toHaveBeenCalled();
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');
expect(dispatchSpy).toHaveBeenCalledWith('saveSettings');
});
it('show a success toast when submit succeed', () => {
dispatchSpy.mockResolvedValue();
form.trigger('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE, {
type: 'success',
});
});
});
it('show an error toast when submit fails', () => {
dispatchSpy.mockRejectedValue();
form.trigger('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE, {
type: 'error',
});
});
});
});
});
 
Loading
Loading
@@ -160,7 +233,7 @@ describe('Settings Form', () => {
it('toggleDescriptionText text reflects enabled property', () => {
const toggleHelpText = findFormGroup('toggle').find('span');
expect(toggleHelpText.html()).toContain('disabled');
wrapper.vm.enabled = true;
wrapper.setData({ enabled: true });
return wrapper.vm.$nextTick().then(() => {
expect(toggleHelpText.html()).toContain('enabled');
});
Loading
Loading
import Api from '~/api';
import createFlash from '~/flash';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/registry/settings/store/actions';
import * as types from '~/registry/settings/store/mutation_types';
import {
UPDATE_SETTINGS_ERROR_MESSAGE,
FETCH_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
} from '~/registry/settings/constants';
jest.mock('~/flash');
 
describe('Actions Registry Store', () => {
describe.each`
Loading
Loading
@@ -25,19 +17,6 @@ describe('Actions Registry Store', () => {
});
});
 
describe.each`
actionName | message
${'receiveSettingsError'} | ${FETCH_SETTINGS_ERROR_MESSAGE}
${'updateSettingsError'} | ${UPDATE_SETTINGS_ERROR_MESSAGE}
`('%s action', ({ actionName, message }) => {
it(`should call createFlash with ${message}`, done => {
testAction(actions[actionName], null, null, [], [], () => {
expect(createFlash).toHaveBeenCalledWith(message);
done();
});
});
});
describe('fetchSettings', () => {
const state = {
projectId: 'bar',
Loading
Loading
@@ -64,18 +43,6 @@ describe('Actions Registry Store', () => {
done,
);
});
it('should call receiveSettingsError on error', done => {
Api.project = jest.fn().mockRejectedValue();
testAction(
actions.fetchSettings,
null,
state,
[],
[{ type: 'toggleLoading' }, { type: 'receiveSettingsError' }, { type: 'toggleLoading' }],
done,
);
});
});
 
describe('saveSettings', () => {
Loading
Loading
@@ -102,21 +69,6 @@ describe('Actions Registry Store', () => {
{ type: 'receiveSettingsSuccess', payload: payload.data.container_expiration_policy },
{ type: 'toggleLoading' },
],
() => {
expect(createFlash).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE, 'success');
done();
},
);
});
it('should call receiveSettingsError on error', done => {
Api.updateProject = jest.fn().mockRejectedValue();
testAction(
actions.saveSettings,
null,
state,
[],
[{ type: 'toggleLoading' }, { type: 'updateSettingsError' }, { type: 'toggleLoading' }],
done,
);
});
Loading
Loading
Loading
Loading
@@ -96,10 +96,10 @@ describe Gitlab::Experimentation do
expect(Gitlab::Tracking).to receive(:event).with(
'Team',
'start',
label: nil,
property: 'experimental_group'
property: 'experimental_group',
value: 'team_id'
)
controller.track_experiment_event(:test_experiment, 'start')
controller.track_experiment_event(:test_experiment, 'start', 'team_id')
end
end
 
Loading
Loading
@@ -112,10 +112,10 @@ describe Gitlab::Experimentation do
expect(Gitlab::Tracking).to receive(:event).with(
'Team',
'start',
label: nil,
property: 'control_group'
property: 'control_group',
value: 'team_id'
)
controller.track_experiment_event(:test_experiment, 'start')
controller.track_experiment_event(:test_experiment, 'start', 'team_id')
end
end
end
Loading
Loading
@@ -144,13 +144,13 @@ describe Gitlab::Experimentation do
end
 
it 'pushes the right parameters to gon' do
controller.frontend_experimentation_tracking_data(:test_experiment, 'start')
controller.frontend_experimentation_tracking_data(:test_experiment, 'start', 'team_id')
expect(Gon.tracking_data).to eq(
{
category: 'Team',
action: 'start',
label: nil,
property: 'experimental_group'
property: 'experimental_group',
value: 'team_id'
}
)
end
Loading
Loading
@@ -164,12 +164,23 @@ describe Gitlab::Experimentation do
end
 
it 'pushes the right parameters to gon' do
controller.frontend_experimentation_tracking_data(:test_experiment, 'start', 'team_id')
expect(Gon.tracking_data).to eq(
{
category: 'Team',
action: 'start',
property: 'control_group',
value: 'team_id'
}
)
end
it 'does not send nil value to gon' do
controller.frontend_experimentation_tracking_data(:test_experiment, 'start')
expect(Gon.tracking_data).to eq(
{
category: 'Team',
action: 'start',
label: nil,
property: 'control_group'
}
)
Loading
Loading
Loading
Loading
@@ -49,6 +49,7 @@ describe Gitlab::UsageData do
create(:clusters_applications_runner, :installed, cluster: gcp_cluster)
create(:clusters_applications_knative, :installed, cluster: gcp_cluster)
create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster)
 
create(:grafana_integration, project: projects[0], enabled: true)
create(:grafana_integration, project: projects[1], enabled: true)
Loading
Loading
@@ -149,6 +150,7 @@ describe Gitlab::UsageData do
clusters_applications_runner
clusters_applications_knative
clusters_applications_elastic_stack
clusters_applications_jupyter
in_review_folder
grafana_integrated_projects
groups
Loading
Loading
@@ -242,6 +244,7 @@ describe Gitlab::UsageData do
expect(count_data[:clusters_applications_knative]).to eq(1)
expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
expect(count_data[:grafana_integrated_projects]).to eq(2)
expect(count_data[:clusters_applications_jupyter]).to eq(1)
end
 
it 'works when queries time out' do
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment