From 75ca86e7a81f0d086c7d0c55f350b4c122f4bf1e Mon Sep 17 00:00:00 2001
From: Tom Quirk <tquirk@gitlab.com>
Date: Thu, 22 Oct 2020 07:37:34 +0000
Subject: [PATCH] Move fullscreen logic from router to component

This scopes complexity to the component for better
maintainability
---
 .../design_management/pages/design/index.vue  |  19 ++-
 .../design_management/router/index.js         |  17 ---
 .../pages/design/index_spec.js                | 110 +++++++++++-------
 .../design_management/pages/index_spec.js     |   8 --
 4 files changed, 87 insertions(+), 67 deletions(-)

diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index 6a96b06dcd89..642d51fbc7a6 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -21,6 +21,7 @@ import {
   updateImageDiffNoteOptimisticResponse,
   toDiffNoteGid,
   extractDesignNoteId,
+  getPageLayoutElement,
 } from '../../utils/design_management_utils';
 import {
   updateStoreAfterAddImageDiffNote,
@@ -38,7 +39,7 @@ import {
 } from '../../utils/error_messages';
 import { trackDesignDetailView } from '../../utils/tracking';
 import { DESIGNS_ROUTE_NAME } from '../../router/constants';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES, DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../../constants';
 
 const DEFAULT_SCALE = 1;
 
@@ -300,6 +301,22 @@ export default {
       this.resolvedDiscussionsExpanded = !this.resolvedDiscussionsExpanded;
     },
   },
+  beforeRouteEnter(to, from, next) {
+    const pageEl = getPageLayoutElement();
+    if (pageEl) {
+      pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+    }
+
+    next();
+  },
+  beforeRouteLeave(to, from, next) {
+    const pageEl = getPageLayoutElement();
+    if (pageEl) {
+      pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+    }
+
+    next();
+  },
   createImageDiffNoteMutation,
   DESIGNS_ROUTE_NAME,
 };
diff --git a/app/assets/javascripts/design_management/router/index.js b/app/assets/javascripts/design_management/router/index.js
index cbeb2f7ce424..12692612bbcd 100644
--- a/app/assets/javascripts/design_management/router/index.js
+++ b/app/assets/javascripts/design_management/router/index.js
@@ -1,9 +1,6 @@
 import Vue from 'vue';
 import VueRouter from 'vue-router';
 import routes from './routes';
-import { DESIGN_ROUTE_NAME } from './constants';
-import { getPageLayoutElement } from '~/design_management/utils/design_management_utils';
-import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../constants';
 
 Vue.use(VueRouter);
 
@@ -13,20 +10,6 @@ export default function createRouter(base) {
     mode: 'history',
     routes,
   });
-  const pageEl = getPageLayoutElement();
-
-  router.beforeEach(({ name }, _, next) => {
-    // apply a fullscreen layout style in Design View (a.k.a design detail)
-    if (pageEl) {
-      if (name === DESIGN_ROUTE_NAME) {
-        pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
-      } else {
-        pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
-      }
-    }
-
-    next();
-  });
 
   return router;
 }
diff --git a/spec/frontend/design_management/pages/design/index_spec.js b/spec/frontend/design_management/pages/design/index_spec.js
index d9f7146d2586..d0c14c4c7eb1 100644
--- a/spec/frontend/design_management/pages/design/index_spec.js
+++ b/spec/frontend/design_management/pages/design/index_spec.js
@@ -24,7 +24,13 @@ import mockAllVersions from '../../mock_data/all_versions';
 jest.mock('~/flash');
 
 const focusInput = jest.fn();
