Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/notes/components')
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js134
-rw-r--r--spec/frontend/notes/components/diff_discussion_header_spec.js4
-rw-r--r--spec/frontend/notes/components/discussion_actions_spec.js2
-rw-r--r--spec/frontend/notes/components/discussion_reply_placeholder_spec.js14
-rw-r--r--spec/frontend/notes/components/note_actions_spec.js11
-rw-r--r--spec/frontend/notes/components/note_form_spec.js2
-rw-r--r--spec/frontend/notes/components/noteable_discussion_spec.js4
-rw-r--r--spec/frontend/notes/components/noteable_note_spec.js214
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js4
9 files changed, 268 insertions, 121 deletions
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 2f58f75ab70..bab90723578 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -1,7 +1,9 @@
+import { GlDropdown, GlAlert } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import Autosize from 'autosize';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import { deprecatedCreateFlash as flash } from '~/flash';
@@ -9,7 +11,8 @@ import axios from '~/lib/utils/axios_utils';
import CommentForm from '~/notes/components/comment_form.vue';
import * as constants from '~/notes/constants';
import eventHub from '~/notes/event_hub';
-import createStore from '~/notes/stores';
+import { COMMENT_FORM } from '~/notes/i18n';
+import notesModule from '~/notes/stores/modules';
import { loggedOutnoteableData, notesDataMock, userDataMock, noteableDataMock } from '../mock_data';
jest.mock('autosize');
@@ -17,15 +20,45 @@ jest.mock('~/commons/nav/user_merge_requests');
jest.mock('~/flash');
jest.mock('~/gl_form');
+Vue.use(Vuex);
+
describe('issue_comment_form component', () => {
let store;
let wrapper;
let axiosMock;
const findCloseReopenButton = () => wrapper.findByTestId('close-reopen-button');
- const findCommentButton = () => wrapper.findByTestId('comment-button');
const findTextArea = () => wrapper.findByTestId('comment-field');
const findConfidentialNoteCheckbox = () => wrapper.findByTestId('confidential-note-checkbox');
+ const findCommentGlDropdown = () => wrapper.find(GlDropdown);
+ const findCommentButton = () => findCommentGlDropdown().find('button');
+ const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers;
+
+ async function clickCommentButton({ waitForComponent = true, waitForNetwork = true } = {}) {
+ findCommentButton().trigger('click');
+
+ if (waitForComponent || waitForNetwork) {
+ // Wait for the click to bubble out and trigger the handler
+ await nextTick();
+
+ if (waitForNetwork) {
+ // Wait for the network request promise to resolve
+ await nextTick();
+ }
+ }
+ }
+
+ function createStore({ actions = {} } = {}) {
+ const baseModule = notesModule();
+
+ return new Vuex.Store({
+ ...baseModule,
+ actions: {
+ ...baseModule.actions,
+ ...actions,
+ },
+ });
+ }
const createNotableDataMock = (data = {}) => {
return {
@@ -101,6 +134,83 @@ describe('issue_comment_form component', () => {
expect(wrapper.vm.resizeTextarea).toHaveBeenCalled();
});
+ it('does not report errors in the UI when the save succeeds', async () => {
+ mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
+
+ jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
+
+ await clickCommentButton();
+
+ // findErrorAlerts().exists returns false if *any* wrapper is empty,
+ // not necessarily that there aren't any at all.
+ // We want to check here that there are none found, so we use the
+ // raw wrapper array length instead.
+ expect(findErrorAlerts().length).toBe(0);
+ });
+
+ it.each`
+ httpStatus | errors
+ ${400} | ${[COMMENT_FORM.GENERIC_UNSUBMITTABLE_NETWORK]}
+ ${422} | ${['error 1']}
+ ${422} | ${['error 1', 'error 2']}
+ ${422} | ${['error 1', 'error 2', 'error 3']}
+ `(
+ 'displays the correct errors ($errors) for a $httpStatus network response',
+ async ({ errors, httpStatus }) => {
+ store = createStore({
+ actions: {
+ saveNote: jest.fn().mockRejectedValue({
+ response: { status: httpStatus, data: { errors: { commands_only: errors } } },
+ }),
+ },
+ });
+
+ mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
+
+ await clickCommentButton();
+
+ const errorAlerts = findErrorAlerts();
+
+ expect(errorAlerts.length).toBe(errors.length);
+ errors.forEach((msg, index) => {
+ const alert = errorAlerts[index];
+
+ expect(alert.text()).toBe(msg);
+ });
+ },
+ );
+
+ it('should remove the correct error from the list when it is dismissed', async () => {
+ const commandErrors = ['1', '2', '3'];
+ store = createStore({
+ actions: {
+ saveNote: jest.fn().mockRejectedValue({
+ response: { status: 422, data: { errors: { commands_only: [...commandErrors] } } },
+ }),
+ },
+ });
+
+ mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
+
+ await clickCommentButton();
+
+ let errorAlerts = findErrorAlerts();
+
+ expect(errorAlerts.length).toBe(commandErrors.length);
+
+ // dismiss the second error
+ extendedWrapper(errorAlerts[1]).findByTestId('close-icon').trigger('click');
+ // Wait for the dismissal to bubble out of the Alert component and be handled in this component
+ await nextTick();
+ // Refresh the list of alerts
+ errorAlerts = findErrorAlerts();
+
+ expect(errorAlerts.length).toBe(commandErrors.length - 1);
+ // We want to know that the *correct* error was dismissed, not just that any one is gone
+ expect(errorAlerts[0].text()).toBe(commandErrors[0]);
+ expect(errorAlerts[1].text()).toBe(commandErrors[2]);
+ });
+
it('should toggle issue state when no note', () => {
mountComponent({ mountFunction: mount });
@@ -243,7 +353,7 @@ describe('issue_comment_form component', () => {
it('should render comment button as disabled', () => {
mountComponent();
- expect(findCommentButton().props('disabled')).toBe(true);
+ expect(findCommentGlDropdown().props('disabled')).toBe(true);
});
it('should enable comment button if it has note', async () => {
@@ -251,7 +361,7 @@ describe('issue_comment_form component', () => {
await wrapper.setData({ note: 'Foo' });
- expect(findCommentButton().props('disabled')).toBe(false);
+ expect(findCommentGlDropdown().props('disabled')).toBe(false);
});
it('should update buttons texts when it has note', () => {
@@ -437,7 +547,7 @@ describe('issue_comment_form component', () => {
await wrapper.vm.$nextTick();
// submit comment
- wrapper.findByTestId('comment-button').trigger('click');
+ findCommentButton().trigger('click');
const [providedData] = wrapper.vm.saveNote.mock.calls[0];
expect(providedData.data.note.confidential).toBe(shouldCheckboxBeChecked);
@@ -472,16 +582,4 @@ describe('issue_comment_form component', () => {
expect(findTextArea().exists()).toBe(false);
});
});
-
- describe('close/reopen button variants', () => {
- it.each([
- [constants.OPENED, 'warning'],
- [constants.REOPENED, 'warning'],
- [constants.CLOSED, 'default'],
- ])('when %s, the variant of the btn is %s', (state, expected) => {
- mountComponent({ noteableData: { ...noteableDataMock, state } });
-
- expect(findCloseReopenButton().props('variant')).toBe(expected);
- });
- });
});
diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js
index fdc89522901..fa34a5e8d39 100644
--- a/spec/frontend/notes/components/diff_discussion_header_spec.js
+++ b/spec/frontend/notes/components/diff_discussion_header_spec.js
@@ -6,14 +6,10 @@ import createStore from '~/notes/stores';
import mockDiffFile from '../../diffs/mock_data/diff_discussions';
import { discussionMock } from '../mock_data';
-const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json';
-
describe('diff_discussion_header component', () => {
let store;
let wrapper;
- preloadFixtures(discussionWithTwoUnresolvedNotes);
-
beforeEach(() => {
window.mrTabs = {};
store = createStore();
diff --git a/spec/frontend/notes/components/discussion_actions_spec.js b/spec/frontend/notes/components/discussion_actions_spec.js
index 03e5842bb0f..c6a7d7ead98 100644
--- a/spec/frontend/notes/components/discussion_actions_spec.js
+++ b/spec/frontend/notes/components/discussion_actions_spec.js
@@ -96,7 +96,7 @@ describe('DiscussionActions', () => {
it('emits showReplyForm event when clicking on reply placeholder', () => {
jest.spyOn(wrapper.vm, '$emit');
- wrapper.find(ReplyPlaceholder).find('button').trigger('click');
+ wrapper.find(ReplyPlaceholder).find('textarea').trigger('focus');
expect(wrapper.vm.$emit).toHaveBeenCalledWith('showReplyForm');
});
diff --git a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
index b7b7ec08867..2a4cd0df0c7 100644
--- a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
+++ b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
@@ -1,17 +1,17 @@
import { shallowMount } from '@vue/test-utils';
import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
-const buttonText = 'Test Button Text';
+const placeholderText = 'Test Button Text';
describe('ReplyPlaceholder', () => {
let wrapper;
- const findButton = () => wrapper.find({ ref: 'button' });
+ const findTextarea = () => wrapper.find({ ref: 'textarea' });
beforeEach(() => {
wrapper = shallowMount(ReplyPlaceholder, {
propsData: {
- buttonText,
+ placeholderText,
},
});
});
@@ -20,17 +20,17 @@ describe('ReplyPlaceholder', () => {
wrapper.destroy();
});
- it('emits onClick event on button click', () => {
- findButton().trigger('click');
+ it('emits focus event on button click', () => {
+ findTextarea().trigger('focus');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted()).toEqual({
- onClick: [[]],
+ focus: [[]],
});
});
});
it('should render reply button', () => {
- expect(findButton().text()).toEqual(buttonText);
+ expect(findTextarea().attributes('placeholder')).toEqual(placeholderText);
});
});
diff --git a/spec/frontend/notes/components/note_actions_spec.js b/spec/frontend/notes/components/note_actions_spec.js
index 17717ebd09a..cc41088e21e 100644
--- a/spec/frontend/notes/components/note_actions_spec.js
+++ b/spec/frontend/notes/components/note_actions_spec.js
@@ -6,6 +6,7 @@ import axios from '~/lib/utils/axios_utils';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import noteActions from '~/notes/components/note_actions.vue';
import createStore from '~/notes/stores';
+import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import { userDataMock } from '../mock_data';
describe('noteActions', () => {
@@ -15,6 +16,9 @@ describe('noteActions', () => {
let actions;
let axiosMock;
+ const findUserAccessRoleBadge = (idx) => wrapper.findAll(UserAccessRoleBadge).at(idx);
+ const findUserAccessRoleBadgeText = (idx) => findUserAccessRoleBadge(idx).text().trim();
+
const mountNoteActions = (propsData, computed) => {
const localVue = createLocalVue();
return mount(localVue.extend(noteActions), {
@@ -44,6 +48,7 @@ describe('noteActions', () => {
projectName: 'project',
reportAbusePath: `${TEST_HOST}/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26`,
showReply: false,
+ awardPath: `${TEST_HOST}/award_emoji`,
};
actions = {
@@ -66,11 +71,11 @@ describe('noteActions', () => {
});
it('should render noteable author badge', () => {
- expect(wrapper.findAll('.note-role').at(0).text().trim()).toEqual('Author');
+ expect(findUserAccessRoleBadgeText(0)).toBe('Author');
});
it('should render access level badge', () => {
- expect(wrapper.findAll('.note-role').at(1).text().trim()).toEqual(props.accessLevel);
+ expect(findUserAccessRoleBadgeText(1)).toBe(props.accessLevel);
});
it('should render contributor badge', () => {
@@ -80,7 +85,7 @@ describe('noteActions', () => {
});
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.findAll('.note-role').at(1).text().trim()).toBe('Contributor');
+ expect(findUserAccessRoleBadgeText(1)).toBe('Contributor');
});
});
diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js
index 7615f3b70f1..92137d3190f 100644
--- a/spec/frontend/notes/components/note_form_spec.js
+++ b/spec/frontend/notes/components/note_form_spec.js
@@ -83,7 +83,7 @@ describe('issue_note_form component', () => {
});
const message =
- 'This comment has changed since you started editing, please review the updated comment to ensure information is not lost.';
+ 'This comment changed after you started editing it. Review the updated comment to ensure information is not lost.';
await nextTick();
diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js
index 87538279c3d..dd65351ef88 100644
--- a/spec/frontend/notes/components/noteable_discussion_spec.js
+++ b/spec/frontend/notes/components/noteable_discussion_spec.js
@@ -24,8 +24,6 @@ describe('noteable_discussion component', () => {
let wrapper;
let originalGon;
- preloadFixtures(discussionWithTwoUnresolvedNotes);
-
beforeEach(() => {
window.mrTabs = {};
store = createStore();
@@ -65,7 +63,7 @@ describe('noteable_discussion component', () => {
expect(wrapper.vm.isReplying).toEqual(false);
const replyPlaceholder = wrapper.find(ReplyPlaceholder);
- replyPlaceholder.vm.$emit('onClick');
+ replyPlaceholder.vm.$emit('focus');
await nextTick();
expect(wrapper.vm.isReplying).toEqual(true);
diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js
index fe78e086403..112983f3ac2 100644
--- a/spec/frontend/notes/components/noteable_note_spec.js
+++ b/spec/frontend/notes/components/noteable_note_spec.js
@@ -1,5 +1,6 @@
import { mount, createLocalVue } from '@vue/test-utils';
import { escape } from 'lodash';
+import waitForPromises from 'helpers/wait_for_promises';
import NoteActions from '~/notes/components/note_actions.vue';
import NoteBody from '~/notes/components/note_body.vue';
import NoteHeader from '~/notes/components/note_header.vue';
@@ -13,7 +14,7 @@ describe('issue_note', () => {
let wrapper;
const findMultilineComment = () => wrapper.find('[data-testid="multiline-comment"]');
- beforeEach(() => {
+ const createWrapper = (props = {}) => {
store = createStore();
store.dispatch('setNoteableData', noteableDataMock);
store.dispatch('setNotesData', notesDataMock);
@@ -23,6 +24,7 @@ describe('issue_note', () => {
store,
propsData: {
note,
+ ...props,
},
localVue,
stubs: [
@@ -33,14 +35,18 @@ describe('issue_note', () => {
'multiline-comment-form',
],
});
- });
+ };
afterEach(() => {
wrapper.destroy();
});
describe('mutiline comments', () => {
- it('should render if has multiline comment', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('should render if has multiline comment', async () => {
const position = {
line_range: {
start: {
@@ -69,9 +75,8 @@ describe('issue_note', () => {
line,
});
- return wrapper.vm.$nextTick().then(() => {
- expect(findMultilineComment().text()).toEqual('Comment on lines 1 to 2');
- });
+ await wrapper.vm.$nextTick();
+ expect(findMultilineComment().text()).toBe('Comment on lines 1 to 2');
});
it('should only render if it has everything it needs', () => {
@@ -147,108 +152,151 @@ describe('issue_note', () => {
});
});
- it('should render user information', () => {
- const { author } = note;
- const avatar = wrapper.find(UserAvatarLink);
- const avatarProps = avatar.props();
+ describe('rendering', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
- expect(avatarProps.linkHref).toBe(author.path);
- expect(avatarProps.imgSrc).toBe(author.avatar_url);
- expect(avatarProps.imgAlt).toBe(author.name);
- expect(avatarProps.imgSize).toBe(40);
- });
+ it('should render user information', () => {
+ const { author } = note;
+ const avatar = wrapper.findComponent(UserAvatarLink);
+ const avatarProps = avatar.props();
- it('should render note header content', () => {
- const noteHeader = wrapper.find(NoteHeader);
- const noteHeaderProps = noteHeader.props();
+ expect(avatarProps.linkHref).toBe(author.path);
+ expect(avatarProps.imgSrc).toBe(author.avatar_url);
+ expect(avatarProps.imgAlt).toBe(author.name);
+ expect(avatarProps.imgSize).toBe(40);
+ });
- expect(noteHeaderProps.author).toEqual(note.author);
- expect(noteHeaderProps.createdAt).toEqual(note.created_at);
- expect(noteHeaderProps.noteId).toEqual(note.id);
- });
+ it('should render note header content', () => {
+ const noteHeader = wrapper.findComponent(NoteHeader);
+ const noteHeaderProps = noteHeader.props();
- it('should render note actions', () => {
- const { author } = note;
- const noteActions = wrapper.find(NoteActions);
- const noteActionsProps = noteActions.props();
-
- expect(noteActionsProps.authorId).toBe(author.id);
- expect(noteActionsProps.noteId).toBe(note.id);
- expect(noteActionsProps.noteUrl).toBe(note.noteable_note_url);
- expect(noteActionsProps.accessLevel).toBe(note.human_access);
- expect(noteActionsProps.canEdit).toBe(note.current_user.can_edit);
- expect(noteActionsProps.canAwardEmoji).toBe(note.current_user.can_award_emoji);
- expect(noteActionsProps.canDelete).toBe(note.current_user.can_edit);
- expect(noteActionsProps.canReportAsAbuse).toBe(true);
- expect(noteActionsProps.canResolve).toBe(false);
- expect(noteActionsProps.reportAbusePath).toBe(note.report_abuse_path);
- expect(noteActionsProps.resolvable).toBe(false);
- expect(noteActionsProps.isResolved).toBe(false);
- expect(noteActionsProps.isResolving).toBe(false);
- expect(noteActionsProps.resolvedBy).toEqual({});
- });
+ expect(noteHeaderProps.author).toBe(note.author);
+ expect(noteHeaderProps.createdAt).toBe(note.created_at);
+ expect(noteHeaderProps.noteId).toBe(note.id);
+ });
- it('should render issue body', () => {
- const noteBody = wrapper.find(NoteBody);
- const noteBodyProps = noteBody.props();
+ it('should render note actions', () => {
+ const { author } = note;
+ const noteActions = wrapper.findComponent(NoteActions);
+ const noteActionsProps = noteActions.props();
- expect(noteBodyProps.note).toEqual(note);
- expect(noteBodyProps.line).toBe(null);
- expect(noteBodyProps.canEdit).toBe(note.current_user.can_edit);
- expect(noteBodyProps.isEditing).toBe(false);
- expect(noteBodyProps.helpPagePath).toBe('');
- });
+ expect(noteActionsProps.authorId).toBe(author.id);
+ expect(noteActionsProps.noteId).toBe(note.id);
+ expect(noteActionsProps.noteUrl).toBe(note.noteable_note_url);
+ expect(noteActionsProps.accessLevel).toBe(note.human_access);
+ expect(noteActionsProps.canEdit).toBe(note.current_user.can_edit);
+ expect(noteActionsProps.canAwardEmoji).toBe(note.current_user.can_award_emoji);
+ expect(noteActionsProps.canDelete).toBe(note.current_user.can_edit);
+ expect(noteActionsProps.canReportAsAbuse).toBe(true);
+ expect(noteActionsProps.canResolve).toBe(false);
+ expect(noteActionsProps.reportAbusePath).toBe(note.report_abuse_path);
+ expect(noteActionsProps.resolvable).toBe(false);
+ expect(noteActionsProps.isResolved).toBe(false);
+ expect(noteActionsProps.isResolving).toBe(false);
+ expect(noteActionsProps.resolvedBy).toEqual({});
+ });
- it('prevents note preview xss', (done) => {
- const imgSrc = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
- const noteBody = `<img src="${imgSrc}" onload="alert(1)" />`;
- const alertSpy = jest.spyOn(window, 'alert');
- store.hotUpdate({
- actions: {
- updateNote() {},
- setSelectedCommentPositionHover() {},
- },
+ it('should render issue body', () => {
+ const noteBody = wrapper.findComponent(NoteBody);
+ const noteBodyProps = noteBody.props();
+
+ expect(noteBodyProps.note).toBe(note);
+ expect(noteBodyProps.line).toBe(null);
+ expect(noteBodyProps.canEdit).toBe(note.current_user.can_edit);
+ expect(noteBodyProps.isEditing).toBe(false);
+ expect(noteBodyProps.helpPagePath).toBe('');
});
- const noteBodyComponent = wrapper.find(NoteBody);
- noteBodyComponent.vm.$emit('handleFormUpdate', noteBody, null, () => {});
+ it('prevents note preview xss', async () => {
+ const noteBody =
+ '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert(1)" />';
+ const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
+ const noteBodyComponent = wrapper.findComponent(NoteBody);
+
+ store.hotUpdate({
+ actions: {
+ updateNote() {},
+ setSelectedCommentPositionHover() {},
+ },
+ });
+
+ noteBodyComponent.vm.$emit('handleFormUpdate', noteBody, null, () => {});
- setImmediate(() => {
+ await waitForPromises();
expect(alertSpy).not.toHaveBeenCalled();
- expect(wrapper.vm.note.note_html).toEqual(escape(noteBody));
- done();
+ expect(wrapper.vm.note.note_html).toBe(escape(noteBody));
});
});
describe('cancel edit', () => {
- it('restores content of updated note', (done) => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('restores content of updated note', async () => {
const updatedText = 'updated note text';
store.hotUpdate({
actions: {
updateNote() {},
},
});
- const noteBody = wrapper.find(NoteBody);
+ const noteBody = wrapper.findComponent(NoteBody);
noteBody.vm.resetAutoSave = () => {};
noteBody.vm.$emit('handleFormUpdate', updatedText, null, () => {});
- wrapper.vm
- .$nextTick()
- .then(() => {
- const noteBodyProps = noteBody.props();
-
- expect(noteBodyProps.note.note_html).toBe(updatedText);
- noteBody.vm.$emit('cancelForm');
- })
- .then(() => wrapper.vm.$nextTick())
- .then(() => {
- const noteBodyProps = noteBody.props();
-
- expect(noteBodyProps.note.note_html).toBe(note.note_html);
- })
- .then(done)
- .catch(done.fail);
+ await wrapper.vm.$nextTick();
+ let noteBodyProps = noteBody.props();
+
+ expect(noteBodyProps.note.note_html).toBe(updatedText);
+
+ noteBody.vm.$emit('cancelForm');
+ await wrapper.vm.$nextTick();
+
+ noteBodyProps = noteBody.props();
+
+ expect(noteBodyProps.note.note_html).toBe(note.note_html);
+ });
+ });
+
+ describe('formUpdateHandler', () => {
+ const updateNote = jest.fn();
+ const params = ['', null, jest.fn(), ''];
+
+ const updateActions = () => {
+ store.hotUpdate({
+ actions: {
+ updateNote,
+ setSelectedCommentPositionHover() {},
+ },
+ });
+ };
+
+ afterEach(() => updateNote.mockReset());
+
+ it('responds to handleFormUpdate', () => {
+ createWrapper();
+ updateActions();
+ wrapper.findComponent(NoteBody).vm.$emit('handleFormUpdate', ...params);
+ expect(wrapper.emitted('handleUpdateNote')).toBeTruthy();
+ });
+
+ it('does not stringify empty position', () => {
+ createWrapper();
+ updateActions();
+ wrapper.findComponent(NoteBody).vm.$emit('handleFormUpdate', ...params);
+ expect(updateNote.mock.calls[0][1].note.note.position).toBeUndefined();
+ });
+
+ it('stringifies populated position', () => {
+ const position = { test: true };
+ const expectation = JSON.stringify(position);
+ createWrapper({ note: { ...note, position } });
+ updateActions();
+ wrapper.findComponent(NoteBody).vm.$emit('handleFormUpdate', ...params);
+ expect(updateNote.mock.calls[0][1].note.note.position).toBe(expectation);
});
});
});
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index efee72dea96..163501d5ce8 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -33,6 +33,8 @@ describe('note_app', () => {
let wrapper;
let store;
+ const findCommentButton = () => wrapper.find('[data-testid="comment-button"]');
+
const getComponentOrder = () => {
return wrapper
.findAll('#notes-list,.js-comment-form')
@@ -144,7 +146,7 @@ describe('note_app', () => {
});
it('should render form comment button as disabled', () => {
- expect(wrapper.find('.js-note-new-discussion').attributes('disabled')).toEqual('disabled');
+ expect(findCommentButton().props('disabled')).toEqual(true);
});
it('updates discussions badge', () => {