summaryrefslogtreecommitdiff
path: root/spec/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/issuables_list/components/issuable_spec.js1
-rw-r--r--spec/frontend/issuables_list/components/issuables_list_app_spec.js1
-rw-r--r--spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap33
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js40
-rw-r--r--spec/frontend/registry/settings/stores/actions_spec.js20
-rw-r--r--spec/frontend/registry/settings/stores/mutations_spec.js21
-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
9 files changed, 460 insertions, 0 deletions
diff --git a/spec/frontend/issuables_list/components/issuable_spec.js b/spec/frontend/issuables_list/components/issuable_spec.js
index 6148f3c68f2..b6851a0e24c 100644
--- a/spec/frontend/issuables_list/components/issuable_spec.js
+++ b/spec/frontend/issuables_list/components/issuable_spec.js
@@ -45,6 +45,7 @@ describe('Issuable component', () => {
...props,
},
sync: false,
+ attachToDocument: true,
});
};
diff --git a/spec/frontend/issuables_list/components/issuables_list_app_spec.js b/spec/frontend/issuables_list/components/issuables_list_app_spec.js
index e598a9c5a5d..dad4e74cb40 100644
--- a/spec/frontend/issuables_list/components/issuables_list_app_spec.js
+++ b/spec/frontend/issuables_list/components/issuables_list_app_spec.js
@@ -49,6 +49,7 @@ describe('Issuables list component', () => {
},
localVue,
sync: false,
+ attachToDocument: true,
});
};
diff --git a/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap b/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
new file mode 100644
index 00000000000..c6dbb1da8e9
--- /dev/null
+++ b/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
@@ -0,0 +1,33 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Registry List renders 1`] = `
+<div>
+ <p>
+
+ Tag retention policies are designed to:
+
+ </p>
+
+ <ul>
+ <li>
+ Keep and protect the images that matter most.
+ </li>
+
+ <li>
+
+ Automatically remove extra images that aren't designed to be kept.
+
+ </li>
+ </ul>
+
+ <p>
+ Read more about the
+ <a
+ href="foo"
+ target="_blank"
+ >
+ Container Registry tag retention policies
+ </a>
+ </p>
+</div>
+`;
diff --git a/spec/frontend/registry/settings/components/registry_settings_app_spec.js b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
new file mode 100644
index 00000000000..666d970aa6b
--- /dev/null
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -0,0 +1,40 @@
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import component from '~/registry/settings/components/registry_settings_app.vue';
+import { createStore } from '~/registry/settings/stores/';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Registry List', () => {
+ let wrapper;
+ let store;
+
+ const helpPagePath = 'foo';
+ const findHelpLink = () => wrapper.find({ ref: 'help-link' }).find('a');
+
+ const mountComponent = (options = {}) =>
+ shallowMount(component, {
+ sync: false,
+ store,
+ ...options,
+ });
+
+ beforeEach(() => {
+ store = createStore();
+ store.dispatch('setInitialState', { helpPagePath });
+ wrapper = mountComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('renders an help link dependant on the helphPagePath', () => {
+ expect(findHelpLink().attributes('href')).toBe(helpPagePath);
+ });
+});
diff --git a/spec/frontend/registry/settings/stores/actions_spec.js b/spec/frontend/registry/settings/stores/actions_spec.js
new file mode 100644
index 00000000000..205c3a6ee21
--- /dev/null
+++ b/spec/frontend/registry/settings/stores/actions_spec.js
@@ -0,0 +1,20 @@
+import * as actions from '~/registry/settings/stores/actions';
+import * as types from '~/registry/settings/stores/mutation_types';
+import testAction from 'helpers/vuex_action_helper';
+
+jest.mock('~/flash.js');
+
+describe('Actions Registry Store', () => {
+ describe('setInitialState', () => {
+ it('should set the initial state', done => {
+ testAction(
+ actions.setInitialState,
+ 'foo',
+ {},
+ [{ type: types.SET_INITIAL_STATE, payload: 'foo' }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/stores/mutations_spec.js b/spec/frontend/registry/settings/stores/mutations_spec.js
new file mode 100644
index 00000000000..421cd3f13cb
--- /dev/null
+++ b/spec/frontend/registry/settings/stores/mutations_spec.js
@@ -0,0 +1,21 @@
+import mutations from '~/registry/settings/stores/mutations';
+import * as types from '~/registry/settings/stores/mutation_types';
+import createState from '~/registry/settings/stores/state';
+
+describe('Mutations Registry Store', () => {
+ let mockState;
+
+ beforeEach(() => {
+ mockState = createState();
+ });
+
+ describe('SET_INITIAL_STATE', () => {
+ it('should set the initial state', () => {
+ const payload = { helpPagePath: 'foo', registrySettingsEndpoint: 'bar' };
+ const expectedState = { ...mockState, ...payload };
+ mutations[types.SET_INITIAL_STATE](mockState, payload);
+
+ expect(mockState.endpoint).toEqual(expectedState.endpoint);
+ });
+ });
+});
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);
+ });
+ });
+ });
+});