Commit 0f281cea authored by Winnie Hellmann's avatar Winnie Hellmann Committed by Mike Greiling

Remove vue-resource from notes service

(cherry picked from commit 7e063c59b6674513a05aa6c5b5c1fae6b2a06435)
(cherry picked from commit 08d6d2bec710b68a4180ec510fe625e2c9c4bf99)
(cherry picked from commit 88a9e2bf368f647f0fe334b6d5d11abb3871e327)
(cherry picked from commit 73e11d773187914bb2aeeea3de7a06d52272aa86)
(cherry picked from commit 3a879d4fb252a66309f3eb1b9d7eefcc67b0f3de)
(cherry picked from commit b95c8391af30bc5d30c7d351d9756c98a0a29ca7)
(cherry picked from commit 984fa368ba59be2468757e9424889ca8162a99e5)
(cherry picked from commit 47a14ca0321a7e1a8364e7f370c28cb1da22b4b9)
(cherry picked from commit 6a2e56a0ac4e8dbddf2af337798083f78c264f5d)
(cherry picked from commit f7830abf1d9976ab0ebd7380874346de4988219f)
(cherry picked from commit 99d9b3a941e615a1f4b4b8823b27fcbc7ee63cb5)
parent e34a67b9
import Vue from 'vue';
import VueResource from 'vue-resource';
import axios from '~/lib/utils/axios_utils';
import * as constants from '../constants';
Vue.use(VueResource);
export default {
fetchDiscussions(endpoint, filter, persistFilter = true) {
const config =
filter !== undefined
? { params: { notes_filter: filter, persist_filter: persistFilter } }
: null;
return Vue.http.get(endpoint, config);
return axios.get(endpoint, config);
},
replyToDiscussion(endpoint, data) {
return Vue.http.post(endpoint, data, { emulateJSON: true });
return axios.post(endpoint, data);
},
updateNote(endpoint, data) {
return Vue.http.put(endpoint, data, { emulateJSON: true });
return axios.put(endpoint, data);
},
createNewNote(endpoint, data) {
return Vue.http.post(endpoint, data, { emulateJSON: true });
return axios.post(endpoint, data);
},
toggleResolveNote(endpoint, isResolved) {
const { RESOLVE_NOTE_METHOD_NAME, UNRESOLVE_NOTE_METHOD_NAME } = constants;
const method = isResolved ? UNRESOLVE_NOTE_METHOD_NAME : RESOLVE_NOTE_METHOD_NAME;
return Vue.http[method](endpoint);
return axios[method](endpoint);
},
poll(data = {}) {
const endpoint = data.notesData.notesPath;
......@@ -36,9 +33,9 @@ export default {
},
};
return Vue.http.get(endpoint, options);
return axios.get(endpoint, options);
},
toggleIssueState(endpoint, data) {
return Vue.http.put(endpoint, data);
return axios.put(endpoint, data);
},
};
......@@ -47,13 +47,10 @@ export const setNotesFetchedState = ({ commit }, state) =>
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
export const fetchDiscussions = ({ commit, dispatch }, { path, filter, persistFilter }) =>
service
.fetchDiscussions(path, filter, persistFilter)
.then(res => res.json())
.then(discussions => {
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
dispatch('updateResolvableDiscussionsCounts');
});
service.fetchDiscussions(path, filter, persistFilter).then(({ data }) => {
commit(types.SET_INITIAL_DISCUSSIONS, data);
dispatch('updateResolvableDiscussionsCounts');
});
export const updateDiscussion = ({ commit, state }, discussion) => {
commit(types.UPDATE_DISCUSSION, discussion);
......@@ -80,13 +77,10 @@ export const deleteNote = ({ dispatch }, note) =>
});
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
service
.updateNote(endpoint, note)
.then(res => res.json())
.then(res => {
commit(types.UPDATE_NOTE, res);
dispatch('startTaskList');
});
service.updateNote(endpoint, note).then(({ data }) => {
commit(types.UPDATE_NOTE, data);
dispatch('startTaskList');
});
export const updateOrCreateNotes = ({ commit, state, getters, dispatch }, notes) => {
const { notesById } = getters;
......@@ -110,40 +104,37 @@ export const updateOrCreateNotes = ({ commit, state, getters, dispatch }, notes)
});
};
export const replyToDiscussion = ({ commit, state, getters, dispatch }, { endpoint, data }) =>
service
.replyToDiscussion(endpoint, data)
.then(res => res.json())
.then(res => {
if (res.discussion) {
commit(types.UPDATE_DISCUSSION, res.discussion);
export const replyToDiscussion = (
{ commit, state, getters, dispatch },
{ endpoint, data: reply },
) =>
service.replyToDiscussion(endpoint, reply).then(({ data }) => {
if (data.discussion) {
commit(types.UPDATE_DISCUSSION, data.discussion);
updateOrCreateNotes({ commit, state, getters, dispatch }, res.discussion.notes);
updateOrCreateNotes({ commit, state, getters, dispatch }, data.discussion.notes);
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
dispatch('updateResolvableDiscussionsCounts');
} else {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, res);
}
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
dispatch('updateResolvableDiscussionsCounts');
} else {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, data);
}
return res;
});
return data;
});
export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
service
.createNewNote(endpoint, data)
.then(res => res.json())
.then(res => {
if (!res.errors) {
commit(types.ADD_NEW_NOTE, res);
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
dispatch('updateResolvableDiscussionsCounts');
}
return res;
});
export const createNewNote = ({ commit, dispatch }, { endpoint, data: reply }) =>
service.createNewNote(endpoint, reply).then(({ data }) => {
if (!data.errors) {
commit(types.ADD_NEW_NOTE, data);
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
dispatch('updateResolvableDiscussionsCounts');
}
return data;
});
export const removePlaceholderNotes = ({ commit }) => commit(types.REMOVE_PLACEHOLDER_NOTES);
......@@ -165,41 +156,32 @@ export const resolveDiscussion = ({ state, dispatch, getters }, { discussionId }
};
export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) =>
service
.toggleResolveNote(endpoint, isResolved)
.then(res => res.json())
.then(res => {
const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
service.toggleResolveNote(endpoint, isResolved).then(({ data }) => {
const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
commit(mutationType, res);
commit(mutationType, data);
dispatch('updateResolvableDiscussionsCounts');
dispatch('updateResolvableDiscussionsCounts');
dispatch('updateMergeRequestWidget');
});
dispatch('updateMergeRequestWidget');
});
export const closeIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
return service
.toggleIssueState(state.notesData.closePath)
.then(res => res.json())
.then(data => {
commit(types.CLOSE_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
return service.toggleIssueState(state.notesData.closePath).then(({ data }) => {
commit(types.CLOSE_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
};
export const reopenIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
return service
.toggleIssueState(state.notesData.reopenPath)
.then(res => res.json())
.then(data => {
commit(types.REOPEN_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
return service.toggleIssueState(state.notesData.reopenPath).then(({ data }) => {
commit(types.REOPEN_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
});
};
export const toggleStateButtonLoading = ({ commit }, value) =>
......@@ -340,8 +322,7 @@ export const poll = ({ commit, state, getters, dispatch }) => {
resource: service,
method: 'poll',
data: state,
successCallback: resp =>
resp.json().then(data => pollSuccessCallBack(data, commit, state, getters, dispatch)),
successCallback: ({ data }) => pollSuccessCallBack(data, commit, state, getters, dispatch),
errorCallback: () => Flash(__('Something went wrong while fetching latest comments.')),
});
......@@ -376,8 +357,7 @@ export const fetchData = ({ commit, state, getters }) => {
service
.poll(requestData)
.then(resp => resp.json)
.then(data => pollSuccessCallBack(data, commit, state, getters))
.then(({ data }) => pollSuccessCallBack(data, commit, state, getters))
.catch(() => Flash(__('Something went wrong while fetching latest comments.')));
};
......
---
title: Remove vue-resource from notes service
merge_request: 32934
author: Lee Tickett
type: other
import $ from 'helpers/jquery';
import AxiosMockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Vue from 'vue';
import { mount, createLocalVue } from '@vue/test-utils';
import NotesApp from '~/notes/components/notes_app.vue';
......@@ -9,19 +11,10 @@ import { setTestTimeout } from 'helpers/timeout';
// TODO: use generated fixture (https://gitlab.com/gitlab-org/gitlab-ce/issues/62491)
import * as mockData from '../../../javascripts/notes/mock_data';
const originalInterceptors = [...Vue.http.interceptors];
const emptyResponseInterceptor = (request, next) => {
next(
request.respondWith(JSON.stringify([]), {
status: 200,
}),
);
};
setTestTimeout(1000);
describe('note_app', () => {
let axiosMock;
let mountComponent;
let wrapper;
let store;
......@@ -45,6 +38,8 @@ describe('note_app', () => {
beforeEach(() => {
$('body').attr('data-page', 'projects:merge_requests:show');
axiosMock = new AxiosMockAdapter(axios);
store = createStore();
mountComponent = data => {
const propsData = data || {
......@@ -74,12 +69,12 @@ describe('note_app', () => {
afterEach(() => {
wrapper.destroy();
Vue.http.interceptors = [...originalInterceptors];
axiosMock.restore();
});
describe('set data', () => {
beforeEach(() => {
Vue.http.interceptors.push(emptyResponseInterceptor);
axiosMock.onAny().reply(200, []);
wrapper = mountComponent();
return waitForDiscussionsRequest();
});
......@@ -105,7 +100,7 @@ describe('note_app', () => {
beforeEach(() => {
setFixtures('<div class="js-discussions-count"></div>');
Vue.http.interceptors.push(mockData.individualNoteInterceptor);
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
wrapper = mountComponent();
return waitForDiscussionsRequest();
});
......@@ -146,7 +141,7 @@ describe('note_app', () => {
beforeEach(() => {
setFixtures('<div class="js-discussions-count"></div>');
Vue.http.interceptors.push(mockData.individualNoteInterceptor);
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
store.state.commentsDisabled = true;
wrapper = mountComponent();
return waitForDiscussionsRequest();
......@@ -163,7 +158,7 @@ describe('note_app', () => {
describe('while fetching data', () => {
beforeEach(() => {
Vue.http.interceptors.push(emptyResponseInterceptor);
axiosMock.onAny().reply(200, []);
wrapper = mountComponent();
});
......@@ -184,7 +179,7 @@ describe('note_app', () => {
describe('update note', () => {
describe('individual note', () => {
beforeEach(() => {
Vue.http.interceptors.push(mockData.individualNoteInterceptor);
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
jest.spyOn(service, 'updateNote');
wrapper = mountComponent();
return waitForDiscussionsRequest().then(() => {
......@@ -206,7 +201,7 @@ describe('note_app', () => {
describe('discussion note', () => {
beforeEach(() => {
Vue.http.interceptors.push(mockData.discussionNoteInterceptor);
axiosMock.onAny().reply(mockData.getDiscussionNoteResponse);
jest.spyOn(service, 'updateNote');
wrapper = mountComponent();
return waitForDiscussionsRequest().then(() => {
......@@ -229,7 +224,7 @@ describe('note_app', () => {
describe('new note form', () => {
beforeEach(() => {
Vue.http.interceptors.push(mockData.individualNoteInterceptor);
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
wrapper = mountComponent();
return waitForDiscussionsRequest();
});
......@@ -259,7 +254,7 @@ describe('note_app', () => {
describe('edit form', () => {
beforeEach(() => {
Vue.http.interceptors.push(mockData.individualNoteInterceptor);
axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
wrapper = mountComponent();
return waitForDiscussionsRequest();
});
......@@ -287,7 +282,7 @@ describe('note_app', () => {
describe('emoji awards', () => {
beforeEach(() => {
Vue.http.interceptors.push(emptyResponseInterceptor);
axiosMock.onAny().reply(200, []);
wrapper = mountComponent();
return waitForDiscussionsRequest();
});
......
......@@ -647,24 +647,12 @@ export const DISCUSSION_NOTE_RESPONSE_MAP = {
},
};
export function individualNoteInterceptor(request, next) {
const body = INDIVIDUAL_NOTE_RESPONSE_MAP[request.method.toUpperCase()][request.url];
next(
request.respondWith(JSON.stringify(body), {
status: 200,
}),
);
export function getIndividualNoteResponse(config) {
return [200, INDIVIDUAL_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
}
export function discussionNoteInterceptor(request, next) {
const body = DISCUSSION_NOTE_RESPONSE_MAP[request.method.toUpperCase()][request.url];
next(
request.respondWith(JSON.stringify(body), {
status: 200,
}),
);
export function getDiscussionNoteResponse(config) {
return [200, DISCUSSION_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
}
export const notesWithDescriptionChanges = [
......
import Vue from 'vue';
import $ from 'jquery';
import _ from 'underscore';
import Api from '~/api';
import { TEST_HOST } from 'spec/test_constants';
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
import actionsModule, * as actions from '~/notes/stores/actions';
import * as mutationTypes from '~/notes/stores/mutation_types';
import * as notesConstants from '~/notes/constants';
......@@ -29,6 +26,7 @@ describe('Actions Notes Store', () => {
let state;
let store;
let flashSpy;
let axiosMock;
beforeEach(() => {
store = createStore();
......@@ -36,10 +34,12 @@ describe('Actions Notes Store', () => {
dispatch = jasmine.createSpy('dispatch');
state = {};
flashSpy = spyOnDependency(actionsModule, 'Flash');
axiosMock = new AxiosMockAdapter(axios);
});
afterEach(() => {
resetStore(store);
axiosMock.restore();
});
describe('setNotesData', () => {
......@@ -160,20 +160,8 @@ describe('Actions Notes Store', () => {
});
describe('async methods', () => {
const interceptor = (request, next) => {
next(
request.respondWith(JSON.stringify({}), {
status: 200,
}),
);
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
axiosMock.onAny().reply(200, {});
});
describe('closeIssue', () => {
......@@ -259,7 +247,7 @@ describe('Actions Notes Store', () => {
beforeEach(done => {
jasmine.clock().install();
spyOn(Vue.http, 'get').and.callThrough();
spyOn(axios, 'get').and.callThrough();
store
.dispatch('setNotesData', notesDataMock)
......@@ -272,31 +260,15 @@ describe('Actions Notes Store', () => {
});
it('calls service with last fetched state', done => {
const interceptor = (request, next) => {
next(
request.respondWith(
JSON.stringify({
notes: [],
last_fetched_at: '123456',
}),
{
status: 200,
headers: {
'poll-interval': '1000',
},
},
),
);
};
Vue.http.interceptors.push(interceptor);
Vue.http.interceptors.push(headersInterceptor);
axiosMock
.onAny()
.reply(200, { notes: [], last_fetched_at: '123456' }, { 'poll-interval': '1000' });
store
.dispatch('poll')
.then(() => new Promise(resolve => requestAnimationFrame(resolve)))
.then(() => {
expect(Vue.http.get).toHaveBeenCalled();
expect(axios.get).toHaveBeenCalled();
expect(store.state.lastFetchedAt).toBe('123456');
jasmine.clock().tick(1500);
......@@ -308,16 +280,12 @@ describe('Actions Notes Store', () => {
}),
)
.then(() => {
expect(Vue.http.get.calls.count()).toBe(2);
expect(Vue.http.get.calls.mostRecent().args[1].headers).toEqual({
expect(axios.get.calls.count()).toBe(2);
expect(axios.get.calls.mostRecent().args[1].headers).toEqual({
'X-Last-Fetched-At': '123456',
});
})
.then(() => store.dispatch('stopPolling'))
.then(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
})
.then(done)
.catch(done.fail);
});
......@@ -338,10 +306,8 @@ describe('Actions Notes Store', () => {
describe('removeNote', () => {
const endpoint = `${TEST_HOST}/note`;
let axiosMock;
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
axiosMock.onDelete(endpoint).replyOnce(200, {});
$('body').attr('data-page', '');
......@@ -411,10 +377,8 @@ describe('Actions Notes Store', () => {
describe('deleteNote', () => {
const endpoint = `${TEST_HOST}/note`;
let axiosMock;
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
axiosMock.onDelete(endpoint).replyOnce(200, {});
$('body').attr('data-page', '');
......@@ -454,20 +418,9 @@ describe('Actions Notes Store', () => {
id: 1,
valid: true,
};
const interceptor = (request, next) => {
next(
request.respondWith(JSON.stringify(res), {
status: 200,
}),
);
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
axiosMock.onAny().reply(200, res);
});
it('commits ADD_NEW_NOTE and dispatches updateMergeRequestWidget', done => {
......@@ -501,20 +454,9 @@ describe('Actions Notes Store', () => {
const res = {
errors: ['error'],
};
const interceptor = (request, next) => {
next(
request.respondWith(JSON.stringify(res), {
status: 200,
}),
);
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
axiosMock.onAny().replyOnce(200, res);
});
it('does not commit ADD_NEW_NOTE or dispatch updateMergeRequestWidget', done => {
......@@ -534,20 +476,9 @@ describe('Actions Notes Store', () => {
const res = {
resolved: true,
};
const interceptor = (request, next) => {
next(
request.respondWith(JSON.stringify(res), {
status: 200,
}),
);
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
axiosMock.onAny().reply(200, res);
});
describe('as note', () => {
......@@ -720,32 +651,19 @@ describe('Actions Notes Store', () => {
});
describe('replyToDiscussion', () => {
let res = { discussion: { notes: [] } };
const payload = { endpoint: TEST_HOST, data: {} };
const interceptor = (request, next) => {
next(
request.respondWith(JSON.stringify(res), {
status: 200,
}),
);
};
beforeEach(() => {
Vue.http.interceptors.push(interceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
});
it('updates discussion if response contains disussion', done => {
const discussion = { notes: [] };
axiosMock.onAny().reply(200, { discussion });
testAction(
actions.replyToDiscussion,
payload,
{
notesById: {},
},
[{ type: mutationTypes.UPDATE_DISCUSSION, payload: res.discussion }],
[{ type: mutationTypes.UPDATE_DISCUSSION, payload: discussion }],
[
{ type: 'updateMergeRequestWidget' },
{ type: 'startTaskList' },
......@@ -756,7 +674,8 @@ describe('Actions Notes Store', () => {
});
it('adds a reply to a discussion', done => {
res = {};
const res = {};
axiosMock.onAny().reply(200, res);
testAction(
actions.replyToDiscussion,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment