Commit 705f625e authored by David O'Regan's avatar David O'Regan

Merge branch '298827-graphql-getting-mr-diff-discussions-often-returns-500' into 'master'

Resolve "GraphQL: getting MR diff discussions often returns 500"

See merge request gitlab-org/gitlab!56037
parents a9f92ed9 36993a83
import { isEmpty } from 'lodash';
import { deprecatedCreateFlash as flash } from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
...@@ -88,18 +89,23 @@ export const updateDiscussionsAfterPublish = async ({ dispatch, getters, rootGet ...@@ -88,18 +89,23 @@ export const updateDiscussionsAfterPublish = async ({ dispatch, getters, rootGet
export const updateDraft = ( export const updateDraft = (
{ commit, getters }, { commit, getters },
{ note, noteText, resolveDiscussion, position, callback }, { note, noteText, resolveDiscussion, position, callback },
) => ) => {
service const params = {
.update(getters.getNotesData.draftsPath, { draftId: note.id,
draftId: note.id, note: noteText,
note: noteText, resolveDiscussion,
resolveDiscussion, };
position: JSON.stringify(position), // Stringifying an empty object yields `{}` which breaks graphql queries
}) // https://gitlab.com/gitlab-org/gitlab/-/issues/298827
if (!isEmpty(position)) params.position = JSON.stringify(position);
return service
.update(getters.getNotesData.draftsPath, params)
.then((res) => res.data) .then((res) => res.data)
.then((data) => commit(types.RECEIVE_DRAFT_UPDATE_SUCCESS, data)) .then((data) => commit(types.RECEIVE_DRAFT_UPDATE_SUCCESS, data))
.then(callback) .then(callback)
.catch(() => flash(__('An error occurred while updating the comment'))); .catch(() => flash(__('An error occurred while updating the comment')));
};
export const scrollToDraft = ({ dispatch, rootGetters }, draft) => { export const scrollToDraft = ({ dispatch, rootGetters }, draft) => {
const discussion = draft.discussion_id && rootGetters.getDiscussion(draft.discussion_id); const discussion = draft.discussion_id && rootGetters.getDiscussion(draft.discussion_id);
......
<script> <script>
import { GlSprintf, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import { GlSprintf, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import $ from 'jquery'; import $ from 'jquery';
import { escape } from 'lodash'; import { escape, isEmpty } from 'lodash';
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
import { INLINE_DIFF_LINES_KEY } from '~/diffs/constants'; import { INLINE_DIFF_LINES_KEY } from '~/diffs/constants';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
...@@ -282,9 +282,13 @@ export default { ...@@ -282,9 +282,13 @@ export default {
note: { note: {
target_type: this.getNoteableData.targetType, target_type: this.getNoteableData.targetType,
target_id: this.note.noteable_id, target_id: this.note.noteable_id,
note: { note: noteText, position: JSON.stringify(position) }, note: { note: noteText },
}, },
}; };
// Stringifying an empty object yields `{}` which breaks graphql queries
// https://gitlab.com/gitlab-org/gitlab/-/issues/298827
if (!isEmpty(position)) data.note.note.position = JSON.stringify(position);
this.isRequesting = true; this.isRequesting = true;
this.oldContent = this.note.note_html; this.oldContent = this.note.note_html;
// eslint-disable-next-line vue/no-mutating-props // eslint-disable-next-line vue/no-mutating-props
......
---
title: fix stringify empty position object
merge_request: 56037
author:
type: fixed
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import service from '~/batch_comments/services/drafts_service';
import * as actions from '~/batch_comments/stores/modules/batch_comments/actions'; import * as actions from '~/batch_comments/stores/modules/batch_comments/actions';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
...@@ -201,6 +202,12 @@ describe('Batch comments store actions', () => { ...@@ -201,6 +202,12 @@ describe('Batch comments store actions', () => {
describe('updateDraft', () => { describe('updateDraft', () => {
let getters; let getters;
service.update = jest.fn();
service.update.mockResolvedValue({ data: { id: 1 } });
const commit = jest.fn();
let context;
let params;
beforeEach(() => { beforeEach(() => {
getters = { getters = {
...@@ -208,43 +215,43 @@ describe('Batch comments store actions', () => { ...@@ -208,43 +215,43 @@ describe('Batch comments store actions', () => {
draftsPath: TEST_HOST, draftsPath: TEST_HOST,
}, },
}; };
});
it('commits RECEIVE_DRAFT_UPDATE_SUCCESS with returned data', (done) => { context = {
const commit = jest.fn();
const context = {
getters, getters,
commit, commit,
}; };
res = { id: 1 }; res = { id: 1 };
mock.onAny().reply(200, res); mock.onAny().reply(200, res);
params = { note: { id: 1 }, noteText: 'test' };
});
actions afterEach(() => jest.clearAllMocks());
.updateDraft(context, { note: { id: 1 }, noteText: 'test', callback() {} })
.then(() => { it('commits RECEIVE_DRAFT_UPDATE_SUCCESS with returned data', () => {
expect(commit).toHaveBeenCalledWith('RECEIVE_DRAFT_UPDATE_SUCCESS', { id: 1 }); return actions.updateDraft(context, { ...params, callback() {} }).then(() => {
}) expect(commit).toHaveBeenCalledWith('RECEIVE_DRAFT_UPDATE_SUCCESS', { id: 1 });
.then(done) });
.catch(done.fail);
}); });
it('calls passed callback', (done) => { it('calls passed callback', () => {
const commit = jest.fn();
const context = {
getters,
commit,
};
const callback = jest.fn(); const callback = jest.fn();
res = { id: 1 }; return actions.updateDraft(context, { ...params, callback }).then(() => {
mock.onAny().reply(200, res); expect(callback).toHaveBeenCalled();
});
});
actions it('does not stringify empty position', () => {
.updateDraft(context, { note: { id: 1 }, noteText: 'test', callback }) return actions.updateDraft(context, { ...params, position: {}, callback() {} }).then(() => {
.then(() => { expect(service.update.mock.calls[0][1].position).toBeUndefined();
expect(callback).toHaveBeenCalled(); });
}) });
.then(done)
.catch(done.fail); it('stringifies a non-empty position', () => {
const position = { test: true };
const expectation = JSON.stringify(position);
return actions.updateDraft(context, { ...params, position, callback() {} }).then(() => {
expect(service.update.mock.calls[0][1].position).toBe(expectation);
});
}); });
}); });
......
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