2305 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			2305 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
import MockAdapter from 'axios-mock-adapter';
 | 
						|
import { createTestingPinia } from '@pinia/testing';
 | 
						|
import api from '~/api';
 | 
						|
import Cookies from '~/lib/utils/cookies';
 | 
						|
import waitForPromises from 'helpers/wait_for_promises';
 | 
						|
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 | 
						|
import { TEST_HOST } from 'helpers/test_constants';
 | 
						|
import { getDiffFileMock } from 'jest/diffs/mock_data/diff_file';
 | 
						|
import {
 | 
						|
  DIFF_VIEW_COOKIE_NAME,
 | 
						|
  INLINE_DIFF_VIEW_TYPE,
 | 
						|
  PARALLEL_DIFF_VIEW_TYPE,
 | 
						|
  EVT_MR_PREPARED,
 | 
						|
  FILE_DIFF_POSITION_TYPE,
 | 
						|
} from '~/diffs/constants';
 | 
						|
import {
 | 
						|
  BUILDING_YOUR_MR,
 | 
						|
  SOMETHING_WENT_WRONG,
 | 
						|
  ENCODED_FILE_PATHS_TITLE,
 | 
						|
  ENCODED_FILE_PATHS_MESSAGE,
 | 
						|
} from '~/diffs/i18n';
 | 
						|
import { createTestPiniaAction, createCustomGetters } from 'helpers/pinia_helpers';
 | 
						|
import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs';
 | 
						|
import * as types from '~/diffs/store/mutation_types';
 | 
						|
import * as utils from '~/diffs/store/utils';
 | 
						|
import * as treeWorkerUtils from '~/diffs/utils/tree_worker_utils';
 | 
						|
import { createAlert } from '~/alert';
 | 
						|
import axios from '~/lib/utils/axios_utils';
 | 
						|
import * as commonUtils from '~/lib/utils/common_utils';
 | 
						|
import {
 | 
						|
  HTTP_STATUS_BAD_REQUEST,
 | 
						|
  HTTP_STATUS_INTERNAL_SERVER_ERROR,
 | 
						|
  HTTP_STATUS_NOT_FOUND,
 | 
						|
  HTTP_STATUS_OK,
 | 
						|
} from '~/lib/utils/http_status';
 | 
						|
import { mergeUrlParams } from '~/lib/utils/url_utility';
 | 
						|
import eventHub from '~/notes/event_hub';
 | 
						|
import diffsEventHub from '~/diffs/event_hub';
 | 
						|
import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/utils/common_utils';
 | 
						|
import setWindowLocation from 'helpers/set_window_location_helper';
 | 
						|
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
 | 
						|
import { useNotes } from '~/notes/store/legacy_notes';
 | 
						|
import { diffMetadata } from '../../mock_data/diff_metadata';
 | 
						|
 | 
						|
jest.mock('~/alert');
 | 
						|
 | 
						|
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
 | 
						|
confirmAction.mockResolvedValueOnce(false);
 | 
						|
 | 
						|
const endpointDiffForPath = '/diffs/set/endpoint/path';
 | 
						|
 | 
						|
