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/environments')
-rw-r--r--spec/frontend/environments/environment_actions_spec.js131
-rw-r--r--spec/frontend/environments/environment_item_spec.js76
-rw-r--r--spec/frontend/environments/mock_data.js97
3 files changed, 249 insertions, 55 deletions
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index d305f5e90bd..cc5153d6eba 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -1,51 +1,69 @@
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, mount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
-import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import eventHub from '~/environments/event_hub';
import EnvironmentActions from '~/environments/components/environment_actions.vue';
+const scheduledJobAction = {
+ name: 'scheduled action',
+ playPath: `${TEST_HOST}/scheduled/job/action`,
+ playable: true,
+ scheduledAt: '2063-04-05T00:42:00Z',
+};
+
+const expiredJobAction = {
+ name: 'expired action',
+ playPath: `${TEST_HOST}/expired/job/action`,
+ playable: true,
+ scheduledAt: '2018-10-05T08:23:00Z',
+};
+
describe('EnvironmentActions Component', () => {
- let vm;
+ let wrapper;
- const findEnvironmentActionsButton = () => vm.find('[data-testid="environment-actions-button"]');
+ const findEnvironmentActionsButton = () =>
+ wrapper.find('[data-testid="environment-actions-button"]');
- beforeEach(() => {
- vm = shallowMount(EnvironmentActions, {
- propsData: { actions: [] },
+ function createComponent(props, { mountFn = shallowMount } = {}) {
+ wrapper = mountFn(EnvironmentActions, {
+ propsData: { actions: [], ...props },
directives: {
GlTooltip: createMockDirective(),
},
});
- });
+ }
+
+ function createComponentWithScheduledJobs(opts = {}) {
+ return createComponent({ actions: [scheduledJobAction, expiredJobAction] }, opts);
+ }
+
+ const findDropdownItem = action => {
+ const buttons = wrapper.findAll(GlDropdownItem);
+ return buttons.filter(button => button.text().startsWith(action.name)).at(0);
+ };
afterEach(() => {
- vm.destroy();
+ wrapper.destroy();
+ wrapper = null;
});
it('should render a dropdown button with 2 icons', () => {
- expect(vm.find('.dropdown-new').findAll(GlIcon).length).toBe(2);
+ createComponent({}, { mountFn: mount });
+ expect(wrapper.find(GlDropdown).findAll(GlIcon).length).toBe(2);
});
it('should render a dropdown button with aria-label description', () => {
- expect(vm.find('.dropdown-new').attributes('aria-label')).toEqual('Deploy to...');
+ createComponent();
+ expect(wrapper.find(GlDropdown).attributes('aria-label')).toBe('Deploy to...');
});
it('should render a tooltip', () => {
+ createComponent();
const tooltip = getBinding(findEnvironmentActionsButton().element, 'gl-tooltip');
expect(tooltip).toBeDefined();
});
- describe('is loading', () => {
- beforeEach(() => {
- vm.setData({ isLoading: true });
- });
-
- it('should render a dropdown button with a loading icon', () => {
- expect(vm.findAll(GlLoadingIcon).length).toBe(1);
- });
- });
-
describe('manual actions', () => {
const actions = [
{
@@ -64,68 +82,71 @@ describe('EnvironmentActions Component', () => {
];
beforeEach(() => {
- vm.setProps({ actions });
+ createComponent({ actions });
});
it('should render a dropdown with the provided list of actions', () => {
- expect(vm.findAll('.dropdown-menu li').length).toEqual(actions.length);
+ expect(wrapper.findAll(GlDropdownItem)).toHaveLength(actions.length);
});
it("should render a disabled action when it's not playable", () => {
- expect(vm.find('.dropdown-menu li:last-child gl-button-stub').props('disabled')).toBe(true);
+ const dropdownItems = wrapper.findAll(GlDropdownItem);
+ const lastDropdownItem = dropdownItems.at(dropdownItems.length - 1);
+ expect(lastDropdownItem.attributes('disabled')).toBe('true');
});
});
describe('scheduled jobs', () => {
- const scheduledJobAction = {
- name: 'scheduled action',
- playPath: `${TEST_HOST}/scheduled/job/action`,
- playable: true,
- scheduledAt: '2063-04-05T00:42:00Z',
- };
- const expiredJobAction = {
- name: 'expired action',
- playPath: `${TEST_HOST}/expired/job/action`,
- playable: true,
- scheduledAt: '2018-10-05T08:23:00Z',
- };
- const findDropdownItem = action => {
- const buttons = vm.findAll('.dropdown-menu li gl-button-stub');
- return buttons.filter(button => button.text().startsWith(action.name)).at(0);
+ let emitSpy;
+
+ const clickAndConfirm = async ({ confirm = true } = {}) => {
+ jest.spyOn(window, 'confirm').mockImplementation(() => confirm);
+
+ findDropdownItem(scheduledJobAction).vm.$emit('click');
+ await wrapper.vm.$nextTick();
};
beforeEach(() => {
+ emitSpy = jest.fn();
+ eventHub.$on('postAction', emitSpy);
jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
- vm.setProps({ actions: [scheduledJobAction, expiredJobAction] });
});
- it('emits postAction event after confirming', () => {
- const emitSpy = jest.fn();
- eventHub.$on('postAction', emitSpy);
- jest.spyOn(window, 'confirm').mockImplementation(() => true);
+ describe('when postAction event is confirmed', () => {
+ beforeEach(async () => {
+ createComponentWithScheduledJobs({ mountFn: mount });
+ clickAndConfirm();
+ });
- findDropdownItem(scheduledJobAction).vm.$emit('click');
+ it('emits postAction event', () => {
+ expect(window.confirm).toHaveBeenCalled();
+ expect(emitSpy).toHaveBeenCalledWith({ endpoint: scheduledJobAction.playPath });
+ });
- expect(window.confirm).toHaveBeenCalled();
- expect(emitSpy).toHaveBeenCalledWith({ endpoint: scheduledJobAction.playPath });
+ it('should render a dropdown button with a loading icon', () => {
+ expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
+ });
});
- it('does not emit postAction event if confirmation is cancelled', () => {
- const emitSpy = jest.fn();
- eventHub.$on('postAction', emitSpy);
- jest.spyOn(window, 'confirm').mockImplementation(() => false);
-
- findDropdownItem(scheduledJobAction).vm.$emit('click');
+ describe('when postAction event is denied', () => {
+ beforeEach(() => {
+ createComponentWithScheduledJobs({ mountFn: mount });
+ clickAndConfirm({ confirm: false });
+ });
- expect(window.confirm).toHaveBeenCalled();
- expect(emitSpy).not.toHaveBeenCalled();
+ it('does not emit postAction event if confirmation is cancelled', () => {
+ expect(window.confirm).toHaveBeenCalled();
+ expect(emitSpy).not.toHaveBeenCalled();
+ });
});
it('displays the remaining time in the dropdown', () => {
+ createComponentWithScheduledJobs();
expect(findDropdownItem(scheduledJobAction).text()).toContain('24:00:00');
});
it('displays 00:00:00 for expired jobs in the dropdown', () => {
+ createComponentWithScheduledJobs();
expect(findDropdownItem(expiredJobAction).text()).toContain('00:00:00');
});
});
diff --git a/spec/frontend/environments/environment_item_spec.js b/spec/frontend/environments/environment_item_spec.js
index 1b429783821..bc692352103 100644
--- a/spec/frontend/environments/environment_item_spec.js
+++ b/spec/frontend/environments/environment_item_spec.js
@@ -1,3 +1,4 @@
+import { cloneDeep } from 'lodash';
import { mount } from '@vue/test-utils';
import { format } from 'timeago.js';
import EnvironmentItem from '~/environments/components/environment_item.vue';
@@ -30,6 +31,11 @@ describe('Environment item', () => {
});
const findAutoStop = () => wrapper.find('.js-auto-stop');
+ const findUpcomingDeployment = () => wrapper.find('[data-testid="upcoming-deployment"]');
+ const findUpcomingDeploymentContent = () =>
+ wrapper.find('[data-testid="upcoming-deployment-content"]');
+ const findUpcomingDeploymentStatusLink = () =>
+ wrapper.find('[data-testid="upcoming-deployment-status-link"]');
afterEach(() => {
wrapper.destroy();
@@ -87,6 +93,72 @@ describe('Environment item', () => {
});
});
+ describe('When the envionment has an upcoming deployment', () => {
+ describe('When the upcoming deployment has a deployable', () => {
+ it('should render the build ID and user', () => {
+ expect(findUpcomingDeploymentContent().text()).toMatchInterpolatedText(
+ '#27 by upcoming-username',
+ );
+ });
+
+ it('should render a status icon with a link and tooltip', () => {
+ expect(findUpcomingDeploymentStatusLink().exists()).toBe(true);
+
+ expect(findUpcomingDeploymentStatusLink().attributes().href).toBe(
+ '/root/environment-test/-/jobs/892',
+ );
+
+ expect(findUpcomingDeploymentStatusLink().attributes().title).toBe(
+ 'Deployment running',
+ );
+ });
+ });
+
+ describe('When the deployment does not have a deployable', () => {
+ beforeEach(() => {
+ const environmentWithoutDeployable = cloneDeep(environment);
+ delete environmentWithoutDeployable.upcoming_deployment.deployable;
+
+ factory({
+ propsData: {
+ model: environmentWithoutDeployable,
+ canReadEnvironment: true,
+ tableData,
+ },
+ });
+ });
+
+ it('should still renders the build ID and user', () => {
+ expect(findUpcomingDeploymentContent().text()).toMatchInterpolatedText(
+ '#27 by upcoming-username',
+ );
+ });
+
+ it('should not render the status icon', () => {
+ expect(findUpcomingDeploymentStatusLink().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Without upcoming deployment', () => {
+ beforeEach(() => {
+ const environmentWithoutUpcomingDeployment = cloneDeep(environment);
+ delete environmentWithoutUpcomingDeployment.upcoming_deployment;
+
+ factory({
+ propsData: {
+ model: environmentWithoutUpcomingDeployment,
+ canReadEnvironment: true,
+ tableData,
+ },
+ });
+ });
+
+ it('should not render anything in the upcoming deployment column', () => {
+ expect(findUpcomingDeploymentContent().exists()).toBe(false);
+ });
+ });
+
describe('Without auto-stop date', () => {
beforeEach(() => {
factory({
@@ -209,6 +281,10 @@ describe('Environment item', () => {
it('should render the number of children in a badge', () => {
expect(wrapper.find('.folder-name .badge').text()).toContain(folder.size);
});
+
+ it('should not render the "Upcoming deployment" column', () => {
+ expect(findUpcomingDeployment().exists()).toBe(false);
+ });
});
describe('When environment can be deleted', () => {
diff --git a/spec/frontend/environments/mock_data.js b/spec/frontend/environments/mock_data.js
index 77c5dad0bbf..e7b99c8688c 100644
--- a/spec/frontend/environments/mock_data.js
+++ b/spec/frontend/environments/mock_data.js
@@ -86,6 +86,98 @@ const environment = {
],
deployed_at: '2016-11-29T18:11:58.430Z',
},
+ upcoming_deployment: {
+ id: 82,
+ iid: 27,
+ sha: '1132df044b73943943c949e7ac2c2f120a89bf59',
+ ref: {
+ name: 'master',
+ ref_path: '/root/environment-test/-/tree/master',
+ },
+ status: 'running',
+ created_at: '2020-12-04T19:57:49.514Z',
+ deployed_at: null,
+ tag: false,
+ 'last?': false,
+ user: {
+ id: 1,
+ name: 'Upcoming Name',
+ username: 'upcoming-username',
+ state: 'active',
+ avatar_url: 'http://0.0.0.0:3000/uploads/-/system/user/avatar/2/avatar.png',
+ web_url: 'http://0.0.0.0:3000/upcoming-username',
+ show_status: false,
+ path: '/upcoming-username',
+ },
+ deployable: {
+ id: 1310,
+ name: 'deploy_to_development',
+ started: '2020-12-04T19:58:10.806Z',
+ archived: false,
+ build_path: '/root/environment-test/-/jobs/892',
+ cancel_path:
+ '/root/environment-test/-/jobs/892/cancel?continue%5Bto%5D=%2Froot%2Fenvironment-test%2F-%2Fjobs%2F892',
+ playable: false,
+ scheduled: false,
+ created_at: '2020-12-04T19:57:49.455Z',
+ updated_at: '2020-12-04T19:58:10.809Z',
+ status: {
+ icon: 'status_running',
+ text: 'running',
+ label: 'running',
+ group: 'running',
+ tooltip: 'running',
+ has_details: true,
+ details_path: '/root/environment-test/-/jobs/892',
+ illustration: {
+ image:
+ '/assets/illustrations/skipped-job_empty-29a8a37d8a61d1b6f68cf3484f9024e53cd6eb95e28eae3554f8011a1146bf27.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/root/environment-test/-/jobs/892/cancel',
+ method: 'post',
+ button_title: 'Cancel this job',
+ },
+ },
+ },
+ commit: {
+ id: '1132df044b73943943c949e7ac2c2f120a89bf59',
+ short_id: '1132df04',
+ created_at: '2020-12-01T15:46:26.000-05:00',
+ parent_ids: ['e0808dee2a5877563ec140e65d8b41908f90098c'],
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Upcoming Name',
+ author_email: 'admin@example.com',
+ authored_date: '2020-12-01T15:46:26.000-05:00',
+ committer_name: 'Upcoming Name',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-12-01T15:46:26.000-05:00',
+ web_url:
+ 'http://0.0.0.0:3000/root/environment-test/-/commit/1132df044b73943943c949e7ac2c2f120a89bf59',
+ author: {
+ id: 1,
+ name: 'Upcoming Name',
+ username: 'upcoming-username',
+ state: 'active',
+ avatar_url: 'http://0.0.0.0:3000/uploads/-/system/user/avatar/2/avatar.png',
+ web_url: 'http://0.0.0.0:3000/upcoming-username',
+ show_status: false,
+ path: '/upcoming-username',
+ },
+ author_gravatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ commit_url:
+ 'http://0.0.0.0:3000/root/environment-test/-/commit/1132df044b73943943c949e7ac2c2f120a89bf59',
+ commit_path: '/root/environment-test/-/commit/1132df044b73943943c949e7ac2c2f120a89bf59',
+ },
+ },
has_stop_action: true,
environment_path: 'root/ci-folders/environments/31',
log_path: 'root/ci-folders/environments/31/logs',
@@ -156,6 +248,11 @@ const tableData = {
title: 'Updated',
spacing: 'section-10',
},
+ upcoming: {
+ title: 'Upcoming',
+ mobileTitle: 'Upcoming deployment',
+ spacing: 'section-10',
+ },
autoStop: {
title: 'Auto stop in',
spacing: 'section-5',