diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js
index da9de25302aa76fd8776bbfb6e098f00fee93767..5e64206714106e83af7e0d07a78881f1d659179f 100644
--- a/app/assets/javascripts/ide/services/index.js
+++ b/app/assets/javascripts/ide/services/index.js
@@ -1,5 +1,6 @@
 import Vue from 'vue';
 import VueResource from 'vue-resource';
+import axios from '~/lib/utils/axios_utils';
 import Api from '~/api';
 
 Vue.use(VueResource);
@@ -69,11 +70,7 @@ export default {
   },
   getFiles(projectUrl, branchId) {
     const url = `${projectUrl}/files/${branchId}`;
-    return Vue.http.get(url, {
-      params: {
-        format: 'json',
-      },
-    });
+    return axios.get(url, { params: { format: 'json' } });
   },
   lastCommitPipelines({ getters }) {
     const commitSha = getters.lastCommit.id;
diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js
index 48750615f3940895a99d38cdb720d1b7f3adf899..f8af23ac70be97b8293b70f779758d5bc030cef1 100644
--- a/app/assets/javascripts/ide/stores/actions/tree.js
+++ b/app/assets/javascripts/ide/stores/actions/tree.js
@@ -70,8 +70,7 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
 
       service
         .getFiles(selectedProject.web_url, branchId)
-        .then(res => res.json())
-        .then(data => {
+        .then(({ data }) => {
           const worker = new FilesDecoratorWorker();
           worker.addEventListener('message', e => {
             const { entries, treeList } = e.data;
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index e843511622117e8869ae61f63e41c0ee23c344fc..c53b6da4b480efcea8e327274ea52d8c8ca7f2af 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -362,4 +362,29 @@ describe('Api', () => {
         .catch(done.fail);
     });
   });
+
+  describe('createBranch', () => {
+    it('creates new branch', done => {
+      const ref = 'master';
+      const branch = 'new-branch-name';
+      const dummyProjectPath = 'gitlab-org/gitlab-ce';
+      const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${encodeURIComponent(
+        dummyProjectPath,
+      )}/repository/branches`;
+
+      spyOn(axios, 'post').and.callThrough();
+
+      mock.onPost(expectedUrl).replyOnce(200, {
+        name: branch,
+      });
+
+      Api.createBranch(dummyProjectPath, { ref, branch })
+        .then(({ data }) => {
+          expect(data.name).toBe(branch);
+          expect(axios.post).toHaveBeenCalledWith(expectedUrl, { ref, branch });
+        })
+        .then(done)
+        .catch(done.fail);
+    });
+  });
 });
diff --git a/spec/javascripts/ide/components/error_message_spec.js b/spec/javascripts/ide/components/error_message_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..70d13a6ceb290dbeac3e43c5a6b59fd7ba85f4e6
--- /dev/null
+++ b/spec/javascripts/ide/components/error_message_spec.js
@@ -0,0 +1,104 @@
+import Vue from 'vue';
+import store from '~/ide/stores';
+import ErrorMessage from '~/ide/components/error_message.vue';
+import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
+import { resetStore } from '../helpers';
+
+describe('IDE error message component', () => {
+  const Component = Vue.extend(ErrorMessage);
+  let vm;
+
+  beforeEach(() => {
+    vm = createComponentWithStore(Component, store, {
+      message: {
+        text: 'error message',
+        action: null,
+        actionText: null,
+      },
+    }).$mount();
+  });
+
+  afterEach(() => {
+    vm.$destroy();
+    resetStore(vm.$store);
+  });
+
+  it('renders error message', () => {
+    expect(vm.$el.textContent).toContain('error message');
+  });
+
+  it('clears error message on click', () => {
+    spyOn(vm, 'setErrorMessage');
+
+    vm.$el.click();
+
+    expect(vm.setErrorMessage).toHaveBeenCalledWith(null);
+  });
+
+  describe('with action', () => {
+    beforeEach(done => {
+      vm.message.action = 'testAction';
+      vm.message.actionText = 'test action';
+      vm.message.actionPayload = 'testActionPayload';
+
+      spyOn(vm.$store, 'dispatch').and.returnValue(Promise.resolve());
+
+      vm.$nextTick(done);
+    });
+
+    it('renders action button', () => {
+      expect(vm.$el.querySelector('.flash-action')).not.toBe(null);
+      expect(vm.$el.textContent).toContain('test action');
+    });
+
+    it('does not clear error message on click', () => {
+      spyOn(vm, 'setErrorMessage');
+
+      vm.$el.click();
+
+      expect(vm.setErrorMessage).not.toHaveBeenCalled();
+    });
+
+    it('dispatches action', done => {
+      vm.$el.querySelector('.flash-action').click();
+
+      vm.$nextTick(() => {
+        expect(vm.$store.dispatch).toHaveBeenCalledWith('testAction', 'testActionPayload');
+
+        done();
+      });
+    });
+
+    it('does not dispatch action when already loading', () => {
+      vm.isLoading = true;
+
+      vm.$el.querySelector('.flash-action').click();
+
+      expect(vm.$store.dispatch).not.toHaveBeenCalledWith();
+    });
+
+    it('resets isLoading after click', done => {
+      vm.$el.querySelector('.flash-action').click();
+
+      expect(vm.isLoading).toBe(true);
+
+      vm.$nextTick(() => {
+        expect(vm.isLoading).toBe(false);
+
+        done();
+      });
+    });
+
+    it('shows loading icon when isLoading is true', done => {
+      expect(vm.$el.querySelector('.loading-container').style.display).not.toBe('');
+
+      vm.isLoading = true;
+
+      vm.$nextTick(() => {
+        expect(vm.$el.querySelector('.loading-container').style.display).toBe('');
+
+        done();
+      });
+    });
+  });
+});
diff --git a/spec/javascripts/ide/components/ide_spec.js b/spec/javascripts/ide/components/ide_spec.js
index 045a60e56a04bed6498257bbb8c832f15764aa3a..708c9fe69af3beb135463d45e4d049842f4842f8 100644
--- a/spec/javascripts/ide/components/ide_spec.js
+++ b/spec/javascripts/ide/components/ide_spec.js
@@ -114,4 +114,18 @@ describe('ide component', () => {
       expect(vm.mousetrapStopCallback(null, document.querySelector('.inputarea'), 't')).toBe(true);
     });
   });
+
+  it('shows error message when set', done => {
+    expect(vm.$el.querySelector('.flash-container')).toBe(null);
+
+    vm.$store.state.errorMessage = {
+      text: 'error',
+    };
+
+    vm.$nextTick(() => {
+      expect(vm.$el.querySelector('.flash-container')).not.toBe(null);
+
+      done();
+    });
+  });
 });
diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js
index 5529fe44ce5ece0b9200bd4c758ad4578442be89..ab8bca52093eb397cc0f4344436c7490873249ea 100644
--- a/spec/javascripts/ide/stores/actions/project_spec.js
+++ b/spec/javascripts/ide/stores/actions/project_spec.js
@@ -1,7 +1,10 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
 import {
   refreshLastCommitData,
   showBranchNotFoundError,
   createNewBranchFromDefault,
+  getBranchData,
 } from '~/ide/stores/actions';
 import store from '~/ide/stores';
 import projectActions from '~/ide/stores/actions/project';
@@ -11,11 +14,19 @@ import { resetStore } from '../../helpers';
 import testAction from '../../../helpers/vuex_action_helper';
 
 describe('IDE store project actions', () => {
+  let mock;
+
   beforeEach(() => {
-    store.state.projects['abc/def'] = {};
+    mock = new MockAdapter(axios);
+
+    store.state.projects['abc/def'] = {
+      branches: {},
+    };
   });
 
   afterEach(() => {
+    mock.restore();
+
     resetStore(store);
   });
 
@@ -164,4 +175,34 @@ describe('IDE store project actions', () => {
       });
     });
   });
+
+  describe('getBranchData', () => {
+    describe('error', () => {
+      it('dispatches branch not found action when response is 404', done => {
+        const dispatch = jasmine.createSpy('dispatchSpy');
+
+        mock.onGet(/(.*)/).replyOnce(404);
+
+        getBranchData(
+          {
+            commit() {},
+            dispatch,
+            state: store.state,
+          },
+          {
+            projectId: 'abc/def',
+            branchId: 'master-testing',
+          },
+        )
+          .then(done.fail)
+          .catch(() => {
+            expect(dispatch.calls.argsFor(0)).toEqual([
+              'showBranchNotFoundError',
+              'master-testing',
+            ]);
+            done();
+          });
+      });
+    });
+  });
 });
diff --git a/spec/javascripts/ide/stores/actions/tree_spec.js b/spec/javascripts/ide/stores/actions/tree_spec.js
index cefed9ddb4335c99522808c8299447ef56bab26c..612a439cfbf5f6f85566c25389fc78bfe11e7c71 100644
--- a/spec/javascripts/ide/stores/actions/tree_spec.js
+++ b/spec/javascripts/ide/stores/actions/tree_spec.js
@@ -1,7 +1,9 @@
+import MockAdapter from 'axios-mock-adapter';
 import Vue from 'vue';
 import testAction from 'spec/helpers/vuex_action_helper';
-import { showTreeEntry } from '~/ide/stores/actions/tree';
+import { showTreeEntry, getFiles } from '~/ide/stores/actions/tree';
 import * as types from '~/ide/stores/mutation_types';
+import axios from '~/lib/utils/axios_utils';
 import store from '~/ide/stores';
 import service from '~/ide/services';
 import router from '~/ide/ide_router';
@@ -9,6 +11,7 @@ import { file, resetStore, createEntriesFromPaths } from '../../helpers';
 
 describe('Multi-file store tree actions', () => {
   let projectTree;
+  let mock;
 
   const basicCallParameters = {
     endpoint: 'rootEndpoint',
@@ -20,6 +23,8 @@ describe('Multi-file store tree actions', () => {
   beforeEach(() => {
     spyOn(router, 'push');
 
+    mock = new MockAdapter(axios);
+
     store.state.currentProjectId = 'abcproject';
     store.state.currentBranchId = 'master';
     store.state.projects.abcproject = {
@@ -33,49 +38,85 @@ describe('Multi-file store tree actions', () => {
   });
 
   afterEach(() => {
+    mock.restore();
     resetStore(store);
   });
 
   describe('getFiles', () => {
-    beforeEach(() => {
-      spyOn(service, 'getFiles').and.returnValue(
-        Promise.resolve({
-          json: () =>
-            Promise.resolve([
-              'file.txt',
-              'folder/fileinfolder.js',
-              'folder/subfolder/fileinsubfolder.js',
-            ]),
-        }),
-      );
+    describe('success', () => {
+      beforeEach(() => {
+        spyOn(service, 'getFiles').and.callThrough();
+
+        mock
+          .onGet(/(.*)/)
+          .replyOnce(200, [
+            'file.txt',
+            'folder/fileinfolder.js',
+            'folder/subfolder/fileinsubfolder.js',
+          ]);
+      });
+
+      it('calls service getFiles', done => {
+        store
+          .dispatch('getFiles', basicCallParameters)
+          .then(() => {
+            expect(service.getFiles).toHaveBeenCalledWith('', 'master');
+
+            done();
+          })
+          .catch(done.fail);
+      });
+
+      it('adds data into tree', done => {
+        store
+          .dispatch('getFiles', basicCallParameters)
+          .then(() => {
+            projectTree = store.state.trees['abcproject/master'];
+            expect(projectTree.tree.length).toBe(2);
+            expect(projectTree.tree[0].type).toBe('tree');
+            expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js');
+            expect(projectTree.tree[1].type).toBe('blob');
+            expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob');
+            expect(projectTree.tree[0].tree[0].tree[0].name).toBe('fileinsubfolder.js');
+
+            done();
+          })
+          .catch(done.fail);
+      });
     });
 
-    it('calls service getFiles', done => {
-      store
-        .dispatch('getFiles', basicCallParameters)
-        .then(() => {
-          expect(service.getFiles).toHaveBeenCalledWith('', 'master');
+    describe('error', () => {
+      it('dispatches branch not found actions when response is 404', done => {
+        const dispatch = jasmine.createSpy('dispatchSpy');
 
-          done();
-        })
-        .catch(done.fail);
-    });
+        store.state.projects = {
+          'abc/def': {
+            web_url: `${gl.TEST_HOST}/files`,
+          },
+        };
 
-    it('adds data into tree', done => {
-      store
-        .dispatch('getFiles', basicCallParameters)
-        .then(() => {
-          projectTree = store.state.trees['abcproject/master'];
-          expect(projectTree.tree.length).toBe(2);
-          expect(projectTree.tree[0].type).toBe('tree');
-          expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js');
-          expect(projectTree.tree[1].type).toBe('blob');
-          expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob');
-          expect(projectTree.tree[0].tree[0].tree[0].name).toBe('fileinsubfolder.js');
+        mock.onGet(/(.*)/).replyOnce(404);
 
-          done();
-        })
-        .catch(done.fail);
+        getFiles(
+          {
+            commit() {},
+            dispatch,
+            state: store.state,
+          },
+          {
+            projectId: 'abc/def',
+            branchId: 'master-testing',
+          },
+        )
+          .then(done.fail)
+          .catch(() => {
+            expect(dispatch.calls.argsFor(0)).toEqual([
+              'showBranchNotFoundError',
+              'master-testing',
+            ]);
+            done();
+          });
+      });
     });
   });
 
@@ -122,9 +163,7 @@ describe('Multi-file store tree actions', () => {
           { type: types.SET_TREE_OPEN, payload: 'grandparent/parent' },
           { type: types.SET_TREE_OPEN, payload: 'grandparent' },
         ],
-        [
-          { type: 'showTreeEntry' },
-        ],
+        [{ type: 'showTreeEntry' }],
         done,
       );
     });