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
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/deploy_freeze')
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js92
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js42
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js70
-rw-r--r--spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js98
-rw-r--r--spec/frontend/deploy_freeze/store/actions_spec.js123
-rw-r--r--spec/frontend/deploy_freeze/store/mutations_spec.js72
6 files changed, 497 insertions, 0 deletions
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
new file mode 100644
index 00000000000..9ecf6bf375b
--- /dev/null
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
@@ -0,0 +1,92 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlButton, GlModal } from '@gitlab/ui';
+import DeployFreezeModal from '~/deploy_freeze/components/deploy_freeze_modal.vue';
+import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue';
+import createStore from '~/deploy_freeze/store';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Deploy freeze modal', () => {
+ let wrapper;
+ let store;
+ const freezePeriodsFixture = getJSONFixture('/api/freeze-periods/freeze_periods.json');
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ beforeEach(() => {
+ store = createStore({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ wrapper = shallowMount(DeployFreezeModal, {
+ attachToDocument: true,
+ stubs: {
+ GlModal,
+ },
+ localVue,
+ store,
+ });
+ });
+
+ const findModal = () => wrapper.find(GlModal);
+ const addDeployFreezeButton = () =>
+ findModal()
+ .findAll(GlButton)
+ .at(1);
+
+ const setInput = (freezeStartCron, freezeEndCron, selectedTimezone) => {
+ store.state.freezeStartCron = freezeStartCron;
+ store.state.freezeEndCron = freezeEndCron;
+ store.state.selectedTimezone = selectedTimezone;
+
+ wrapper.find('#deploy-freeze-start').trigger('input');
+ wrapper.find('#deploy-freeze-end').trigger('input');
+ wrapper.find(TimezoneDropdown).trigger('input');
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('Basic interactions', () => {
+ it('button is disabled when freeze period is invalid', () => {
+ expect(addDeployFreezeButton().attributes('disabled')).toBeTruthy();
+ });
+ });
+
+ describe('Adding a new deploy freeze', () => {
+ beforeEach(() => {
+ const { freeze_start, freeze_end, cron_timezone } = freezePeriodsFixture[0];
+ setInput(freeze_start, freeze_end, cron_timezone);
+ });
+
+ it('button is enabled when valid freeze period settings are present', () => {
+ expect(addDeployFreezeButton().attributes('disabled')).toBeUndefined();
+ });
+ });
+
+ describe('Validations', () => {
+ describe('when the cron state is invalid', () => {
+ beforeEach(() => {
+ setInput('invalid cron', 'invalid cron', 'invalid timezone');
+ });
+
+ it('disables the add deploy freeze button', () => {
+ expect(addDeployFreezeButton().attributes('disabled')).toBeTruthy();
+ });
+ });
+
+ describe('when the cron state is valid', () => {
+ beforeEach(() => {
+ const { freeze_start, freeze_end, cron_timezone } = freezePeriodsFixture[0];
+ setInput(freeze_start, freeze_end, cron_timezone);
+ });
+
+ it('does not disable the submit button', () => {
+ expect(addDeployFreezeButton().attributes('disabled')).toBeFalsy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js
new file mode 100644
index 00000000000..d40df7de7d1
--- /dev/null
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_settings_spec.js
@@ -0,0 +1,42 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import DeployFreezeSettings from '~/deploy_freeze/components/deploy_freeze_settings.vue';
+import DeployFreezeTable from '~/deploy_freeze/components/deploy_freeze_table.vue';
+import DeployFreezeModal from '~/deploy_freeze/components/deploy_freeze_modal.vue';
+import createStore from '~/deploy_freeze/store';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Deploy freeze settings', () => {
+ let wrapper;
+ let store;
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ beforeEach(() => {
+ store = createStore({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ wrapper = shallowMount(DeployFreezeSettings, {
+ localVue,
+ store,
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('Deploy freeze table contains components', () => {
+ it('contains deploy freeze table', () => {
+ expect(wrapper.find(DeployFreezeTable).exists()).toBe(true);
+ });
+
+ it('contains deploy freeze modal', () => {
+ expect(wrapper.find(DeployFreezeModal).exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
new file mode 100644
index 00000000000..383ffa90b22
--- /dev/null
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
@@ -0,0 +1,70 @@
+import Vuex from 'vuex';
+import { createLocalVue, mount } from '@vue/test-utils';
+import DeployFreezeTable from '~/deploy_freeze/components/deploy_freeze_table.vue';
+import createStore from '~/deploy_freeze/store';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Deploy freeze table', () => {
+ let wrapper;
+ let store;
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ const createComponent = () => {
+ store = createStore({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ wrapper = mount(DeployFreezeTable, {
+ attachToDocument: true,
+ localVue,
+ store,
+ });
+ };
+
+ const findEmptyFreezePeriods = () => wrapper.find('[data-testid="empty-freeze-periods"]');
+ const findAddDeployFreezeButton = () => wrapper.find('[data-testid="add-deploy-freeze"]');
+ const findDeployFreezeTable = () => wrapper.find('[data-testid="deploy-freeze-table"]');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('dispatches fetchFreezePeriods when mounted', () => {
+ expect(store.dispatch).toHaveBeenCalledWith('fetchFreezePeriods');
+ });
+
+ describe('Renders correct data', () => {
+ it('displays empty', () => {
+ expect(findEmptyFreezePeriods().exists()).toBe(true);
+ expect(findEmptyFreezePeriods().text()).toBe(
+ 'No deploy freezes exist for this project. To add one, click Add deploy freeze',
+ );
+ });
+
+ it('displays data', () => {
+ const freezePeriodsFixture = getJSONFixture('/api/freeze-periods/freeze_periods.json');
+ store.state.freezePeriods = freezePeriodsFixture;
+
+ return wrapper.vm.$nextTick(() => {
+ const tableRows = findDeployFreezeTable().findAll('tbody tr');
+ expect(tableRows.length).toBe(freezePeriodsFixture.length);
+ expect(findEmptyFreezePeriods().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Table click actions', () => {
+ it('displays add deploy freeze button', () => {
+ expect(findAddDeployFreezeButton().exists()).toBe(true);
+ expect(findAddDeployFreezeButton().text()).toBe('Add deploy freeze');
+ });
+ });
+});
diff --git a/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js
new file mode 100644
index 00000000000..644cd0b5f27
--- /dev/null
+++ b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js
@@ -0,0 +1,98 @@
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlDeprecatedDropdownItem, GlNewDropdown } from '@gitlab/ui';
+import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue';
+import createStore from '~/deploy_freeze/store';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Deploy freeze timezone dropdown', () => {
+ let wrapper;
+ let store;
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ const createComponent = (searchTerm, selectedTimezone) => {
+ store = createStore({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ wrapper = shallowMount(TimezoneDropdown, {
+ store,
+ localVue,
+ propsData: {
+ value: selectedTimezone,
+ timezoneData: timezoneDataFixture,
+ },
+ });
+
+ wrapper.setData({ searchTerm });
+ };
+
+ const findAllDropdownItems = () => wrapper.findAll(GlDeprecatedDropdownItem);
+ const findDropdownItemByIndex = index => wrapper.findAll(GlDeprecatedDropdownItem).at(index);
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('No time zones found', () => {
+ beforeEach(() => {
+ createComponent('UTC timezone');
+ });
+
+ it('renders empty results message', () => {
+ expect(findDropdownItemByIndex(0).text()).toBe('No matching results');
+ });
+ });
+
+ describe('Search term is empty', () => {
+ beforeEach(() => {
+ createComponent('');
+ });
+
+ it('renders all timezones when search term is empty', () => {
+ expect(findAllDropdownItems()).toHaveLength(timezoneDataFixture.length);
+ });
+ });
+
+ describe('Time zones found', () => {
+ beforeEach(() => {
+ createComponent('Alaska');
+ });
+
+ it('renders only the time zone searched for', () => {
+ expect(findAllDropdownItems()).toHaveLength(1);
+ expect(findDropdownItemByIndex(0).text()).toBe('[UTC -8] Alaska');
+ });
+
+ it('should not display empty results message', () => {
+ expect(wrapper.find('[data-testid="noMatchingResults"]').exists()).toBe(false);
+ });
+
+ describe('Custom events', () => {
+ it('should emit input if a time zone is clicked', () => {
+ findDropdownItemByIndex(0).vm.$emit('click');
+ expect(wrapper.emitted('input')).toEqual([
+ [
+ {
+ formattedTimezone: '[UTC -8] Alaska',
+ identifier: 'America/Juneau',
+ },
+ ],
+ ]);
+ });
+ });
+ });
+
+ describe('Selected time zone', () => {
+ beforeEach(() => {
+ createComponent('', 'Alaska');
+ });
+
+ it('renders selected time zone as dropdown label', () => {
+ expect(wrapper.find(GlNewDropdown).vm.text).toBe('Alaska');
+ });
+ });
+});
diff --git a/spec/frontend/deploy_freeze/store/actions_spec.js b/spec/frontend/deploy_freeze/store/actions_spec.js
new file mode 100644
index 00000000000..97f94cdbf5e
--- /dev/null
+++ b/spec/frontend/deploy_freeze/store/actions_spec.js
@@ -0,0 +1,123 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import Api from '~/api';
+import axios from '~/lib/utils/axios_utils';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import getInitialState from '~/deploy_freeze/store/state';
+import * as actions from '~/deploy_freeze/store/actions';
+import * as types from '~/deploy_freeze/store/mutation_types';
+
+jest.mock('~/api.js');
+jest.mock('~/flash.js');
+
+describe('deploy freeze store actions', () => {
+ let mock;
+ let state;
+ const freezePeriodsFixture = getJSONFixture('/api/freeze-periods/freeze_periods.json');
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ state = getInitialState({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ Api.freezePeriods.mockResolvedValue({ data: freezePeriodsFixture });
+ Api.createFreezePeriod.mockResolvedValue();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('setSelectedTimezone', () => {
+ it('commits SET_SELECTED_TIMEZONE mutation', () => {
+ testAction(actions.setSelectedTimezone, {}, {}, [
+ {
+ payload: {},
+ type: types.SET_SELECTED_TIMEZONE,
+ },
+ ]);
+ });
+ });
+
+ describe('setFreezeStartCron', () => {
+ it('commits SET_FREEZE_START_CRON mutation', () => {
+ testAction(actions.setFreezeStartCron, {}, {}, [
+ {
+ type: types.SET_FREEZE_START_CRON,
+ },
+ ]);
+ });
+ });
+
+ describe('setFreezeEndCron', () => {
+ it('commits SET_FREEZE_END_CRON mutation', () => {
+ testAction(actions.setFreezeEndCron, {}, {}, [
+ {
+ type: types.SET_FREEZE_END_CRON,
+ },
+ ]);
+ });
+ });
+
+ describe('addFreezePeriod', () => {
+ it('dispatch correct actions on adding a freeze period', () => {
+ testAction(
+ actions.addFreezePeriod,
+ {},
+ state,
+ [{ type: 'RESET_MODAL' }],
+ [
+ { type: 'requestAddFreezePeriod' },
+ { type: 'receiveAddFreezePeriodSuccess' },
+ { type: 'fetchFreezePeriods' },
+ ],
+ );
+ });
+
+ it('should show flash error and set error in state on add failure', () => {
+ Api.createFreezePeriod.mockRejectedValue();
+
+ testAction(
+ actions.addFreezePeriod,
+ {},
+ state,
+ [],
+ [{ type: 'requestAddFreezePeriod' }, { type: 'receiveAddFreezePeriodError' }],
+ () => expect(createFlash).toHaveBeenCalled(),
+ );
+ });
+ });
+
+ describe('fetchFreezePeriods', () => {
+ it('dispatch correct actions on fetchFreezePeriods', () => {
+ testAction(
+ actions.fetchFreezePeriods,
+ {},
+ state,
+ [
+ { type: types.REQUEST_FREEZE_PERIODS },
+ { type: types.RECEIVE_FREEZE_PERIODS_SUCCESS, payload: freezePeriodsFixture },
+ ],
+ [],
+ );
+ });
+
+ it('should show flash error and set error in state on fetch variables failure', () => {
+ Api.freezePeriods.mockRejectedValue();
+
+ testAction(
+ actions.fetchFreezePeriods,
+ {},
+ state,
+ [{ type: types.REQUEST_FREEZE_PERIODS }],
+ [],
+ () =>
+ expect(createFlash).toHaveBeenCalledWith(
+ 'There was an error fetching the deploy freezes.',
+ ),
+ );
+ });
+ });
+});
diff --git a/spec/frontend/deploy_freeze/store/mutations_spec.js b/spec/frontend/deploy_freeze/store/mutations_spec.js
new file mode 100644
index 00000000000..0453e037e15
--- /dev/null
+++ b/spec/frontend/deploy_freeze/store/mutations_spec.js
@@ -0,0 +1,72 @@
+import state from '~/deploy_freeze/store/state';
+import mutations from '~/deploy_freeze/store/mutations';
+import * as types from '~/deploy_freeze/store/mutation_types';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+describe('Deploy freeze mutations', () => {
+ let stateCopy;
+ const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
+
+ beforeEach(() => {
+ stateCopy = state({
+ projectId: '8',
+ timezoneData: timezoneDataFixture,
+ });
+ });
+
+ describe('RESET_MODAL', () => {
+ it('should reset modal state', () => {
+ mutations[types.RESET_MODAL](stateCopy);
+
+ expect(stateCopy.freezeStartCron).toBe('');
+ expect(stateCopy.freezeEndCron).toBe('');
+ expect(stateCopy.selectedTimezone).toBe('');
+ expect(stateCopy.selectedTimezoneIdentifier).toBe('');
+ });
+ });
+
+ describe('RECEIVE_FREEZE_PERIODS_SUCCESS', () => {
+ it('should set freeze periods and format timezones from identifiers to names', () => {
+ const timezoneNames = ['Berlin', 'UTC', 'Eastern Time (US & Canada)'];
+ const freezePeriodsFixture = getJSONFixture('/api/freeze-periods/freeze_periods.json');
+
+ mutations[types.RECEIVE_FREEZE_PERIODS_SUCCESS](stateCopy, freezePeriodsFixture);
+
+ const expectedFreezePeriods = freezePeriodsFixture.map((freezePeriod, index) => ({
+ ...convertObjectPropsToCamelCase(freezePeriod),
+ cronTimezone: timezoneNames[index],
+ }));
+
+ expect(stateCopy.freezePeriods).toMatchObject(expectedFreezePeriods);
+ });
+ });
+
+ describe('SET_SELECTED_TIMEZONE', () => {
+ it('should set the cron timezone', () => {
+ const timezone = {
+ formattedTimezone: '[UTC -7] Pacific Time (US & Canada)',
+ identifier: 'America/Los_Angeles',
+ };
+ mutations[types.SET_SELECTED_TIMEZONE](stateCopy, timezone);
+
+ expect(stateCopy.selectedTimezone).toEqual(timezone.formattedTimezone);
+ expect(stateCopy.selectedTimezoneIdentifier).toEqual(timezone.identifier);
+ });
+ });
+
+ describe('SET_FREEZE_START_CRON', () => {
+ it('should set freezeStartCron', () => {
+ mutations[types.SET_FREEZE_START_CRON](stateCopy, '5 0 * 8 *');
+
+ expect(stateCopy.freezeStartCron).toBe('5 0 * 8 *');
+ });
+ });
+
+ describe('SET_FREEZE_ENDT_CRON', () => {
+ it('should set freezeEndCron', () => {
+ mutations[types.SET_FREEZE_END_CRON](stateCopy, '5 0 * 8 *');
+
+ expect(stateCopy.freezeEndCron).toBe('5 0 * 8 *');
+ });
+ });
+});