summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js')
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js220
1 files changed, 220 insertions, 0 deletions
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
new file mode 100644
index 00000000000..6449272e6ed
--- /dev/null
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
@@ -0,0 +1,220 @@
+import { mount } from '@vue/test-utils';
+import createFlash from '~/flash';
+import { visitUrl } from '~/lib/utils/url_utility';
+import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
+import DeploymentActions from '~/vue_merge_request_widget/components/deployment/deployment_actions.vue';
+import {
+ CREATED,
+ MANUAL_DEPLOY,
+ FAILED,
+ DEPLOYING,
+ REDEPLOYING,
+ STOPPING,
+} from '~/vue_merge_request_widget/components/deployment/constants';
+import {
+ actionButtonMocks,
+ deploymentMockData,
+ playDetails,
+ retryDetails,
+} from './deployment_mock_data';
+
+jest.mock('~/flash');
+jest.mock('~/lib/utils/url_utility');
+
+describe('DeploymentAction component', () => {
+ let wrapper;
+ let executeActionSpy;
+
+ const factory = (options = {}) => {
+ // This destroys any wrappers created before a nested call to factory reassigns it
+ if (wrapper && wrapper.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = mount(DeploymentActions, {
+ ...options,
+ provide: { glFeatures: { deployFromFooter: true } },
+ });
+ };
+
+ const findStopButton = () => wrapper.find('.js-stop-env');
+ const findDeployButton = () => wrapper.find('.js-manual-deploy-action');
+ const findRedeployButton = () => wrapper.find('.js-manual-redeploy-action');
+
+ beforeEach(() => {
+ executeActionSpy = jest.spyOn(MRWidgetService, 'executeInlineAction');
+
+ factory({
+ propsData: {
+ computedDeploymentStatus: CREATED,
+ deployment: deploymentMockData,
+ showVisualReviewApp: false,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('actions do not appear when conditions are unmet', () => {
+ describe('when there is no stop_url', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ computedDeploymentStatus: CREATED,
+ deployment: {
+ ...deploymentMockData,
+ stop_url: null,
+ },
+ showVisualReviewApp: false,
+ },
+ });
+ });
+
+ it('the stop button does not appear', () => {
+ expect(findStopButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when there is no play_path in details', () => {
+ it('the manual deploy button does not appear', () => {
+ expect(findDeployButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when there is no retry_path in details', () => {
+ it('the manual redeploy button does not appear', () => {
+ expect(findRedeployButton().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('when conditions are met', () => {
+ describe.each`
+ configConst | computedDeploymentStatus | displayConditionChanges | finderFn | endpoint
+ ${STOPPING} | ${CREATED} | ${{}} | ${findStopButton} | ${deploymentMockData.stop_url}
+ ${DEPLOYING} | ${MANUAL_DEPLOY} | ${playDetails} | ${findDeployButton} | ${playDetails.playable_build.play_path}
+ ${REDEPLOYING} | ${FAILED} | ${retryDetails} | ${findRedeployButton} | ${retryDetails.playable_build.retry_path}
+ `(
+ '$configConst action',
+ ({ configConst, computedDeploymentStatus, displayConditionChanges, finderFn, endpoint }) => {
+ describe(`${configConst} action`, () => {
+ const confirmAction = () => {
+ jest.spyOn(window, 'confirm').mockReturnValueOnce(true);
+ finderFn().trigger('click');
+ };
+
+ const rejectAction = () => {
+ jest.spyOn(window, 'confirm').mockReturnValueOnce(false);
+ finderFn().trigger('click');
+ };
+
+ beforeEach(() => {
+ factory({
+ propsData: {
+ computedDeploymentStatus,
+ deployment: {
+ ...deploymentMockData,
+ details: displayConditionChanges,
+ },
+ showVisualReviewApp: false,
+ },
+ });
+ });
+
+ it('the button is rendered', () => {
+ expect(finderFn().exists()).toBe(true);
+ });
+
+ describe('when clicked', () => {
+ describe('should show a confirm dialog but not call executeInlineAction when declined', () => {
+ beforeEach(() => {
+ executeActionSpy.mockResolvedValueOnce();
+ rejectAction();
+ });
+
+ it('should show the confirm dialog', () => {
+ expect(window.confirm).toHaveBeenCalled();
+ expect(window.confirm).toHaveBeenCalledWith(
+ actionButtonMocks[configConst].confirmMessage,
+ );
+ });
+
+ it('should not execute the action', () => {
+ expect(MRWidgetService.executeInlineAction).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('should show a confirm dialog and call executeInlineAction when accepted', () => {
+ beforeEach(() => {
+ executeActionSpy.mockResolvedValueOnce();
+ confirmAction();
+ });
+
+ it('should show the confirm dialog', () => {
+ expect(window.confirm).toHaveBeenCalled();
+ expect(window.confirm).toHaveBeenCalledWith(
+ actionButtonMocks[configConst].confirmMessage,
+ );
+ });
+
+ it('should execute the action with expected URL', () => {
+ expect(MRWidgetService.executeInlineAction).toHaveBeenCalled();
+ expect(MRWidgetService.executeInlineAction).toHaveBeenCalledWith(endpoint);
+ });
+
+ it('should not throw an error', () => {
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ describe('response includes redirect_url', () => {
+ const url = '/root/example';
+ beforeEach(() => {
+ executeActionSpy.mockResolvedValueOnce({
+ data: { redirect_url: url },
+ });
+ confirmAction();
+ });
+
+ it('calls visit url with the redirect_url', () => {
+ expect(visitUrl).toHaveBeenCalled();
+ expect(visitUrl).toHaveBeenCalledWith(url);
+ });
+ });
+
+ describe('it should call the executeAction method ', () => {
+ beforeEach(() => {
+ jest.spyOn(wrapper.vm, 'executeAction').mockImplementation();
+ confirmAction();
+ });
+
+ it('calls with the expected arguments', () => {
+ expect(wrapper.vm.executeAction).toHaveBeenCalled();
+ expect(wrapper.vm.executeAction).toHaveBeenCalledWith(
+ endpoint,
+ actionButtonMocks[configConst],
+ );
+ });
+ });
+
+ describe('when executeInlineAction errors', () => {
+ beforeEach(() => {
+ executeActionSpy.mockRejectedValueOnce();
+ confirmAction();
+ });
+
+ it('should call createFlash with error message', () => {
+ expect(createFlash).toHaveBeenCalled();
+ expect(createFlash).toHaveBeenCalledWith(
+ actionButtonMocks[configConst].errorMessage,
+ );
+ });
+ });
+ });
+ });
+ });
+ },
+ );
+ });
+});