-
+const mutate = jest.fn().mockResolvedValue();
+const mockPageLayoutElement = {
+  classList: {
+    add: jest.fn(),
+    remove: jest.fn(),
+  },
+};
 const DesignReplyForm = {
   template: '<div><textarea ref="textarea"></textarea></div>',
   methods: {
@@ -37,6 +43,32 @@ const mockDesignNoDiscussions = {
     nodes: [],
   },
 };
+const newComment = 'new comment';
+const annotationCoordinates = {
+  x: 10,
+  y: 10,
+  width: 100,
+  height: 100,
+};
+const createDiscussionMutationVariables = {
+  mutation: createImageDiffNoteMutation,
+  update: expect.anything(),
+  variables: {
+    input: {
+      body: newComment,
+      noteableId: design.id,
+      position: {
+        headSha: 'headSha',
+        baseSha: 'baseSha',
+        startSha: 'startSha',
+        paths: {
+          newPath: 'full-design-path',
+        },
+        ...annotationCoordinates,
+      },
+    },
+  },
+};
 
 const localVue = createLocalVue();
 localVue.use(VueRouter);
@@ -45,35 +77,6 @@ describe('Design management design index page', () => {
   let wrapper;
   let router;
 
-  const newComment = 'new comment';
-  const annotationCoordinates = {
-    x: 10,
-    y: 10,
-    width: 100,
-    height: 100,
-  };
-  const createDiscussionMutationVariables = {
-    mutation: createImageDiffNoteMutation,
-    update: expect.anything(),
-    variables: {
-      input: {
-        body: newComment,
-        noteableId: design.id,
-        position: {
-          headSha: 'headSha',
-          baseSha: 'baseSha',
-          startSha: 'startSha',
-          paths: {
-            newPath: 'full-design-path',
-          },
-          ...annotationCoordinates,
-        },
-      },
-    },
-  };
-
-  const mutate = jest.fn().mockResolvedValue();
-
   const findDiscussionForm = () => wrapper.find(DesignReplyForm);
   const findSidebar = () => wrapper.find(DesignSidebar);
   const findDesignPresentation = () => wrapper.find(DesignPresentation);
@@ -122,19 +125,44 @@ describe('Design management design index page', () => {
     wrapper.destroy();
   });
 
-  describe('when navigating', () => {
-    it('applies fullscreen layout', () => {
-      const mockEl = {
-        classList: {
-          add: jest.fn(),
-          remove: jest.fn(),
-        },
-      };
-      jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockEl);
+  describe('when navigating to component', () => {
+    it('applies fullscreen layout class', () => {
+      jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageLayoutElement);
       createComponent({ loading: true });
 
-      expect(mockEl.classList.add).toHaveBeenCalledTimes(1);
-      expect(mockEl.classList.add).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+      expect(mockPageLayoutElement.classList.add).toHaveBeenCalledTimes(1);
+      expect(mockPageLayoutElement.classList.add).toHaveBeenCalledWith(
+        ...DESIGN_DETAIL_LAYOUT_CLASSLIST,
+      );
+    });
+  });
+
+  describe('when navigating within the component', () => {
+    it('`scale` prop of DesignPresentation component is 1', async () => {
+      jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageLayoutElement);
+      createComponent({ loading: false }, { data: { design, scale: 2 } });
+
+      await wrapper.vm.$nextTick();
+      expect(findDesignPresentation().props('scale')).toBe(2);
+
+      DesignIndex.beforeRouteUpdate.call(wrapper.vm, {}, {}, jest.fn());
+      await wrapper.vm.$nextTick();
+
+      expect(findDesignPresentation().props('scale')).toBe(1);
+    });
+  });
+
+  describe('when navigating away from component', () => {
+    it('removes fullscreen layout class', async () => {
+      jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageLayoutElement);
+      createComponent({ loading: true });
+
+      wrapper.vm.$options.beforeRouteLeave[0].call(wrapper.vm, {}, {}, jest.fn());
+
+      expect(mockPageLayoutElement.classList.remove).toHaveBeenCalledTimes(1);
+      expect(mockPageLayoutElement.classList.remove).toHaveBeenCalledWith(
+        ...DESIGN_DETAIL_LAYOUT_CLASSLIST,
+      );
     });
   });
 
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index 27a91b114489..279403789f12 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -19,7 +19,6 @@ import {
 import { deprecatedCreateFlash as createFlash } from '~/flash';
 import createRouter from '~/design_management/router';
 import * as utils from '~/design_management/utils/design_management_utils';
-import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
 import {
   designListQueryResponse,
   designUploadMutationCreatedResponse,
@@ -682,13 +681,6 @@ describe('Design management index page', () => {
   });
 
   describe('when navigating', () => {
-    it('ensures fullscreen layout is not applied', () => {
-      createComponent({ loading: true });
-
-      expect(mockPageEl.classList.remove).toHaveBeenCalledTimes(1);
-      expect(mockPageEl.classList.remove).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
-    });
-
     it('should trigger a scrollIntoView method if designs route is detected', () => {
       router.replace({
         path: '/designs',
-- 
GitLab