summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_mr_widget
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-05 12:07:43 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-05 12:07:43 +0000
commit872319738757edc0483346c75a2407f7019b963f (patch)
treed5953edec6184dda1f53c5994c3ebcebc9e815a2 /spec/frontend/vue_mr_widget
parent8f764d21b0011056e1492d92afe3bd40b847b9f7 (diff)
downloadgitlab-ce-872319738757edc0483346c75a2407f7019b963f.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/vue_mr_widget')
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_mock_data.js32
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_spec.js194
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_view_button_spec.js118
3 files changed, 344 insertions, 0 deletions
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_mock_data.js b/spec/frontend/vue_mr_widget/deployment/deployment_mock_data.js
new file mode 100644
index 00000000000..f8f4cb627dd
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_mock_data.js
@@ -0,0 +1,32 @@
+import { SUCCESS } from '~/vue_merge_request_widget/components/deployment/constants';
+
+const deploymentMockData = {
+ id: 15,
+ name: 'review/diplo',
+ url: '/root/review-apps/environments/15',
+ stop_url: '/root/review-apps/environments/15/stop',
+ metrics_url: '/root/review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/review-apps/environments/15/metrics',
+ external_url: 'http://gitlab.com.',
+ external_url_formatted: 'gitlab',
+ deployed_at: '2017-03-22T22:44:42.258Z',
+ deployed_at_formatted: 'Mar 22, 2017 10:44pm',
+ details: {},
+ status: SUCCESS,
+ changes: [
+ {
+ path: 'index.html',
+ external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/index.html',
+ },
+ {
+ path: 'imgs/gallery.html',
+ external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
+ },
+ {
+ path: 'about/',
+ external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/about/',
+ },
+ ],
+};
+
+export default deploymentMockData;
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_spec.js
new file mode 100644
index 00000000000..78e086e473d
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_spec.js
@@ -0,0 +1,194 @@
+import { mount } from '@vue/test-utils';
+import DeploymentComponent from '~/vue_merge_request_widget/components/deployment/deployment.vue';
+import DeploymentInfo from '~/vue_merge_request_widget/components/deployment/deployment_info.vue';
+import DeploymentViewButton from '~/vue_merge_request_widget/components/deployment/deployment_view_button.vue';
+import DeploymentStopButton from '~/vue_merge_request_widget/components/deployment/deployment_stop_button.vue';
+import {
+ CREATED,
+ RUNNING,
+ SUCCESS,
+ FAILED,
+ CANCELED,
+} from '~/vue_merge_request_widget/components/deployment/constants';
+import deploymentMockData from './deployment_mock_data';
+
+const deployDetail = {
+ playable_build: {
+ retry_path: '/root/test-deployments/-/jobs/1131/retry',
+ play_path: '/root/test-deployments/-/jobs/1131/play',
+ },
+ isManual: true,
+};
+
+describe('Deployment component', () => {
+ let wrapper;
+
+ const factory = (options = {}) => {
+ // This destroys any wrappers created before a nested call to factory reassigns it
+ if (wrapper && wrapper.destroy) {
+ wrapper.destroy();
+ }
+ wrapper = mount(DeploymentComponent, {
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: deploymentMockData,
+ showMetrics: false,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('always renders DeploymentInfo', () => {
+ expect(wrapper.find(DeploymentInfo).exists()).toBe(true);
+ });
+
+ describe('status message and buttons', () => {
+ const noActions = [];
+ const noDetails = { isManual: false };
+ const deployGroup = [DeploymentViewButton, DeploymentStopButton];
+
+ describe.each`
+ status | previous | deploymentDetails | text | actionButtons
+ ${CREATED} | ${true} | ${deployDetail} | ${'Can deploy manually to'} | ${deployGroup}
+ ${CREATED} | ${true} | ${noDetails} | ${'Will deploy to'} | ${deployGroup}
+ ${CREATED} | ${false} | ${deployDetail} | ${'Can deploy manually to'} | ${noActions}
+ ${CREATED} | ${false} | ${noDetails} | ${'Will deploy to'} | ${noActions}
+ ${RUNNING} | ${true} | ${deployDetail} | ${'Deploying to'} | ${deployGroup}
+ ${RUNNING} | ${true} | ${noDetails} | ${'Deploying to'} | ${deployGroup}
+ ${RUNNING} | ${false} | ${deployDetail} | ${'Deploying to'} | ${noActions}
+ ${RUNNING} | ${false} | ${noDetails} | ${'Deploying to'} | ${noActions}
+ ${SUCCESS} | ${true} | ${deployDetail} | ${'Deployed to'} | ${deployGroup}
+ ${SUCCESS} | ${true} | ${noDetails} | ${'Deployed to'} | ${deployGroup}
+ ${SUCCESS} | ${false} | ${deployDetail} | ${'Deployed to'} | ${deployGroup}
+ ${SUCCESS} | ${false} | ${noDetails} | ${'Deployed to'} | ${deployGroup}
+ ${FAILED} | ${true} | ${deployDetail} | ${'Failed to deploy to'} | ${deployGroup}
+ ${FAILED} | ${true} | ${noDetails} | ${'Failed to deploy to'} | ${deployGroup}
+ ${FAILED} | ${false} | ${deployDetail} | ${'Failed to deploy to'} | ${noActions}
+ ${FAILED} | ${false} | ${noDetails} | ${'Failed to deploy to'} | ${noActions}
+ ${CANCELED} | ${true} | ${deployDetail} | ${'Canceled deploy to'} | ${deployGroup}
+ ${CANCELED} | ${true} | ${noDetails} | ${'Canceled deploy to'} | ${deployGroup}
+ ${CANCELED} | ${false} | ${deployDetail} | ${'Canceled deploy to'} | ${noActions}
+ ${CANCELED} | ${false} | ${noDetails} | ${'Canceled deploy to'} | ${noActions}
+ `(
+ '$status + previous: $previous + manual: $deploymentDetails.isManual',
+ ({ status, previous, deploymentDetails, text, actionButtons }) => {
+ beforeEach(() => {
+ const previousOrSuccess = Boolean(previous || status === SUCCESS);
+ const updatedDeploymentData = {
+ status,
+ deployed_at: previous ? deploymentMockData.deployed_at : null,
+ deployed_at_formatted: previous ? deploymentMockData.deployed_at_formatted : null,
+ external_url: previousOrSuccess ? deploymentMockData.external_url : null,
+ external_url_formatted: previousOrSuccess
+ ? deploymentMockData.external_url_formatted
+ : null,
+ stop_url: previousOrSuccess ? deploymentMockData.stop_url : null,
+ details: deploymentDetails,
+ };
+
+ factory({
+ propsData: {
+ showMetrics: false,
+ deployment: {
+ ...deploymentMockData,
+ ...updatedDeploymentData,
+ },
+ },
+ });
+ });
+
+ it(`renders the text: ${text}`, () => {
+ expect(wrapper.find(DeploymentInfo).text()).toContain(text);
+ });
+
+ if (actionButtons.length > 0) {
+ describe('renders the expected button group', () => {
+ actionButtons.forEach(button => {
+ it(`renders ${button.name}`, () => {
+ expect(wrapper.find(button).exists()).toBe(true);
+ });
+ });
+ });
+ }
+
+ if (actionButtons.length === 0) {
+ describe('does not render the button group', () => {
+ [DeploymentViewButton, DeploymentStopButton].forEach(button => {
+ it(`does not render ${button.name}`, () => {
+ expect(wrapper.find(button).exists()).toBe(false);
+ });
+ });
+ });
+ }
+
+ if (actionButtons.includes(DeploymentViewButton)) {
+ it('renders the View button with expected text', () => {
+ if (status === SUCCESS) {
+ expect(wrapper.find(DeploymentViewButton).text()).toContain('View app');
+ } else {
+ expect(wrapper.find(DeploymentViewButton).text()).toContain('View previous app');
+ }
+ });
+ }
+ },
+ );
+ });
+
+ describe('hasExternalUrls', () => {
+ describe('when deployment has both external_url_formatted and external_url', () => {
+ it('should return true', () => {
+ expect(wrapper.vm.hasExternalUrls).toEqual(true);
+ });
+
+ it('should render the View Button', () => {
+ expect(wrapper.find(DeploymentViewButton).exists()).toBe(true);
+ });
+ });
+
+ describe('when deployment has no external_url_formatted', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: { ...deploymentMockData, external_url_formatted: null },
+ showMetrics: false,
+ },
+ });
+ });
+
+ it('should return false', () => {
+ expect(wrapper.vm.hasExternalUrls).toEqual(false);
+ });
+
+ it('should not render the View Button', () => {
+ expect(wrapper.find(DeploymentViewButton).exists()).toBe(false);
+ });
+ });
+
+ describe('when deployment has no external_url', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: { ...deploymentMockData, external_url: null },
+ showMetrics: false,
+ },
+ });
+ });
+
+ it('should return false', () => {
+ expect(wrapper.vm.hasExternalUrls).toEqual(false);
+ });
+
+ it('should not render the View Button', () => {
+ expect(wrapper.find(DeploymentViewButton).exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_view_button_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_view_button_spec.js
new file mode 100644
index 00000000000..6e3c6f64c68
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_view_button_spec.js
@@ -0,0 +1,118 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import DeploymentViewButton from '~/vue_merge_request_widget/components/deployment/deployment_view_button.vue';
+import ReviewAppLink from '~/vue_merge_request_widget/components/review_app_link.vue';
+import deploymentMockData from './deployment_mock_data';
+
+describe('Deployment View App button', () => {
+ let wrapper;
+
+ const factory = (options = {}) => {
+ const localVue = createLocalVue();
+
+ wrapper = mount(localVue.extend(DeploymentViewButton), {
+ localVue,
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: deploymentMockData,
+ isCurrent: true,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('text', () => {
+ describe('when app is current', () => {
+ it('shows View app', () => {
+ expect(wrapper.find(ReviewAppLink).text()).toContain('View app');
+ });
+ });
+
+ describe('when app is not current', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: deploymentMockData,
+ isCurrent: false,
+ },
+ });
+ });
+
+ it('shows View Previous app', () => {
+ expect(wrapper.find(ReviewAppLink).text()).toContain('View previous app');
+ });
+ });
+ });
+
+ describe('without changes', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: { ...deploymentMockData, changes: null },
+ isCurrent: false,
+ },
+ });
+ });
+
+ it('renders the link to the review app without dropdown', () => {
+ expect(wrapper.find('.js-mr-wigdet-deployment-dropdown').exists()).toBe(false);
+ });
+ });
+
+ describe('with a single change', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: { ...deploymentMockData, changes: [deploymentMockData.changes[0]] },
+ isCurrent: false,
+ },
+ });
+ });
+
+ it('renders the link to the review app without dropdown', () => {
+ expect(wrapper.find('.js-mr-wigdet-deployment-dropdown').exists()).toBe(false);
+ });
+
+ it('renders the link to the review app linked to to the first change', () => {
+ const expectedUrl = deploymentMockData.changes[0].external_url;
+ const deployUrl = wrapper.find('.js-deploy-url');
+
+ expect(deployUrl.attributes().href).not.toBeNull();
+ expect(deployUrl.attributes().href).toEqual(expectedUrl);
+ });
+ });
+
+ describe('with multiple changes', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ deployment: deploymentMockData,
+ isCurrent: false,
+ },
+ });
+ });
+
+ it('renders the link to the review app with dropdown', () => {
+ expect(wrapper.find('.js-mr-wigdet-deployment-dropdown').exists()).toBe(true);
+ });
+
+ it('renders all the links to the review apps', () => {
+ const allUrls = wrapper.findAll('.js-deploy-url-menu-item').wrappers;
+ const expectedUrls = deploymentMockData.changes.map(change => change.external_url);
+
+ expectedUrls.forEach((expectedUrl, idx) => {
+ const deployUrl = allUrls[idx];
+
+ expect(deployUrl.attributes().href).not.toBeNull();
+ expect(deployUrl.attributes().href).toEqual(expectedUrl);
+ });
+ });
+ });
+});