diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 8d65585f760a696061d842a9ede7b626b1ae6214..5063f0c7d00899500be0a7c704e4d04354a70b82 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -14,6 +14,7 @@ import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link import { detectAndConfirmSensitiveTokens } from '~/lib/utils/secret_detection'; import { FILE_DIFF_POSITION_TYPE, IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants'; import { useNotes } from '~/notes/store/legacy_notes'; +import { useLegacyDiffs } from '~/diffs/stores/legacy_diffs'; import eventHub from '../event_hub'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; @@ -188,6 +189,9 @@ export default { isDiscussionInternal() { return this.discussion.notes[0]?.internal; }, + commentLines() { + return this.getLinesForDiscussion({ discussion: this.discussion }); + }, discussionHolderClass() { return { 'is-replying': this.isReplying, @@ -216,6 +220,7 @@ export default { 'removeConvertedDiscussion', 'expandDiscussion', ]), + ...mapActions(useLegacyDiffs, ['getLinesForDiscussion']), showReplyForm(text) { this.isReplying = true; @@ -378,6 +383,7 @@ export default { :discussion="discussion" :diff-file="diffFile" :line="diffLine" + :lines="commentLines" :save-button-title="saveButtonTitle" :autofocus="!hasDraft" :autosave-key="autosaveKey" diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js index be8e86c86215e250d7ab4eb79431130937a9c10e..ab9c649a0897f945f9e6c0f2a9bd84e69cfa72cf 100644 --- a/spec/frontend/notes/components/noteable_discussion_spec.js +++ b/spec/frontend/notes/components/noteable_discussion_spec.js @@ -36,10 +36,23 @@ Vue.use(PiniaVuePlugin); jest.mock('~/behaviors/markdown/render_gfm'); jest.mock('~/alert'); +function createPinia({ stubActions = true } = {}) { + const pinia = createTestingPinia({ stubActions, plugins: [globalAccessorPlugin] }); + const diffsStore = useLegacyDiffs(); + useNotes().noteableData = noteableDataMock; + useNotes().notesData = notesDataMock; + useNotes().saveNote.mockResolvedValue(); + useNotes().fetchDiscussionDiffLines.mockResolvedValue(); + useBatchComments(); + + return { pinia, diffsStore }; +} + describe('noteable_discussion component', () => { let pinia; let wrapper; let axiosMock; + let diffsStore; const createComponent = ({ discussion = discussionMock } = {}) => { wrapper = mountExtended(NoteableDiscussion, { @@ -49,13 +62,7 @@ describe('noteable_discussion component', () => { }; beforeEach(() => { - pinia = createTestingPinia({ plugins: [globalAccessorPlugin] }); - useLegacyDiffs(); - useNotes().noteableData = noteableDataMock; - useNotes().notesData = notesDataMock; - useNotes().saveNote.mockResolvedValue(); - useNotes().fetchDiscussionDiffLines.mockResolvedValue(); - useBatchComments(); + ({ pinia, diffsStore } = createPinia()); axiosMock = new MockAdapter(axios); createComponent(); }); @@ -306,6 +313,61 @@ describe('noteable_discussion component', () => { }); }); + it('includes the original line range when replying', async () => { + wrapper.vm.showReplyForm(); + + await nextTick(); + + const form = wrapper.findComponent(NoteForm); + + expect(form.props('lines')).toEqual([]); + }); + + describe('multi-line comments', () => { + let discussion; + let startCode; + let endCode; + + beforeEach(() => { + ({ pinia, diffsStore } = createPinia({ stubActions: false })); + + const file = getDiffFileMock(); + diffsStore.diffFiles = [file]; + + startCode = file.highlighted_diff_lines[6].line_code; + endCode = file.highlighted_diff_lines[7].line_code; + + discussion = { + ...discussionMock, + diff_file: file, + position: { + line_range: { + start: { + line_code: startCode, + }, + end: { + line_code: endCode, + }, + }, + }, + }; + + createComponent({ discussion }); + }); + + it('includes the original line range when replying to a multiline comment', async () => { + wrapper.vm.showReplyForm(); + await nextTick(); + + const form = wrapper.findComponent(NoteForm); + + expect(form.props('lines')).toEqual([ + expect.objectContaining({ line_code: startCode }), + expect.objectContaining({ line_code: endCode }), + ]); + }); + }); + it('supports direct call on showReplyForm', async () => { const mock = jest.fn(); wrapper = mount(NoteableDiscussion, {