import { GlSprintf } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { __, s__ } from '~/locale'; import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue'; import EnvironmentsDetailHeader from '~/environments/components/environments_detail_header.vue'; import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; import { createEnvironment } from './mock_data'; describe('Environments detail header component', () => { const cancelAutoStopPath = '/my-environment/cancel/path'; const terminalPath = '/my-environment/terminal/path'; const metricsPath = '/my-environment/metrics/path'; const updatePath = '/my-environment/edit/path'; let wrapper; const findHeader = () => wrapper.findByRole('heading'); const findAutoStopsAt = () => wrapper.findByTestId('auto-stops-at'); const findCancelAutoStopAtButton = () => wrapper.findByTestId('cancel-auto-stop-button'); const findCancelAutoStopAtForm = () => wrapper.findByTestId('cancel-auto-stop-form'); const findTerminalButton = () => wrapper.findByTestId('terminal-button'); const findExternalUrlButton = () => wrapper.findByTestId('external-url-button'); const findMetricsButton = () => wrapper.findByTestId('metrics-button'); const findEditButton = () => wrapper.findByTestId('edit-button'); const findStopButton = () => wrapper.findByTestId('stop-button'); const findDestroyButton = () => wrapper.findByTestId('destroy-button'); const findStopEnvironmentModal = () => wrapper.findComponent(StopEnvironmentModal); const findDeleteEnvironmentModal = () => wrapper.findComponent(DeleteEnvironmentModal); const buttons = [ ['Cancel Auto Stop At', findCancelAutoStopAtButton], ['Terminal', findTerminalButton], ['External Url', findExternalUrlButton], ['Metrics', findMetricsButton], ['Edit', findEditButton], ['Stop', findStopButton], ['Destroy', findDestroyButton], ]; const createWrapper = ({ props }) => { wrapper = shallowMountExtended(EnvironmentsDetailHeader, { stubs: { GlSprintf, TimeAgo, }, directives: { GlTooltip: createMockDirective(), }, propsData: { canAdminEnvironment: false, canUpdateEnvironment: false, canStopEnvironment: false, canDestroyEnvironment: false, ...props, }, }); }; afterEach(() => { wrapper.destroy(); }); describe('default state with minimal access', () => { beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ externalUrl: null }) } }); }); it('displays the environment name', () => { expect(findHeader().text()).toBe('My environment'); }); it('does not display an auto stops at text', () => { expect(findAutoStopsAt().exists()).toBe(false); }); it.each(buttons)('does not display button: %s', (_, findSelector) => { expect(findSelector().exists()).toBe(false); }); it('does not display stop environment modal', () => { expect(findStopEnvironmentModal().exists()).toBe(false); }); it('does not display delete environment modal', () => { expect(findDeleteEnvironmentModal().exists()).toBe(false); }); }); describe('when auto stops at is enabled and environment is available', () => { beforeEach(() => { const now = new Date(); const tomorrow = new Date(); tomorrow.setDate(now.getDate() + 1); createWrapper({ props: { environment: createEnvironment({ autoStopAt: tomorrow.toISOString() }), cancelAutoStopPath, }, }); }); it('displays a text that describes when the environment is going to be stopped', () => { expect(findAutoStopsAt().text()).toBe('Auto stops in 1 day'); }); it('displays a cancel auto stops at button with a form to make a post request', () => { const button = findCancelAutoStopAtButton(); const form = findCancelAutoStopAtForm(); expect(form.attributes('action')).toBe(cancelAutoStopPath); expect(form.attributes('method')).toBe('POST'); expect(button.props('icon')).toBe('thumbtack'); expect(button.attributes('type')).toBe('submit'); }); it('includes a csrf token', () => { const input = findCancelAutoStopAtForm().find('input'); expect(input.attributes('name')).toBe('authenticity_token'); }); }); describe('when auto stops at is enabled and environment is unavailable (already stopped)', () => { beforeEach(() => { const now = new Date(); const tomorrow = new Date(); tomorrow.setDate(now.getDate() + 1); createWrapper({ props: { environment: createEnvironment({ autoStopAt: tomorrow.toISOString(), isAvailable: false, }), cancelAutoStopPath, }, }); }); it('does not display a text that describes when the environment is going to be stopped', () => { expect(findAutoStopsAt().exists()).toBe(false); }); it('displays a cancel auto stops at button with correct path', () => { expect(findCancelAutoStopAtButton().exists()).toBe(false); }); }); describe('when has a terminal', () => { beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ hasTerminals: true }), canAdminEnvironment: true, terminalPath, }, }); }); it('displays the terminal button with correct path', () => { expect(findTerminalButton().attributes('href')).toBe(terminalPath); }); }); describe('when has an external url enabled', () => { const externalUrl = 'https://example.com/my-environment/external/url'; beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ hasTerminals: true, externalUrl }), }, }); }); it('displays the external url button with correct path', () => { expect(findExternalUrlButton().attributes('href')).toBe(externalUrl); }); }); describe('when metrics are enabled', () => { beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ metricsUrl: 'my metrics url' }), metricsPath, }, }); }); it('displays the metrics button with correct path', () => { expect(findMetricsButton().attributes('href')).toBe(metricsPath); }); it('uses a gl tooltip for the title', () => { const button = findMetricsButton(); const tooltip = getBinding(button.element, 'gl-tooltip'); expect(tooltip).toBeDefined(); expect(button.attributes('title')).toBe('See metrics'); }); }); describe('when has all admin rights', () => { beforeEach(() => { createWrapper({ props: { environment: createEnvironment(), canAdminEnvironment: true, canStopEnvironment: true, canUpdateEnvironment: true, updatePath, }, }); }); it('displays the edit button with correct path', () => { expect(findEditButton().attributes('href')).toBe(updatePath); }); it('displays the stop button with correct icon', () => { expect(findStopButton().attributes('icon')).toBe('stop'); }); it('displays stop environment modal', () => { expect(findStopEnvironmentModal().exists()).toBe(true); }); }); describe('when the environment is unavailable and user has destroy permissions', () => { beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ isAvailable: false }), canDestroyEnvironment: true, }, }); }); it('displays a delete button', () => { expect(findDestroyButton().exists()).toBe(true); }); it('displays delete environment modal', () => { expect(findDeleteEnvironmentModal().exists()).toBe(true); }); }); describe('when the environment has an unsafe external url', () => { const externalUrl = 'postgres://staging'; beforeEach(() => { createWrapper({ props: { environment: createEnvironment({ externalUrl }), }, }); }); it('should show a copy button instead', () => { const button = wrapper.findComponent(ModalCopyButton); expect(button.props('title')).toBe(s__('Environments|Copy live environment URL')); expect(button.props('text')).toBe(externalUrl); expect(button.text()).toBe(__('Copy URL')); }); }); });