diff options
Diffstat (limited to 'spec/frontend/clusters')
13 files changed, 2 insertions, 2250 deletions
diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js index cd0eda2ab49..42990334f0a 100644 --- a/spec/frontend/clusters/clusters_bundle_spec.js +++ b/spec/frontend/clusters/clusters_bundle_spec.js @@ -2,15 +2,12 @@ import MockAdapter from 'axios-mock-adapter'; import { loadHTMLFixture } from 'helpers/fixtures'; import { setTestTimeout } from 'helpers/timeout'; import Clusters from '~/clusters/clusters_bundle'; -import { APPLICATION_STATUS, APPLICATIONS, RUNNER } from '~/clusters/constants'; import axios from '~/lib/utils/axios_utils'; import initProjectSelectDropdown from '~/project_select'; jest.mock('~/lib/utils/poll'); jest.mock('~/project_select'); -const { INSTALLING, INSTALLABLE, INSTALLED, UNINSTALLING } = APPLICATION_STATUS; - describe('Clusters', () => { setTestTimeout(1000); @@ -57,67 +54,6 @@ describe('Clusters', () => { }); }); - describe('checkForNewInstalls', () => { - const INITIAL_APP_MAP = { - helm: { status: null, title: 'Helm Tiller' }, - ingress: { status: null, title: 'Ingress' }, - runner: { status: null, title: 'GitLab Runner' }, - }; - - it('does not show alert when things transition from initial null state to something', () => { - cluster.checkForNewInstalls(INITIAL_APP_MAP, { - ...INITIAL_APP_MAP, - helm: { status: INSTALLABLE, title: 'Helm Tiller' }, - }); - - const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text'); - - expect(flashMessage).toBeNull(); - }); - - it('shows an alert when something gets newly installed', () => { - cluster.checkForNewInstalls( - { - ...INITIAL_APP_MAP, - helm: { status: INSTALLING, title: 'Helm Tiller' }, - }, - { - ...INITIAL_APP_MAP, - helm: { status: INSTALLED, title: 'Helm Tiller' }, - }, - ); - - const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text'); - - expect(flashMessage).not.toBeNull(); - expect(flashMessage.textContent.trim()).toEqual( - 'Helm Tiller was successfully installed on your Kubernetes cluster', - ); - }); - - it('shows an alert when multiple things gets newly installed', () => { - cluster.checkForNewInstalls( - { - ...INITIAL_APP_MAP, - helm: { status: INSTALLING, title: 'Helm Tiller' }, - ingress: { status: INSTALLABLE, title: 'Ingress' }, - }, - { - ...INITIAL_APP_MAP, - helm: { status: INSTALLED, title: 'Helm Tiller' }, - ingress: { status: INSTALLED, title: 'Ingress' }, - }, - ); - - const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text'); - - expect(flashMessage).not.toBeNull(); - expect(flashMessage.textContent.trim()).toEqual( - 'Helm Tiller, Ingress was successfully installed on your Kubernetes cluster', - ); - }); - }); - describe('updateContainer', () => { const { location } = window; @@ -237,77 +173,6 @@ describe('Clusters', () => { }); }); - describe('installApplication', () => { - it.each(APPLICATIONS)('tries to install %s', (applicationId, done) => { - jest.spyOn(cluster.service, 'installApplication').mockResolvedValue(); - - cluster.store.state.applications[applicationId].status = INSTALLABLE; - - const params = {}; - if (applicationId === 'knative') { - params.hostname = 'test-example.com'; - } - - // eslint-disable-next-line promise/valid-params - cluster - .installApplication({ id: applicationId, params }) - .then(() => { - expect(cluster.store.state.applications[applicationId].status).toEqual(INSTALLING); - expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null); - expect(cluster.service.installApplication).toHaveBeenCalledWith(applicationId, params); - done(); - }) - .catch(); - }); - - it('sets error request status when the request fails', () => { - jest - .spyOn(cluster.service, 'installApplication') - .mockRejectedValueOnce(new Error('STUBBED ERROR')); - - cluster.store.state.applications.helm.status = INSTALLABLE; - - const promise = cluster.installApplication({ id: 'helm' }); - - return promise.then(() => { - expect(cluster.store.state.applications.helm.status).toEqual(INSTALLABLE); - expect(cluster.store.state.applications.helm.installFailed).toBe(true); - - expect(cluster.store.state.applications.helm.requestReason).toBeDefined(); - }); - }); - }); - - describe('uninstallApplication', () => { - it.each(APPLICATIONS)('tries to uninstall %s', (applicationId) => { - jest.spyOn(cluster.service, 'uninstallApplication').mockResolvedValueOnce(); - - cluster.store.state.applications[applicationId].status = INSTALLED; - - cluster.uninstallApplication({ id: applicationId }); - - expect(cluster.store.state.applications[applicationId].status).toEqual(UNINSTALLING); - expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null); - expect(cluster.service.uninstallApplication).toHaveBeenCalledWith(applicationId); - }); - - it('sets error request status when the uninstall request fails', () => { - jest - .spyOn(cluster.service, 'uninstallApplication') - .mockRejectedValueOnce(new Error('STUBBED ERROR')); - - cluster.store.state.applications.helm.status = INSTALLED; - - const promise = cluster.uninstallApplication({ id: 'helm' }); - - return promise.then(() => { - expect(cluster.store.state.applications.helm.status).toEqual(INSTALLED); - expect(cluster.store.state.applications.helm.uninstallFailed).toBe(true); - expect(cluster.store.state.applications.helm.requestReason).toBeDefined(); - }); - }); - }); - describe('fetch cluster environments success', () => { beforeEach(() => { jest.spyOn(cluster.store, 'toggleFetchEnvironments').mockReturnThis(); @@ -328,7 +193,6 @@ describe('Clusters', () => { describe('handleClusterStatusSuccess', () => { beforeEach(() => { jest.spyOn(cluster.store, 'updateStateFromServer').mockReturnThis(); - jest.spyOn(cluster, 'checkForNewInstalls').mockReturnThis(); jest.spyOn(cluster, 'updateContainer').mockReturnThis(); cluster.handleClusterStatusSuccess({ data: {} }); }); @@ -337,38 +201,8 @@ describe('Clusters', () => { expect(cluster.store.updateStateFromServer).toHaveBeenCalled(); }); - it('checks for new installable apps', () => { - expect(cluster.checkForNewInstalls).toHaveBeenCalled(); - }); - it('updates message containers', () => { expect(cluster.updateContainer).toHaveBeenCalled(); }); }); - - describe('updateApplication', () => { - const params = { version: '1.0.0' }; - let storeUpdateApplication; - let installApplication; - - beforeEach(() => { - storeUpdateApplication = jest.spyOn(cluster.store, 'updateApplication'); - installApplication = jest.spyOn(cluster.service, 'installApplication'); - - cluster.updateApplication({ id: RUNNER, params }); - }); - - afterEach(() => { - storeUpdateApplication.mockRestore(); - installApplication.mockRestore(); - }); - - it('calls store updateApplication method', () => { - expect(storeUpdateApplication).toHaveBeenCalledWith(RUNNER); - }); - - it('sends installApplication request', () => { - expect(installApplication).toHaveBeenCalledWith(RUNNER, params); - }); - }); }); diff --git a/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap deleted file mode 100644 index c2ace1b4e30..00000000000 --- a/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap +++ /dev/null @@ -1,105 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Applications Cert-Manager application shows the correct description 1`] = ` -<p - data-testid="certManagerDescription" -> - Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by - <a - class="gl-link" - href="https://letsencrypt.org/" - rel="noopener noreferrer" - target="_blank" - > - Let's Encrypt - </a> - and ensure that certificates are valid and up-to-date. -</p> -`; - -exports[`Applications Cilium application shows the correct description 1`] = ` -<p - data-testid="ciliumDescription" -> - Protect your clusters with GitLab Container Network Policies by enforcing how pods communicate with each other and other network endpoints. - <a - class="gl-link" - href="cilium-help-path" - rel="noopener" - target="_blank" - > - Learn more about configuring Network Policies here. - </a> -</p> -`; - -exports[`Applications Crossplane application shows the correct description 1`] = ` -<p - data-testid="crossplaneDescription" -> - Crossplane enables declarative provisioning of managed services from your cloud of choice using - <code> - kubectl - </code> - or - <a - class="gl-link" - href="https://docs.gitlab.com/ee/user/clusters/applications.html#crossplane" - rel="noopener noreferrer" - target="_blank" - > - GitLab Integration - </a> - . Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on. -</p> -`; - -exports[`Applications Ingress application shows the correct warning message 1`] = ` -<span - data-testid="ingressCostWarning" -> - Installing Ingress may incur additional costs. Learn more about - <a - class="gl-link" - href="https://cloud.google.com/compute/pricing#lb" - rel="noopener noreferrer" - target="_blank" - > - pricing - </a> - . -</span> -`; - -exports[`Applications Knative application shows the correct description 1`] = ` -<span - data-testid="installed-via" -> - installed via - <a - class="gl-link" - href="" - rel="noopener" - target="_blank" - > - Cloud Run - </a> -</span> -`; - -exports[`Applications Prometheus application shows the correct description 1`] = ` -<span - data-testid="prometheusDescription" -> - Prometheus is an open-source monitoring system with - <a - class="gl-link" - href="https://docs.gitlab.com/ee/user/project/integrations/prometheus.html" - rel="noopener noreferrer" - target="_blank" - > - GitLab Integration - </a> - to monitor deployed applications. -</span> -`; diff --git a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap index e5e336eb3d5..0e1fe790771 100644 --- a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap +++ b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap @@ -156,7 +156,6 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ <!----> </div> - </ul> </div> diff --git a/spec/frontend/clusters/components/application_row_spec.js b/spec/frontend/clusters/components/application_row_spec.js deleted file mode 100644 index 6bad1db542b..00000000000 --- a/spec/frontend/clusters/components/application_row_spec.js +++ /dev/null @@ -1,505 +0,0 @@ -import { GlSprintf } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import ApplicationRow from '~/clusters/components/application_row.vue'; -import UninstallApplicationConfirmationModal from '~/clusters/components/uninstall_application_confirmation_modal.vue'; -import UpdateApplicationConfirmationModal from '~/clusters/components/update_application_confirmation_modal.vue'; -import { APPLICATION_STATUS, ELASTIC_STACK } from '~/clusters/constants'; -import eventHub from '~/clusters/event_hub'; - -import { DEFAULT_APPLICATION_STATE } from '../services/mock_data'; - -describe('Application Row', () => { - let wrapper; - - afterEach(() => { - wrapper.destroy(); - }); - - const mountComponent = (data) => { - wrapper = shallowMount(ApplicationRow, { - stubs: { GlSprintf }, - propsData: { - ...DEFAULT_APPLICATION_STATE, - ...data, - }, - }); - }; - - describe('Title', () => { - it('shows title', () => { - mountComponent({ titleLink: null }); - - const title = wrapper.find('.js-cluster-application-title'); - - expect(title.element).toBeInstanceOf(HTMLSpanElement); - expect(title.text()).toEqual(DEFAULT_APPLICATION_STATE.title); - }); - - it('shows title link', () => { - expect(DEFAULT_APPLICATION_STATE.titleLink).toBeDefined(); - mountComponent(); - const title = wrapper.find('.js-cluster-application-title'); - - expect(title.element).toBeInstanceOf(HTMLAnchorElement); - expect(title.text()).toEqual(DEFAULT_APPLICATION_STATE.title); - }); - }); - - describe('Install button', () => { - const button = () => wrapper.find('.js-cluster-application-install-button'); - const checkButtonState = (label, loading, disabled) => { - expect(button().text()).toEqual(label); - expect(button().props('loading')).toEqual(loading); - expect(button().props('disabled')).toEqual(disabled); - }; - - it('has indeterminate state on page load', () => { - mountComponent({ status: null }); - - expect(button().text()).toBe(''); - }); - - it('has install button', () => { - mountComponent(); - - expect(button().exists()).toBe(true); - }); - - it('has disabled "Install" when APPLICATION_STATUS.NOT_INSTALLABLE', () => { - mountComponent({ status: APPLICATION_STATUS.NOT_INSTALLABLE }); - - checkButtonState('Install', false, true); - }); - - it('has enabled "Install" when APPLICATION_STATUS.INSTALLABLE', () => { - mountComponent({ status: APPLICATION_STATUS.INSTALLABLE }); - - checkButtonState('Install', false, false); - }); - - it('has loading "Installing" when APPLICATION_STATUS.INSTALLING', () => { - mountComponent({ status: APPLICATION_STATUS.INSTALLING }); - - checkButtonState('Installing', true, true); - }); - - it('has disabled "Install" when APPLICATION_STATUS.UNINSTALLED', () => { - mountComponent({ status: APPLICATION_STATUS.UNINSTALLED }); - - checkButtonState('Install', false, true); - }); - - it('has disabled "Externally installed" when APPLICATION_STATUS.EXTERNALLY_INSTALLED', () => { - mountComponent({ status: APPLICATION_STATUS.EXTERNALLY_INSTALLED }); - - checkButtonState('Externally installed', false, true); - }); - - it('has disabled "Installed" when application is installed and not uninstallable', () => { - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - installed: true, - uninstallable: false, - }); - - checkButtonState('Installed', false, true); - }); - - it('hides when application is installed and uninstallable', () => { - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - installed: true, - uninstallable: true, - }); - - expect(button().exists()).toBe(false); - }); - - it('has enabled "Install" when install fails', () => { - mountComponent({ - status: APPLICATION_STATUS.INSTALLABLE, - installFailed: true, - }); - - checkButtonState('Install', false, false); - }); - - it('has disabled "Install" when installation disabled', () => { - mountComponent({ - status: APPLICATION_STATUS.INSTALLABLE, - installable: false, - }); - - checkButtonState('Install', false, true); - }); - - it('has enabled "Install" when REQUEST_FAILURE (so you can try installing again)', () => { - mountComponent({ status: APPLICATION_STATUS.INSTALLABLE }); - - checkButtonState('Install', false, false); - }); - - it('clicking install button emits event', () => { - const spy = jest.spyOn(eventHub, '$emit'); - mountComponent({ status: APPLICATION_STATUS.INSTALLABLE }); - - button().vm.$emit('click'); - - expect(spy).toHaveBeenCalledWith('installApplication', { - id: DEFAULT_APPLICATION_STATE.id, - params: {}, - }); - }); - - it('clicking install button when installApplicationRequestParams are provided emits event', () => { - const spy = jest.spyOn(eventHub, '$emit'); - mountComponent({ - status: APPLICATION_STATUS.INSTALLABLE, - installApplicationRequestParams: { hostname: 'jupyter' }, - }); - - button().vm.$emit('click'); - - expect(spy).toHaveBeenCalledWith('installApplication', { - id: DEFAULT_APPLICATION_STATE.id, - params: { hostname: 'jupyter' }, - }); - }); - - it('clicking disabled install button emits nothing', () => { - const spy = jest.spyOn(eventHub, '$emit'); - mountComponent({ status: APPLICATION_STATUS.INSTALLING }); - - expect(button().props('disabled')).toEqual(true); - - button().vm.$emit('click'); - - expect(spy).not.toHaveBeenCalled(); - }); - }); - - describe('Uninstall button', () => { - it('displays button when app is installed and uninstallable', () => { - mountComponent({ - installed: true, - uninstallable: true, - status: APPLICATION_STATUS.NOT_INSTALLABLE, - }); - const uninstallButton = wrapper.find('.js-cluster-application-uninstall-button'); - - expect(uninstallButton.exists()).toBe(true); - }); - - it('displays a success toast message if application uninstall was successful', async () => { - mountComponent({ - title: 'GitLab Runner', - uninstallSuccessful: false, - }); - - wrapper.vm.$toast = { show: jest.fn() }; - wrapper.setProps({ uninstallSuccessful: true }); - - await wrapper.vm.$nextTick(); - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - 'GitLab Runner uninstalled successfully.', - ); - }); - }); - - describe('when confirmation modal triggers confirm event', () => { - it('triggers uninstallApplication event', () => { - jest.spyOn(eventHub, '$emit'); - mountComponent(); - wrapper.find(UninstallApplicationConfirmationModal).vm.$emit('confirm'); - - expect(eventHub.$emit).toHaveBeenCalledWith('uninstallApplication', { - id: DEFAULT_APPLICATION_STATE.id, - }); - }); - }); - - describe('Update button', () => { - const button = () => wrapper.find('.js-cluster-application-update-button'); - - it('has indeterminate state on page load', () => { - mountComponent(); - - expect(button().exists()).toBe(false); - }); - - it('has enabled "Update" when "updateAvailable" is true', () => { - mountComponent({ updateAvailable: true }); - - expect(button().exists()).toBe(true); - expect(button().text()).toContain('Update'); - }); - - it('has enabled "Retry update" when update process fails', () => { - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - updateFailed: true, - }); - - expect(button().exists()).toBe(true); - expect(button().text()).toContain('Retry update'); - }); - - it('has disabled "Updating" when APPLICATION_STATUS.UPDATING', () => { - mountComponent({ status: APPLICATION_STATUS.UPDATING }); - - expect(button().exists()).toBe(true); - expect(button().text()).toContain('Updating'); - }); - - it('clicking update button emits event', () => { - const spy = jest.spyOn(eventHub, '$emit'); - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - updateAvailable: true, - }); - - button().vm.$emit('click'); - - expect(spy).toHaveBeenCalledWith('updateApplication', { - id: DEFAULT_APPLICATION_STATE.id, - params: {}, - }); - }); - - it('clicking disabled update button emits nothing', () => { - const spy = jest.spyOn(eventHub, '$emit'); - mountComponent({ status: APPLICATION_STATUS.UPDATING }); - - button().vm.$emit('click'); - - expect(spy).not.toHaveBeenCalled(); - }); - - it('displays an error message if application update failed', () => { - mountComponent({ - title: 'GitLab Runner', - status: APPLICATION_STATUS.INSTALLED, - updateFailed: true, - }); - const failureMessage = wrapper.find('.js-cluster-application-update-details'); - - expect(failureMessage.exists()).toBe(true); - expect(failureMessage.text()).toContain( - 'Update failed. Please check the logs and try again.', - ); - }); - - it('displays a success toast message if application update was successful', async () => { - mountComponent({ - title: 'GitLab Runner', - updateSuccessful: false, - }); - - wrapper.vm.$toast = { show: jest.fn() }; - wrapper.setProps({ updateSuccessful: true }); - - await wrapper.vm.$nextTick(); - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('GitLab Runner updated successfully.'); - }); - - describe('when updating does not require confirmation', () => { - beforeEach(() => mountComponent({ updateAvailable: true })); - - it('the modal is not rendered', () => { - expect(wrapper.find(UpdateApplicationConfirmationModal).exists()).toBe(false); - }); - - it('the correct button is rendered', () => { - expect(wrapper.find("[data-qa-selector='update_button']").exists()).toBe(true); - }); - }); - - describe('when updating requires confirmation', () => { - beforeEach(() => { - mountComponent({ - updateAvailable: true, - id: ELASTIC_STACK, - version: '1.1.2', - }); - }); - - it('displays a modal', () => { - expect(wrapper.find(UpdateApplicationConfirmationModal).exists()).toBe(true); - }); - - it('the correct button is rendered', () => { - expect(wrapper.find("[data-qa-selector='update_button_with_confirmation']").exists()).toBe( - true, - ); - }); - - it('triggers updateApplication event', () => { - jest.spyOn(eventHub, '$emit'); - wrapper.find(UpdateApplicationConfirmationModal).vm.$emit('confirm'); - - expect(eventHub.$emit).toHaveBeenCalledWith('updateApplication', { - id: ELASTIC_STACK, - params: {}, - }); - }); - }); - - describe('updating Elastic Stack special case', () => { - it('needs confirmation if version is lower than 3.0.0', () => { - mountComponent({ - updateAvailable: true, - id: ELASTIC_STACK, - version: '1.1.2', - }); - - expect(wrapper.find("[data-qa-selector='update_button_with_confirmation']").exists()).toBe( - true, - ); - expect(wrapper.find(UpdateApplicationConfirmationModal).exists()).toBe(true); - }); - - it('does not need confirmation is version is 3.0.0', () => { - mountComponent({ - updateAvailable: true, - id: ELASTIC_STACK, - version: '3.0.0', - }); - - expect(wrapper.find("[data-qa-selector='update_button']").exists()).toBe(true); - expect(wrapper.find(UpdateApplicationConfirmationModal).exists()).toBe(false); - }); - - it('does not need confirmation if version is higher than 3.0.0', () => { - mountComponent({ - updateAvailable: true, - id: ELASTIC_STACK, - version: '5.2.1', - }); - - expect(wrapper.find("[data-qa-selector='update_button']").exists()).toBe(true); - expect(wrapper.find(UpdateApplicationConfirmationModal).exists()).toBe(false); - }); - }); - }); - - describe('Version', () => { - const updateDetails = () => wrapper.find('.js-cluster-application-update-details'); - const versionEl = () => wrapper.find('.js-cluster-application-update-version'); - - it('displays a version number if application has been updated', () => { - const version = '0.1.45'; - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - updateSuccessful: true, - version, - }); - - expect(updateDetails().text()).toBe(`Updated to chart v${version}`); - }); - - it('contains a link to the chart repo if application has been updated', () => { - const version = '0.1.45'; - const chartRepo = 'https://gitlab.com/gitlab-org/charts/gitlab-runner'; - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - updateSuccessful: true, - chartRepo, - version, - }); - - expect(versionEl().attributes('href')).toEqual(chartRepo); - expect(versionEl().props('target')).toEqual('_blank'); - }); - - it('does not display a version number if application update failed', () => { - const version = '0.1.45'; - mountComponent({ - status: APPLICATION_STATUS.INSTALLED, - updateFailed: true, - version, - }); - - expect(updateDetails().text()).toBe('Update failed'); - expect(versionEl().exists()).toBe(false); - }); - - it('displays updating when the application update is currently updating', () => { - mountComponent({ - status: APPLICATION_STATUS.UPDATING, - updateSuccessful: true, - version: '1.2.3', - }); - - expect(updateDetails().text()).toBe('Updating'); - expect(versionEl().exists()).toBe(false); - }); - }); - - describe('Error block', () => { - const generalErrorMessage = () => wrapper.find('.js-cluster-application-general-error-message'); - - describe('when nothing fails', () => { - it('does not show error block', () => { - mountComponent(); - - expect(generalErrorMessage().exists()).toBe(false); - }); - }); - - describe('when install or uninstall fails', () => { - const statusReason = 'We broke it 0.0'; - const requestReason = 'We broke the request 0.0'; - - beforeEach(() => { - mountComponent({ - status: APPLICATION_STATUS.ERROR, - statusReason, - requestReason, - installFailed: true, - }); - }); - - it('shows status reason if it is available', () => { - const statusErrorMessage = wrapper.find('.js-cluster-application-status-error-message'); - - expect(statusErrorMessage.text()).toEqual(statusReason); - }); - - it('shows request reason if it is available', () => { - const requestErrorMessage = wrapper.find('.js-cluster-application-request-error-message'); - - expect(requestErrorMessage.text()).toEqual(requestReason); - }); - }); - - describe('when install fails', () => { - beforeEach(() => { - mountComponent({ - status: APPLICATION_STATUS.ERROR, - installFailed: true, - }); - }); - - it('shows a general message indicating the installation failed', () => { - expect(generalErrorMessage().text()).toEqual( - `Something went wrong while installing ${DEFAULT_APPLICATION_STATE.title}`, - ); - }); - }); - - describe('when uninstall fails', () => { - beforeEach(() => { - mountComponent({ - status: APPLICATION_STATUS.ERROR, - uninstallFailed: true, - }); - }); - - it('shows a general message indicating the uninstalling failed', () => { - expect(generalErrorMessage().text()).toEqual( - `Something went wrong while uninstalling ${DEFAULT_APPLICATION_STATE.title}`, - ); - }); - }); - }); -}); diff --git a/spec/frontend/clusters/components/applications_spec.js b/spec/frontend/clusters/components/applications_spec.js deleted file mode 100644 index 511f5fc1d89..00000000000 --- a/spec/frontend/clusters/components/applications_spec.js +++ /dev/null @@ -1,510 +0,0 @@ -import { shallowMount, mount } from '@vue/test-utils'; -import ApplicationRow from '~/clusters/components/application_row.vue'; -import Applications from '~/clusters/components/applications.vue'; -import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue'; -import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue'; -import { CLUSTER_TYPE, PROVIDER_TYPE } from '~/clusters/constants'; -import eventHub from '~/clusters/event_hub'; -import { APPLICATIONS_MOCK_STATE } from '../services/mock_data'; - -describe('Applications', () => { - let wrapper; - - beforeEach(() => { - gon.features = gon.features || {}; - }); - - const createComponent = ({ applications, type, propsData } = {}, isShallow) => { - const mountMethod = isShallow ? shallowMount : mount; - - wrapper = mountMethod(Applications, { - stubs: { ApplicationRow }, - propsData: { - type, - applications: { ...APPLICATIONS_MOCK_STATE, ...applications }, - ...propsData, - }, - }); - }; - - const createShallowComponent = (options) => createComponent(options, true); - const findByTestId = (id) => wrapper.find(`[data-testid="${id}"]`); - afterEach(() => { - wrapper.destroy(); - }); - - describe('Project cluster applications', () => { - beforeEach(() => { - createComponent({ type: CLUSTER_TYPE.PROJECT }); - }); - - it('renders a row for Ingress', () => { - expect(wrapper.find('.js-cluster-application-row-ingress').exists()).toBe(true); - }); - - it('renders a row for Cert-Manager', () => { - expect(wrapper.find('.js-cluster-application-row-cert_manager').exists()).toBe(true); - }); - - it('renders a row for Crossplane', () => { - expect(wrapper.find('.js-cluster-application-row-crossplane').exists()).toBe(true); - }); - - it('renders a row for Prometheus', () => { - expect(wrapper.find('.js-cluster-application-row-prometheus').exists()).toBe(true); - }); - - it('renders a row for GitLab Runner', () => { - expect(wrapper.find('.js-cluster-application-row-runner').exists()).toBe(true); - }); - - it('renders a row for Jupyter', () => { - expect(wrapper.find('.js-cluster-application-row-jupyter').exists()).toBe(true); - }); - - it('renders a row for Knative', () => { - expect(wrapper.find('.js-cluster-application-row-knative').exists()).toBe(true); - }); - - it('renders a row for Elastic Stack', () => { - expect(wrapper.find('.js-cluster-application-row-elastic_stack').exists()).toBe(true); - }); - - it('renders a row for Cilium', () => { - expect(wrapper.find('.js-cluster-application-row-cilium').exists()).toBe(true); - }); - }); - - describe('Group cluster applications', () => { - beforeEach(() => { - createComponent({ type: CLUSTER_TYPE.GROUP }); - }); - - it('renders a row for Ingress', () => { - expect(wrapper.find('.js-cluster-application-row-ingress').exists()).toBe(true); - }); - - it('renders a row for Cert-Manager', () => { - expect(wrapper.find('.js-cluster-application-row-cert_manager').exists()).toBe(true); - }); - - it('renders a row for Crossplane', () => { - expect(wrapper.find('.js-cluster-application-row-crossplane').exists()).toBe(true); - }); - - it('renders a row for Prometheus', () => { - expect(wrapper.find('.js-cluster-application-row-prometheus').exists()).toBe(true); - }); - - it('renders a row for GitLab Runner', () => { - expect(wrapper.find('.js-cluster-application-row-runner').exists()).toBe(true); - }); - - it('renders a row for Jupyter', () => { - expect(wrapper.find('.js-cluster-application-row-jupyter').exists()).toBe(true); - }); - - it('renders a row for Knative', () => { - expect(wrapper.find('.js-cluster-application-row-knative').exists()).toBe(true); - }); - - it('renders a row for Elastic Stack', () => { - expect(wrapper.find('.js-cluster-application-row-elastic_stack').exists()).toBe(true); - }); - - it('renders a row for Cilium', () => { - expect(wrapper.find('.js-cluster-application-row-cilium').exists()).toBe(true); - }); - }); - - describe('Instance cluster applications', () => { - beforeEach(() => { - createComponent({ type: CLUSTER_TYPE.INSTANCE }); - }); - - it('renders a row for Ingress', () => { - expect(wrapper.find('.js-cluster-application-row-ingress').exists()).toBe(true); - }); - - it('renders a row for Cert-Manager', () => { - expect(wrapper.find('.js-cluster-application-row-cert_manager').exists()).toBe(true); - }); - - it('renders a row for Crossplane', () => { - expect(wrapper.find('.js-cluster-application-row-crossplane').exists()).toBe(true); - }); - - it('renders a row for Prometheus', () => { - expect(wrapper.find('.js-cluster-application-row-prometheus').exists()).toBe(true); - }); - - it('renders a row for GitLab Runner', () => { - expect(wrapper.find('.js-cluster-application-row-runner').exists()).toBe(true); - }); - - it('renders a row for Jupyter', () => { - expect(wrapper.find('.js-cluster-application-row-jupyter').exists()).toBe(true); - }); - - it('renders a row for Knative', () => { - expect(wrapper.find('.js-cluster-application-row-knative').exists()).toBe(true); - }); - - it('renders a row for Elastic Stack', () => { - expect(wrapper.find('.js-cluster-application-row-elastic_stack').exists()).toBe(true); - }); - - it('renders a row for Cilium', () => { - expect(wrapper.find('.js-cluster-application-row-cilium').exists()).toBe(true); - }); - }); - - describe('Helm application', () => { - it('does not render a row for Helm Tiller', () => { - createComponent(); - expect(wrapper.find('.js-cluster-application-row-helm').exists()).toBe(false); - }); - }); - - describe('Ingress application', () => { - it('shows the correct warning message', () => { - createComponent(); - expect(findByTestId('ingressCostWarning').element).toMatchSnapshot(); - }); - - describe('when installed', () => { - describe('with ip address', () => { - it('renders ip address with a clipboard button', () => { - createComponent({ - applications: { - ingress: { - title: 'Ingress', - status: 'installed', - externalIp: '0.0.0.0', - }, - }, - }); - - expect(wrapper.find('.js-endpoint').element.value).toEqual('0.0.0.0'); - expect(wrapper.find('.js-clipboard-btn').attributes('data-clipboard-text')).toEqual( - '0.0.0.0', - ); - }); - }); - - describe('with hostname', () => { - it('renders hostname with a clipboard button', () => { - createComponent({ - applications: { - ingress: { - title: 'Ingress', - status: 'installed', - externalHostname: 'localhost.localdomain', - }, - cert_manager: { title: 'Cert-Manager' }, - crossplane: { title: 'Crossplane', stack: '' }, - runner: { title: 'GitLab Runner' }, - prometheus: { title: 'Prometheus' }, - jupyter: { title: 'JupyterHub', hostname: '' }, - knative: { title: 'Knative', hostname: '' }, - elastic_stack: { title: 'Elastic Stack' }, - cilium: { title: 'GitLab Container Network Policies' }, - }, - }); - - expect(wrapper.find('.js-endpoint').element.value).toEqual('localhost.localdomain'); - - expect(wrapper.find('.js-clipboard-btn').attributes('data-clipboard-text')).toEqual( - 'localhost.localdomain', - ); - }); - }); - - describe('without ip address', () => { - it('renders an input text with a loading icon and an alert text', () => { - createComponent({ - applications: { - ingress: { - title: 'Ingress', - status: 'installed', - }, - }, - }); - - expect(wrapper.find('.js-ingress-ip-loading-icon').exists()).toBe(true); - expect(wrapper.find('.js-no-endpoint-message').exists()).toBe(true); - }); - }); - }); - - describe('before installing', () => { - it('does not render the IP address', () => { - createComponent(); - - expect(wrapper.text()).not.toContain('Ingress IP Address'); - expect(wrapper.find('.js-endpoint').exists()).toBe(false); - }); - }); - }); - - describe('Cert-Manager application', () => { - it('shows the correct description', () => { - createComponent(); - expect(findByTestId('certManagerDescription').element).toMatchSnapshot(); - }); - - describe('when not installed', () => { - it('renders email & allows editing', () => { - createComponent({ - applications: { - cert_manager: { - title: 'Cert-Manager', - email: 'before@example.com', - status: 'installable', - }, - }, - }); - - expect(wrapper.find('.js-email').element.value).toEqual('before@example.com'); - expect(wrapper.find('.js-email').attributes('readonly')).toBe(undefined); - }); - }); - - describe('when installed', () => { - it('renders email in readonly', () => { - createComponent({ - applications: { - cert_manager: { - title: 'Cert-Manager', - email: 'after@example.com', - status: 'installed', - }, - }, - }); - - expect(wrapper.find('.js-email').element.value).toEqual('after@example.com'); - expect(wrapper.find('.js-email').attributes('readonly')).toEqual('readonly'); - }); - }); - }); - - describe('Jupyter application', () => { - describe('with ingress installed with ip & jupyter installable', () => { - it('renders hostname active input', () => { - createComponent({ - applications: { - ingress: { - title: 'Ingress', - status: 'installed', - externalIp: '1.1.1.1', - }, - }, - }); - - expect( - wrapper.find('.js-cluster-application-row-jupyter .js-hostname').attributes('readonly'), - ).toEqual(undefined); - }); - }); - - describe('with ingress installed without external ip', () => { - it('does not render hostname input', () => { - createComponent({ - applications: { - ingress: { title: 'Ingress', status: 'installed' }, - }, - }); - - expect(wrapper.find('.js-cluster-application-row-jupyter .js-hostname').exists()).toBe( - false, - ); - }); - }); - - describe('with ingress & jupyter installed', () => { - it('renders readonly input', () => { - createComponent({ - applications: { - ingress: { - title: 'Ingress', - status: 'installed', - externalIp: '1.1.1.1', - }, - jupyter: { title: 'JupyterHub', status: 'installed', hostname: '' }, - }, - }); - - expect( - wrapper.find('.js-cluster-application-row-jupyter .js-hostname').attributes('readonly'), - ).toEqual('readonly'); - }); - }); - - describe('without ingress installed', () => { - beforeEach(() => { - createComponent(); - }); - - it('does not render input', () => { - expect(wrapper.find('.js-cluster-application-row-jupyter .js-hostname').exists()).toBe( - false, - ); - }); - }); - }); - - describe('Prometheus application', () => { - it('shows the correct description', () => { - createComponent(); - expect(findByTestId('prometheusDescription').element).toMatchSnapshot(); - }); - }); - - describe('Knative application', () => { - const availableDomain = { - id: 4, - domain: 'newhostname.com', - }; - const propsData = { - applications: { - knative: { - title: 'Knative', - hostname: 'example.com', - status: 'installed', - externalIp: '1.1.1.1', - installed: true, - availableDomains: [availableDomain], - pagesDomain: null, - }, - }, - }; - let knativeDomainEditor; - - beforeEach(() => { - createShallowComponent(propsData); - jest.spyOn(eventHub, '$emit'); - - knativeDomainEditor = wrapper.find(KnativeDomainEditor); - }); - - it('shows the correct description', async () => { - createComponent(); - wrapper.setProps({ - providerType: PROVIDER_TYPE.GCP, - preInstalledKnative: true, - }); - - await wrapper.vm.$nextTick(); - - expect(findByTestId('installed-via').element).toMatchSnapshot(); - }); - - it('emits saveKnativeDomain event when knative domain editor emits save event', () => { - propsData.applications.knative.hostname = availableDomain.domain; - propsData.applications.knative.pagesDomain = availableDomain; - knativeDomainEditor.vm.$emit('save'); - - expect(eventHub.$emit).toHaveBeenCalledWith('saveKnativeDomain', { - id: 'knative', - params: { - hostname: availableDomain.domain, - pages_domain_id: availableDomain.id, - }, - }); - }); - - it('emits saveKnativeDomain event when knative domain editor emits save event with custom domain', () => { - const newHostName = 'someothernewhostname.com'; - propsData.applications.knative.hostname = newHostName; - propsData.applications.knative.pagesDomain = null; - knativeDomainEditor.vm.$emit('save'); - - expect(eventHub.$emit).toHaveBeenCalledWith('saveKnativeDomain', { - id: 'knative', - params: { - hostname: newHostName, - pages_domain_id: undefined, - }, - }); - }); - - it('emits setKnativeHostname event when knative domain editor emits change event', () => { - wrapper.find(KnativeDomainEditor).vm.$emit('set', { - domain: availableDomain.domain, - domainId: availableDomain.id, - }); - - expect(eventHub.$emit).toHaveBeenCalledWith('setKnativeDomain', { - id: 'knative', - domain: availableDomain.domain, - domainId: availableDomain.id, - }); - }); - }); - - describe('Crossplane application', () => { - const propsData = { - applications: { - crossplane: { - title: 'Crossplane', - stack: { - code: '', - }, - }, - }, - }; - - beforeEach(() => createShallowComponent(propsData)); - - it('renders the correct Component', () => { - const crossplane = wrapper.find(CrossplaneProviderStack); - expect(crossplane.exists()).toBe(true); - }); - - it('shows the correct description', () => { - createComponent(); - expect(findByTestId('crossplaneDescription').element).toMatchSnapshot(); - }); - }); - - describe('Elastic Stack application', () => { - describe('with elastic stack installable', () => { - it('renders the install button enabled', () => { - createComponent(); - - expect( - wrapper - .find( - '.js-cluster-application-row-elastic_stack .js-cluster-application-install-button', - ) - .attributes('disabled'), - ).toBeUndefined(); - }); - }); - - describe('elastic stack installed', () => { - it('renders uninstall button', () => { - createComponent({ - applications: { - elastic_stack: { title: 'Elastic Stack', status: 'installed' }, - }, - }); - - expect( - wrapper - .find( - '.js-cluster-application-row-elastic_stack .js-cluster-application-install-button', - ) - .attributes('disabled'), - ).toEqual('disabled'); - }); - }); - }); - - describe('Cilium application', () => { - it('shows the correct description', () => { - createComponent({ propsData: { ciliumHelpPath: 'cilium-help-path' } }); - expect(findByTestId('ciliumDescription').element).toMatchSnapshot(); - }); - }); -}); diff --git a/spec/frontend/clusters/components/knative_domain_editor_spec.js b/spec/frontend/clusters/components/knative_domain_editor_spec.js deleted file mode 100644 index 207eb071171..00000000000 --- a/spec/frontend/clusters/components/knative_domain_editor_spec.js +++ /dev/null @@ -1,179 +0,0 @@ -import { GlDropdownItem, GlButton } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue'; -import { APPLICATION_STATUS } from '~/clusters/constants'; - -const { UPDATING } = APPLICATION_STATUS; - -describe('KnativeDomainEditor', () => { - let wrapper; - let knative; - - const createComponent = (props = {}) => { - wrapper = shallowMount(KnativeDomainEditor, { - propsData: { ...props }, - }); - }; - - beforeEach(() => { - knative = { - title: 'Knative', - hostname: 'example.com', - installed: true, - }; - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - describe('knative has an assigned IP address', () => { - beforeEach(() => { - knative.externalIp = '1.1.1.1'; - createComponent({ knative }); - }); - - it('renders ip address with a clipboard button', () => { - expect(wrapper.find('.js-knative-endpoint').exists()).toBe(true); - expect(wrapper.find('.js-knative-endpoint').element.value).toEqual(knative.externalIp); - }); - - it('displays ip address clipboard button', () => { - expect(wrapper.find('.js-knative-endpoint-clipboard-btn').attributes('text')).toEqual( - knative.externalIp, - ); - }); - - it('renders domain & allows editing', () => { - const domainNameInput = wrapper.find('.js-knative-domainname'); - - expect(domainNameInput.element.value).toEqual(knative.hostname); - expect(domainNameInput.attributes('readonly')).toBeFalsy(); - }); - - it('renders an update/save Knative domain button', () => { - expect(wrapper.find('.js-knative-save-domain-button').exists()).toBe(true); - }); - }); - - describe('knative without ip address', () => { - beforeEach(() => { - knative.externalIp = null; - createComponent({ knative }); - }); - - it('renders an input text with a loading icon', () => { - expect(wrapper.find('.js-knative-ip-loading-icon').exists()).toBe(true); - }); - - it('renders message indicating there is not IP address assigned', () => { - expect(wrapper.find('.js-no-knative-endpoint-message').exists()).toBe(true); - }); - }); - - describe('clicking save changes button', () => { - beforeEach(() => { - createComponent({ knative }); - }); - - it('triggers save event and pass current knative hostname', () => { - wrapper.find(GlButton).vm.$emit('click'); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('save').length).toEqual(1); - }); - }); - }); - - describe('when knative domain name was saved successfully', () => { - beforeEach(() => { - createComponent({ knative }); - }); - - it('displays toast indicating a successful update', () => { - wrapper.vm.$toast = { show: jest.fn() }; - wrapper.setProps({ knative: { updateSuccessful: true, ...knative } }); - - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( - 'Knative domain name was updated successfully.', - ); - }); - }); - }); - - describe('when knative domain name input changes', () => { - it('emits "set" event with updated domain name', () => { - const newDomain = { - id: 4, - domain: 'newhostname.com', - }; - - createComponent({ knative: { ...knative, availableDomains: [newDomain] } }); - jest.spyOn(wrapper.vm, 'selectDomain'); - - wrapper.find(GlDropdownItem).vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.selectDomain).toHaveBeenCalledWith(newDomain); - expect(wrapper.emitted('set')[0]).toEqual([ - { - domain: newDomain.domain, - domainId: newDomain.id, - }, - ]); - }); - }); - - it('emits "set" event with updated custom domain name', () => { - const newHostname = 'newhostname.com'; - - createComponent({ knative }); - jest.spyOn(wrapper.vm, 'selectCustomDomain'); - - wrapper.setData({ knativeHostname: newHostname }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.selectCustomDomain).toHaveBeenCalledWith(newHostname); - expect(wrapper.emitted('set')[0]).toEqual([ - { - domain: newHostname, - domainId: null, - }, - ]); - }); - }); - }); - - describe('when updating knative domain name failed', () => { - beforeEach(() => { - createComponent({ knative }); - }); - - it('displays an error banner indicating the operation failure', () => { - wrapper.setProps({ knative: { updateFailed: true, ...knative } }); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find('.js-cluster-knative-domain-name-failure-message').exists()).toBe(true); - }); - }); - }); - - describe(`when knative status is ${UPDATING}`, () => { - beforeEach(() => { - createComponent({ knative: { status: UPDATING, ...knative } }); - }); - - it('renders loading spinner in save button', () => { - expect(wrapper.find(GlButton).props('loading')).toBe(true); - }); - - it('renders disabled save button', () => { - expect(wrapper.find(GlButton).props('disabled')).toBe(true); - }); - - it('renders save button with "Saving" label', () => { - expect(wrapper.find(GlButton).text()).toBe('Saving'); - }); - }); -}); diff --git a/spec/frontend/clusters/components/uninstall_application_button_spec.js b/spec/frontend/clusters/components/uninstall_application_button_spec.js deleted file mode 100644 index 2596820e5ac..00000000000 --- a/spec/frontend/clusters/components/uninstall_application_button_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import { GlButton } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import UninstallApplicationButton from '~/clusters/components/uninstall_application_button.vue'; -import { APPLICATION_STATUS } from '~/clusters/constants'; - -const { INSTALLED, UPDATING, UNINSTALLING } = APPLICATION_STATUS; - -describe('UninstallApplicationButton', () => { - let wrapper; - - const createComponent = (props = {}) => { - wrapper = shallowMount(UninstallApplicationButton, { - propsData: { ...props }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe.each` - status | loading | disabled | text - ${INSTALLED} | ${false} | ${false} | ${'Uninstall'} - ${UPDATING} | ${false} | ${true} | ${'Uninstall'} - ${UNINSTALLING} | ${true} | ${true} | ${'Uninstalling'} - `('when app status is $status', ({ loading, disabled, status, text }) => { - beforeEach(() => { - createComponent({ status }); - }); - - it(`renders a button with loading=${loading} and disabled=${disabled}`, () => { - expect(wrapper.find(GlButton).props()).toMatchObject({ loading, disabled }); - }); - - it(`renders a button with text="${text}"`, () => { - expect(wrapper.find(GlButton).text()).toBe(text); - }); - }); -}); diff --git a/spec/frontend/clusters/components/uninstall_application_confirmation_modal_spec.js b/spec/frontend/clusters/components/uninstall_application_confirmation_modal_spec.js deleted file mode 100644 index 74ae4ecc486..00000000000 --- a/spec/frontend/clusters/components/uninstall_application_confirmation_modal_spec.js +++ /dev/null @@ -1,57 +0,0 @@ -import { GlModal } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import UninstallApplicationConfirmationModal from '~/clusters/components/uninstall_application_confirmation_modal.vue'; -import { INGRESS } from '~/clusters/constants'; - -describe('UninstallApplicationConfirmationModal', () => { - let wrapper; - const appTitle = 'Ingress'; - - const createComponent = (props = {}) => { - wrapper = shallowMount(UninstallApplicationConfirmationModal, { - propsData: { ...props }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - beforeEach(() => { - createComponent({ application: INGRESS, applicationTitle: appTitle }); - }); - - it(`renders a modal with a title "Uninstall ${appTitle}"`, () => { - expect(wrapper.find(GlModal).attributes('title')).toEqual(`Uninstall ${appTitle}`); - }); - - it(`renders a modal with an ok button labeled "Uninstall ${appTitle}"`, () => { - expect(wrapper.find(GlModal).attributes('ok-title')).toEqual(`Uninstall ${appTitle}`); - }); - - describe('when ok button is clicked', () => { - beforeEach(() => { - jest.spyOn(wrapper.vm, 'trackUninstallButtonClick'); - wrapper.find(GlModal).vm.$emit('ok'); - }); - - it('emits confirm event', () => - wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('confirm')).toBeTruthy(); - })); - - it('calls track uninstall button click mixin', () => { - expect(wrapper.vm.trackUninstallButtonClick).toHaveBeenCalledWith(INGRESS); - }); - }); - - it('displays a warning text indicating the app will be uninstalled', () => { - expect(wrapper.text()).toContain(`You are about to uninstall ${appTitle} from your cluster.`); - }); - - it('displays a custom warning text depending on the application', () => { - expect(wrapper.text()).toContain( - `The associated load balancer and IP will be deleted and cannot be restored.`, - ); - }); -}); diff --git a/spec/frontend/clusters/components/update_application_confirmation_modal_spec.js b/spec/frontend/clusters/components/update_application_confirmation_modal_spec.js deleted file mode 100644 index e933f17a980..00000000000 --- a/spec/frontend/clusters/components/update_application_confirmation_modal_spec.js +++ /dev/null @@ -1,52 +0,0 @@ -import { GlModal } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import UpdateApplicationConfirmationModal from '~/clusters/components/update_application_confirmation_modal.vue'; -import { ELASTIC_STACK } from '~/clusters/constants'; - -describe('UpdateApplicationConfirmationModal', () => { - let wrapper; - const appTitle = 'Elastic stack'; - - const createComponent = (props = {}) => { - wrapper = shallowMount(UpdateApplicationConfirmationModal, { - propsData: { ...props }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - beforeEach(() => { - createComponent({ application: ELASTIC_STACK, applicationTitle: appTitle }); - }); - - it(`renders a modal with a title "Update ${appTitle}"`, () => { - expect(wrapper.find(GlModal).attributes('title')).toEqual(`Update ${appTitle}`); - }); - - it(`renders a modal with an ok button labeled "Update ${appTitle}"`, () => { - expect(wrapper.find(GlModal).attributes('ok-title')).toEqual(`Update ${appTitle}`); - }); - - describe('when ok button is clicked', () => { - beforeEach(() => { - wrapper.find(GlModal).vm.$emit('ok'); - }); - - it('emits confirm event', () => - wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('confirm')).toBeTruthy(); - })); - - it('displays a warning text indicating the app will be updated', () => { - expect(wrapper.text()).toContain(`You are about to update ${appTitle} on your cluster.`); - }); - - it('displays a custom warning text depending on the application', () => { - expect(wrapper.text()).toContain( - `Your Elasticsearch cluster will be re-created during this upgrade. Your logs will be re-indexed, and you will lose historical logs from hosts terminated in the last 30 days.`, - ); - }); - }); -}); diff --git a/spec/frontend/clusters/services/application_state_machine_spec.js b/spec/frontend/clusters/services/application_state_machine_spec.js deleted file mode 100644 index 4e731e331c2..00000000000 --- a/spec/frontend/clusters/services/application_state_machine_spec.js +++ /dev/null @@ -1,206 +0,0 @@ -import { - APPLICATION_STATUS, - UNINSTALL_EVENT, - UPDATE_EVENT, - INSTALL_EVENT, -} from '~/clusters/constants'; -import transitionApplicationState from '~/clusters/services/application_state_machine'; - -const { - NO_STATUS, - SCHEDULED, - NOT_INSTALLABLE, - INSTALLABLE, - INSTALLING, - INSTALLED, - ERROR, - UPDATING, - UPDATED, - UPDATE_ERRORED, - UNINSTALLING, - UNINSTALL_ERRORED, - UNINSTALLED, - PRE_INSTALLED, - EXTERNALLY_INSTALLED, -} = APPLICATION_STATUS; - -const NO_EFFECTS = 'no effects'; - -describe('applicationStateMachine', () => { - const noEffectsToEmptyObject = (effects) => (typeof effects === 'string' ? {} : effects); - - describe(`current state is ${NO_STATUS}`, () => { - it.each` - expectedState | event | effects - ${INSTALLING} | ${SCHEDULED} | ${NO_EFFECTS} - ${NOT_INSTALLABLE} | ${NOT_INSTALLABLE} | ${NO_EFFECTS} - ${INSTALLABLE} | ${INSTALLABLE} | ${NO_EFFECTS} - ${INSTALLING} | ${INSTALLING} | ${NO_EFFECTS} - ${INSTALLED} | ${INSTALLED} | ${NO_EFFECTS} - ${INSTALLABLE} | ${ERROR} | ${{ installFailed: true }} - ${UPDATING} | ${UPDATING} | ${NO_EFFECTS} - ${INSTALLED} | ${UPDATED} | ${NO_EFFECTS} - ${INSTALLED} | ${UPDATE_ERRORED} | ${{ updateFailed: true }} - ${UNINSTALLING} | ${UNINSTALLING} | ${NO_EFFECTS} - ${INSTALLED} | ${UNINSTALL_ERRORED} | ${{ uninstallFailed: true }} - ${UNINSTALLED} | ${UNINSTALLED} | ${NO_EFFECTS} - ${PRE_INSTALLED} | ${PRE_INSTALLED} | ${NO_EFFECTS} - ${EXTERNALLY_INSTALLED} | ${EXTERNALLY_INSTALLED} | ${NO_EFFECTS} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: NO_STATUS, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - - describe(`current state is ${NOT_INSTALLABLE}`, () => { - it.each` - expectedState | event | effects - ${INSTALLABLE} | ${INSTALLABLE} | ${NO_EFFECTS} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: NOT_INSTALLABLE, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - - describe(`current state is ${INSTALLABLE}`, () => { - it.each` - expectedState | event | effects - ${INSTALLING} | ${INSTALL_EVENT} | ${{ installFailed: false }} - ${INSTALLED} | ${INSTALLED} | ${{ installFailed: false }} - ${NOT_INSTALLABLE} | ${NOT_INSTALLABLE} | ${NO_EFFECTS} - ${UNINSTALLED} | ${UNINSTALLED} | ${{ installFailed: false }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: INSTALLABLE, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - - describe(`current state is ${INSTALLING}`, () => { - it.each` - expectedState | event | effects - ${INSTALLED} | ${INSTALLED} | ${NO_EFFECTS} - ${INSTALLABLE} | ${ERROR} | ${{ installFailed: true }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: INSTALLING, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - - describe(`current state is ${INSTALLED}`, () => { - it.each` - expectedState | event | effects - ${UPDATING} | ${UPDATE_EVENT} | ${{ updateFailed: false, updateSuccessful: false }} - ${UNINSTALLING} | ${UNINSTALL_EVENT} | ${{ uninstallFailed: false, uninstallSuccessful: false }} - ${NOT_INSTALLABLE} | ${NOT_INSTALLABLE} | ${NO_EFFECTS} - ${UNINSTALLED} | ${UNINSTALLED} | ${NO_EFFECTS} - ${INSTALLABLE} | ${ERROR} | ${{ installFailed: true }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: INSTALLED, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - - describe(`current state is ${UPDATING}`, () => { - it.each` - expectedState | event | effects - ${INSTALLED} | ${UPDATED} | ${{ updateSuccessful: true }} - ${INSTALLED} | ${UPDATE_ERRORED} | ${{ updateFailed: true }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: UPDATING, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...effects, - }); - }); - }); - - describe(`current state is ${UNINSTALLING}`, () => { - it.each` - expectedState | event | effects - ${INSTALLABLE} | ${INSTALLABLE} | ${{ uninstallSuccessful: true }} - ${INSTALLED} | ${UNINSTALL_ERRORED} | ${{ uninstallFailed: true }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: UNINSTALLING, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...effects, - }); - }); - }); - - describe(`current state is ${UNINSTALLED}`, () => { - it.each` - expectedState | event | effects - ${INSTALLED} | ${INSTALLED} | ${NO_EFFECTS} - ${INSTALLABLE} | ${ERROR} | ${{ installFailed: true }} - `(`transitions to $expectedState on $event event and applies $effects`, (data) => { - const { expectedState, event, effects } = data; - const currentAppState = { - status: UNINSTALLED, - }; - - expect(transitionApplicationState(currentAppState, event)).toEqual({ - status: expectedState, - ...noEffectsToEmptyObject(effects), - }); - }); - }); - describe('current state is undefined', () => { - it('returns the current state without having any effects', () => { - const currentAppState = {}; - expect(transitionApplicationState(currentAppState, INSTALLABLE)).toEqual(currentAppState); - }); - }); - - describe('with event is undefined', () => { - it('returns the current state without having any effects', () => { - const currentAppState = { - status: NO_STATUS, - }; - expect(transitionApplicationState(currentAppState, undefined)).toEqual(currentAppState); - }); - }); -}); diff --git a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js deleted file mode 100644 index f95b175ca64..00000000000 --- a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js +++ /dev/null @@ -1,85 +0,0 @@ -import { GlDropdownItem, GlIcon } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue'; - -describe('CrossplaneProviderStack component', () => { - let wrapper; - - const defaultProps = { - stacks: [ - { - name: 'Google Cloud Platform', - code: 'gcp', - }, - { - name: 'Amazon Web Services', - code: 'aws', - }, - ], - }; - - function createComponent(props = {}) { - const propsData = { - ...defaultProps, - ...props, - }; - - wrapper = shallowMount(CrossplaneProviderStack, { - propsData, - }); - } - - beforeEach(() => { - const crossplane = { - title: 'crossplane', - stack: '', - }; - createComponent({ crossplane }); - }); - - const findDropdownElements = () => wrapper.findAll(GlDropdownItem); - const findFirstDropdownElement = () => findDropdownElements().at(0); - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders all of the available stacks in the dropdown', () => { - const dropdownElements = findDropdownElements(); - - expect(dropdownElements.length).toBe(defaultProps.stacks.length); - - defaultProps.stacks.forEach((stack, index) => - expect(dropdownElements.at(index).text()).toEqual(stack.name), - ); - }); - - it('displays the correct label for the first dropdown item if a stack is selected', () => { - const crossplane = { - title: 'crossplane', - stack: 'gcp', - }; - createComponent({ crossplane }); - expect(wrapper.vm.dropdownText).toBe('Google Cloud Platform'); - }); - - it('emits the "set" event with the selected stack value', () => { - const crossplane = { - title: 'crossplane', - stack: 'gcp', - }; - createComponent({ crossplane }); - findFirstDropdownElement().vm.$emit('click'); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted().set[0][0].code).toEqual('gcp'); - }); - }); - - it('renders the correct dropdown text when no stack is selected', () => { - expect(wrapper.vm.dropdownText).toBe('Select Stack'); - }); - - it('renders an external link', () => { - expect(wrapper.find(GlIcon).props('name')).toBe('external-link'); - }); -}); diff --git a/spec/frontend/clusters/services/mock_data.js b/spec/frontend/clusters/services/mock_data.js index a75fcb0cb06..cf63d5452ac 100644 --- a/spec/frontend/clusters/services/mock_data.js +++ b/spec/frontend/clusters/services/mock_data.js @@ -1,170 +1,19 @@ -import { APPLICATION_STATUS } from '~/clusters/constants'; - const CLUSTERS_MOCK_DATA = { GET: { '/gitlab-org/gitlab-shell/clusters/1/status.json': { data: { status: 'errored', status_reason: 'Failed to request to CloudPlatform.', - applications: [ - { - name: 'helm', - status: APPLICATION_STATUS.INSTALLABLE, - status_reason: null, - can_uninstall: false, - }, - { - name: 'ingress', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - external_ip: null, - external_hostname: null, - can_uninstall: false, - }, - { - name: 'runner', - status: APPLICATION_STATUS.INSTALLING, - status_reason: null, - can_uninstall: false, - }, - { - name: 'prometheus', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - can_uninstall: false, - }, - { - name: 'jupyter', - status: APPLICATION_STATUS.INSTALLING, - status_reason: 'Cannot connect', - can_uninstall: false, - }, - { - name: 'knative', - status: APPLICATION_STATUS.INSTALLING, - status_reason: 'Cannot connect', - can_uninstall: false, - }, - { - name: 'cert_manager', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - email: 'test@example.com', - can_uninstall: false, - }, - { - name: 'crossplane', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - can_uninstall: false, - }, - { - name: 'elastic_stack', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - can_uninstall: false, - }, - ], }, }, '/gitlab-org/gitlab-shell/clusters/2/status.json': { data: { status: 'errored', status_reason: 'Failed to request to CloudPlatform.', - applications: [ - { - name: 'helm', - status: APPLICATION_STATUS.INSTALLED, - status_reason: null, - }, - { - name: 'ingress', - status: APPLICATION_STATUS.INSTALLED, - status_reason: 'Cannot connect', - external_ip: '1.1.1.1', - external_hostname: null, - }, - { - name: 'runner', - status: APPLICATION_STATUS.INSTALLING, - status_reason: null, - }, - { - name: 'prometheus', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - }, - { - name: 'jupyter', - status: APPLICATION_STATUS.INSTALLABLE, - status_reason: 'Cannot connect', - }, - { - name: 'knative', - status: APPLICATION_STATUS.INSTALLABLE, - status_reason: 'Cannot connect', - }, - { - name: 'cert_manager', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - email: 'test@example.com', - }, - { - name: 'crossplane', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - stack: 'gcp', - }, - { - name: 'elastic_stack', - status: APPLICATION_STATUS.ERROR, - status_reason: 'Cannot connect', - }, - ], }, }, }, - POST: { - '/gitlab-org/gitlab-shell/clusters/1/applications/helm': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/ingress': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/crossplane': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/cert_manager': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/runner': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/jupyter': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/knative': {}, - '/gitlab-org/gitlab-shell/clusters/1/applications/elastic_stack': {}, - }, -}; - -const DEFAULT_APPLICATION_STATE = { - id: 'some-app', - title: 'My App', - titleLink: 'https://about.gitlab.com/', - description: 'Some description about this interesting application!', - status: null, - statusReason: null, - requestReason: null, -}; - -const APPLICATIONS_MOCK_STATE = { - helm: { title: 'Helm Tiller', status: 'installable' }, - ingress: { - title: 'Ingress', - status: 'installable', - }, - crossplane: { title: 'Crossplane', status: 'installable', stack: '' }, - cert_manager: { title: 'Cert-Manager', status: 'installable' }, - runner: { title: 'GitLab Runner' }, - prometheus: { title: 'Prometheus' }, - jupyter: { title: 'JupyterHub', status: 'installable', hostname: '' }, - knative: { title: 'Knative ', status: 'installable', hostname: '' }, - elastic_stack: { title: 'Elastic Stack', status: 'installable' }, - cilium: { - title: 'GitLab Container Network Policies', - status: 'not_installable', - }, + POST: {}, }; -export { CLUSTERS_MOCK_DATA, DEFAULT_APPLICATION_STATE, APPLICATIONS_MOCK_STATE }; +export { CLUSTERS_MOCK_DATA }; diff --git a/spec/frontend/clusters/stores/clusters_store_spec.js b/spec/frontend/clusters/stores/clusters_store_spec.js index cdba6fc6ab8..5e797bbf8a8 100644 --- a/spec/frontend/clusters/stores/clusters_store_spec.js +++ b/spec/frontend/clusters/stores/clusters_store_spec.js @@ -1,4 +1,3 @@ -import { APPLICATION_INSTALLED_STATUSES, APPLICATION_STATUS, RUNNER } from '~/clusters/constants'; import ClustersStore from '~/clusters/stores/clusters_store'; import { CLUSTERS_MOCK_DATA } from '../services/mock_data'; @@ -31,17 +30,6 @@ describe('Clusters Store', () => { }); }); - describe('updateAppProperty', () => { - it('should store new request reason', () => { - expect(store.state.applications.helm.requestReason).toEqual(null); - - const newReason = 'We broke it.'; - store.updateAppProperty('helm', 'requestReason', newReason); - - expect(store.state.applications.helm.requestReason).toEqual(newReason); - }); - }); - describe('updateStateFromServer', () => { it('should store new polling data from server', () => { const mockResponseData = @@ -50,196 +38,16 @@ describe('Clusters Store', () => { expect(store.state).toEqual({ helpPath: null, - helmHelpPath: null, - ingressHelpPath: null, environmentsHelpPath: null, clustersHelpPath: null, deployBoardsHelpPath: null, - cloudRunHelpPath: null, status: mockResponseData.status, statusReason: mockResponseData.status_reason, providerType: null, - preInstalledKnative: false, rbac: false, - applications: { - helm: { - title: 'Legacy Helm Tiller server', - status: mockResponseData.applications[0].status, - statusReason: mockResponseData.applications[0].status_reason, - requestReason: null, - installable: true, - installed: false, - installFailed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - ingress: { - title: 'Ingress', - status: APPLICATION_STATUS.INSTALLABLE, - statusReason: mockResponseData.applications[1].status_reason, - requestReason: null, - externalIp: null, - externalHostname: null, - installable: true, - installed: false, - installFailed: true, - uninstallable: false, - updateFailed: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - runner: { - title: 'GitLab Runner', - status: mockResponseData.applications[2].status, - statusReason: mockResponseData.applications[2].status_reason, - requestReason: null, - version: mockResponseData.applications[2].version, - updateAvailable: mockResponseData.applications[2].update_available, - chartRepo: 'https://gitlab.com/gitlab-org/charts/gitlab-runner', - installable: true, - installed: false, - installFailed: false, - updateFailed: false, - updateSuccessful: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - prometheus: { - title: 'Prometheus', - status: APPLICATION_STATUS.INSTALLABLE, - statusReason: mockResponseData.applications[3].status_reason, - requestReason: null, - installable: true, - installed: false, - installFailed: true, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - jupyter: { - title: 'JupyterHub', - status: mockResponseData.applications[4].status, - statusReason: mockResponseData.applications[4].status_reason, - requestReason: null, - hostname: '', - installable: true, - installed: false, - installFailed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - knative: { - title: 'Knative', - status: mockResponseData.applications[5].status, - statusReason: mockResponseData.applications[5].status_reason, - requestReason: null, - hostname: null, - isEditingDomain: false, - externalIp: null, - externalHostname: null, - installable: true, - installed: false, - installFailed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - updateSuccessful: false, - updateFailed: false, - validationError: null, - }, - cert_manager: { - title: 'Cert-Manager', - status: APPLICATION_STATUS.INSTALLABLE, - installFailed: true, - statusReason: mockResponseData.applications[6].status_reason, - requestReason: null, - email: mockResponseData.applications[6].email, - installable: true, - installed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - elastic_stack: { - title: 'Elastic Stack', - status: APPLICATION_STATUS.INSTALLABLE, - installFailed: true, - statusReason: mockResponseData.applications[7].status_reason, - requestReason: null, - installable: true, - installed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - crossplane: { - title: 'Crossplane', - status: APPLICATION_STATUS.INSTALLABLE, - installFailed: true, - statusReason: mockResponseData.applications[8].status_reason, - requestReason: null, - installable: true, - installed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - cilium: { - title: 'GitLab Container Network Policies', - status: null, - statusReason: null, - requestReason: null, - installable: false, - installed: false, - installFailed: false, - uninstallable: false, - uninstallSuccessful: false, - uninstallFailed: false, - validationError: null, - }, - }, environments: [], fetchingEnvironments: false, }); }); - - describe.each(APPLICATION_INSTALLED_STATUSES)( - 'given the current app status is %s', - (status) => { - it('marks application as installed', () => { - const mockResponseData = - CLUSTERS_MOCK_DATA.GET['/gitlab-org/gitlab-shell/clusters/2/status.json'].data; - const runnerAppIndex = 2; - - mockResponseData.applications[runnerAppIndex].status = status; - - store.updateStateFromServer(mockResponseData); - - expect(store.state.applications[RUNNER].installed).toBe(true); - }); - }, - ); - - it('sets default hostname for jupyter when ingress has a ip address', () => { - const mockResponseData = - CLUSTERS_MOCK_DATA.GET['/gitlab-org/gitlab-shell/clusters/2/status.json'].data; - - store.updateStateFromServer(mockResponseData); - - expect(store.state.applications.jupyter.hostname).toEqual( - `jupyter.${store.state.applications.ingress.externalIp}.nip.io`, - ); - }); }); }); |