Commit 36993a83 authored by Justin Boyson's avatar Justin Boyson Committed by David O'Regan

Check for empty position object before stringify

Updates specs to check for correct string parsing
parent da75cd82
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