From fa8c82c7ec6bb380c1b90421e99b6e8cdee3d790 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 28 Jun 2018 15:09:21 +0100 Subject: [PATCH] :white_check_mark: added specs for file actions in this it also removes Vue Resource from the IDE, axios is nicer to test --- app/assets/javascripts/ide/services/index.js | 33 +- .../javascripts/ide/stores/actions/file.js | 8 +- .../components/repo_commit_section_spec.js | 17 - .../ide/stores/actions/file_spec.js | 300 +++++++++++------- .../ide/stores/actions/project_spec.js | 2 +- 5 files changed, 205 insertions(+), 155 deletions(-) diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index 5e642067141..3e939f0c1a3 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -1,16 +1,11 @@ -import Vue from 'vue'; -import VueResource from 'vue-resource'; import axios from '~/lib/utils/axios_utils'; import Api from '~/api'; -Vue.use(VueResource); - export default { - getTreeData(endpoint) { - return Vue.http.get(endpoint, { params: { format: 'json' } }); - }, getFileData(endpoint) { - return Vue.http.get(endpoint, { params: { format: 'json', viewer: 'none' } }); + return axios.get(endpoint, { + params: { format: 'json', viewer: 'none' }, + }); }, getRawFileData(file) { if (file.tempFile) { @@ -21,7 +16,11 @@ export default { return Promise.resolve(file.raw); } - return Vue.http.get(file.rawPath, { params: { format: 'json' } }).then(res => res.text()); + return axios + .get(file.rawPath, { + params: { format: 'json' }, + }) + .then(({ data }) => data); }, getBaseRawFileData(file, sha) { if (file.tempFile) { @@ -32,11 +31,11 @@ export default { return Promise.resolve(file.baseRaw); } - return Vue.http + return axios .get(file.rawPath.replace(`/raw/${file.branchId}/${file.path}`, `/raw/${sha}/${file.path}`), { params: { format: 'json' }, }) - .then(res => res.text()); + .then(({ data }) => data); }, getProjectData(namespace, project) { return Api.project(`${namespace}/${project}`); @@ -53,21 +52,9 @@ export default { getBranchData(projectId, currentBranchId) { return Api.branchSingle(projectId, currentBranchId); }, - createBranch(projectId, payload) { - const url = Api.buildUrl(Api.createBranchPath).replace(':id', projectId); - - return Vue.http.post(url, payload); - }, commit(projectId, payload) { return Api.commitMultiple(projectId, payload); }, - getTreeLastCommit(endpoint) { - return Vue.http.get(endpoint, { - params: { - format: 'json', - }, - }); - }, getFiles(projectUrl, branchId) { const url = `${projectUrl}/files/${branchId}`; return axios.get(url, { params: { format: 'json' } }); diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 9fb964e299b..1111a14a7d7 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -66,13 +66,9 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive .getFileData( `${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`, ) - .then(res => { - const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']); - setPageTitle(pageTitle); + .then(({ data, headers }) => { + setPageTitle(decodeURI(headers['page-title'])); - return res.json(); - }) - .then(data => { commit(types.SET_FILE_DATA, { data, file }); commit(types.TOGGLE_FILE_OPEN, path); if (makeFileActive) dispatch('setFileActive', path); diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 6bf309fb4bf..8df48d8aeae 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -68,23 +68,6 @@ describe('RepoCommitSection', () => { vm.$mount(); - spyOn(service, 'getTreeData').and.returnValue( - Promise.resolve({ - headers: { - 'page-title': 'test', - }, - json: () => - Promise.resolve({ - last_commit_path: 'last_commit_path', - parent_tree_url: 'parent_tree_url', - path: '/', - trees: [{ name: 'tree' }], - blobs: [{ name: 'blob' }], - submodules: [{ name: 'submodule' }], - }), - }), - ); - Vue.nextTick(done); }); diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js index 5746683917e..36f21f22d62 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/javascripts/ide/stores/actions/file_spec.js @@ -1,5 +1,8 @@ import Vue from 'vue'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; import store from '~/ide/stores'; +import { getFileData, getRawFileData } from '~/ide/stores/actions/file'; import * as actions from '~/ide/stores/actions/file'; import * as types from '~/ide/stores/mutation_types'; import service from '~/ide/services'; @@ -9,11 +12,16 @@ import { file, resetStore } from '../../helpers'; import testAction from '../../../helpers/vuex_action_helper'; describe('IDE store file actions', () => { + let mock; + beforeEach(() => { + mock = new MockAdapter(axios); + spyOn(router, 'push'); }); afterEach(() => { + mock.restore(); resetStore(store); }); @@ -183,94 +191,131 @@ describe('IDE store file actions', () => { let localFile; beforeEach(() => { - spyOn(service, 'getFileData').and.returnValue( - Promise.resolve({ - headers: { - 'page-title': 'testing getFileData', - }, - json: () => - Promise.resolve({ - blame_path: 'blame_path', - commits_path: 'commits_path', - permalink: 'permalink', - raw_path: 'raw_path', - binary: false, - html: '123', - render_error: '', - }), - }), - ); + spyOn(service, 'getFileData').and.callThrough(); localFile = file(`newCreate-${Math.random()}`); - localFile.url = 'getFileDataURL'; + localFile.url = `${gl.TEST_HOST}/getFileDataURL`; store.state.entries[localFile.path] = localFile; }); - it('calls the service', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(service.getFileData).toHaveBeenCalledWith('getFileDataURL'); + describe('success', () => { + beforeEach(() => { + mock.onGet(`${gl.TEST_HOST}/getFileDataURL`).replyOnce( + 200, + { + blame_path: 'blame_path', + commits_path: 'commits_path', + permalink: 'permalink', + raw_path: 'raw_path', + binary: false, + html: '123', + render_error: '', + }, + { + 'page-title': 'testing getFileData', + }, + ); + }); - done(); - }) - .catch(done.fail); + it('calls the service', done => { + store + .dispatch('getFileData', { path: localFile.path }) + .then(() => { + expect(service.getFileData).toHaveBeenCalledWith(`${gl.TEST_HOST}/getFileDataURL`); + + done(); + }) + .catch(done.fail); + }); + + it('sets the file data', done => { + store + .dispatch('getFileData', { path: localFile.path }) + .then(() => { + expect(localFile.blamePath).toBe('blame_path'); + + done(); + }) + .catch(done.fail); + }); + + it('sets document title', done => { + store + .dispatch('getFileData', { path: localFile.path }) + .then(() => { + expect(document.title).toBe('testing getFileData'); + + done(); + }) + .catch(done.fail); + }); + + it('sets the file as active', done => { + store + .dispatch('getFileData', { path: localFile.path }) + .then(() => { + expect(localFile.active).toBeTruthy(); + + done(); + }) + .catch(done.fail); + }); + + it('sets the file not as active if we pass makeFileActive false', done => { + store + .dispatch('getFileData', { path: localFile.path, makeFileActive: false }) + .then(() => { + expect(localFile.active).toBeFalsy(); + + done(); + }) + .catch(done.fail); + }); + + it('adds the file to open files', done => { + store + .dispatch('getFileData', { path: localFile.path }) + .then(() => { + expect(store.state.openFiles.length).toBe(1); + expect(store.state.openFiles[0].name).toBe(localFile.name); + + done(); + }) + .catch(done.fail); + }); }); - it('sets the file data', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(localFile.blamePath).toBe('blame_path'); + describe('error', () => { + beforeEach(() => { + mock.onGet(`${gl.TEST_HOST}/getFileDataURL`).networkError(); + }); - done(); - }) - .catch(done.fail); - }); + it('dispatches error action', done => { + const dispatch = jasmine.createSpy('dispatch'); - it('sets document title', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(document.title).toBe('testing getFileData'); + getFileData( + { + state: store.state, + commit() {}, + dispatch, + }, + { path: localFile.path }, + ) + .then(() => { + expect(dispatch).toHaveBeenCalledWith('setErrorMessage', { + text: 'An error occured whilst loading the file.', + action: jasmine.any(Function), + actionText: 'Please try again', + actionPayload: { + path: localFile.path, + makeFileActive: true, + }, + }); - done(); - }) - .catch(done.fail); - }); - - it('sets the file as active', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(localFile.active).toBeTruthy(); - - done(); - }) - .catch(done.fail); - }); - - it('sets the file not as active if we pass makeFileActive false', done => { - store - .dispatch('getFileData', { path: localFile.path, makeFileActive: false }) - .then(() => { - expect(localFile.active).toBeFalsy(); - - done(); - }) - .catch(done.fail); - }); - - it('adds the file to open files', done => { - store - .dispatch('getFileData', { path: localFile.path }) - .then(() => { - expect(store.state.openFiles.length).toBe(1); - expect(store.state.openFiles[0].name).toBe(localFile.name); - - done(); - }) - .catch(done.fail); + done(); + }) + .catch(done.fail); + }); }); }); @@ -278,48 +323,87 @@ describe('IDE store file actions', () => { let tmpFile; beforeEach(() => { - spyOn(service, 'getRawFileData').and.returnValue(Promise.resolve('raw')); + spyOn(service, 'getRawFileData').and.callThrough(); tmpFile = file('tmpFile'); store.state.entries[tmpFile.path] = tmpFile; }); - it('calls getRawFileData service method', done => { - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(service.getRawFileData).toHaveBeenCalledWith(tmpFile); + describe('success', () => { + beforeEach(() => { + mock.onGet(/(.*)/).replyOnce(200, 'raw'); + }); - done(); - }) - .catch(done.fail); + it('calls getRawFileData service method', done => { + store + .dispatch('getRawFileData', { path: tmpFile.path }) + .then(() => { + expect(service.getRawFileData).toHaveBeenCalledWith(tmpFile); + + done(); + }) + .catch(done.fail); + }); + + it('updates file raw data', done => { + store + .dispatch('getRawFileData', { path: tmpFile.path }) + .then(() => { + expect(tmpFile.raw).toBe('raw'); + + done(); + }) + .catch(done.fail); + }); + + it('calls also getBaseRawFileData service method', done => { + spyOn(service, 'getBaseRawFileData').and.returnValue(Promise.resolve('baseraw')); + + tmpFile.mrChange = { new_file: false }; + + store + .dispatch('getRawFileData', { path: tmpFile.path, baseSha: 'SHA' }) + .then(() => { + expect(service.getBaseRawFileData).toHaveBeenCalledWith(tmpFile, 'SHA'); + expect(tmpFile.baseRaw).toBe('baseraw'); + + done(); + }) + .catch(done.fail); + }); }); - it('updates file raw data', done => { - store - .dispatch('getRawFileData', { path: tmpFile.path }) - .then(() => { - expect(tmpFile.raw).toBe('raw'); + describe('error', () => { + beforeEach(() => { + mock.onGet(/(.*)/).networkError(); + }); - done(); - }) - .catch(done.fail); - }); + it('dispatches error action', done => { + const dispatch = jasmine.createSpy('dispatch'); - it('calls also getBaseRawFileData service method', done => { - spyOn(service, 'getBaseRawFileData').and.returnValue(Promise.resolve('baseraw')); + getRawFileData( + { + state: store.state, + commit() {}, + dispatch, + }, + { path: tmpFile.path, baseSha: tmpFile.baseSha }, + ) + .then(done.fail) + .catch(() => { + expect(dispatch).toHaveBeenCalledWith('setErrorMessage', { + text: 'An error occured whilst loading the file content.', + action: jasmine.any(Function), + actionText: 'Please try again', + actionPayload: { + path: tmpFile.path, + baseSha: tmpFile.baseSha, + }, + }); - tmpFile.mrChange = { new_file: false }; - - store - .dispatch('getRawFileData', { path: tmpFile.path, baseSha: 'SHA' }) - .then(() => { - expect(service.getBaseRawFileData).toHaveBeenCalledWith(tmpFile, 'SHA'); - expect(tmpFile.baseRaw).toBe('baseraw'); - - done(); - }) - .catch(done.fail); + done(); + }); + }); }); }); diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js index c1f9fc4f148..ca79edafb7e 100644 --- a/spec/javascripts/ide/stores/actions/project_spec.js +++ b/spec/javascripts/ide/stores/actions/project_spec.js @@ -110,7 +110,7 @@ describe('IDE store project actions', () => { type: 'setErrorMessage', payload: { text: "Branch master was not found in this project's repository.", - action: 'createNewBranchFromDefault', + action: jasmine.any(Function), actionText: 'Create branch', actionPayload: 'master', },