describe('legacyDiffs actions', () => {
 | 
						|
  let getters = {};
 | 
						|
  let notesGetters = {};
 | 
						|
 | 
						|
  createTestingPinia({
 | 
						|
    stubActions: false,
 | 
						|
    plugins: [
 | 
						|
      createCustomGetters(() => ({
 | 
						|
        legacyDiffs: getters,
 | 
						|
        legacyNotes: notesGetters,
 | 
						|
      })),
 | 
						|
    ],
 | 
						|
  });
 | 
						|
 | 
						|
  let mock;
 | 
						|
  const store = useLegacyDiffs();
 | 
						|
  const testAction = createTestPiniaAction(store);
 | 
						|
 | 
						|
  useLocalStorageSpy();
 | 
						|
 | 
						|
  const originalMethods = {
 | 
						|
    requestAnimationFrame: global.requestAnimationFrame,
 | 
						|
    requestIdleCallback: global.requestIdleCallback,
 | 
						|
  };
 | 
						|
 | 
						|
  beforeEach(() => {
 | 
						|
    getters = {};
 | 
						|
    jest.spyOn(window.history, 'pushState');
 | 
						|
    jest.spyOn(commonUtils, 'historyPushState');
 | 
						|
    jest.spyOn(commonUtils, 'handleLocationHash').mockImplementation(() => null);
 | 
						|
    jest.spyOn(commonUtils, 'scrollToElement').mockImplementation(() => null);
 | 
						|
    jest.spyOn(utils, 'convertExpandLines').mockImplementation(() => null);
 | 
						|
    jest.spyOn(utils, 'idleCallback').mockImplementation(() => null);
 | 
						|
    ['requestAnimationFrame', 'requestIdleCallback'].forEach((method) => {
 | 
						|
      global[method] = (cb) => {
 | 
						|
        cb({ timeRemaining: () => 10 });
 | 
						|
      };
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  beforeEach(() => {
 | 
						|
    store.$reset();
 | 
						|
    useNotes().$reset();
 | 
						|
    mock = new MockAdapter(axios);
 | 
						|
  });
 | 
						|
 | 
						|
  afterEach(() => {
 | 
						|
    ['requestAnimationFrame', 'requestIdleCallback'].forEach((method) => {
 | 
						|
      global[method] = originalMethods[method];
 | 
						|
    });
 | 
						|
    createAlert.mockClear();
 | 
						|
    mock.restore();
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setBaseConfig', () => {
 | 
						|
    it('should set given endpoint and project path', () => {
 | 
						|
      const endpoint = '/diffs/set/endpoint';
 | 
						|
      const endpointMetadata = '/diffs/set/endpoint/metadata';
 | 
						|
      const endpointBatch = '/diffs/set/endpoint/batch';
 | 
						|
      const endpointCoverage = '/diffs/set/coverage_reports';
 | 
						|
      const projectPath = '/root/project';
 | 
						|
      const dismissEndpoint = '/-/user_callouts';
 | 
						|
      const showSuggestPopover = false;
 | 
						|
      const mrReviews = {
 | 
						|
        a: ['z', 'hash:a'],
 | 
						|
        b: ['y', 'hash:a'],
 | 
						|
      };
 | 
						|
      const diffViewType = 'inline';
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.setBaseConfig,
 | 
						|
        {
 | 
						|
          endpoint,
 | 
						|
          endpointBatch,
 | 
						|
          endpointDiffForPath,
 | 
						|
          endpointMetadata,
 | 
						|
          endpointCoverage,
 | 
						|
          projectPath,
 | 
						|
          dismissEndpoint,
 | 
						|
          showSuggestPopover,
 | 
						|
          mrReviews,
 | 
						|
          diffViewType,
 | 
						|
        },
 | 
						|
        {
 | 
						|
          endpoint: '',
 | 
						|
          endpointBatch: '',
 | 
						|
          endpointDiffForPath: '',
 | 
						|
          endpointMetadata: '',
 | 
						|
          endpointCoverage: '',
 | 
						|
          projectPath: '',
 | 
						|
          dismissEndpoint: '',
 | 
						|
          showSuggestPopover: true,
 | 
						|
        },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_BASE_CONFIG],
 | 
						|
            payload: {
 | 
						|
              endpoint,
 | 
						|
              endpointMetadata,
 | 
						|
              endpointBatch,
 | 
						|
              endpointDiffForPath,
 | 
						|
              endpointCoverage,
 | 
						|
              projectPath,
 | 
						|
              dismissEndpoint,
 | 
						|
              showSuggestPopover,
 | 
						|
              mrReviews,
 | 
						|
              diffViewType,
 | 
						|
            },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_FILE_VIEWED],
 | 
						|
            payload: { id: 'z', seen: true },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_FILE_VIEWED],
 | 
						|
            payload: { id: 'a', seen: true },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_FILE_VIEWED],
 | 
						|
            payload: { id: 'y', seen: true },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('prefetchSingleFile', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      window.location.hash = 'e334a2a10f036c00151a04cea7938a5d4213a818';
 | 
						|
    });
 | 
						|
 | 
						|
    it('should do nothing if the tree entry is already loading', () => {
 | 
						|
      return testAction(store.prefetchSingleFile, { diffLoading: true }, {}, [], []);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should do nothing if the tree entry has already been marked as loaded', () => {
 | 
						|
      return testAction(
 | 
						|
        store.prefetchSingleFile,
 | 
						|
        { diffLoaded: true },
 | 
						|
        {
 | 
						|
          flatBlobsList: [
 | 
						|
            { fileHash: 'e334a2a10f036c00151a04cea7938a5d4213a818', diffLoaded: true },
 | 
						|
          ],
 | 
						|
        },
 | 
						|
        [],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    describe('when a tree entry exists for the file, but it has not been marked as loaded', () => {
 | 
						|
      let state;
 | 
						|
      let hubSpy;
 | 
						|
      const defaultParams = {
 | 
						|
        old_path: 'old/123',
 | 
						|
        new_path: 'new/123',
 | 
						|
        w: '1',
 | 
						|
        view: 'inline',
 | 
						|
        diff_head: true,
 | 
						|
      };
 | 
						|
      const diffForPath = mergeUrlParams(defaultParams, endpointDiffForPath);
 | 
						|
      const treeEntry = {
 | 
						|
        fileHash: 'e334a2a10f036c00151a04cea7938a5d4213a818',
 | 
						|
        filePaths: { old: 'old/123', new: 'new/123' },
 | 
						|
      };
 | 
						|
      const fileResult = {
 | 
						|
        diff_files: [{ file_hash: 'e334a2a10f036c00151a04cea7938a5d4213a818' }],
 | 
						|
      };
 | 
						|
 | 
						|
      beforeEach(() => {
 | 
						|
        state = {
 | 
						|
          endpointDiffForPath,
 | 
						|
          showWhitespace: false,
 | 
						|
          treeEntries: {
 | 
						|
            [treeEntry.filePaths.new]: {},
 | 
						|
          },
 | 
						|
          diffFiles: [],
 | 
						|
        };
 | 
						|
        getters = {
 | 
						|
          flatBlobsList: [treeEntry],
 | 
						|
        };
 | 
						|
        store.$patch(state);
 | 
						|
        hubSpy = jest.spyOn(diffsEventHub, '$emit');
 | 
						|
      });
 | 
						|
 | 
						|
      it('does nothing if the file already exists in the loaded diff files', () => {
 | 
						|
        store.$patch({ diffFiles: fileResult.diff_files });
 | 
						|
 | 
						|
        return testAction(store.prefetchSingleFile, treeEntry, getters, [], []);
 | 
						|
      });
 | 
						|
 | 
						|
      it('does some standard work every time', async () => {
 | 
						|
        mock.onGet(diffForPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
        expect(store[types.TREE_ENTRY_DIFF_LOADING]).toHaveBeenCalledWith({
 | 
						|
          path: treeEntry.filePaths.new,
 | 
						|
        });
 | 
						|
 | 
						|
        // wait for the mocked network request to return
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        expect(store[types.SET_DIFF_DATA_BATCH].mock.calls[0]).toMatchObject([fileResult]);
 | 
						|
 | 
						|
        expect(hubSpy).toHaveBeenCalledWith('diffFilesModified');
 | 
						|
      });
 | 
						|
 | 
						|
      it('should fetch data without commit ID', async () => {
 | 
						|
        getters.commitId = null;
 | 
						|
        mock.onGet(diffForPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
        // wait for the mocked network request to return and start processing the .then
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        // This tests that commit_id is NOT added, if there isn't one in the store
 | 
						|
        expect(mock.history.get[0].url).toEqual(diffForPath);
 | 
						|
      });
 | 
						|
 | 
						|
      it('should fetch data with commit ID', async () => {
 | 
						|
        const finalPath = mergeUrlParams(
 | 
						|
          { ...defaultParams, commit_id: '123' },
 | 
						|
          endpointDiffForPath,
 | 
						|
        );
 | 
						|
 | 
						|
        getters.commitId = '123';
 | 
						|
        mock.onGet(finalPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
        // wait for the mocked network request to return and start processing the .then
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        expect(mock.history.get[0].url).toContain(
 | 
						|
          'old_path=old%2F123&new_path=new%2F123&w=1&view=inline&commit_id=123',
 | 
						|
        );
 | 
						|
      });
 | 
						|
 | 
						|
      describe('version parameters', () => {
 | 
						|
        const diffId = '4';
 | 
						|
        const startSha = 'abc';
 | 
						|
        const pathRoot = 'a/a/-/merge_requests/1';
 | 
						|
 | 
						|
        it('fetches the data when there is no mergeRequestDiff', async () => {
 | 
						|
          store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
          // wait for the mocked network request to return and start processing the .then
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(mock.history.get[0].url).toEqual(diffForPath);
 | 
						|
        });
 | 
						|
 | 
						|
        it.each`
 | 
						|
          desc                                   | versionPath                                              | start_sha    | diff_id
 | 
						|
          ${'no additional version information'} | ${`${pathRoot}?search=terms`}                            | ${undefined} | ${undefined}
 | 
						|
          ${'the diff_id'}                       | ${`${pathRoot}?diff_id=${diffId}`}                       | ${undefined} | ${diffId}
 | 
						|
          ${'the start_sha'}                     | ${`${pathRoot}?start_sha=${startSha}`}                   | ${startSha}  | ${undefined}
 | 
						|
          ${'all available version information'} | ${`${pathRoot}?diff_id=${diffId}&start_sha=${startSha}`} | ${startSha}  | ${diffId}
 | 
						|
        `('fetches the data and includes $desc', async ({ versionPath, start_sha, diff_id }) => {
 | 
						|
          const finalPath = mergeUrlParams(
 | 
						|
            { ...defaultParams, diff_id, start_sha },
 | 
						|
            endpointDiffForPath,
 | 
						|
          );
 | 
						|
          store.$patch({
 | 
						|
            mergeRequestDiff: { version_path: versionPath },
 | 
						|
            endpointBatch: versionPath,
 | 
						|
          });
 | 
						|
          mock.onGet(finalPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
          store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
          // wait for the mocked network request to return
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(mock.history.get[0].url).toEqual(finalPath);
 | 
						|
        });
 | 
						|
      });
 | 
						|
 | 
						|
      describe('when the prefetch fails', () => {
 | 
						|
        beforeEach(() => {
 | 
						|
          mock.onGet(diffForPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
        });
 | 
						|
 | 
						|
        it('should commit a mutation to set the tree entry diff loading to false', async () => {
 | 
						|
          store.prefetchSingleFile(treeEntry);
 | 
						|
 | 
						|
          // wait for the mocked network request to return
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(store[types.TREE_ENTRY_DIFF_LOADING]).toHaveBeenCalledWith({
 | 
						|
            path: treeEntry.filePaths.new,
 | 
						|
            loading: false,
 | 
						|
          });
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchFileByFile', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      window.location.hash = 'e334a2a10f036c00151a04cea7938a5d4213a818';
 | 
						|
    });
 | 
						|
 | 
						|
    it('should do nothing if there is no tree entry for the file ID', () => {
 | 
						|
      return testAction(store.fetchFileByFile, {}, { flatBlobsList: [] }, [], []);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should do nothing if the tree entry for the file ID has already been marked as loaded', () => {
 | 
						|
      return testAction(
 | 
						|
        store.fetchFileByFile,
 | 
						|
        {},
 | 
						|
        {
 | 
						|
          flatBlobsList: [
 | 
						|
            { fileHash: 'e334a2a10f036c00151a04cea7938a5d4213a818', diffLoaded: true },
 | 
						|
          ],
 | 
						|
        },
 | 
						|
        [],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    describe('when a tree entry exists for the file, but it has not been marked as loaded', () => {
 | 
						|
      let state;
 | 
						|
      let hubSpy;
 | 
						|
      const defaultParams = {
 | 
						|
        old_path: 'old/123',
 | 
						|
        new_path: 'new/123',
 | 
						|
        w: '1',
 | 
						|
        view: 'inline',
 | 
						|
        diff_head: true,
 | 
						|
      };
 | 
						|
      const diffForPath = mergeUrlParams(defaultParams, endpointDiffForPath);
 | 
						|
      const treeEntry = {
 | 
						|
        fileHash: 'e334a2a10f036c00151a04cea7938a5d4213a818',
 | 
						|
        filePaths: { old: 'old/123', new: 'new/123' },
 | 
						|
      };
 | 
						|
      const fileResult = {
 | 
						|
        diff_files: [{ file_hash: 'e334a2a10f036c00151a04cea7938a5d4213a818' }],
 | 
						|
      };
 | 
						|
 | 
						|
      beforeEach(() => {
 | 
						|
        state = {
 | 
						|
          endpointDiffForPath,
 | 
						|
          showWhitespace: false,
 | 
						|
          diffFiles: [],
 | 
						|
        };
 | 
						|
        getters = {
 | 
						|
          flatBlobsList: [treeEntry],
 | 
						|
        };
 | 
						|
        store.$patch(state);
 | 
						|
        hubSpy = jest.spyOn(diffsEventHub, '$emit');
 | 
						|
      });
 | 
						|
 | 
						|
      it('does nothing if the file already exists in the loaded diff files', () => {
 | 
						|
        store.$patch({ diffFiles: fileResult.diff_files });
 | 
						|
 | 
						|
        return testAction(store.fetchFileByFile, state, {}, [], []);
 | 
						|
      });
 | 
						|
 | 
						|
      it('does some standard work every time', async () => {
 | 
						|
        mock.onGet(diffForPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.fetchFileByFile();
 | 
						|
 | 
						|
        expect(store[types.SET_BATCH_LOADING_STATE]).toHaveBeenCalledWith('loading');
 | 
						|
        expect(store[types.SET_RETRIEVING_BATCHES]).toHaveBeenCalledWith(true);
 | 
						|
 | 
						|
        // wait for the mocked network request to return and start processing the .then
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        expect(store[types.SET_DIFF_DATA_BATCH].mock.calls[0]).toMatchObject([fileResult]);
 | 
						|
        expect(store[types.SET_BATCH_LOADING_STATE]).toHaveBeenCalledWith('loaded');
 | 
						|
 | 
						|
        expect(hubSpy).toHaveBeenCalledWith('diffFilesModified');
 | 
						|
      });
 | 
						|
 | 
						|
      it.each`
 | 
						|
        urlHash               | diffFiles                | expected
 | 
						|
        ${treeEntry.fileHash} | ${[]}                    | ${'e334a2a10f036c00151a04cea7938a5d4213a818'}
 | 
						|
        ${'abcdef1234567890'} | ${fileResult.diff_files} | ${'e334a2a10f036c00151a04cea7938a5d4213a818'}
 | 
						|
      `(
 | 
						|
        "sets the current file to the first diff file ('$id') if it's not a note hash and there isn't a current ID set",
 | 
						|
        async ({ urlHash, diffFiles, expected }) => {
 | 
						|
          window.location.hash = urlHash;
 | 
						|
          mock.onGet(diffForPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
          store.$patch({ diffFiles });
 | 
						|
 | 
						|
          await store.fetchFileByFile();
 | 
						|
 | 
						|
          // wait for the mocked network request to return and start processing the .then
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(store[types.SET_CURRENT_DIFF_FILE]).toHaveBeenCalledWith(expected);
 | 
						|
        },
 | 
						|
      );
 | 
						|
 | 
						|
      it('should fetch data without commit ID', async () => {
 | 
						|
        store.$patch({ commitId: null });
 | 
						|
        mock.onGet(diffForPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.fetchFileByFile();
 | 
						|
 | 
						|
        // wait for the mocked network request to return and start processing the .then
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        // This tests that commit_id is NOT added, if there isn't one in the store
 | 
						|
        expect(mock.history.get[0].url).toEqual(diffForPath);
 | 
						|
      });
 | 
						|
 | 
						|
      it('should fetch data with commit ID', async () => {
 | 
						|
        const finalPath = mergeUrlParams(
 | 
						|
          { ...defaultParams, commit_id: '123' },
 | 
						|
          endpointDiffForPath,
 | 
						|
        );
 | 
						|
 | 
						|
        store.$patch({ commit: { id: '123' } });
 | 
						|
        mock.onGet(finalPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
        await store.fetchFileByFile();
 | 
						|
 | 
						|
        // wait for the mocked network request to return and start processing the .then
 | 
						|
        await waitForPromises();
 | 
						|
 | 
						|
        expect(mock.history.get[0].url).toContain(
 | 
						|
          'old_path=old%2F123&new_path=new%2F123&w=1&view=inline&commit_id=123',
 | 
						|
        );
 | 
						|
      });
 | 
						|
 | 
						|
      describe('version parameters', () => {
 | 
						|
        const diffId = '4';
 | 
						|
        const startSha = 'abc';
 | 
						|
        const pathRoot = 'a/a/-/merge_requests/1';
 | 
						|
 | 
						|
        it('fetches the data when there is no mergeRequestDiff', async () => {
 | 
						|
          store.fetchFileByFile();
 | 
						|
 | 
						|
          // wait for the mocked network request to return and start processing the .then
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(mock.history.get[0].url).toEqual(diffForPath);
 | 
						|
        });
 | 
						|
 | 
						|
        it.each`
 | 
						|
          desc                                   | versionPath                                              | start_sha    | diff_id
 | 
						|
          ${'no additional version information'} | ${`${pathRoot}?search=terms`}                            | ${undefined} | ${undefined}
 | 
						|
          ${'the diff_id'}                       | ${`${pathRoot}?diff_id=${diffId}`}                       | ${undefined} | ${diffId}
 | 
						|
          ${'the start_sha'}                     | ${`${pathRoot}?start_sha=${startSha}`}                   | ${startSha}  | ${undefined}
 | 
						|
          ${'all available version information'} | ${`${pathRoot}?diff_id=${diffId}&start_sha=${startSha}`} | ${startSha}  | ${diffId}
 | 
						|
        `('fetches the data and includes $desc', async ({ versionPath, start_sha, diff_id }) => {
 | 
						|
          const finalPath = mergeUrlParams(
 | 
						|
            { ...defaultParams, diff_id, start_sha },
 | 
						|
            endpointDiffForPath,
 | 
						|
          );
 | 
						|
          store.$patch({ endpointBatch: versionPath });
 | 
						|
          mock.onGet(finalPath).reply(HTTP_STATUS_OK, fileResult);
 | 
						|
 | 
						|
          store.fetchFileByFile();
 | 
						|
 | 
						|
          // wait for the mocked network request to return and start processing the .then
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(mock.history.get[0].url).toEqual(finalPath);
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchDiffFilesBatch', () => {
 | 
						|
    it('should fetch batch diff files', () => {
 | 
						|
      const endpointBatch = '/fetch/diffs_batch';
 | 
						|
      const res1 = { diff_files: [{ file_hash: 'test' }], pagination: { total_pages: 2 } };
 | 
						|
      const res2 = { diff_files: [{ file_hash: 'test2' }], pagination: { total_pages: 2 } };
 | 
						|
      mock
 | 
						|
        .onGet(
 | 
						|
          mergeUrlParams(
 | 
						|
            {
 | 
						|
              w: '1',
 | 
						|
              view: 'inline',
 | 
						|
              page: 0,
 | 
						|
              per_page: 5,
 | 
						|
            },
 | 
						|
            endpointBatch,
 | 
						|
          ),
 | 
						|
        )
 | 
						|
        .reply(HTTP_STATUS_OK, res1)
 | 
						|
        .onGet(
 | 
						|
          mergeUrlParams(
 | 
						|
            {
 | 
						|
              w: '1',
 | 
						|
              view: 'inline',
 | 
						|
              page: 5,
 | 
						|
              per_page: 7,
 | 
						|
            },
 | 
						|
            endpointBatch,
 | 
						|
          ),
 | 
						|
        )
 | 
						|
        .reply(HTTP_STATUS_OK, res2);
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.fetchDiffFilesBatch,
 | 
						|
        undefined,
 | 
						|
        {
 | 
						|
          endpointBatch,
 | 
						|
          diffViewType: 'inline',
 | 
						|
          diffFiles: [],
 | 
						|
          perPage: 5,
 | 
						|
          showWhitespace: false,
 | 
						|
        },
 | 
						|
        [
 | 
						|
          { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loading' },
 | 
						|
          { type: store[types.SET_RETRIEVING_BATCHES], payload: true },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_DATA_BATCH],
 | 
						|
            payload: {
 | 
						|
              get diff_files() {
 | 
						|
                return [store.diffFiles[0]];
 | 
						|
              },
 | 
						|
            },
 | 
						|
          },
 | 
						|
          { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loaded' },
 | 
						|
          { type: store[types.SET_CURRENT_DIFF_FILE], payload: 'test' },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_DATA_BATCH],
 | 
						|
            payload: {
 | 
						|
              get diff_files() {
 | 
						|
                return [store.diffFiles[1]];
 | 
						|
              },
 | 
						|
            },
 | 
						|
          },
 | 
						|
          { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loaded' },
 | 
						|
          { type: store[types.SET_RETRIEVING_BATCHES], payload: false },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchDiffFilesMeta', () => {
 | 
						|
    const endpointMetadata = '/fetch/diffs_metadata.json?view=inline&w=0';
 | 
						|
    const noFilesData = { ...diffMetadata };
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      delete noFilesData.diff_files;
 | 
						|
    });
 | 
						|
 | 
						|
    it('should fetch diff meta information', () => {
 | 
						|
      mock.onGet(endpointMetadata).reply(HTTP_STATUS_OK, diffMetadata);
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.fetchDiffFilesMeta,
 | 
						|
        {},
 | 
						|
        { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
 | 
						|
        [
 | 
						|
          { type: store[types.SET_LOADING], payload: true },
 | 
						|
          { type: store[types.SET_LOADING], payload: false },
 | 
						|
          { type: store[types.SET_MERGE_REQUEST_DIFFS], payload: diffMetadata.merge_request_diffs },
 | 
						|
          { type: store[types.SET_DIFF_METADATA], payload: noFilesData },
 | 
						|
          // Workers are synchronous in Jest environment (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58805)
 | 
						|
          {
 | 
						|
            type: store[types.SET_TREE_DATA],
 | 
						|
            payload: treeWorkerUtils.generateTreeList(diffMetadata.diff_files),
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    describe('when diff metadata returns has_encoded_file_paths as true', () => {
 | 
						|
      beforeEach(() => {
 | 
						|
        mock
 | 
						|
          .onGet(endpointMetadata)
 | 
						|
          .reply(HTTP_STATUS_OK, { ...diffMetadata, has_encoded_file_paths: true });
 | 
						|
      });
 | 
						|
 | 
						|
      it('should show a non-dismissible alert', async () => {
 | 
						|
        await testAction(
 | 
						|
          store.fetchDiffFilesMeta,
 | 
						|
          {},
 | 
						|
          { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
 | 
						|
          [
 | 
						|
            { type: store[types.SET_LOADING], payload: true },
 | 
						|
            { type: store[types.SET_LOADING], payload: false },
 | 
						|
            {
 | 
						|
              type: store[types.SET_MERGE_REQUEST_DIFFS],
 | 
						|
              payload: diffMetadata.merge_request_diffs,
 | 
						|
            },
 | 
						|
            {
 | 
						|
              type: store[types.SET_DIFF_METADATA],
 | 
						|
              payload: { ...noFilesData, has_encoded_file_paths: true },
 | 
						|
            },
 | 
						|
            // Workers are synchronous in Jest environment (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58805)
 | 
						|
            {
 | 
						|
              type: store[types.SET_TREE_DATA],
 | 
						|
              payload: treeWorkerUtils.generateTreeList(diffMetadata.diff_files),
 | 
						|
            },
 | 
						|
          ],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
 | 
						|
        expect(createAlert).toHaveBeenCalledTimes(1);
 | 
						|
        expect(createAlert).toHaveBeenCalledWith({
 | 
						|
          title: ENCODED_FILE_PATHS_TITLE,
 | 
						|
          message: ENCODED_FILE_PATHS_MESSAGE,
 | 
						|
          dismissible: false,
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('on a 404 response', () => {
 | 
						|
      let dismissAlert;
 | 
						|
 | 
						|
      beforeAll(() => {
 | 
						|
        dismissAlert = jest.fn();
 | 
						|
 | 
						|
        mock.onGet(endpointMetadata).reply(HTTP_STATUS_NOT_FOUND);
 | 
						|
        createAlert.mockImplementation(() => ({ dismiss: dismissAlert }));
 | 
						|
      });
 | 
						|
 | 
						|
      it('should show a warning', async () => {
 | 
						|
        await testAction(
 | 
						|
          store.fetchDiffFilesMeta,
 | 
						|
          {},
 | 
						|
          { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
 | 
						|
          [{ type: store[types.SET_LOADING], payload: true }],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
 | 
						|
        expect(createAlert).toHaveBeenCalledTimes(1);
 | 
						|
        expect(createAlert).toHaveBeenCalledWith({
 | 
						|
          message: BUILDING_YOUR_MR,
 | 
						|
          variant: 'warning',
 | 
						|
        });
 | 
						|
      });
 | 
						|
 | 
						|
      it("should attempt to close the alert if the MR reports that it's been prepared", async () => {
 | 
						|
        await testAction(
 | 
						|
          store.fetchDiffFilesMeta,
 | 
						|
          {},
 | 
						|
          { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
 | 
						|
          [{ type: store[types.SET_LOADING], payload: true }],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
 | 
						|
        diffsEventHub.$emit(EVT_MR_PREPARED);
 | 
						|
 | 
						|
        expect(dismissAlert).toHaveBeenCalled();
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should show no warning on any other status code', async () => {
 | 
						|
      mock.onGet(endpointMetadata).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
 | 
						|
      try {
 | 
						|
        await testAction(
 | 
						|
          store.fetchDiffFilesMeta,
 | 
						|
          {},
 | 
						|
          { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
 | 
						|
          [{ type: store[types.SET_LOADING], payload: true }],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
      } catch (error) {
 | 
						|
        expect(error.response.status).toBe(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
      }
 | 
						|
 | 
						|
      expect(createAlert).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('prefetchFileNeighbors', () => {
 | 
						|
    it('dispatches two requests to prefetch the next/previous files', () => {
 | 
						|
      store.prefetchSingleFile.mockReturnValue({});
 | 
						|
      return testAction(
 | 
						|
        store.prefetchFileNeighbors,
 | 
						|
        {},
 | 
						|
        {
 | 
						|
          currentDiffFileId: 'ghi',
 | 
						|
          treeEntries: {
 | 
						|
            abc: {
 | 
						|
              type: 'blob',
 | 
						|
              fileHash: 'abc',
 | 
						|
            },
 | 
						|
            ghi: {
 | 
						|
              type: 'blob',
 | 
						|
              fileHash: 'ghi',
 | 
						|
            },
 | 
						|
            def: {
 | 
						|
              type: 'blob',
 | 
						|
              fileHash: 'def',
 | 
						|
            },
 | 
						|
          },
 | 
						|
        },
 | 
						|
        [],
 | 
						|
        [
 | 
						|
          { type: store.prefetchSingleFile, payload: { type: 'blob', fileHash: 'def' } },
 | 
						|
          { type: store.prefetchSingleFile, payload: { type: 'blob', fileHash: 'abc' } },
 | 
						|
        ],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchCoverageFiles', () => {
 | 
						|
    const endpointCoverage = '/fetch';
 | 
						|
 | 
						|
    it('should commit SET_COVERAGE_DATA with received response', () => {
 | 
						|
      const data = { files: { 'app.js': { 1: 0, 2: 1 } } };
 | 
						|
 | 
						|
      mock.onGet(endpointCoverage).reply(HTTP_STATUS_OK, { data });
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.fetchCoverageFiles,
 | 
						|
        {},
 | 
						|
        { endpointCoverage },
 | 
						|
        [{ type: store[types.SET_COVERAGE_DATA], payload: { data } }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('should show alert on API error', async () => {
 | 
						|
      mock.onGet(endpointCoverage).reply(HTTP_STATUS_BAD_REQUEST);
 | 
						|
 | 
						|
      await testAction(store.fetchCoverageFiles, {}, { endpointCoverage }, [], []);
 | 
						|
      expect(createAlert).toHaveBeenCalledTimes(1);
 | 
						|
      expect(createAlert).toHaveBeenCalledWith({
 | 
						|
        message: SOMETHING_WENT_WRONG,
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setHighlightedRow', () => {
 | 
						|
    it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
 | 
						|
      return testAction(store.setHighlightedRow, { lineCode: 'ABC_123' }, {}, [
 | 
						|
        { type: store[types.SET_HIGHLIGHTED_ROW], payload: 'ABC_123' },
 | 
						|
        { type: store[types.SET_CURRENT_DIFF_FILE], payload: 'ABC' },
 | 
						|
      ]);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should prevent default event', () => {
 | 
						|
      const preventDefault = jest.fn();
 | 
						|
      const target = { href: TEST_HOST };
 | 
						|
      const event = { target, preventDefault };
 | 
						|
      testAction(store.setHighlightedRow, { lineCode: 'ABC_123', event }, {}, [
 | 
						|
        { type: store[types.SET_HIGHLIGHTED_ROW], payload: 'ABC_123' },
 | 
						|
        { type: store[types.SET_CURRENT_DIFF_FILE], payload: 'ABC' },
 | 
						|
      ]);
 | 
						|
      expect(preventDefault).toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should filter out linked file param', () => {
 | 
						|
      const target = { href: `${TEST_HOST}/diffs?file=foo#abc_11` };
 | 
						|
      const event = { target, preventDefault: jest.fn() };
 | 
						|
      testAction(store.setHighlightedRow, { lineCode: 'ABC_123', event }, {}, [
 | 
						|
        { type: store[types.SET_HIGHLIGHTED_ROW], payload: 'ABC_123' },
 | 
						|
        { type: store[types.SET_CURRENT_DIFF_FILE], payload: 'ABC' },
 | 
						|
      ]);
 | 
						|
      expect(window.location.href).toBe(`${TEST_HOST}/diffs#abc_11`);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('assignDiscussionsToDiff', () => {
 | 
						|
    afterEach(() => {
 | 
						|
      window.location.hash = '';
 | 
						|
    });
 | 
						|
 | 
						|
    it('should merge discussions into diffs', () => {
 | 
						|
      window.location.hash = 'ABC_123';
 | 
						|
 | 
						|
      const state = {
 | 
						|
        diffFiles: [
 | 
						|
          {
 | 
						|
            file_hash: 'ABC',
 | 
						|
            parallel_diff_lines: [
 | 
						|
              {
 | 
						|
                left: {
 | 
						|
                  line_code: 'ABC_1_1',
 | 
						|
                  discussions: [],
 | 
						|
                },
 | 
						|
                right: {
 | 
						|
                  line_code: 'ABC_1_1',
 | 
						|
                  discussions: [],
 | 
						|
                },
 | 
						|
              },
 | 
						|
            ],
 | 
						|
            highlighted_diff_lines: [
 | 
						|
              {
 | 
						|
                line_code: 'ABC_1_1',
 | 
						|
                discussions: [],
 | 
						|
                old_line: 5,
 | 
						|
                new_line: null,
 | 
						|
              },
 | 
						|
            ],
 | 
						|
            diff_refs: {
 | 
						|
              base_sha: 'abc',
 | 
						|
              head_sha: 'def',
 | 
						|
              start_sha: 'ghi',
 | 
						|
            },
 | 
						|
            new_path: 'file1',
 | 
						|
            old_path: 'file2',
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      };
 | 
						|
 | 
						|
      const diffPosition = {
 | 
						|
        base_sha: 'abc',
 | 
						|
        head_sha: 'def',
 | 
						|
        start_sha: 'ghi',
 | 
						|
        new_line: null,
 | 
						|
        new_path: 'file1',
 | 
						|
        old_line: 5,
 | 
						|
        old_path: 'file2',
 | 
						|
      };
 | 
						|
 | 
						|
      const singleDiscussion = {
 | 
						|
        line_code: 'ABC_1_1',
 | 
						|
        diff_discussion: {},
 | 
						|
        diff_file: {
 | 
						|
          file_hash: 'ABC',
 | 
						|
        },
 | 
						|
        file_hash: 'ABC',
 | 
						|
        resolvable: true,
 | 
						|
        position: diffPosition,
 | 
						|
        original_position: diffPosition,
 | 
						|
      };
 | 
						|
 | 
						|
      const discussions = [singleDiscussion];
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.assignDiscussionsToDiff,
 | 
						|
        discussions,
 | 
						|
        state,
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_LINE_DISCUSSIONS_FOR_FILE],
 | 
						|
            payload: {
 | 
						|
              discussion: singleDiscussion,
 | 
						|
              diffPositionByLineCode: {
 | 
						|
                ABC_1_1: {
 | 
						|
                  base_sha: 'abc',
 | 
						|
                  head_sha: 'def',
 | 
						|
                  start_sha: 'ghi',
 | 
						|
                  new_line: null,
 | 
						|
                  new_path: 'file1',
 | 
						|
                  old_line: 5,
 | 
						|
                  old_path: 'file2',
 | 
						|
                  line_range: null,
 | 
						|
                  line_code: 'ABC_1_1',
 | 
						|
                  position_type: 'text',
 | 
						|
                },
 | 
						|
              },
 | 
						|
              hash: 'ABC_123',
 | 
						|
            },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches setCurrentDiffFileIdFromNote with note ID', () => {
 | 
						|
      window.location.hash = 'note_123';
 | 
						|
 | 
						|
      getters = {
 | 
						|
        flatBlobsList: [],
 | 
						|
      };
 | 
						|
      notesGetters = {
 | 
						|
        notesById: {},
 | 
						|
      };
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.assignDiscussionsToDiff,
 | 
						|
        [],
 | 
						|
        { diffFiles: [] },
 | 
						|
        [],
 | 
						|
        [{ type: store.setCurrentDiffFileIdFromNote, payload: '123' }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('removeDiscussionsFromDiff', () => {
 | 
						|
    it('does not call mutation if no diff file is on discussion', () => {
 | 
						|
      testAction(
 | 
						|
        store.removeDiscussionsFromDiff,
 | 
						|
        {
 | 
						|
          id: '1',
 | 
						|
          line_code: 'ABC_1_1',
 | 
						|
        },
 | 
						|
        {},
 | 
						|
        [],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('should remove discussions from diffs', () => {
 | 
						|
      const state = {
 | 
						|
        diffFiles: [
 | 
						|
          {
 | 
						|
            file_hash: 'ABC',
 | 
						|
            parallel_diff_lines: [
 | 
						|
              {
 | 
						|
                left: {
 | 
						|
                  line_code: 'ABC_1_1',
 | 
						|
                  discussions: [
 | 
						|
                    {
 | 
						|
                      id: 1,
 | 
						|
                    },
 | 
						|
                  ],
 | 
						|
                },
 | 
						|
                right: {
 | 
						|
                  line_code: 'ABC_1_1',
 | 
						|
                  discussions: [],
 | 
						|
                },
 | 
						|
              },
 | 
						|
            ],
 | 
						|
            highlighted_diff_lines: [
 | 
						|
              {
 | 
						|
                line_code: 'ABC_1_1',
 | 
						|
                discussions: [],
 | 
						|
              },
 | 
						|
            ],
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      };
 | 
						|
      const singleDiscussion = {
 | 
						|
        id: '1',
 | 
						|
        diff_file: { file_hash: 'ABC' },
 | 
						|
        line_code: 'ABC_1_1',
 | 
						|
      };
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.removeDiscussionsFromDiff,
 | 
						|
        singleDiscussion,
 | 
						|
        state,
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE],
 | 
						|
            payload: {
 | 
						|
              id: '1',
 | 
						|
              fileHash: 'ABC',
 | 
						|
              lineCode: 'ABC_1_1',
 | 
						|
            },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setDiffViewType', () => {
 | 
						|
    it.each([['inline'], ['parallel']])(
 | 
						|
      'should set the diff view type to $p and set the cookie',
 | 
						|
      async (diffViewType) => {
 | 
						|
        await testAction(
 | 
						|
          store.setDiffViewType,
 | 
						|
          diffViewType,
 | 
						|
          {},
 | 
						|
          [{ type: store[types.SET_DIFF_VIEW_TYPE], payload: diffViewType }],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
        expect(window.location.toString()).toContain(`?view=${diffViewType}`);
 | 
						|
        expect(Cookies.get(DIFF_VIEW_COOKIE_NAME)).toEqual(diffViewType);
 | 
						|
      },
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  describe('showCommentForm', () => {
 | 
						|
    it('should call mutation to show comment form', () => {
 | 
						|
      const payload = { lineCode: 'lineCode', fileHash: 'hash' };
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.showCommentForm,
 | 
						|
        payload,
 | 
						|
        {},
 | 
						|
        [{ type: store[types.TOGGLE_LINE_HAS_FORM], payload: { ...payload, hasForm: true } }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('cancelCommentForm', () => {
 | 
						|
    it('should call mutation to cancel comment form', () => {
 | 
						|
      const payload = { lineCode: 'lineCode', fileHash: 'hash' };
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.cancelCommentForm,
 | 
						|
        payload,
 | 
						|
        {},
 | 
						|
        [{ type: store[types.TOGGLE_LINE_HAS_FORM], payload: { ...payload, hasForm: false } }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('loadMoreLines', () => {
 | 
						|
    it('should call mutation to show comment form', () => {
 | 
						|
      const endpoint = '/diffs/load/more/lines';
 | 
						|
      const params = { since: 6, to: 26 };
 | 
						|
      const lineNumbers = { oldLineNumber: 3, newLineNumber: 5 };
 | 
						|
      const fileHash = 'ff9200';
 | 
						|
      const isExpandDown = false;
 | 
						|
      const nextLineNumbers = {};
 | 
						|
      const options = { endpoint, params, lineNumbers, fileHash, isExpandDown, nextLineNumbers };
 | 
						|
      const contextLines = [{ lineCode: 6 }];
 | 
						|
      mock.onGet(endpoint).reply(HTTP_STATUS_OK, contextLines);
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.loadMoreLines,
 | 
						|
        options,
 | 
						|
        { diffFiles: [{ file_hash: fileHash, highlighted_diff_lines: [] }] },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.ADD_CONTEXT_LINES],
 | 
						|
            payload: {
 | 
						|
              lineNumbers,
 | 
						|
              contextLines: [{ ...contextLines[0], new_line: 4, old_line: 2 }],
 | 
						|
              params,
 | 
						|
              fileHash,
 | 
						|
              isExpandDown,
 | 
						|
              nextLineNumbers,
 | 
						|
            },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('loadCollapsedDiff', () => {
 | 
						|
    it('should fetch data and call mutation with response and the give parameter', async () => {
 | 
						|
      const file = {
 | 
						|
        file_hash: 'collapsed',
 | 
						|
        hash: 123,
 | 
						|
        load_collapsed_diff_url: '/load/collapsed/diff/url',
 | 
						|
      };
 | 
						|
      const data = { hash: 123, parallelDiffLines: [{ lineCode: 1 }] };
 | 
						|
      mock.onGet(file.loadCollapsedDiffUrl).reply(HTTP_STATUS_OK, data);
 | 
						|
      store.$patch({
 | 
						|
        showWhitespace: true,
 | 
						|
        commit: { id: null },
 | 
						|
        diffFiles: [{ file_hash: file.file_hash }],
 | 
						|
      });
 | 
						|
 | 
						|
      await store.loadCollapsedDiff({ file });
 | 
						|
 | 
						|
      expect(store[types.ADD_COLLAPSED_DIFFS]).toHaveBeenCalledWith({ file, data });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should fetch data without commit ID', () => {
 | 
						|
      const file = { file_hash: 'collapsed', load_collapsed_diff_url: '/load/collapsed/diff/url' };
 | 
						|
      store.$patch({ commit: { id: null }, diffFiles: [{ file_hash: file.file_hash }] });
 | 
						|
 | 
						|
      jest.spyOn(axios, 'get').mockReturnValue(Promise.resolve({ data: {} }));
 | 
						|
 | 
						|
      store.loadCollapsedDiff({ file });
 | 
						|
 | 
						|
      expect(axios.get).toHaveBeenCalledWith(file.load_collapsed_diff_url, {
 | 
						|
        params: { commit_id: null, w: '0' },
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should pass through params', () => {
 | 
						|
      const file = { file_hash: 'collapsed', load_collapsed_diff_url: '/load/collapsed/diff/url' };
 | 
						|
      store.$patch({ commit: { id: null }, diffFiles: [{ file_hash: file.file_hash }] });
 | 
						|
 | 
						|
      jest.spyOn(axios, 'get').mockReturnValue(Promise.resolve({ data: {} }));
 | 
						|
 | 
						|
      store.loadCollapsedDiff({ file, params: { w: '1' } });
 | 
						|
 | 
						|
      expect(axios.get).toHaveBeenCalledWith(file.load_collapsed_diff_url, {
 | 
						|
        params: { commit_id: null, w: '1' },
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should fetch data with commit ID', () => {
 | 
						|
      const file = { file_hash: 'collapsed', load_collapsed_diff_url: '/load/collapsed/diff/url' };
 | 
						|
      store.$patch({ commit: { id: '123' }, diffFiles: [{ file_hash: file.file_hash }] });
 | 
						|
 | 
						|
      jest.spyOn(axios, 'get').mockReturnValue(Promise.resolve({ data: {} }));
 | 
						|
 | 
						|
      store.loadCollapsedDiff({ file });
 | 
						|
 | 
						|
      expect(axios.get).toHaveBeenCalledWith(file.load_collapsed_diff_url, {
 | 
						|
        params: { commit_id: '123', w: '0' },
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('version parameters', () => {
 | 
						|
      const diffId = '4';
 | 
						|
      const startSha = 'abc';
 | 
						|
      const pathRoot = 'a/a/-/merge_requests/1';
 | 
						|
      let file;
 | 
						|
 | 
						|
      beforeAll(() => {
 | 
						|
        file = { file_hash: 'collapsed', load_collapsed_diff_url: '/load/collapsed/diff/url' };
 | 
						|
      });
 | 
						|
 | 
						|
      beforeEach(() => {
 | 
						|
        store.$patch({ diffFiles: [{ file_hash: file.file_hash }] });
 | 
						|
        jest.spyOn(axios, 'get').mockReturnValue(Promise.resolve({ data: {} }));
 | 
						|
      });
 | 
						|
 | 
						|
      it('fetches the data when there is no mergeRequestDiff', () => {
 | 
						|
        store.loadCollapsedDiff({ file });
 | 
						|
 | 
						|
        expect(axios.get).toHaveBeenCalledWith(file.load_collapsed_diff_url, {
 | 
						|
          params: expect.any(Object),
 | 
						|
        });
 | 
						|
      });
 | 
						|
 | 
						|
      it.each`
 | 
						|
        desc                                   | versionPath                                              | start_sha    | diff_id
 | 
						|
        ${'no additional version information'} | ${`${pathRoot}?search=terms`}                            | ${undefined} | ${undefined}
 | 
						|
        ${'the diff_id'}                       | ${`${pathRoot}?diff_id=${diffId}`}                       | ${undefined} | ${diffId}
 | 
						|
        ${'the start_sha'}                     | ${`${pathRoot}?start_sha=${startSha}`}                   | ${startSha}  | ${undefined}
 | 
						|
        ${'all available version information'} | ${`${pathRoot}?diff_id=${diffId}&start_sha=${startSha}`} | ${startSha}  | ${diffId}
 | 
						|
      `('fetches the data and includes $desc', ({ versionPath, start_sha, diff_id }) => {
 | 
						|
        jest.spyOn(axios, 'get').mockReturnValue(Promise.resolve({ data: {} }));
 | 
						|
 | 
						|
        store.$patch({ mergeRequestDiff: { version_path: versionPath } });
 | 
						|
 | 
						|
        store.loadCollapsedDiff({ file });
 | 
						|
 | 
						|
        expect(axios.get).toHaveBeenCalledWith(file.load_collapsed_diff_url, {
 | 
						|
          params: expect.objectContaining({ start_sha, diff_id }),
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('scrollToLineIfNeededInline', () => {
 | 
						|
    const lineMock = {
 | 
						|
      line_code: 'ABC_123',
 | 
						|
    };
 | 
						|
 | 
						|
    it('should not call handleLocationHash when there is not hash', () => {
 | 
						|
      window.location.hash = '';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededInline(lineMock);
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not call handleLocationHash when the hash does not match any line', () => {
 | 
						|
      window.location.hash = 'XYZ_456';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededInline(lineMock);
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should call handleLocationHash only when the hash matches a line', () => {
 | 
						|
      window.location.hash = 'ABC_123';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededInline({
 | 
						|
        lineCode: 'ABC_456',
 | 
						|
      });
 | 
						|
      store.scrollToLineIfNeededInline(lineMock);
 | 
						|
      store.scrollToLineIfNeededInline({
 | 
						|
        lineCode: 'XYZ_456',
 | 
						|
      });
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).toHaveBeenCalled();
 | 
						|
      expect(commonUtils.handleLocationHash).toHaveBeenCalledTimes(1);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('scrollToLineIfNeededParallel', () => {
 | 
						|
    const lineMock = {
 | 
						|
      left: null,
 | 
						|
      right: {
 | 
						|
        line_code: 'ABC_123',
 | 
						|
      },
 | 
						|
    };
 | 
						|
 | 
						|
    it('should not call handleLocationHash when there is not hash', () => {
 | 
						|
      window.location.hash = '';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededParallel(lineMock);
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not call handleLocationHash when the hash does not match any line', () => {
 | 
						|
      window.location.hash = 'XYZ_456';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededParallel(lineMock);
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should call handleLocationHash only when the hash matches a line', () => {
 | 
						|
      window.location.hash = 'ABC_123';
 | 
						|
 | 
						|
      store.scrollToLineIfNeededParallel({
 | 
						|
        left: null,
 | 
						|
        right: {
 | 
						|
          lineCode: 'ABC_456',
 | 
						|
        },
 | 
						|
      });
 | 
						|
      store.scrollToLineIfNeededParallel(lineMock);
 | 
						|
      store.scrollToLineIfNeededParallel({
 | 
						|
        left: null,
 | 
						|
        right: {
 | 
						|
          lineCode: 'XYZ_456',
 | 
						|
        },
 | 
						|
      });
 | 
						|
 | 
						|
      expect(commonUtils.handleLocationHash).toHaveBeenCalled();
 | 
						|
      expect(commonUtils.handleLocationHash).toHaveBeenCalledTimes(1);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('saveDiffDiscussion', () => {
 | 
						|
    const endpoint = '/create-note-path';
 | 
						|
    const commitId = 'something';
 | 
						|
    const formData = {
 | 
						|
      diffFile: getDiffFileMock(),
 | 
						|
      noteableData: {
 | 
						|
        create_note_path: endpoint,
 | 
						|
      },
 | 
						|
      positionType: FILE_DIFF_POSITION_TYPE,
 | 
						|
    };
 | 
						|
    const note = 'note';
 | 
						|
    const state = {
 | 
						|
      commit: {
 | 
						|
        id: commitId,
 | 
						|
      },
 | 
						|
    };
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      store.$patch(state);
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches actions', async () => {
 | 
						|
      const discussion = { id: 1 };
 | 
						|
      useNotes().saveNote.mockResolvedValue(Promise.resolve({ discussion }));
 | 
						|
      useNotes().updateDiscussion.mockResolvedValue(Promise.resolve('discussion'));
 | 
						|
      useNotes().updateResolvableDiscussionsCounts.mockResolvedValue(Promise.resolve());
 | 
						|
      store.assignDiscussionsToDiff.mockResolvedValueOnce(Promise.resolve());
 | 
						|
      store.toggleFileCommentForm.mockResolvedValueOnce(Promise.resolve());
 | 
						|
      store.closeDiffFileCommentForm.mockResolvedValueOnce(Promise.resolve());
 | 
						|
 | 
						|
      await store.saveDiffDiscussion({ note, formData });
 | 
						|
 | 
						|
      expect(useNotes().saveNote.mock.calls[0][0]).toMatchObject({
 | 
						|
        data: {
 | 
						|
          note: {
 | 
						|
            commit_id: commitId,
 | 
						|
            note,
 | 
						|
          },
 | 
						|
        },
 | 
						|
        endpoint,
 | 
						|
      });
 | 
						|
      expect(useNotes().updateDiscussion).toHaveBeenCalledWith(discussion);
 | 
						|
      expect(useNotes().updateResolvableDiscussionsCounts).toHaveBeenCalledTimes(1);
 | 
						|
      expect(store.assignDiscussionsToDiff).toHaveBeenCalledWith(['discussion']);
 | 
						|
      expect(store.closeDiffFileCommentForm).toHaveBeenCalledWith(formData.diffFile.file_hash);
 | 
						|
      expect(store.toggleFileCommentForm).toHaveBeenCalledWith(formData.diffFile.file_path);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not allow adding note with sensitive token', async () => {
 | 
						|
      const sensitiveMessage = 'token: glpat-1234567890abcdefghij';
 | 
						|
 | 
						|
      await store.saveDiffDiscussion({ note: sensitiveMessage, formData });
 | 
						|
      expect(useNotes().saveNote).not.toHaveBeenCalled();
 | 
						|
      expect(confirmAction).toHaveBeenCalledWith(
 | 
						|
        '',
 | 
						|
        expect.objectContaining({
 | 
						|
          title: 'Warning: Potential secret detected',
 | 
						|
        }),
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('toggleTreeOpen', () => {
 | 
						|
    it('commits TOGGLE_FOLDER_OPEN', () => {
 | 
						|
      return testAction(
 | 
						|
        store.toggleTreeOpen,
 | 
						|
        'path',
 | 
						|
        { treeEntries: { path: {} } },
 | 
						|
        [{ type: store[types.TOGGLE_FOLDER_OPEN], payload: 'path' }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('goToFile', () => {
 | 
						|
    const file = { path: 'path' };
 | 
						|
    const fileHash = 'test';
 | 
						|
    let state;
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      getters.isTreePathLoaded = () => false;
 | 
						|
      state = {
 | 
						|
        viewDiffsFileByFile: true,
 | 
						|
        treeEntries: {
 | 
						|
          path: {
 | 
						|
            fileHash,
 | 
						|
          },
 | 
						|
        },
 | 
						|
      };
 | 
						|
      store.$patch(state);
 | 
						|
    });
 | 
						|
 | 
						|
    it('immediately defers to scrollToFile if the app is not in file-by-file mode', () => {
 | 
						|
      store.$patch({ viewDiffsFileByFile: false });
 | 
						|
 | 
						|
      store.goToFile(file);
 | 
						|
 | 
						|
      expect(store.scrollToFile).toHaveBeenCalledWith(file);
 | 
						|
    });
 | 
						|
 | 
						|
    describe('when the app is in fileByFile mode', () => {
 | 
						|
      it('commits SET_CURRENT_DIFF_FILE', () => {
 | 
						|
        store.goToFile(file);
 | 
						|
 | 
						|
        expect(store[types.SET_CURRENT_DIFF_FILE]).toHaveBeenCalledWith(fileHash);
 | 
						|
      });
 | 
						|
 | 
						|
      it('does nothing more if the path has already been loaded', () => {
 | 
						|
        getters.isTreePathLoaded = () => true;
 | 
						|
 | 
						|
        store.goToFile(file);
 | 
						|
 | 
						|
        expect(store[types.SET_CURRENT_DIFF_FILE]).toHaveBeenCalledWith(fileHash);
 | 
						|
        expect(store.fetchFileByFile).not.toHaveBeenCalled();
 | 
						|
      });
 | 
						|
 | 
						|
      describe('when the tree entry has not been loaded', () => {
 | 
						|
        it('updates location hash', () => {
 | 
						|
          store.goToFile(file);
 | 
						|
 | 
						|
          expect(historyPushState).toHaveBeenCalledWith(new URL(`${TEST_HOST}#test`), {
 | 
						|
            skipScrolling: true,
 | 
						|
          });
 | 
						|
          expect(scrollToElement).toHaveBeenCalledWith('.diff-files-holder', { duration: 0 });
 | 
						|
        });
 | 
						|
 | 
						|
        it('loads the file and then scrolls to it', async () => {
 | 
						|
          store.goToFile(file);
 | 
						|
 | 
						|
          // Wait for the fetchFileByFile dispatch to return, to trigger scrollToFile
 | 
						|
          await waitForPromises();
 | 
						|
 | 
						|
          expect(store.fetchFileByFile).toHaveBeenCalled();
 | 
						|
          expect(commonUtils.historyPushState).toHaveBeenCalledWith(new URL(`${TEST_HOST}/#test`), {
 | 
						|
            skipScrolling: true,
 | 
						|
          });
 | 
						|
          expect(commonUtils.scrollToElement).toHaveBeenCalledWith('.diff-files-holder', {
 | 
						|
            duration: 0,
 | 
						|
          });
 | 
						|
          expect(store.fetchFileByFile).toHaveBeenCalledWith();
 | 
						|
        });
 | 
						|
 | 
						|
        it('unlinks the file', () => {
 | 
						|
          store.goToFile(file);
 | 
						|
          expect(store.unlinkFile).toHaveBeenCalledWith();
 | 
						|
        });
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('scrollToFile', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      getters = { isVirtualScrollingEnabled: false };
 | 
						|
    });
 | 
						|
 | 
						|
    it('updates location hash', () => {
 | 
						|
      const state = {
 | 
						|
        treeEntries: {
 | 
						|
          path: {
 | 
						|
            fileHash: 'test',
 | 
						|
          },
 | 
						|
        },
 | 
						|
      };
 | 
						|
 | 
						|
      store.$patch(state);
 | 
						|
      store.scrollToFile({ path: 'path' });
 | 
						|
 | 
						|
      expect(document.location.hash).toBe('#test');
 | 
						|
    });
 | 
						|
 | 
						|
    it('commits SET_CURRENT_DIFF_FILE', () => {
 | 
						|
      const state = {
 | 
						|
        treeEntries: {
 | 
						|
          path: {
 | 
						|
            fileHash: 'test',
 | 
						|
          },
 | 
						|
        },
 | 
						|
      };
 | 
						|
 | 
						|
      store.$patch(state);
 | 
						|
      store.scrollToFile({ path: 'path' });
 | 
						|
 | 
						|
      expect(store[types.SET_CURRENT_DIFF_FILE]).toHaveBeenCalledWith('test');
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setShowTreeList', () => {
 | 
						|
    it('commits toggle', () => {
 | 
						|
      return testAction(
 | 
						|
        store.setShowTreeList,
 | 
						|
        { showTreeList: true },
 | 
						|
        {},
 | 
						|
        [{ type: store[types.SET_SHOW_TREE_LIST], payload: true }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('updates localStorage', () => {
 | 
						|
      jest.spyOn(localStorage, 'setItem').mockImplementation(() => {});
 | 
						|
 | 
						|
      store.setShowTreeList({ showTreeList: true });
 | 
						|
 | 
						|
      expect(localStorage.setItem).toHaveBeenCalledWith('mr_tree_show', true);
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not update localStorage', () => {
 | 
						|
      jest.spyOn(localStorage, 'setItem').mockImplementation(() => {});
 | 
						|
 | 
						|
      store.setShowTreeList({ showTreeList: true, saving: false });
 | 
						|
 | 
						|
      expect(localStorage.setItem).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('renderFileForDiscussionId', () => {
 | 
						|
    const notesState = {
 | 
						|
      notes: {
 | 
						|
        discussions: [
 | 
						|
          {
 | 
						|
            id: '123',
 | 
						|
            diff_file: {
 | 
						|
              file_hash: 'HASH',
 | 
						|
            },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            id: '456',
 | 
						|
            diff_file: {
 | 
						|
              file_hash: 'HASH',
 | 
						|
            },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    };
 | 
						|
    let $emit;
 | 
						|
    const state = ({ collapsed, renderIt }) => ({
 | 
						|
      diffFiles: [
 | 
						|
        {
 | 
						|
          file_hash: 'HASH',
 | 
						|
          viewer: {
 | 
						|
            automaticallyCollapsed: collapsed,
 | 
						|
          },
 | 
						|
          renderIt,
 | 
						|
        },
 | 
						|
      ],
 | 
						|
    });
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      useNotes().$patch(notesState);
 | 
						|
      $emit = jest.spyOn(eventHub, '$emit');
 | 
						|
    });
 | 
						|
 | 
						|
    it('expands the file for the given discussion id', () => {
 | 
						|
      const localState = state({ collapsed: true, renderIt: false });
 | 
						|
      store.$patch(localState);
 | 
						|
 | 
						|
      store.renderFileForDiscussionId('123');
 | 
						|
 | 
						|
      expect($emit).toHaveBeenCalledTimes(1);
 | 
						|
      expect(commonUtils.scrollToElement).toHaveBeenCalledTimes(1);
 | 
						|
    });
 | 
						|
 | 
						|
    it('jumps to discussion on already rendered and expanded file', () => {
 | 
						|
      const localState = state({ collapsed: false, renderIt: true });
 | 
						|
      store.$patch(localState);
 | 
						|
 | 
						|
      store.renderFileForDiscussionId('123');
 | 
						|
 | 
						|
      expect(store[types.SET_FILE_COLLAPSED]).not.toHaveBeenCalled();
 | 
						|
      expect($emit).toHaveBeenCalledTimes(1);
 | 
						|
      expect(commonUtils.scrollToElement).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setRenderTreeList', () => {
 | 
						|
    it('commits SET_RENDER_TREE_LIST', () => {
 | 
						|
      return testAction(
 | 
						|
        store.setRenderTreeList,
 | 
						|
        { renderTreeList: true },
 | 
						|
        {},
 | 
						|
        [{ type: store[types.SET_RENDER_TREE_LIST], payload: true }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('sets localStorage', () => {
 | 
						|
      store.setRenderTreeList({ renderTreeList: true });
 | 
						|
 | 
						|
      expect(localStorage.setItem).toHaveBeenCalledWith('mr_diff_tree_list', true);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setShowWhitespace', () => {
 | 
						|
    const endpointUpdateUser = 'user/prefs';
 | 
						|
    let putSpy;
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      jest.spyOn(api, 'trackRedisHllUserEvent').mockImplementation(() => {});
 | 
						|
      putSpy = jest.spyOn(axios, 'put');
 | 
						|
 | 
						|
      mock.onPut(endpointUpdateUser).reply(HTTP_STATUS_OK, {});
 | 
						|
      jest.spyOn(eventHub, '$emit').mockImplementation();
 | 
						|
    });
 | 
						|
 | 
						|
    it('commits SET_SHOW_WHITESPACE', () => {
 | 
						|
      return testAction(
 | 
						|
        store.setShowWhitespace,
 | 
						|
        { showWhitespace: true, updateDatabase: false },
 | 
						|
        {},
 | 
						|
        [{ type: store[types.SET_SHOW_WHITESPACE], payload: true }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('saves to the database when the user is logged in', async () => {
 | 
						|
      window.gon = { current_user_id: 12345 };
 | 
						|
      store.$patch({ endpointUpdateUser });
 | 
						|
 | 
						|
      await store.setShowWhitespace({ showWhitespace: true, updateDatabase: true });
 | 
						|
 | 
						|
      expect(putSpy).toHaveBeenCalledWith(endpointUpdateUser, { show_whitespace_in_diffs: true });
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not try to save to the API if the user is not logged in', async () => {
 | 
						|
      window.gon = {};
 | 
						|
      store.$patch({ endpointUpdateUser });
 | 
						|
 | 
						|
      await store.setShowWhitespace({ showWhitespace: true, updateDatabase: true });
 | 
						|
 | 
						|
      expect(putSpy).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('emits eventHub event', async () => {
 | 
						|
      await store.setShowWhitespace({ showWhitespace: true, updateDatabase: false });
 | 
						|
 | 
						|
      expect(eventHub.$emit).toHaveBeenCalledWith('refetchDiffData');
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('receiveFullDiffError', () => {
 | 
						|
    it('updates state with the file that did not load', () => {
 | 
						|
      return testAction(
 | 
						|
        store.receiveFullDiffError,
 | 
						|
        'file',
 | 
						|
        { diffFiles: [{ file_path: 'file' }] },
 | 
						|
        [{ type: store[types.RECEIVE_FULL_DIFF_ERROR], payload: 'file' }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchFullDiff', () => {
 | 
						|
    describe('success', () => {
 | 
						|
      beforeEach(() => {
 | 
						|
        mock.onGet(`${TEST_HOST}/context`).replyOnce(HTTP_STATUS_OK, ['test']);
 | 
						|
      });
 | 
						|
 | 
						|
      it('commits the success and dispatches an action to expand the new lines', () => {
 | 
						|
        const file = {
 | 
						|
          context_lines_path: `${TEST_HOST}/context`,
 | 
						|
          file_path: 'test',
 | 
						|
          file_hash: 'test',
 | 
						|
        };
 | 
						|
        return testAction(
 | 
						|
          store.fetchFullDiff,
 | 
						|
          file,
 | 
						|
          { diffFiles: [file] },
 | 
						|
          [{ type: store[types.RECEIVE_FULL_DIFF_SUCCESS], payload: { filePath: 'test' } }],
 | 
						|
          [{ type: store.setExpandedDiffLines, payload: { file, data: ['test'] } }],
 | 
						|
        );
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('error', () => {
 | 
						|
      beforeEach(() => {
 | 
						|
        mock.onGet(`${TEST_HOST}/context`).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
      });
 | 
						|
 | 
						|
      it('dispatches receiveFullDiffError', () => {
 | 
						|
        const file = {
 | 
						|
          context_lines_path: `${TEST_HOST}/context`,
 | 
						|
          file_path: 'test',
 | 
						|
          file_hash: 'test',
 | 
						|
        };
 | 
						|
        return testAction(
 | 
						|
          store.fetchFullDiff,
 | 
						|
          file,
 | 
						|
          { diffFiles: [file] },
 | 
						|
          [],
 | 
						|
          [{ type: store.receiveFullDiffError, payload: 'test' }],
 | 
						|
        );
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('toggleFullDiff', () => {
 | 
						|
    let state;
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      state = {
 | 
						|
        diffFiles: [{ file_path: 'test', isShowingFullFile: false }],
 | 
						|
      };
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches fetchFullDiff when file is not expanded', () => {
 | 
						|
      return testAction(
 | 
						|
        store.toggleFullDiff,
 | 
						|
        'test',
 | 
						|
        state,
 | 
						|
        [{ type: store[types.REQUEST_FULL_DIFF], payload: 'test' }],
 | 
						|
        [{ type: store.fetchFullDiff, payload: state.diffFiles[0] }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('switchToFullDiffFromRenamedFile', () => {
 | 
						|
    const SUCCESS_URL = 'fakehost/context.success';
 | 
						|
    const testFilePath = 'testpath';
 | 
						|
    const updatedViewerName = 'testviewer';
 | 
						|
    const preparedLine = { prepared: 'in-a-test' };
 | 
						|
    const testFile = {
 | 
						|
      file_path: testFilePath,
 | 
						|
      file_hash: 'testhash',
 | 
						|
      alternate_viewer: { name: updatedViewerName },
 | 
						|
    };
 | 
						|
    const updatedViewer = {
 | 
						|
      name: updatedViewerName,
 | 
						|
      automaticallyCollapsed: false,
 | 
						|
      manuallyCollapsed: false,
 | 
						|
      forceOpen: false,
 | 
						|
    };
 | 
						|
    const testData = [{ rich_text: 'test' }, { rich_text: 'file2' }];
 | 
						|
    let renamedFile;
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      jest.spyOn(utils, 'prepareLineForRenamedFile').mockImplementation(() => preparedLine);
 | 
						|
    });
 | 
						|
 | 
						|
    afterEach(() => {
 | 
						|
      renamedFile = null;
 | 
						|
    });
 | 
						|
 | 
						|
    describe('success', () => {
 | 
						|
      beforeEach(() => {
 | 
						|
        renamedFile = { ...testFile, context_lines_path: SUCCESS_URL };
 | 
						|
        mock.onGet(SUCCESS_URL).replyOnce(HTTP_STATUS_OK, testData);
 | 
						|
      });
 | 
						|
 | 
						|
      it.each`
 | 
						|
        diffViewType
 | 
						|
        ${INLINE_DIFF_VIEW_TYPE}
 | 
						|
        ${PARALLEL_DIFF_VIEW_TYPE}
 | 
						|
      `(
 | 
						|
        'performs the correct mutations and starts a render queue for view type $diffViewType',
 | 
						|
        ({ diffViewType }) => {
 | 
						|
          return testAction(
 | 
						|
            store.switchToFullDiffFromRenamedFile,
 | 
						|
            { diffFile: renamedFile },
 | 
						|
            { diffFiles: [renamedFile], diffViewType },
 | 
						|
            [
 | 
						|
              {
 | 
						|
                type: store[types.SET_DIFF_FILE_VIEWER],
 | 
						|
                payload: { filePath: testFilePath, viewer: updatedViewer },
 | 
						|
              },
 | 
						|
              {
 | 
						|
                type: store[types.SET_CURRENT_VIEW_DIFF_FILE_LINES],
 | 
						|
                payload: { filePath: testFilePath, lines: [preparedLine, preparedLine] },
 | 
						|
              },
 | 
						|
            ],
 | 
						|
            [],
 | 
						|
          );
 | 
						|
        },
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setFileCollapsedByUser', () => {
 | 
						|
    it('commits SET_FILE_COLLAPSED', () => {
 | 
						|
      return testAction(
 | 
						|
        store.setFileCollapsedByUser,
 | 
						|
        { filePath: 'test', collapsed: true },
 | 
						|
        null,
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_FILE_COLLAPSED],
 | 
						|
            payload: { filePath: 'test', collapsed: true, trigger: 'manual' },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setFileForcedOpen', () => {
 | 
						|
    it('commits SET_FILE_FORCED_OPEN', () => {
 | 
						|
      return testAction(
 | 
						|
        store.setFileForcedOpen,
 | 
						|
        { filePath: 'test', forced: true },
 | 
						|
        { diffFiles: [{ file_path: 'test', viewer: {} }] },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_FILE_FORCED_OPEN],
 | 
						|
            payload: { filePath: 'test', forced: true },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setExpandedDiffLines', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      utils.idleCallback.mockImplementation((cb) => {
 | 
						|
        cb({ timeRemaining: () => 50 });
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('commits SET_CURRENT_VIEW_DIFF_FILE_LINES when lines less than MAX_RENDERING_DIFF_LINES', () => {
 | 
						|
      utils.convertExpandLines.mockImplementation(() => ['test']);
 | 
						|
 | 
						|
      const file = { file_path: 'path' };
 | 
						|
      return testAction(
 | 
						|
        store.setExpandedDiffLines,
 | 
						|
        { file, data: [] },
 | 
						|
        { diffFiles: [file], diffViewType: 'inline' },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store.SET_CURRENT_VIEW_DIFF_FILE_LINES,
 | 
						|
            payload: { filePath: 'path', lines: ['test'] },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('commits ADD_CURRENT_VIEW_DIFF_FILE_LINES when lines more than MAX_RENDERING_DIFF_LINES', () => {
 | 
						|
      const lines = new Array(501).fill().map((_, i) => `line-${i}`);
 | 
						|
      utils.convertExpandLines.mockReturnValue(lines);
 | 
						|
 | 
						|
      const file = { file_path: 'path' };
 | 
						|
      return testAction(
 | 
						|
        store.setExpandedDiffLines,
 | 
						|
        { file, data: [] },
 | 
						|
        { diffFiles: [file], diffViewType: 'inline' },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store.SET_CURRENT_VIEW_DIFF_FILE_LINES,
 | 
						|
            payload: { filePath: 'path', lines: lines.slice(0, 200) },
 | 
						|
          },
 | 
						|
          { type: store.TOGGLE_DIFF_FILE_RENDERING_MORE, payload: 'path' },
 | 
						|
          ...new Array(301).fill().map((_, i) => ({
 | 
						|
            type: store.ADD_CURRENT_VIEW_DIFF_FILE_LINES,
 | 
						|
            payload: { filePath: 'path', line: `line-${i + 200}` },
 | 
						|
          })),
 | 
						|
          { type: store.TOGGLE_DIFF_FILE_RENDERING_MORE, payload: 'path' },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setSuggestPopoverDismissed', () => {
 | 
						|
    it('commits SET_SHOW_SUGGEST_POPOVER', async () => {
 | 
						|
      const state = { dismissEndpoint: `${TEST_HOST}/-/user_callouts` };
 | 
						|
      mock.onPost(state.dismissEndpoint).reply(HTTP_STATUS_OK, {});
 | 
						|
 | 
						|
      jest.spyOn(axios, 'post');
 | 
						|
 | 
						|
      await testAction(
 | 
						|
        store.setSuggestPopoverDismissed,
 | 
						|
        null,
 | 
						|
        state,
 | 
						|
        [{ type: store[types.SET_SHOW_SUGGEST_POPOVER] }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
      expect(axios.post).toHaveBeenCalledWith(state.dismissEndpoint, {
 | 
						|
        feature_name: 'suggest_popover_dismissed',
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('changeCurrentCommit', () => {
 | 
						|
    it('commits the new commit information and re-requests the diff metadata for the commit', () => {
 | 
						|
      return testAction(
 | 
						|
        store.changeCurrentCommit,
 | 
						|
        { commitId: 'NEW' },
 | 
						|
        {
 | 
						|
          commit: {
 | 
						|
            id: 'OLD',
 | 
						|
          },
 | 
						|
          endpoint: 'URL/OLD',
 | 
						|
          endpointBatch: 'URL/OLD',
 | 
						|
          endpointMetadata: 'URL/OLD',
 | 
						|
        },
 | 
						|
        [
 | 
						|
          { type: store[types.SET_DIFF_FILES], payload: [] },
 | 
						|
          {
 | 
						|
            type: store[types.SET_BASE_CONFIG],
 | 
						|
            payload: {
 | 
						|
              ...store.$state,
 | 
						|
              commit: {
 | 
						|
                id: 'OLD', // Not a typo: the action fired next will overwrite all of the `commit` in state
 | 
						|
              },
 | 
						|
              endpoint: 'URL/NEW',
 | 
						|
              endpointBatch: 'URL/NEW',
 | 
						|
              endpointMetadata: 'URL/NEW',
 | 
						|
            },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [{ type: store.fetchDiffFilesMeta }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it.each`
 | 
						|
      commitId     | commit           | msg
 | 
						|
      ${undefined} | ${{ id: 'OLD' }} | ${'`commitId` is a required argument'}
 | 
						|
      ${'NEW'}     | ${null}          | ${'`state` must already contain a valid `commit`'}
 | 
						|
      ${undefined} | ${null}          | ${'`commitId` is a required argument'}
 | 
						|
    `(
 | 
						|
      'returns a rejected promise with the error message $msg given `{ "commitId": $commitId, "state.commit": $commit }`',
 | 
						|
      ({ commitId, commit, msg }) => {
 | 
						|
        const err = new Error(msg);
 | 
						|
        const actionReturn = testAction(
 | 
						|
          store.changeCurrentCommit,
 | 
						|
          { commitId },
 | 
						|
          {
 | 
						|
            endpoint: 'URL/OLD',
 | 
						|
            endpointBatch: 'URL/OLD',
 | 
						|
            endpointMetadata: 'URL/OLD',
 | 
						|
            commit,
 | 
						|
          },
 | 
						|
          [],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
 | 
						|
        return expect(actionReturn).rejects.toStrictEqual(err);
 | 
						|
      },
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  describe('moveToNeighboringCommit', () => {
 | 
						|
    it.each`
 | 
						|
      direction     | expected         | currentCommit
 | 
						|
      ${'next'}     | ${'NEXTSHA'}     | ${{ next_commit_id: 'NEXTSHA' }}
 | 
						|
      ${'previous'} | ${'PREVIOUSSHA'} | ${{ prev_commit_id: 'PREVIOUSSHA' }}
 | 
						|
    `(
 | 
						|
      'for the direction "$direction", dispatches the action to move to the SHA "$expected"',
 | 
						|
      ({ direction, expected, currentCommit }) => {
 | 
						|
        return testAction(
 | 
						|
          store.moveToNeighboringCommit,
 | 
						|
          { direction },
 | 
						|
          { isLoading: false, commit: currentCommit },
 | 
						|
          [],
 | 
						|
          [{ type: store.changeCurrentCommit, payload: { commitId: expected } }],
 | 
						|
        );
 | 
						|
      },
 | 
						|
    );
 | 
						|
 | 
						|
    it.each`
 | 
						|
      direction     | diffsAreLoading | currentCommit
 | 
						|
      ${'next'}     | ${false}        | ${{ prev_commit_id: 'PREVIOUSSHA' }}
 | 
						|
      ${'next'}     | ${true}         | ${{ prev_commit_id: 'PREVIOUSSHA' }}
 | 
						|
      ${'next'}     | ${false}        | ${undefined}
 | 
						|
      ${'previous'} | ${false}        | ${{ next_commit_id: 'NEXTSHA' }}
 | 
						|
      ${'previous'} | ${true}         | ${{ next_commit_id: 'NEXTSHA' }}
 | 
						|
      ${'previous'} | ${false}        | ${undefined}
 | 
						|
    `(
 | 
						|
      'given `{ "isloading": $diffsAreLoading, "commit": $currentCommit }` in state, no actions are dispatched',
 | 
						|
      ({ direction, diffsAreLoading, currentCommit }) => {
 | 
						|
        return testAction(
 | 
						|
          store.moveToNeighboringCommit,
 | 
						|
          { direction },
 | 
						|
          { commit: currentCommit, isLoading: diffsAreLoading },
 | 
						|
          [],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
      },
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  describe('rereadNoteHash', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      window.location.hash = 'note_123';
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches setCurrentDiffFileIdFromNote if the hash is a note URL', () => {
 | 
						|
      window.location.hash = 'note_123';
 | 
						|
      store.setCurrentDiffFileIdFromNote.mockReturnValueOnce(Promise.resolve());
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.rereadNoteHash,
 | 
						|
        {},
 | 
						|
        {},
 | 
						|
        [],
 | 
						|
        [{ type: store.setCurrentDiffFileIdFromNote, payload: '123' }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches fetchFileByFile if the app is in fileByFile mode', () => {
 | 
						|
      window.location.hash = 'note_123';
 | 
						|
      store.setCurrentDiffFileIdFromNote.mockReturnValueOnce(Promise.resolve());
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.rereadNoteHash,
 | 
						|
        {},
 | 
						|
        { viewDiffsFileByFile: true },
 | 
						|
        [],
 | 
						|
        [
 | 
						|
          { type: store.setCurrentDiffFileIdFromNote, payload: '123' },
 | 
						|
          { type: store.fetchFileByFile },
 | 
						|
        ],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not try to fetch the diff file if the app is not in fileByFile mode', () => {
 | 
						|
      window.location.hash = 'note_123';
 | 
						|
      store.setCurrentDiffFileIdFromNote.mockReturnValueOnce(Promise.resolve());
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.rereadNoteHash,
 | 
						|
        {},
 | 
						|
        { viewDiffsFileByFile: false },
 | 
						|
        [],
 | 
						|
        [{ type: store.setCurrentDiffFileIdFromNote, payload: '123' }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('does nothing if the hash is not a note URL', () => {
 | 
						|
      window.location.hash = 'abcdef1234567890';
 | 
						|
 | 
						|
      return testAction(store.rereadNoteHash, {}, {}, [], []);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setCurrentDiffFileIdFromNote', () => {
 | 
						|
    it('commits SET_CURRENT_DIFF_FILE', () => {
 | 
						|
      getters = { flatBlobsList: [{ fileHash: '123' }] };
 | 
						|
      notesGetters = {
 | 
						|
        getDiscussion: () => ({ diff_file: { file_hash: '123' } }),
 | 
						|
        notesById: { 1: { discussion_id: '2' } },
 | 
						|
      };
 | 
						|
 | 
						|
      store.setCurrentDiffFileIdFromNote('1');
 | 
						|
 | 
						|
      expect(store[types.SET_CURRENT_DIFF_FILE]).toHaveBeenCalledWith('123');
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not commit SET_CURRENT_DIFF_FILE when discussion has no diff_file', () => {
 | 
						|
      const commit = jest.fn();
 | 
						|
      notesGetters = {
 | 
						|
        getDiscussion: () => ({ id: '1' }),
 | 
						|
        notesById: { 1: { discussion_id: '2' } },
 | 
						|
      };
 | 
						|
 | 
						|
      store.setCurrentDiffFileIdFromNote('1');
 | 
						|
 | 
						|
      expect(commit).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not commit SET_CURRENT_DIFF_FILE when diff file does not exist', () => {
 | 
						|
      const commit = jest.fn();
 | 
						|
      getters = { flatBlobsList: [{ fileHash: '123' }] };
 | 
						|
      notesGetters = {
 | 
						|
        getDiscussion: () => ({ diff_file: { file_hash: '124' } }),
 | 
						|
        notesById: { 1: { discussion_id: '2' } },
 | 
						|
      };
 | 
						|
 | 
						|
      store.setCurrentDiffFileIdFromNote('1');
 | 
						|
 | 
						|
      expect(commit).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('navigateToDiffFileIndex', () => {
 | 
						|
    it('commits SET_CURRENT_DIFF_FILE', () => {
 | 
						|
      getters = { flatBlobsList: [{ fileHash: '123' }] };
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.navigateToDiffFileIndex,
 | 
						|
        0,
 | 
						|
        null,
 | 
						|
        [{ type: store[types.SET_CURRENT_DIFF_FILE], payload: '123' }],
 | 
						|
        [{ type: store.unlinkFile }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('dispatches the fetchFileByFile action when the state value viewDiffsFileByFile is true', () => {
 | 
						|
      getters = { flatBlobsList: [{ fileHash: '123' }] };
 | 
						|
      store.fetchFileByFile.mockReturnValueOnce(Promise.resolve());
 | 
						|
 | 
						|
      return testAction(
 | 
						|
        store.navigateToDiffFileIndex,
 | 
						|
        0,
 | 
						|
        { viewDiffsFileByFile: true },
 | 
						|
        [{ type: store[types.SET_CURRENT_DIFF_FILE], payload: '123' }],
 | 
						|
        [{ type: store.unlinkFile }, { type: store.fetchFileByFile }],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('setFileByFile', () => {
 | 
						|
    const updateUserEndpoint = 'user/prefs';
 | 
						|
    let putSpy;
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      putSpy = jest.spyOn(axios, 'put');
 | 
						|
 | 
						|
      mock.onPut(updateUserEndpoint).reply(HTTP_STATUS_OK, {});
 | 
						|
    });
 | 
						|
 | 
						|
    it.each`
 | 
						|
      value
 | 
						|
      ${true}
 | 
						|
      ${false}
 | 
						|
    `(
 | 
						|
      'commits SET_FILE_BY_FILE and persists the File-by-File user preference with the new value $value',
 | 
						|
      async ({ value }) => {
 | 
						|
        await testAction(
 | 
						|
          store.setFileByFile,
 | 
						|
          { fileByFile: value },
 | 
						|
          {
 | 
						|
            viewDiffsFileByFile: null,
 | 
						|
            endpointUpdateUser: updateUserEndpoint,
 | 
						|
          },
 | 
						|
          [{ type: store[types.SET_FILE_BY_FILE], payload: value }],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
 | 
						|
        expect(putSpy).toHaveBeenCalledWith(updateUserEndpoint, { view_diffs_file_by_file: value });
 | 
						|
      },
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  describe('reviewFile', () => {
 | 
						|
    const file = {
 | 
						|
      id: '123',
 | 
						|
      file_hash: 'xyz',
 | 
						|
      file_identifier_hash: 'abc',
 | 
						|
      load_collapsed_diff_url: 'gitlab-org/gitlab-test/-/merge_requests/1/diffs',
 | 
						|
    };
 | 
						|
    it.each`
 | 
						|
      reviews                         | diffFile | reviewed
 | 
						|
      ${{ abc: ['123', 'hash:xyz'] }} | ${file}  | ${true}
 | 
						|
      ${{}}                           | ${file}  | ${false}
 | 
						|
    `(
 | 
						|
      'sets reviews ($reviews) to localStorage and state for file $file if it is marked reviewed=$reviewed',
 | 
						|
      ({ reviews, diffFile, reviewed }) => {
 | 
						|
        store.$patch({ mrReviews: { abc: ['123'] } });
 | 
						|
 | 
						|
        store.reviewFile({
 | 
						|
          file: diffFile,
 | 
						|
          reviewed,
 | 
						|
        });
 | 
						|
 | 
						|
        expect(localStorage.setItem).toHaveBeenCalledTimes(1);
 | 
						|
        expect(localStorage.setItem).toHaveBeenCalledWith(
 | 
						|
          'gitlab-org/gitlab-test/-/merge_requests/1-file-reviews',
 | 
						|
          JSON.stringify(reviews),
 | 
						|
        );
 | 
						|
        expect(store[types.SET_MR_FILE_REVIEWS]).toHaveBeenCalledWith(reviews);
 | 
						|
      },
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  describe('toggleFileCommentForm', () => {
 | 
						|
    it('commits TOGGLE_FILE_COMMENT_FORM', () => {
 | 
						|
      const file = getDiffFileMock();
 | 
						|
      return testAction(
 | 
						|
        store.toggleFileCommentForm,
 | 
						|
        file.file_path,
 | 
						|
        {
 | 
						|
          diffFiles: [file],
 | 
						|
        },
 | 
						|
        [
 | 
						|
          { type: store[types.TOGGLE_FILE_COMMENT_FORM], payload: file.file_path },
 | 
						|
          {
 | 
						|
            type: store[types.SET_FILE_COLLAPSED],
 | 
						|
            payload: { filePath: file.file_path, collapsed: false },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    it('always opens if file is collapsed', () => {
 | 
						|
      const file = {
 | 
						|
        ...getDiffFileMock(),
 | 
						|
        viewer: {
 | 
						|
          ...getDiffFileMock().viewer,
 | 
						|
          manuallyCollapsed: true,
 | 
						|
        },
 | 
						|
      };
 | 
						|
      return testAction(
 | 
						|
        store.toggleFileCommentForm,
 | 
						|
        file.file_path,
 | 
						|
        {
 | 
						|
          diffFiles: [file],
 | 
						|
        },
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_FILE_COMMENT_FORM],
 | 
						|
            payload: { filePath: file.file_path, expanded: true },
 | 
						|
          },
 | 
						|
          {
 | 
						|
            type: store[types.SET_FILE_COLLAPSED],
 | 
						|
            payload: { filePath: file.file_path, collapsed: false },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('addDraftToFile', () => {
 | 
						|
    it('commits ADD_DRAFT_TO_FILE', () => {
 | 
						|
      return testAction(
 | 
						|
        store.addDraftToFile,
 | 
						|
        { filePath: 'path', draft: 'draft' },
 | 
						|
        {},
 | 
						|
        [{ type: store[types.ADD_DRAFT_TO_FILE], payload: { filePath: 'path', draft: 'draft' } }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('fetchLinkedFile', () => {
 | 
						|
    it('fetches linked file', async () => {
 | 
						|
      const linkedFileHref = `${TEST_HOST}/linked-file`;
 | 
						|
      const linkedFile = getDiffFileMock();
 | 
						|
      const diffFiles = [linkedFile];
 | 
						|
      const hubSpy = jest.spyOn(diffsEventHub, '$emit');
 | 
						|
      mock.onGet(new RegExp(linkedFileHref)).reply(HTTP_STATUS_OK, { diff_files: diffFiles });
 | 
						|
 | 
						|
      await testAction(
 | 
						|
        store.fetchLinkedFile,
 | 
						|
        linkedFileHref,
 | 
						|
        {},
 | 
						|
        [
 | 
						|
          { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loading' },
 | 
						|
          { type: store[types.SET_RETRIEVING_BATCHES], payload: true },
 | 
						|
          {
 | 
						|
            type: store[types.SET_DIFF_DATA_BATCH],
 | 
						|
            payload: {
 | 
						|
              get diff_files() {
 | 
						|
                return store.diffFiles;
 | 
						|
              },
 | 
						|
              updatePosition: false,
 | 
						|
            },
 | 
						|
          },
 | 
						|
          { type: store[types.SET_LINKED_FILE_HASH], payload: linkedFile.file_hash },
 | 
						|
          { type: store[types.SET_CURRENT_DIFF_FILE], payload: linkedFile.file_hash },
 | 
						|
          { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loaded' },
 | 
						|
          { type: store[types.SET_RETRIEVING_BATCHES], payload: false },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
 | 
						|
      jest.runAllTimers();
 | 
						|
      expect(hubSpy).toHaveBeenCalledWith('diffFilesModified');
 | 
						|
      expect(handleLocationHash).toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('handles load error', async () => {
 | 
						|
      const linkedFileHref = `${TEST_HOST}/linked-file`;
 | 
						|
      const hubSpy = jest.spyOn(diffsEventHub, '$emit');
 | 
						|
      mock.onGet(new RegExp(linkedFileHref)).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
 | 
						|
      try {
 | 
						|
        await testAction(
 | 
						|
          store.fetchLinkedFile,
 | 
						|
          linkedFileHref,
 | 
						|
          {},
 | 
						|
          [
 | 
						|
            { type: store[types.SET_BATCH_LOADING_STATE], payload: 'loading' },
 | 
						|
            { type: store[types.SET_RETRIEVING_BATCHES], payload: true },
 | 
						|
            { type: store[types.SET_BATCH_LOADING_STATE], payload: 'error' },
 | 
						|
            { type: store[types.SET_RETRIEVING_BATCHES], payload: false },
 | 
						|
          ],
 | 
						|
          [],
 | 
						|
        );
 | 
						|
      } catch (error) {
 | 
						|
        expect(error.response.status).toBe(HTTP_STATUS_INTERNAL_SERVER_ERROR);
 | 
						|
      }
 | 
						|
 | 
						|
      jest.runAllTimers();
 | 
						|
      expect(hubSpy).not.toHaveBeenCalledWith('diffFilesModified');
 | 
						|
      expect(handleLocationHash).not.toHaveBeenCalled();
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('unlinkFile', () => {
 | 
						|
    it('unlinks linked file', () => {
 | 
						|
      const linkedFile = getDiffFileMock();
 | 
						|
      setWindowLocation(`${TEST_HOST}/?file=${linkedFile.file_hash}#${linkedFile.file_hash}_10_10`);
 | 
						|
      testAction(
 | 
						|
        store.unlinkFile,
 | 
						|
        undefined,
 | 
						|
        { diffFiles: [linkedFile], linkedFileHash: linkedFile.file_hash },
 | 
						|
        [{ type: store[types.SET_LINKED_FILE_HASH], payload: null }],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
      expect(window.location.hash).toBe('');
 | 
						|
      expect(window.location.search).toBe('');
 | 
						|
    });
 | 
						|
 | 
						|
    it('does nothing when no linked file present', () => {
 | 
						|
      testAction(store.unlinkFile, undefined, {}, [], []);
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('expandAllFiles', () => {
 | 
						|
    it('triggers mutation', () => {
 | 
						|
      testAction(
 | 
						|
        store.expandAllFiles,
 | 
						|
        undefined,
 | 
						|
        {},
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_COLLAPSED_STATE_FOR_ALL_FILES],
 | 
						|
            payload: { collapsed: false },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('collapseAllFiles', () => {
 | 
						|
    it('triggers mutation', () => {
 | 
						|
      testAction(
 | 
						|
        store.collapseAllFiles,
 | 
						|
        undefined,
 | 
						|
        {},
 | 
						|
        [
 | 
						|
          {
 | 
						|
            type: store[types.SET_COLLAPSED_STATE_FOR_ALL_FILES],
 | 
						|
            payload: { collapsed: true },
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        [],
 | 
						|
      );
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 |