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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-08 12:08:58 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-08 12:08:58 +0300
commitee5990fa228fbbb7223b88837f83dd76feb75b9c (patch)
tree0d6e9e2fac97f23878dd155c4f25a964b250dd23 /spec/frontend/notes
parent02255a8b6d16c4c9fc7ec5453df18f9c7e6b085e (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/notes')
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js114
1 files changed, 111 insertions, 3 deletions
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 6393394b68c..bab90723578 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -1,8 +1,9 @@
-import { GlDropdown } from '@gitlab/ui';
+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';
@@ -10,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');
@@ -18,6 +20,8 @@ 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;
@@ -28,6 +32,33 @@ describe('issue_comment_form component', () => {
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 {
@@ -103,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 });