Commit c3468692 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch '8225-allow-add-discussion-to-review' into 'master'

Allow Add Comment To Review

See merge request gitlab-org/gitlab!51718
parents 996f03eb 08721092
......@@ -41,13 +41,17 @@ export default {
titleText() {
const file = this.discussion ? this.discussion.diff_file : this.draft;
if (file) {
if (file?.file_path) {
return file.file_path;
}
return sprintf(__("%{authorsName}'s thread"), {
authorsName: this.discussion.notes.find((note) => !note.system).author.name,
});
if (this.discussion) {
return sprintf(__("%{authorsName}'s thread"), {
authorsName: this.discussion.notes.find((note) => !note.system).author.name,
});
}
return __('Your new comment');
},
linePosition() {
if (this.position?.position_type === IMAGE_DIFF_POSITION_TYPE) {
......@@ -94,7 +98,7 @@ export default {
<span class="review-preview-item-header">
<gl-icon class="flex-shrink-0" :name="iconName" />
<span class="bold text-nowrap gl-align-items-center">
<span class="review-preview-item-header-text block-truncated">
<span class="review-preview-item-header-text block-truncated gl-ml-2">
{{ titleText }}
</span>
<template v-if="showLinePosition">
......
......@@ -84,6 +84,7 @@ export default {
'getNoteableDataByProp',
'getNotesData',
'openState',
'hasDrafts',
]),
...mapState(['isToggleStateButtonLoading']),
isNoteTypeComment() {
......@@ -171,6 +172,9 @@ export default {
endpoint() {
return this.getNoteableData.create_note_path;
},
draftEndpoint() {
return this.getNotesData.draftsPath;
},
issuableTypeTitle() {
return this.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE
? this.$options.i18n.mergeRequest
......@@ -214,12 +218,15 @@ export default {
this.errors = [this.$options.i18n.GENERIC_UNSUBMITTABLE_NETWORK];
}
},
handleSave(withIssueAction) {
handleSaveDraft() {
this.handleSave({ isDraft: true });
},
handleSave({ withIssueAction = false, isDraft = false } = {}) {
this.errors = [];
if (this.note.length) {
const noteData = {
endpoint: this.endpoint,
endpoint: isDraft ? this.draftEndpoint : this.endpoint,
data: {
note: {
noteable_type: this.noteableType,
......@@ -229,6 +236,7 @@ export default {
},
merge_request_diff_head_sha: this.getNoteableData.diff_head_sha,
},
isDraft,
};
if (this.noteType === constants.DISCUSSION) {
......@@ -392,62 +400,82 @@ export default {
</markdown-field>
</comment-field-layout>
<div class="note-form-actions">
<gl-form-checkbox
v-if="confidentialNotesEnabled && canSetConfidential"
v-model="noteIsConfidential"
class="gl-mb-6"
data-testid="confidential-note-checkbox"
>
{{ $options.i18n.confidential }}
<gl-icon
v-gl-tooltip:tooltipcontainer.bottom
name="question"
:size="16"
:title="$options.i18n.confidentialVisibility"
class="gl-text-gray-500"
/>
</gl-form-checkbox>
<gl-dropdown
split
:text="commentButtonTitle"
class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown"
category="primary"
variant="confirm"
:disabled="disableSubmitButton"
data-testid="comment-button"
data-qa-selector="comment_button"
:data-track-label="trackingLabel"
data-track-event="click_button"
@click="handleSave()"
>
<gl-dropdown-item
is-check-item
:is-checked="isNoteTypeComment"
:selected="isNoteTypeComment"
@click="setNoteTypeToComment"
<template v-if="hasDrafts">
<gl-button
:disabled="disableSubmitButton"
data-testid="add-to-review-button"
type="submit"
category="primary"
variant="success"
@click.prevent="handleSaveDraft()"
>{{ __('Add to review') }}</gl-button
>
<gl-button
:disabled="disableSubmitButton"
data-testid="add-comment-now-button"
category="secondary"
@click.prevent="handleSave()"
>{{ __('Add comment now') }}</gl-button
>
</template>
<template v-else>
<gl-form-checkbox
v-if="confidentialNotesEnabled && canSetConfidential"
v-model="noteIsConfidential"
class="gl-mb-6"
data-testid="confidential-note-checkbox"
>
<strong>{{ $options.i18n.submitButton.comment }}</strong>
<p class="gl-m-0">{{ commentDescription }}</p>
</gl-dropdown-item>
<gl-dropdown-divider />
<gl-dropdown-item
is-check-item
:is-checked="isNoteTypeDiscussion"
:selected="isNoteTypeDiscussion"
data-qa-selector="discussion_menu_item"
@click="setNoteTypeToDiscussion"
{{ $options.i18n.confidential }}
<gl-icon
v-gl-tooltip:tooltipcontainer.bottom
name="question"
:size="16"
:title="$options.i18n.confidentialVisibility"
class="gl-text-gray-500"
/>
</gl-form-checkbox>
<gl-dropdown
split
:text="commentButtonTitle"
class="gl-mr-3 js-comment-button js-comment-submit-button comment-type-dropdown"
category="primary"
variant="confirm"
:disabled="disableSubmitButton"
data-testid="comment-button"
data-qa-selector="comment_button"
:data-track-label="trackingLabel"
data-track-event="click_button"
@click="handleSave()"
>
<strong>{{ $options.i18n.submitButton.startThread }}</strong>
<p class="gl-m-0">{{ startDiscussionDescription }}</p>
</gl-dropdown-item>
</gl-dropdown>
<gl-dropdown-item
is-check-item
:is-checked="isNoteTypeComment"
:selected="isNoteTypeComment"
@click="setNoteTypeToComment"
>
<strong>{{ $options.i18n.submitButton.comment }}</strong>
<p class="gl-m-0">{{ commentDescription }}</p>
</gl-dropdown-item>
<gl-dropdown-divider />
<gl-dropdown-item
is-check-item
:is-checked="isNoteTypeDiscussion"
:selected="isNoteTypeDiscussion"
data-qa-selector="discussion_menu_item"
@click="setNoteTypeToDiscussion"
>
<strong>{{ $options.i18n.submitButton.startThread }}</strong>
<p class="gl-m-0">{{ startDiscussionDescription }}</p>
</gl-dropdown-item>
</gl-dropdown>
</template>
<gl-button
v-if="canToggleIssueState"
:loading="isToggleStateButtonLoading"
:class="[actionButtonClassNames, 'btn-comment btn-comment-and-close']"
:disabled="isSubmitting"
data-testid="close-reopen-button"
@click="handleSave(true)"
@click="handleSave({ withIssueAction: true })"
>{{ issueActionButtonTitle }}</gl-button
>
</div>
......
......@@ -3,8 +3,10 @@ import { mapGetters, mapActions } from 'vuex';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
import { __ } from '~/locale';
import initUserPopovers from '~/user_popovers';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import OrderedLayout from '~/vue_shared/components/ordered_layout.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import draftNote from '../../batch_comments/components/draft_note.vue';
import { deprecatedCreateFlash as Flash } from '../../flash';
import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
......@@ -32,6 +34,8 @@ export default {
discussionFilterNote,
OrderedLayout,
SidebarSubscription,
draftNote,
TimelineEntryItem,
},
mixins: [glFeatureFlagsMixin()],
props: {
......@@ -276,6 +280,9 @@ export default {
<ul id="notes-list" class="notes main-notes-list timeline">
<template v-for="discussion in allDiscussions">
<skeleton-loading-container v-if="discussion.isSkeletonNote" :key="discussion.id" />
<timeline-entry-item v-else-if="discussion.isDraft" :key="discussion.id">
<draft-note :draft="discussion" />
</timeline-entry-item>
<template v-else-if="discussion.isPlaceholderNote">
<placeholder-system-note
v-if="discussion.placeholderType === $options.systemNote"
......
......@@ -2,7 +2,23 @@ import { flattenDeep, clone } from 'lodash';
import * as constants from '../constants';
import { collapseSystemNotes } from './collapse_utils';
export const discussions = (state) => {
const getDraftComments = (state) => {
if (!state.batchComments) {
return [];
}
return state.batchComments.drafts
.filter((draft) => !draft.line_code && !draft.discussion_id)
.map((x) => ({
...x,
// Treat a top-level draft note as individual_note so it's not included in
// expand/collapse threads
individual_note: true,
}))
.sort((a, b) => a.id - b.id);
};
export const discussions = (state, getters, rootState) => {
let discussionsInState = clone(state.discussions);
// NOTE: not testing bc will be removed when backend is finished.
......@@ -22,11 +38,15 @@ export const discussions = (state) => {
.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
}
discussionsInState = collapseSystemNotes(discussionsInState);
discussionsInState = discussionsInState.concat(getDraftComments(rootState));
if (state.discussionSortOrder === constants.DESC) {
discussionsInState = discussionsInState.reverse();
}
return collapseSystemNotes(discussionsInState);
return discussionsInState;
};
export const convertedDisscussionIds = (state) => state.convertedDisscussionIds;
......@@ -257,3 +277,6 @@ export const commentsDisabled = (state) => state.commentsDisabled;
export const suggestionsCount = (state, getters) =>
Object.values(getters.notesById).filter((n) => n.suggestions.length).length;
export const hasDrafts = (state, getters, rootState, rootGetters) =>
Boolean(rootGetters['batchComments/hasDrafts']);
---
title: Allow Add Comment To Review
merge_request: 51718
author: Lee Tickett @leetickett
type: added
......@@ -334,22 +334,28 @@ comment itself.
![Unresolve status](img/mr_review_unresolve.png)
### Adding a new comment
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8225) in GitLab 13.10.
If you have a review in progress, you will be presented with the option to **Add to review**:
![New thread](img/mr_review_new_comment_v13_11.png)
### Submitting a review
If you have any comments that have not been submitted, a bar displays at the
bottom of the screen with two buttons:
- **Discard**: Discards all comments that have not been submitted.
- **Finish review**: Opens a list of comments ready to be submitted for review.
Clicking **Submit review** publishes all comments. Any quick actions
submitted are performed at this time.
- **Pending comments**: Opens a list of comments ready to be submitted for review.
- **Submit review**: Publishes all comments. Any quick actions submitted are performed at this time.
Alternatively, to finish the entire review from a pending comment:
- Click the **Finish review** button on the comment.
- Click the **Submit review** button on the comment.
- Use the `/submit_review` [quick action](../project/quick_actions.md) in the text of non-review comment.
![Review submission](img/review_preview.png)
![Review submission](img/review_preview_v13_11.png)
Submitting the review sends a single email to every notifiable user of the
merge request with all the comments associated to it.
......
......@@ -40,20 +40,18 @@ button[disabled] {
vertical-align: text-top;
}
.discussion-body,
.diff-file {
.notes .note {
&.draft-note {
margin: 0 0 $gl-padding;
padding: 0;
border: 0;
.note.draft-note {
margin: 0 0 $gl-padding;
padding: 0;
border: 0;
&.is-editing {
margin-bottom: 0;
}
}
&.is-editing {
margin-bottom: 0;
}
}
.discussion-body,
.diff-file {
.notes_holder {
.notes-content {
.notes {
......
......@@ -36303,6 +36303,9 @@ msgstr ""
msgid "Your new SCIM token"
msgstr ""
msgid "Your new comment"
msgstr ""
msgid "Your new personal access token has been created."
msgstr ""
......
......@@ -28,7 +28,7 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
it 'adds draft note' do
write_comment
write_diff_comment
expect(find('.draft-note-component')).to have_content('Line is wrong')
......@@ -38,7 +38,7 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
it 'publishes review' do
write_comment
write_diff_comment
page.within('.review-bar-content') do
click_button 'Submit review'
......@@ -52,7 +52,7 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
it 'publishes single comment' do
write_comment
write_diff_comment
click_button 'Add comment now'
......@@ -64,7 +64,7 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
it 'deletes draft note' do
write_comment
write_diff_comment
accept_alert { find('.js-note-delete').click }
......@@ -74,21 +74,57 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
it 'edits draft note' do
write_comment
write_diff_comment
find('.js-note-edit').click
# make sure comment form is in view
execute_script("window.scrollBy(0, 200)")
page.within('.js-discussion-note-form') do
fill_in('note_note', with: 'Testing update')
click_button('Save comment')
write_comment(text: 'Testing update', button_text: 'Save comment')
expect(page).to have_selector('.draft-note-component', text: 'Testing update')
end
context 'adding single comment to review' do
before do
visit_overview
end
wait_for_requests
it 'at first does not show `Add to review` and `Add comment now` buttons' do
expect(page).to have_no_button('Add to review')
expect(page).to have_no_button('Add comment now')
end
expect(page).to have_selector('.draft-note-component', text: 'Testing update')
context 'when review has started' do
before do
visit_diffs
write_diff_comment
visit_overview
end
it 'can add comment to review' do
write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a draft comment', button_text: 'Add to review')
expect(page).to have_selector('.draft-note-component', text: 'Its a draft comment')
click_button('Pending comments')
expect(page).to have_text('2 pending comments')
end
it 'can add comment right away' do
write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a regular comment', button_text: 'Add comment now')
expect(page).to have_selector('.note:not(.draft-note)', text: 'Its a regular comment')
click_button('Pending comments')
expect(page).to have_text('1 pending comment')
end
end
end
context 'in parallel diff' do
......@@ -197,46 +233,51 @@ RSpec.describe 'Merge request > Batch comments', :js do
wait_for_requests
end
def write_comment(button_text: 'Start a review', text: 'Line is wrong')
click_diff_line(find("[id='#{sample_compare.changes[0][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: text)
click_button(button_text)
end
def visit_overview
visit project_merge_request_path(merge_request.project, merge_request)
wait_for_requests
end
def write_parallel_comment(line, button_text: 'Start a review', text: 'Line is wrong')
def write_diff_comment(**params)
click_diff_line(find("[id='#{sample_compare.changes[0][:line_code]}']"))
write_comment(**params)
end
def write_parallel_comment(line, **params)
find("td[id='#{line}']").hover
find(".is-over button").click
page.within("form[data-line-code='#{line}']") do
fill_in('note_note', with: text)
write_comment(selector: "form[data-line-code='#{line}']", **params)
end
def write_comment(selector: '.js-discussion-note-form', field: 'note_note', button_text: 'Start a review', text: 'Line is wrong')
page.within(selector) do
fill_in(field, with: text)
click_button(button_text)
end
wait_for_requests
end
end
def write_reply_to_discussion(button_text: 'Start a review', text: 'Line is wrong', resolve: false, unresolve: false)
page.within(first('.diff-files-holder .discussion-reply-holder')) do
find_field('Reply…', match: :first).click
def write_reply_to_discussion(button_text: 'Start a review', text: 'Line is wrong', resolve: false, unresolve: false)
page.within(first('.diff-files-holder .discussion-reply-holder')) do
find_field('Reply…', match: :first).click
fill_in('note_note', with: text)
fill_in('note_note', with: text)
if resolve
page.check('Resolve thread')
end
if resolve
page.check('Resolve thread')
end
if unresolve
page.check('Unresolve thread')
if unresolve
page.check('Unresolve thread')
end
click_button(button_text)
end
click_button(button_text)
wait_for_requests
end
wait_for_requests
end
......@@ -124,4 +124,16 @@ describe('Batch comments draft preview item component', () => {
);
});
});
describe('for new comment', () => {
it('renders title', () => {
createComponent(false, {}, (store) => {
store.state.notes.discussions.push({});
});
expect(vm.$el.querySelector('.review-preview-item-header-text').textContent).toContain(
'Your new comment',
);
});
});
});
import { GlDropdown, GlAlert } from '@gitlab/ui';
import { GlAlert } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import Autosize from 'autosize';
import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import batchComments from '~/batch_comments/stores/modules/batch_comments';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import { deprecatedCreateFlash as flash } from '~/flash';
import axios from '~/lib/utils/axios_utils';
......@@ -29,8 +30,10 @@ describe('issue_comment_form component', () => {
const findCloseReopenButton = () => wrapper.findByTestId('close-reopen-button');
const findTextArea = () => wrapper.findByTestId('comment-field');
const findAddToReviewButton = () => wrapper.findByTestId('add-to-review-button');
const findAddCommentNowButton = () => wrapper.findByTestId('add-comment-now-button');
const findConfidentialNoteCheckbox = () => wrapper.findByTestId('confidential-note-checkbox');
const findCommentGlDropdown = () => wrapper.find(GlDropdown);
const findCommentGlDropdown = () => wrapper.findByTestId('comment-button');
const findCommentButton = () => findCommentGlDropdown().find('button');
const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers;
......@@ -582,4 +585,64 @@ describe('issue_comment_form component', () => {
expect(findTextArea().exists()).toBe(false);
});
});
describe('with batchComments in store', () => {
beforeEach(() => {
store.registerModule('batchComments', batchComments());
});
describe('add to review and comment now buttons', () => {
it('when no drafts exist, should not render', () => {
mountComponent();
expect(findCommentGlDropdown().exists()).toBe(true);
expect(findAddToReviewButton().exists()).toBe(false);
expect(findAddCommentNowButton().exists()).toBe(false);
});
describe('when drafts exist', () => {
beforeEach(() => {
store.state.batchComments.drafts = [{ note: 'A' }];
});
it('should render', () => {
mountComponent();
expect(findCommentGlDropdown().exists()).toBe(false);
expect(findAddToReviewButton().exists()).toBe(true);
expect(findAddCommentNowButton().exists()).toBe(true);
});
it('clicking `add to review`, should call draft endpoint, set `isDraft` true', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'a draft note' } });
jest.spyOn(store, 'dispatch').mockResolvedValue();
findAddToReviewButton().trigger('click');
expect(store.dispatch).toHaveBeenCalledWith(
'saveNote',
expect.objectContaining({
endpoint: notesDataMock.draftsPath,
isDraft: true,
}),
);
});
it('clicking `add comment now`, should call note endpoint, set `isDraft` false ', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'a comment' } });
jest.spyOn(store, 'dispatch').mockResolvedValue();
findAddCommentNowButton().trigger('click');
expect(store.dispatch).toHaveBeenCalledWith(
'saveNote',
expect.objectContaining({
endpoint: noteableDataMock.create_note_path,
isDraft: false,
}),
);
});
});
});
});
});
......@@ -3,6 +3,8 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import Vue from 'vue';
import { setTestTimeout } from 'helpers/timeout';
import DraftNote from '~/batch_comments/components/draft_note.vue';
import batchComments from '~/batch_comments/stores/modules/batch_comments';
import axios from '~/lib/utils/axios_utils';
import * as urlUtility from '~/lib/utils/url_utility';
import CommentForm from '~/notes/components/comment_form.vue';
......@@ -400,4 +402,34 @@ describe('note_app', () => {
expect(getComponentOrder()).toStrictEqual([TYPE_NOTES_LIST, TYPE_COMMENT_FORM]);
});
});
describe('when multiple draft types are present', () => {
beforeEach(() => {
store = createStore();
store.registerModule('batchComments', batchComments());
store.state.batchComments.drafts = [
{ line_code: 1, isDraft: true },
{ discussion_id: 1, isDraft: true },
{ note: 'A', isDraft: true },
{ note: 'B', isDraft: true },
];
store.state.isLoading = false;
wrapper = shallowMount(NotesApp, {
propsData,
store,
stubs: {
OrderedLayout,
},
});
});
it('correctly finds only draft comments', () => {
const drafts = wrapper.findAll(DraftNote).wrappers;
expect(drafts.map((x) => x.props('draft'))).toEqual([
expect.objectContaining({ note: 'A' }),
expect.objectContaining({ note: 'B' }),
]);
});
});
});
......@@ -6,6 +6,7 @@ export const notesDataMock = {
markdownDocsPath: '/help/user/markdown',
newSessionPath: '/users/sign_in?redirect_to_referer=yes',
notesPath: '/gitlab-org/gitlab-foss/noteable/issue/98/notes',
draftsPath: '/flightjs/flight/-/merge_requests/4/drafts',
quickActionsDocsPath: '/help/user/project/quick_actions',
registerPath: '/users/sign_up?redirect_to_referer=yes',
prerenderedNotesCount: 1,
......@@ -1270,3 +1271,12 @@ export const batchSuggestionsInfoMock = [
discussionId: 'c003',
},
];
export const draftComments = [
{ id: 7, note: 'test draft note' },
{ id: 9, note: 'draft note 2' },
];
export const draftReply = { id: 8, note: 'draft reply', discussion_id: 1 };
export const draftDiffDiscussion = { id: 6, note: 'draft diff discussion', line_code: 1 };
import { DESC } from '~/notes/constants';
import { DESC, ASC } from '~/notes/constants';
import * as getters from '~/notes/stores/getters';
import {
notesDataMock,
......@@ -12,6 +12,9 @@ import {
discussion3,
resolvedDiscussion1,
unresolvableDiscussion,
draftComments,
draftReply,
draftDiffDiscussion,
} from '../mock_data';
const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json';
......@@ -23,6 +26,8 @@ const createDiscussionNeighborParams = (discussionId, diffOrder, step) => ({
step,
});
const asDraftDiscussion = (x) => ({ ...x, individual_note: true });
describe('Getters Notes Store', () => {
let state;
......@@ -61,20 +66,58 @@ describe('Getters Notes Store', () => {
});
describe('discussions', () => {
it('should return all discussions in the store', () => {
expect(getters.discussions(state)).toEqual([individualNote]);
});
let batchComments = null;
const getDiscussions = () => getters.discussions(state, {}, { batchComments });
describe('without batchComments module', () => {
it('should return all discussions in the store', () => {
expect(getDiscussions()).toEqual([individualNote]);
});
it('should transform discussion to individual notes in timeline view', () => {
state.discussions = [discussionMock];
state.isTimelineEnabled = true;
it('should transform discussion to individual notes in timeline view', () => {
state.discussions = [discussionMock];
state.isTimelineEnabled = true;
const discussions = getDiscussions();
expect(discussions.length).toEqual(discussionMock.notes.length);
discussions.forEach((discussion) => {
expect(discussion.individual_note).toBe(true);
expect(discussion.id).toBe(discussion.notes[0].id);
expect(discussion.created_at).toBe(discussion.notes[0].created_at);
});
});
});
expect(getters.discussions(state).length).toEqual(discussionMock.notes.length);
getters.discussions(state).forEach((discussion) => {
expect(discussion.individual_note).toBe(true);
expect(discussion.id).toBe(discussion.notes[0].id);
expect(discussion.created_at).toBe(discussion.notes[0].created_at);
describe('with batchComments', () => {
beforeEach(() => {
batchComments = { drafts: [...draftComments, draftReply, draftDiffDiscussion] };
});
it.each`
discussionSortOrder | expectation
${ASC} | ${[individualNote, ...draftComments.map(asDraftDiscussion)]}
${DESC} | ${[...draftComments.reverse().map(asDraftDiscussion), individualNote]}
`(
'only appends draft comments (discussionSortOrder=$discussionSortOrder)',
({ discussionSortOrder, expectation }) => {
state.discussionSortOrder = discussionSortOrder;
expect(getDiscussions()).toEqual(expectation);
},
);
});
});
describe('hasDrafts', () => {
it.each`
rootGetters | expected
${{}} | ${false}
${{ 'batchComments/hasDrafts': true }} | ${true}
${{ 'batchComments/hasDrafts': false }} | ${false}
`('with rootGetters=$rootGetters, returns $expected', ({ rootGetters, expected }) => {
expect(getters.hasDrafts({}, {}, {}, rootGetters)).toBe(expected);
});
});
......@@ -103,7 +146,7 @@ describe('Getters Notes Store', () => {
};
it('should return a single system note when a description was updated multiple times', () => {
expect(getters.discussions(stateCollapsedNotes).length).toEqual(1);
expect(getters.discussions(stateCollapsedNotes, {}, {}).length).toEqual(1);
});
});
......
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