import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility';
import { createStore } from '~/ide/stores';
import { createRouter } from '~/ide/ide_router';
import {
  stageAllChanges,
  unstageAllChanges,
  toggleFileFinder,
  setCurrentBranchId,
  setEmptyStateSvgs,
  updateActivityBarView,
  updateTempFlagForEntry,
  setErrorMessage,
  deleteEntry,
  renameEntry,
  getBranchData,
  createTempEntry,
  discardAllChanges,
} from '~/ide/stores/actions';
import axios from '~/lib/utils/axios_utils';
import * as types from '~/ide/stores/mutation_types';
import { file, createTriggerRenameAction, createTriggerChangeAction } from '../helpers';
import testAction from '../../helpers/vuex_action_helper';
import eventHub from '~/ide/eventhub';

jest.mock('~/lib/utils/url_utility', () => ({
  visitUrl: jest.fn(),
  joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));

describe('Multi-file store actions', () => {
  let store;
  let router;

  beforeEach(() => {
    store = createStore();
    router = createRouter(store);

    jest.spyOn(store, 'commit');
    jest.spyOn(store, 'dispatch');
    jest.spyOn(router, 'push').mockImplementation();
  });

  describe('redirectToUrl', () => {
    it('calls visitUrl', done => {
      store
        .dispatch('redirectToUrl', 'test')
        .then(() => {
          expect(visitUrl).toHaveBeenCalledWith('test');

          done();
        })
        .catch(done.fail);
    });
  });

  describe('setInitialData', () => {
    it('commits initial data', done => {
      store
        .dispatch('setInitialData', { canCommit: true })
        .then(() => {
          expect(store.state.canCommit).toBeTruthy();
          done();
        })
        .catch(done.fail);
    });
  });

  describe('discardAllChanges', () => {
    const paths = ['to_discard', 'another_one_to_discard'];

    beforeEach(() => {
      paths.forEach(path => {
        const f = file(path);
        f.changed = true;

        store.state.openFiles.push(f);
        store.state.changedFiles.push(f);
        store.state.entries[f.path] = f;
      });
    });

    it('discards all changes in file', () => {
      const expectedCalls = paths.map(path => ['restoreOriginalFile', path]);

      discardAllChanges(store);

      expect(store.dispatch.mock.calls).toEqual(expect.arrayContaining(expectedCalls));
    });

    it('removes all files from changedFiles state', done => {
      store
        .dispatch('discardAllChanges')
        .then(() => {
          expect(store.state.changedFiles.length).toBe(0);
          expect(store.state.openFiles.length).toBe(2);
        })
        .then(done)
        .catch(done.fail);
    });
  });

  describe('createTempEntry', () => {
    beforeEach(() => {
      document.body.innerHTML += '<div class="flash-container"></div>';

      store.state.currentProjectId = 'abcproject';
      store.state.currentBranchId = 'mybranch';

      store.state.trees['abcproject/mybranch'] = {
        tree: [],
      };
      store.state.projects.abcproject = {
        web_url: '',
      };
    });

    afterEach(() => {
      document.querySelector('.flash-container').remove();
    });

    describe('tree', () => {
      it('creates temp tree', done => {
        store
          .dispatch('createTempEntry', {
            name: 'test',
            type: 'tree',
          })
          .then(() => {
            const entry = store.state.entries.test;

            expect(entry).not.toBeNull();
            expect(entry.type).toBe('tree');

            done();
          })
          .catch(done.fail);
      });

      it('creates new folder inside another tree', done => {
        const tree = {
          type: 'tree',
          name: 'testing',
          path: 'testing',
          tree: [],
        };

        store.state.entries[tree.path] = tree;

        store
          .dispatch('createTempEntry', {
            name: 'testing/test',
            type: 'tree',
          })
          .then(() => {
            expect(tree.tree[0].tempFile).toBeTruthy();
            expect(tree.tree[0].name).toBe('test');
            expect(tree.tree[0].type).toBe('tree');

            done();
          })
          .catch(done.fail);
      });

      it('does not create new tree if already exists', done => {
        const tree = {
          type: 'tree',
          path: 'testing',
          tempFile: false,
          tree: [],
        };

        store.state.entries[tree.path] = tree;

        store
          .dispatch('createTempEntry', {
            name: 'testing',
            type: 'tree',
          })
          .then(() => {
            expect(store.state.entries[tree.path].tempFile).toEqual(false);
            expect(document.querySelector('.flash-alert')).not.toBeNull();

            done();
          })
          .catch(done.fail);
      });
    });

    describe('blob', () => {
      it('creates temp file', done => {
        const name = 'test';

        store
          .dispatch('createTempEntry', {
            name,
            type: 'blob',
          })
          .then(() => {
            const f = store.state.entries[name];

            expect(f.tempFile).toBeTruthy();
            expect(store.state.trees['abcproject/mybranch'].tree.length).toBe(1);

            done();
          })
          .catch(done.fail);
      });

      it('adds tmp file to open files', done => {
        const name = 'test';

        store
          .dispatch('createTempEntry', {
            name,
            type: 'blob',
          })
          .then(() => {
            const f = store.state.entries[name];

            expect(store.state.openFiles.length).toBe(1);
            expect(store.state.openFiles[0].name).toBe(f.name);

            done();
          })
          .catch(done.fail);
      });

      it('adds tmp file to staged files', done => {
        const name = 'test';

        store
          .dispatch('createTempEntry', {
            name,
            type: 'blob',
          })
          .then(() => {
            expect(store.state.stagedFiles).toEqual([expect.objectContaining({ name })]);

            done();
          })
          .catch(done.fail);
      });

      it('sets tmp file as active', () => {
        createTempEntry(store, { name: 'test', type: 'blob' });

        expect(store.dispatch).toHaveBeenCalledWith('setFileActive', 'test');
      });

      it('creates flash message if file already exists', done => {
        const f = file('test', '1', 'blob');
        store.state.trees['abcproject/mybranch'].tree = [f];
        store.state.entries[f.path] = f;

        store
          .dispatch('createTempEntry', {
            name: 'test',
            type: 'blob',
          })
          .then(() => {
            expect(document.querySelector('.flash-alert')?.textContent.trim()).toEqual(
              `The name "${f.name}" is already taken in this directory.`,
            );

            done();
          })
          .catch(done.fail);
      });
    });
  });

  describe('scrollToTab', () => {
    it('focuses the current active element', done => {
      document.body.innerHTML +=
        '<div id="tabs"><div class="active"><div class="repo-tab"></div></div></div>';
      const el = document.querySelector('.repo-tab');
      jest.spyOn(el, 'focus').mockImplementation();

      store
        .dispatch('scrollToTab')
        .then(() => {
          setImmediate(() => {
            expect(el.focus).toHaveBeenCalled();

            document.getElementById('tabs').remove();

            done();
          });
        })
        .catch(done.fail);
    });
  });

  describe('stage/unstageAllChanges', () => {
    let file1;
    let file2;

    beforeEach(() => {
      file1 = { ...file('test'), content: 'changed test', raw: 'test' };
      file2 = { ...file('test2'), content: 'changed test2', raw: 'test2' };

      store.state.openFiles = [file1];
      store.state.changedFiles = [file1];
      store.state.stagedFiles = [{ ...file2, content: 'staged test' }];

      store.state.entries = {
        [file1.path]: { ...file1 },
        [file2.path]: { ...file2 },
      };
    });

    describe('stageAllChanges', () => {
      it('adds all files from changedFiles to stagedFiles', () => {
        stageAllChanges(store);

        expect(store.commit.mock.calls).toEqual(
          expect.arrayContaining([
            [types.SET_LAST_COMMIT_MSG, ''],
            [types.STAGE_CHANGE, expect.objectContaining({ path: file1.path })],
          ]),
        );
      });

      it('opens pending tab if a change exists in that file', () => {
        stageAllChanges(store);

        expect(store.dispatch.mock.calls).toEqual([
          [
            'openPendingTab',
            { file: { ...file1, staged: true, changed: true }, keyPrefix: 'staged' },
          ],
        ]);
      });

      it('does not open pending tab if no change exists in that file', () => {
        store.state.entries[file1.path].content = 'test';
        store.state.stagedFiles = [file1];
        store.state.changedFiles = [store.state.entries[file1.path]];

        stageAllChanges(store);

        expect(store.dispatch).not.toHaveBeenCalled();
      });
    });

    describe('unstageAllChanges', () => {
      it('removes all files from stagedFiles after unstaging', () => {
        unstageAllChanges(store);

        expect(store.commit.mock.calls).toEqual(
          expect.arrayContaining([
            [types.UNSTAGE_CHANGE, expect.objectContaining({ path: file2.path })],
          ]),
        );
      });

      it('opens pending tab if a change exists in that file', () => {
        unstageAllChanges(store);

        expect(store.dispatch.mock.calls).toEqual([
          ['openPendingTab', { file: file1, keyPrefix: 'unstaged' }],
        ]);
      });

      it('does not open pending tab if no change exists in that file', () => {
        store.state.entries[file1.path].content = 'test';
        store.state.stagedFiles = [file1];
        store.state.changedFiles = [store.state.entries[file1.path]];

        unstageAllChanges(store);

        expect(store.dispatch).not.toHaveBeenCalled();
      });
    });
  });

  describe('updateViewer', () => {
    it('updates viewer state', done => {
      store
        .dispatch('updateViewer', 'diff')
        .then(() => {
          expect(store.state.viewer).toBe('diff');
        })
        .then(done)
        .catch(done.fail);
    });
  });

  describe('updateActivityBarView', () => {
    it('commits UPDATE_ACTIVITY_BAR_VIEW', done => {
      testAction(
        updateActivityBarView,
        'test',
        {},
        [{ type: 'UPDATE_ACTIVITY_BAR_VIEW', payload: 'test' }],
        [],
        done,
      );
    });
  });

  describe('setEmptyStateSvgs', () => {
    it('commits setEmptyStateSvgs', done => {
      testAction(
        setEmptyStateSvgs,
        'svg',
        {},
        [{ type: 'SET_EMPTY_STATE_SVGS', payload: 'svg' }],
        [],
        done,
      );
    });
  });

  describe('updateTempFlagForEntry', () => {
    it('commits UPDATE_TEMP_FLAG', done => {
      const f = {
        ...file(),
        path: 'test',
        tempFile: true,
      };
      store.state.entries[f.path] = f;

      testAction(
        updateTempFlagForEntry,
        { file: f, tempFile: false },
        store.state,
        [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
        [],
        done,
      );
    });

    it('commits UPDATE_TEMP_FLAG and dispatches for parent', done => {
      const parent = {
        ...file(),
        path: 'testing',
      };
      const f = {
        ...file(),
        path: 'test',
        parentPath: 'testing',
      };
      store.state.entries[parent.path] = parent;
      store.state.entries[f.path] = f;

      testAction(
        updateTempFlagForEntry,
        { file: f, tempFile: false },
        store.state,
        [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
        [{ type: 'updateTempFlagForEntry', payload: { file: parent, tempFile: false } }],
        done,
      );
    });

    it('does not dispatch for parent, if parent does not exist', done => {
      const f = {
        ...file(),
        path: 'test',
        parentPath: 'testing',
      };
      store.state.entries[f.path] = f;

      testAction(
        updateTempFlagForEntry,
        { file: f, tempFile: false },
        store.state,
        [{ type: 'UPDATE_TEMP_FLAG', payload: { path: f.path, tempFile: false } }],
        [],
        done,
      );
    });
  });

  describe('setCurrentBranchId', () => {
    it('commits setCurrentBranchId', done => {
      testAction(
        setCurrentBranchId,
        'branchId',
        {},
        [{ type: 'SET_CURRENT_BRANCH', payload: 'branchId' }],
        [],
        done,
      );
    });
  });

  describe('toggleFileFinder', () => {
    it('commits TOGGLE_FILE_FINDER', done => {
      testAction(
        toggleFileFinder,
        true,
        null,
        [{ type: 'TOGGLE_FILE_FINDER', payload: true }],
        [],
        done,
      );
    });
  });

  describe('setErrorMessage', () => {
    it('commis error messsage', done => {
      testAction(
        setErrorMessage,
        'error',
        null,
        [{ type: types.SET_ERROR_MESSAGE, payload: 'error' }],
        [],
        done,
      );
    });
  });

  describe('deleteEntry', () => {
    it('commits entry deletion', done => {
      store.state.entries.path = 'testing';

      testAction(
        deleteEntry,
        'path',
        store.state,
        [{ type: types.DELETE_ENTRY, payload: 'path' }],
        [{ type: 'stageChange', payload: 'path' }, createTriggerChangeAction()],
        done,
      );
    });

    it('does not delete a folder after it is emptied', done => {
      const testFolder = {
        type: 'tree',
        tree: [],
      };
      const testEntry = {
        path: 'testFolder/entry-to-delete',
        parentPath: 'testFolder',
        opened: false,
        tree: [],
      };
      testFolder.tree.push(testEntry);
      store.state.entries = {
        testFolder,
        'testFolder/entry-to-delete': testEntry,
      };

      testAction(
        deleteEntry,
        'testFolder/entry-to-delete',
        store.state,
        [{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
        [
          { type: 'stageChange', payload: 'testFolder/entry-to-delete' },
          createTriggerChangeAction(),
        ],
        done,
      );
    });

    describe('when renamed', () => {
      let testEntry;

      beforeEach(() => {
        testEntry = {
          path: 'test',
          name: 'test',
          prevPath: 'test_old',
          prevName: 'test_old',
          prevParentPath: '',
        };

        store.state.entries = { test: testEntry };
      });

      describe('and previous does not exist', () => {
        it('reverts the rename before deleting', done => {
          testAction(
            deleteEntry,
            testEntry.path,
            store.state,
            [],
            [
              {
                type: 'renameEntry',
                payload: {
                  path: testEntry.path,
                  name: testEntry.prevName,
                  parentPath: testEntry.prevParentPath,
                },
              },
              {
                type: 'deleteEntry',
                payload: testEntry.prevPath,
              },
            ],
            done,
          );
        });
      });

      describe('and previous exists', () => {
        beforeEach(() => {
          const oldEntry = {
            path: testEntry.prevPath,
            name: testEntry.prevName,
          };

          store.state.entries[oldEntry.path] = oldEntry;
        });

        it('does not revert rename before deleting', done => {
          testAction(
            deleteEntry,
            testEntry.path,
            store.state,
            [{ type: types.DELETE_ENTRY, payload: testEntry.path }],
            [{ type: 'stageChange', payload: testEntry.path }, createTriggerChangeAction()],
            done,
          );
        });

        it('when previous is deleted, it reverts rename before deleting', done => {
          store.state.entries[testEntry.prevPath].deleted = true;

          testAction(
            deleteEntry,
            testEntry.path,
            store.state,
            [],
            [
              {
                type: 'renameEntry',
                payload: {
                  path: testEntry.path,
                  name: testEntry.prevName,
                  parentPath: testEntry.prevParentPath,
                },
              },
              {
                type: 'deleteEntry',
                payload: testEntry.prevPath,
              },
            ],
            done,
          );
        });
      });
    });
  });

  describe('renameEntry', () => {
    describe('purging of file model cache', () => {
      beforeEach(() => {
        jest.spyOn(eventHub, '$emit').mockImplementation();
      });

      it('does not purge model cache for temporary entries that got renamed', done => {
        Object.assign(store.state.entries, {
          test: {
            ...file('test'),
            key: 'foo-key',
            type: 'blob',
            tempFile: true,
          },
        });

        store
          .dispatch('renameEntry', {
            path: 'test',
            name: 'new',
          })
          .then(() => {
            expect(eventHub.$emit.mock.calls).not.toContain('editor.update.model.dispose.foo-bar');
          })
          .then(done)
          .catch(done.fail);
      });

      it('purges model cache for renamed entry', done => {
        Object.assign(store.state.entries, {
          test: {
            ...file('test'),
            key: 'foo-key',
            type: 'blob',
            tempFile: false,
          },
        });

        store
          .dispatch('renameEntry', {
            path: 'test',
            name: 'new',
          })
          .then(() => {
            expect(eventHub.$emit).toHaveBeenCalled();
            expect(eventHub.$emit).toHaveBeenCalledWith(`editor.update.model.dispose.foo-key`);
          })
          .then(done)
          .catch(done.fail);
      });
    });

    describe('single entry', () => {
      let origEntry;
      let renamedEntry;

      beforeEach(() => {
        // Need to insert both because `testAction` doesn't actually call the mutation
        origEntry = file('orig', 'orig', 'blob');
        renamedEntry = {
          ...file('renamed', 'renamed', 'blob'),
          prevKey: origEntry.key,
          prevName: origEntry.name,
          prevPath: origEntry.path,
        };

        Object.assign(store.state.entries, {
          orig: origEntry,
          renamed: renamedEntry,
        });
      });

      it('by default renames an entry and stages it', () => {
        const dispatch = jest.fn();
        const commit = jest.fn();

        renameEntry(
          { dispatch, commit, state: store.state, getters: store.getters },
          { path: 'orig', name: 'renamed' },
        );

        expect(commit.mock.calls).toEqual([
          [types.RENAME_ENTRY, { path: 'orig', name: 'renamed', parentPath: undefined }],
          [types.STAGE_CHANGE, expect.objectContaining({ path: 'renamed' })],
        ]);
      });

      it('if not changed, completely unstages and discards entry if renamed to original', done => {
        testAction(
          renameEntry,
          { path: 'renamed', name: 'orig' },
          store.state,
          [
            {
              type: types.RENAME_ENTRY,
              payload: {
                path: 'renamed',
                name: 'orig',
                parentPath: undefined,
              },
            },
            {
              type: types.REMOVE_FILE_FROM_STAGED_AND_CHANGED,
              payload: origEntry,
            },
          ],
          [createTriggerRenameAction('renamed', 'orig')],
          done,
        );
      });

      it('if already in changed, does not add to change', done => {
        store.state.changedFiles.push(renamedEntry);

        testAction(
          renameEntry,
          { path: 'orig', name: 'renamed' },
          store.state,
          [expect.objectContaining({ type: types.RENAME_ENTRY })],
          [createTriggerRenameAction('orig', 'renamed')],
          done,
        );
      });

      it('routes to the renamed file if the original file has been opened', done => {
        store.state.currentProjectId = 'test/test';
        store.state.currentBranchId = 'master';

        Object.assign(store.state.entries.orig, {
          opened: true,
        });

        store
          .dispatch('renameEntry', {
            path: 'orig',
            name: 'renamed',
          })
          .then(() => {
            expect(router.push.mock.calls).toHaveLength(1);
            expect(router.push).toHaveBeenCalledWith(`/project/test/test/tree/master/-/renamed/`);
          })
          .then(done)
          .catch(done.fail);
      });
    });

    describe('folder', () => {
      let folder;
      let file1;
      let file2;

      beforeEach(() => {
        folder = file('folder', 'folder', 'tree');
        file1 = file('file-1', 'file-1', 'blob', folder);
        file2 = file('file-2', 'file-2', 'blob', folder);

        folder.tree = [file1, file2];

        Object.assign(store.state.entries, {
          [folder.path]: folder,
          [file1.path]: file1,
          [file2.path]: file2,
        });
      });

      it('updates entries in a folder correctly, when folder is renamed', done => {
        store
          .dispatch('renameEntry', {
            path: 'folder',
            name: 'new-folder',
          })
          .then(() => {
            const keys = Object.keys(store.state.entries);

            expect(keys.length).toBe(3);
            expect(keys.indexOf('new-folder')).toBe(0);
            expect(keys.indexOf('new-folder/file-1')).toBe(1);
            expect(keys.indexOf('new-folder/file-2')).toBe(2);
          })
          .then(done)
          .catch(done.fail);
      });

      it('discards renaming of an entry if the root folder is renamed back to a previous name', done => {
        const rootFolder = file('old-folder', 'old-folder', 'tree');
        const testEntry = file('test', 'test', 'blob', rootFolder);

        Object.assign(store.state, {
          entries: {
            'old-folder': {
              ...rootFolder,
              tree: [testEntry],
            },
            'old-folder/test': testEntry,
          },
        });

        store
          .dispatch('renameEntry', {
            path: 'old-folder',
            name: 'new-folder',
          })
          .then(() => {
            const { entries } = store.state;

            expect(Object.keys(entries).length).toBe(2);
            expect(entries['old-folder']).toBeUndefined();
            expect(entries['old-folder/test']).toBeUndefined();

            expect(entries['new-folder']).toBeDefined();
            expect(entries['new-folder/test']).toEqual(
              expect.objectContaining({
                path: 'new-folder/test',
                name: 'test',
                prevPath: 'old-folder/test',
                prevName: 'test',
              }),
            );
          })
          .then(() =>
            store.dispatch('renameEntry', {
              path: 'new-folder',
              name: 'old-folder',
            }),
          )
          .then(() => {
            const { entries } = store.state;

            expect(Object.keys(entries).length).toBe(2);
            expect(entries['new-folder']).toBeUndefined();
            expect(entries['new-folder/test']).toBeUndefined();

            expect(entries['old-folder']).toBeDefined();
            expect(entries['old-folder/test']).toEqual(
              expect.objectContaining({
                path: 'old-folder/test',
                name: 'test',
                prevPath: undefined,
                prevName: undefined,
              }),
            );
          })
          .then(done)
          .catch(done.fail);
      });

      describe('with file in directory', () => {
        const parentPath = 'original-dir';
        const newParentPath = 'new-dir';
        const fileName = 'test.md';
        const filePath = `${parentPath}/${fileName}`;

        let rootDir;

        beforeEach(() => {
          const parentEntry = file(parentPath, parentPath, 'tree');
          const fileEntry = file(filePath, filePath, 'blob', parentEntry);
          rootDir = {
            tree: [],
          };

          Object.assign(store.state, {
            entries: {
              [parentPath]: {
                ...parentEntry,
                tree: [fileEntry],
              },
              [filePath]: fileEntry,
            },
            trees: {
              '/': rootDir,
            },
          });
        });

        it('creates new directory', done => {
          expect(store.state.entries[newParentPath]).toBeUndefined();

          store
            .dispatch('renameEntry', { path: filePath, name: fileName, parentPath: newParentPath })
            .then(() => {
              expect(store.state.entries[newParentPath]).toEqual(
                expect.objectContaining({
                  path: newParentPath,
                  type: 'tree',
                  tree: expect.arrayContaining([
                    store.state.entries[`${newParentPath}/${fileName}`],
                  ]),
                }),
              );
            })
            .then(done)
            .catch(done.fail);
        });

        describe('when new directory exists', () => {
          let newDir;

          beforeEach(() => {
            newDir = file(newParentPath, newParentPath, 'tree');

            store.state.entries[newDir.path] = newDir;
            rootDir.tree.push(newDir);
          });

          it('inserts in new directory', done => {
            expect(newDir.tree).toEqual([]);

            store
              .dispatch('renameEntry', {
                path: filePath,
                name: fileName,
                parentPath: newParentPath,
              })
              .then(() => {
                expect(newDir.tree).toEqual([store.state.entries[`${newParentPath}/${fileName}`]]);
              })
              .then(done)
              .catch(done.fail);
          });

          it('when new directory is deleted, it undeletes it', done => {
            store.dispatch('deleteEntry', newParentPath);

            expect(store.state.entries[newParentPath].deleted).toBe(true);
            expect(rootDir.tree.some(x => x.path === newParentPath)).toBe(false);

            store
              .dispatch('renameEntry', {
                path: filePath,
                name: fileName,
                parentPath: newParentPath,
              })
              .then(() => {
                expect(store.state.entries[newParentPath].deleted).toBe(false);
                expect(rootDir.tree.some(x => x.path === newParentPath)).toBe(true);
              })
              .then(done)
              .catch(done.fail);
          });
        });
      });
    });
  });

  describe('getBranchData', () => {
    let mock;

    beforeEach(() => {
      mock = new MockAdapter(axios);
    });

    afterEach(() => {
      mock.restore();
    });

    describe('error', () => {
      let dispatch;
      let callParams;

      beforeEach(() => {
        callParams = [
          {
            commit() {},
            state: store.state,
          },
          {
            projectId: 'abc/def',
            branchId: 'master-testing',
          },
        ];
        dispatch = jest.fn();
        document.body.innerHTML += '<div class="flash-container"></div>';
      });

      afterEach(() => {
        document.querySelector('.flash-container').remove();
      });

      it('passes the error further unchanged without dispatching any action when response is 404', done => {
        mock.onGet(/(.*)/).replyOnce(404);

        getBranchData(...callParams)
          .then(done.fail)
          .catch(e => {
            expect(dispatch.mock.calls).toHaveLength(0);
            expect(e.response.status).toEqual(404);
            expect(document.querySelector('.flash-alert')).toBeNull();
            done();
          });
      });

      it('does not pass the error further and flashes an alert if error is not 404', done => {
        mock.onGet(/(.*)/).replyOnce(418);

        getBranchData(...callParams)
          .then(done.fail)
          .catch(e => {
            expect(dispatch.mock.calls).toHaveLength(0);
            expect(e.response).toBeUndefined();
            expect(document.querySelector('.flash-alert')).not.toBeNull();
            done();
          });
      });
    });
  });
});
