Commit d333bec4 authored by Paul Slaughter's avatar Paul Slaughter

Remove unused environments/ modules

parent 25b1d1d1
<script>
import { GlBadge, GlButton, GlModalDirective, GlTab, GlTabs } from '@gitlab/ui';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import EnvironmentsPaginationApiMixin from '../mixins/environments_pagination_api_mixin';
import ConfirmRollbackModal from './confirm_rollback_modal.vue';
import DeleteEnvironmentModal from './delete_environment_modal.vue';
import emptyState from './empty_state.vue';
import EnableReviewAppModal from './enable_review_app_modal.vue';
import StopEnvironmentModal from './stop_environment_modal.vue';
export default {
i18n: {
newEnvironmentButtonLabel: s__('Environments|New environment'),
reviewAppButtonLabel: s__('Environments|Enable review app'),
},
modal: {
id: 'enable-review-app-info',
},
components: {
ConfirmRollbackModal,
emptyState,
EnableReviewAppModal,
GlBadge,
GlButton,
GlTab,
GlTabs,
StopEnvironmentModal,
DeleteEnvironmentModal,
},
directives: {
'gl-modal': GlModalDirective,
},
mixins: [EnvironmentsPaginationApiMixin, environmentsMixin],
props: {
endpoint: {
type: String,
required: true,
},
canCreateEnvironment: {
type: Boolean,
required: true,
},
newEnvironmentPath: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
},
created() {
eventHub.$on('toggleFolder', this.toggleFolder);
eventHub.$on('toggleDeployBoard', this.toggleDeployBoard);
},
beforeDestroy() {
// eslint-disable-next-line @gitlab/no-global-event-off
eventHub.$off('toggleFolder');
// eslint-disable-next-line @gitlab/no-global-event-off
eventHub.$off('toggleDeployBoard');
},
methods: {
toggleDeployBoard(model) {
this.store.toggleDeployBoard(model.id);
},
toggleFolder(folder) {
this.store.toggleFolder(folder);
if (!folder.isOpen) {
this.fetchChildEnvironments(folder, true);
}
},
fetchChildEnvironments(folder, showLoader = false) {
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
this.service
.getFolderContent(folder.folder_path, folder.state)
.then((response) => this.store.setfolderContent(folder, response.data.environments))
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
.catch(() => {
createFlash({
message: s__('Environments|An error occurred while fetching the environments.'),
});
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
});
},
successCallback(resp) {
this.saveData(resp);
// We need to verify if any folder is open to also update it
const openFolders = this.store.getOpenFolders();
if (openFolders.length) {
openFolders.forEach((folder) => this.fetchChildEnvironments(folder));
}
},
},
};
</script>
<template>
<div class="environments-section">
<stop-environment-modal :environment="environmentInStopModal" />
<delete-environment-modal :environment="environmentInDeleteModal" />
<confirm-rollback-modal :environment="environmentInRollbackModal" />
<div class="gl-w-full">
<div class="gl-display-flex gl-flex-direction-column gl-mt-3 gl-md-display-none!">
<gl-button
v-if="state.reviewAppDetails.can_setup_review_app"
v-gl-modal="$options.modal.id"
data-testid="enable-review-app"
variant="info"
category="secondary"
type="button"
class="gl-mb-3 gl-flex-grow-1"
>{{ $options.i18n.reviewAppButtonLabel }}</gl-button
>
<gl-button
v-if="canCreateEnvironment"
:href="newEnvironmentPath"
data-testid="new-environment"
category="primary"
variant="confirm"
>{{ $options.i18n.newEnvironmentButtonLabel }}</gl-button
>
</div>
<gl-tabs :value="activeTab" content-class="gl-display-none">
<gl-tab
v-for="(tab, idx) in tabs"
:key="idx"
:title-item-class="`js-environments-tab-${tab.scope}`"
@click="onChangeTab(tab.scope)"
>
<template #title>
<span>{{ tab.name }}</span>
<gl-badge size="sm" class="gl-tab-counter-badge">{{ tab.count }}</gl-badge>
</template>
</gl-tab>
<template #tabs-end>
<div
class="gl-display-none gl-md-display-flex gl-lg-align-items-center gl-lg-flex-direction-row gl-lg-flex-fill-1 gl-lg-justify-content-end gl-lg-mt-0"
>
<gl-button
v-if="state.reviewAppDetails.can_setup_review_app"
v-gl-modal="$options.modal.id"
data-testid="enable-review-app"
variant="info"
category="secondary"
type="button"
class="gl-mb-3 gl-lg-mr-3 gl-lg-mb-0"
>{{ $options.i18n.reviewAppButtonLabel }}</gl-button
>
<gl-button
v-if="canCreateEnvironment"
:href="newEnvironmentPath"
data-testid="new-environment"
category="primary"
variant="confirm"
>{{ $options.i18n.newEnvironmentButtonLabel }}</gl-button
>
</div>
</template>
</gl-tabs>
<container
:is-loading="isLoading"
:environments="state.environments"
:pagination="state.paginationInformation"
@onChangePage="onChangePage"
>
<template v-if="!isLoading && state.environments.length === 0" #empty-state>
<empty-state :help-path="helpPagePath" />
</template>
</container>
<enable-review-app-modal
v-if="state.reviewAppDetails.can_setup_review_app"
:modal-id="$options.modal.id"
data-testid="enable-review-app-modal"
/>
</div>
</div>
</template>
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate';
import environmentsComponent from './components/environments_app.vue';
Vue.use(Translate);
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default (el) => {
if (el) {
return new Vue({
el,
components: {
environmentsComponent,
},
apolloProvider,
provide: {
projectPath: el.dataset.projectPath,
projectId: el.dataset.projectId,
defaultBranchName: el.dataset.defaultBranchName,
},
data() {
const environmentsData = el.dataset;
return {
endpoint: environmentsData.environmentsDataEndpoint,
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
canCreateEnvironment: parseBoolean(environmentsData.canCreateEnvironment),
};
},
render(createElement) {
return createElement('environments-component', {
props: {
endpoint: this.endpoint,
newEnvironmentPath: this.newEnvironmentPath,
helpPagePath: this.helpPagePath,
canCreateEnvironment: this.canCreateEnvironment,
},
});
},
});
}
return null;
};
import initEnvironments from '~/environments/';
import initNewEnvironments from '~/environments/new_index';
let el = document.getElementById('environments-list-view');
const el = document.getElementById('environments-table');
if (el) {
initEnvironments(el);
} else {
el = document.getElementById('environments-table');
initNewEnvironments(el);
}
initNewEnvironments(el);
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import DeployBoard from '~/environments/components/deploy_board.vue';
import EnvironmentsComponent from '~/environments/components/environments_app.vue';
import axios from '~/lib/utils/axios_utils';
import { environment } from './mock_data';
describe('Environment', () => {
let mock;
let wrapper;
const mockData = {
canCreateEnvironment: true,
endpoint: 'environments.json',
helpCanaryDeploymentsPath: 'help/canary-deployments',
helpPagePath: 'help',
lockPromotionSvgPath: '/assets/illustrations/lock-promotion.svg',
newEnvironmentPath: 'environments/new',
userCalloutsPath: '/callouts',
};
const createWrapper = () => {
wrapper = mount(EnvironmentsComponent, { propsData: mockData });
return axios.waitForAll();
};
const mockRequest = (environmentList) => {
mock.onGet(mockData.endpoint).reply(
200,
{
environments: environmentList,
stopped_count: 1,
available_count: 0,
},
{
'X-nExt-pAge': '2',
'x-page': '1',
'X-Per-Page': '1',
'X-Prev-Page': '',
'X-TOTAL': '37',
'X-Total-Pages': '2',
},
);
};
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
mock.restore();
});
describe('with paginated environments', () => {
beforeEach(() => {
mockRequest([environment]);
return createWrapper();
});
describe('deploy boards', () => {
beforeEach(() => {
const deployEnvironment = {
...environment,
rollout_status: {
status: 'found',
},
};
mockRequest([environment, deployEnvironment]);
return createWrapper();
});
it('should render deploy boards', () => {
expect(wrapper.findComponent(DeployBoard).exists()).toBe(true);
});
it('should render arrow to open deploy boards', () => {
expect(wrapper.find('.deploy-board-icon [data-testid="chevron-down-icon"]').exists()).toBe(
true,
);
});
});
});
});
import { GlTabs } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import Container from '~/environments/components/container.vue';
import DeployBoard from '~/environments/components/deploy_board.vue';
import EmptyState from '~/environments/components/empty_state.vue';
import EnableReviewAppModal from '~/environments/components/enable_review_app_modal.vue';
import EnvironmentsApp from '~/environments/components/environments_app.vue';
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { environment, folder } from './mock_data';
describe('Environment', () => {
let mock;
let wrapper;
const mockData = {
endpoint: 'environments.json',
canCreateEnvironment: true,
newEnvironmentPath: 'environments/new',
helpPagePath: 'help',
userCalloutsPath: '/callouts',
lockPromotionSvgPath: '/assets/illustrations/lock-promotion.svg',
helpCanaryDeploymentsPath: 'help/canary-deployments',
};
const mockRequest = (response, body) => {
mock.onGet(mockData.endpoint).reply(response, body, {
'X-nExt-pAge': '2',
'x-page': '1',
'X-Per-Page': '1',
'X-Prev-Page': '',
'X-TOTAL': '37',
'X-Total-Pages': '2',
});
};
const createWrapper = (shallow = false, props = {}) => {
const fn = shallow ? shallowMount : mount;
wrapper = extendedWrapper(fn(EnvironmentsApp, { propsData: { ...mockData, ...props } }));
return axios.waitForAll();
};
const findEnableReviewAppButton = () => wrapper.findByTestId('enable-review-app');
const findEnableReviewAppModal = () => wrapper.findAll(EnableReviewAppModal);
const findNewEnvironmentButton = () => wrapper.findByTestId('new-environment');
const findEnvironmentsTabAvailable = () => wrapper.find('.js-environments-tab-available > a');
const findEnvironmentsTabStopped = () => wrapper.find('.js-environments-tab-stopped > a');
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
mock.restore();
});
describe('successful request', () => {
describe('without environments', () => {
beforeEach(() => {
mockRequest(200, { environments: [] });
return createWrapper();
});
it('should render the empty state', () => {
expect(wrapper.find(EmptyState).exists()).toBe(true);
});
});
describe('with paginated environments', () => {
const environmentList = [environment];
beforeEach(() => {
mockRequest(200, {
environments: environmentList,
stopped_count: 1,
available_count: 0,
});
return createWrapper();
});
it('should render a container table with environments', () => {
const containerTable = wrapper.find(Container);
expect(containerTable.exists()).toBe(true);
expect(containerTable.props('environments').length).toEqual(environmentList.length);
expect(containerTable.find('.environment-name').text()).toEqual(environmentList[0].name);
});
describe('pagination', () => {
it('should render pagination', () => {
expect(wrapper.findAll('.gl-pagination li').length).toEqual(9);
});
it('should make an API request when page is clicked', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
wrapper.find('.gl-pagination li:nth-child(3) .page-link').trigger('click');
expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
scope: 'available',
page: '2',
nested: true,
});
});
it('should make an API request when using tabs', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
findEnvironmentsTabStopped().trigger('click');
expect(wrapper.vm.updateContent).toHaveBeenCalledWith({
scope: 'stopped',
page: '1',
nested: true,
});
});
it('should not make the same API request when clicking on the current scope tab', () => {
// component starts at available
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
findEnvironmentsTabAvailable().trigger('click');
expect(wrapper.vm.updateContent).toHaveBeenCalledTimes(0);
});
});
describe('deploy boards', () => {
beforeEach(() => {
const deployEnvironment = {
...environment,
rollout_status: {
status: 'found',
},
};
mockRequest(200, {
environments: [deployEnvironment],
stopped_count: 1,
available_count: 0,
});
return createWrapper();
});
it('should render deploy boards', () => {
expect(wrapper.find(DeployBoard).exists()).toBe(true);
});
it('should render arrow to open deploy boards', () => {
expect(
wrapper.find('.deploy-board-icon [data-testid="chevron-down-icon"]').exists(),
).toBe(true);
});
});
});
});
describe('unsuccessful request', () => {
beforeEach(() => {
mockRequest(500, {});
return createWrapper();
});
it('should render empty state', () => {
expect(wrapper.find(EmptyState).exists()).toBe(true);
});
});
describe('expandable folders', () => {
beforeEach(() => {
mockRequest(200, {
environments: [folder],
stopped_count: 1,
available_count: 0,
});
mock.onGet(environment.folder_path).reply(200, { environments: [environment] });
return createWrapper().then(() => {
// open folder
wrapper.find('.folder-name').trigger('click');
return axios.waitForAll();
});
});
it('should open a closed folder', () => {
expect(wrapper.find('.folder-icon[data-testid="chevron-right-icon"]').exists()).toBe(false);
});
it('should close an opened folder', async () => {
expect(wrapper.find('.folder-icon[data-testid="chevron-down-icon"]').exists()).toBe(true);
// close folder
wrapper.find('.folder-name').trigger('click');
await nextTick();
expect(wrapper.find('.folder-icon[data-testid="chevron-down-icon"]').exists()).toBe(false);
});
it('should show children environments', () => {
expect(wrapper.findAll('.js-child-row').length).toEqual(1);
});
it('should show a button to show all environments', () => {
expect(wrapper.find('.text-center > a.btn').text()).toContain('Show all');
});
});
describe('environment button', () => {
describe('when user can create environment', () => {
beforeEach(() => {
mockRequest(200, { environments: [] });
return createWrapper(true);
});
it('should render', () => {
expect(findNewEnvironmentButton().exists()).toBe(true);
});
});
describe('when user can not create environment', () => {
beforeEach(() => {
mockRequest(200, { environments: [] });
return createWrapper(true, { ...mockData, canCreateEnvironment: false });
});
it('should not render', () => {
expect(findNewEnvironmentButton().exists()).toBe(false);
});
});
});
describe('review app modal', () => {
describe('when it is not possible to enable a review app', () => {
beforeEach(() => {
mockRequest(200, { environments: [] });
return createWrapper(true);
});
it('should not render the enable review app button', () => {
expect(findEnableReviewAppButton().exists()).toBe(false);
});
it('should not render a review app modal', () => {
const modal = findEnableReviewAppModal();
expect(modal).toHaveLength(0);
expect(modal.exists()).toBe(false);
});
});
describe('when it is possible to enable a review app', () => {
beforeEach(() => {
mockRequest(200, { environments: [], review_app: { can_setup_review_app: true } });
return createWrapper(true);
});
it('should render the enable review app button', () => {
expect(findEnableReviewAppButton().exists()).toBe(true);
expect(findEnableReviewAppButton().text()).toContain('Enable review app');
});
it('should render only one review app modal', () => {
const modal = findEnableReviewAppModal();
expect(modal).toHaveLength(1);
expect(modal.at(0).exists()).toBe(true);
});
});
});
describe('tabs', () => {
beforeEach(() => {
mockRequest(200, { environments: [] });
jest
.spyOn(urlUtils, 'getParameterByName')
.mockImplementation((param) => (param === 'scope' ? 'stopped' : null));
return createWrapper(true);
});
it('selects the tab for the parameter', () => {
expect(wrapper.findComponent(GlTabs).attributes('value')).toBe('1');
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment