From 41fe97390ceddf945f3d967b8fdb3de4c66b7dea Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 18 Mar 2022 20:02:30 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-9-stable-ee --- .../components/content_editor_alert_spec.js | 17 +++-- .../components/content_editor_spec.js | 77 ++-------------------- .../components/editor_state_observer_spec.js | 63 +++++++++++++++++- .../components/loading_indicator_spec.js | 71 ++++++++++++++++++++ .../components/toolbar_button_spec.js | 2 + .../components/toolbar_link_button_spec.js | 2 + .../components/toolbar_text_style_dropdown_spec.js | 2 + 7 files changed, 156 insertions(+), 78 deletions(-) create mode 100644 spec/frontend/content_editor/components/loading_indicator_spec.js (limited to 'spec/frontend/content_editor/components') diff --git a/spec/frontend/content_editor/components/content_editor_alert_spec.js b/spec/frontend/content_editor/components/content_editor_alert_spec.js index 2ddcd8f024e..12484cb13c6 100644 --- a/spec/frontend/content_editor/components/content_editor_alert_spec.js +++ b/spec/frontend/content_editor/components/content_editor_alert_spec.js @@ -3,20 +3,25 @@ import { nextTick } from 'vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue'; import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; -import { createTestEditor, emitEditorEvent } from '../test_utils'; +import eventHubFactory from '~/helpers/event_hub_factory'; +import { ALERT_EVENT } from '~/content_editor/constants'; +import { createTestEditor } from '../test_utils'; describe('content_editor/components/content_editor_alert', () => { let wrapper; let tiptapEditor; + let eventHub; const findErrorAlert = () => wrapper.findComponent(GlAlert); const createWrapper = async () => { tiptapEditor = createTestEditor(); + eventHub = eventHubFactory(); wrapper = shallowMountExtended(ContentEditorAlert, { provide: { tiptapEditor, + eventHub, }, stubs: { EditorStateObserver, @@ -37,7 +42,9 @@ describe('content_editor/components/content_editor_alert', () => { async ({ message, variant }) => { createWrapper(); - await emitEditorEvent({ tiptapEditor, event: 'alert', params: { message, variant } }); + eventHub.$emit(ALERT_EVENT, { message, variant }); + + await nextTick(); expect(findErrorAlert().text()).toBe(message); expect(findErrorAlert().attributes().variant).toBe(variant); @@ -48,11 +55,9 @@ describe('content_editor/components/content_editor_alert', () => { const message = 'error message'; createWrapper(); - - await emitEditorEvent({ tiptapEditor, event: 'alert', params: { message } }); - + eventHub.$emit(ALERT_EVENT, { message }); + await nextTick(); findErrorAlert().vm.$emit('dismiss'); - await nextTick(); expect(findErrorAlert().exists()).toBe(false); diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js index 9a772c41e52..73fcfeab8bc 100644 --- a/spec/frontend/content_editor/components/content_editor_spec.js +++ b/spec/frontend/content_editor/components/content_editor_spec.js @@ -1,6 +1,4 @@ -import { GlLoadingIcon } from '@gitlab/ui'; import { EditorContent } from '@tiptap/vue-2'; -import { nextTick } from 'vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ContentEditor from '~/content_editor/components/content_editor.vue'; import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue'; @@ -8,11 +6,7 @@ import ContentEditorProvider from '~/content_editor/components/content_editor_pr import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; import FormattingBubbleMenu from '~/content_editor/components/formatting_bubble_menu.vue'; import TopToolbar from '~/content_editor/components/top_toolbar.vue'; -import { - LOADING_CONTENT_EVENT, - LOADING_SUCCESS_EVENT, - LOADING_ERROR_EVENT, -} from '~/content_editor/constants'; +import LoadingIndicator from '~/content_editor/components/loading_indicator.vue'; import { emitEditorEvent } from '../test_utils'; jest.mock('~/emoji'); @@ -25,9 +19,6 @@ describe('ContentEditor', () => { const findEditorElement = () => wrapper.findByTestId('content-editor'); const findEditorContent = () => wrapper.findComponent(EditorContent); - const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findBubbleMenu = () => wrapper.findComponent(FormattingBubbleMenu); - const createWrapper = (propsData = {}) => { renderMarkdown = jest.fn(); @@ -117,69 +108,15 @@ describe('ContentEditor', () => { expect(wrapper.findComponent(ContentEditorAlert).exists()).toBe(true); }); - describe('when loading content', () => { - beforeEach(async () => { - createWrapper(); - - contentEditor.emit(LOADING_CONTENT_EVENT); - - await nextTick(); - }); - - it('displays loading indicator', () => { - expect(findLoadingIcon().exists()).toBe(true); - }); - - it('hides EditorContent component', () => { - expect(findEditorContent().exists()).toBe(false); - }); - - it('hides formatting bubble menu', () => { - expect(findBubbleMenu().exists()).toBe(false); - }); - }); - - describe('when loading content succeeds', () => { - beforeEach(async () => { - createWrapper(); - - contentEditor.emit(LOADING_CONTENT_EVENT); - await nextTick(); - contentEditor.emit(LOADING_SUCCESS_EVENT); - await nextTick(); - }); - - it('hides loading indicator', () => { - expect(findLoadingIcon().exists()).toBe(false); - }); + it('renders loading indicator component', () => { + createWrapper(); - it('displays EditorContent component', () => { - expect(findEditorContent().exists()).toBe(true); - }); + expect(wrapper.findComponent(LoadingIndicator).exists()).toBe(true); }); - describe('when loading content fails', () => { - const error = 'error'; - - beforeEach(async () => { - createWrapper(); - - contentEditor.emit(LOADING_CONTENT_EVENT); - await nextTick(); - contentEditor.emit(LOADING_ERROR_EVENT, error); - await nextTick(); - }); - - it('hides loading indicator', () => { - expect(findLoadingIcon().exists()).toBe(false); - }); - - it('displays EditorContent component', () => { - expect(findEditorContent().exists()).toBe(true); - }); + it('renders formatting bubble menu', () => { + createWrapper(); - it('displays formatting bubble menu', () => { - expect(findBubbleMenu().exists()).toBe(true); - }); + expect(wrapper.findComponent(FormattingBubbleMenu).exists()).toBe(true); }); }); diff --git a/spec/frontend/content_editor/components/editor_state_observer_spec.js b/spec/frontend/content_editor/components/editor_state_observer_spec.js index 5e4bb348e1f..51a594a606b 100644 --- a/spec/frontend/content_editor/components/editor_state_observer_spec.js +++ b/spec/frontend/content_editor/components/editor_state_observer_spec.js @@ -3,6 +3,13 @@ import { each } from 'lodash'; import EditorStateObserver, { tiptapToComponentMap, } from '~/content_editor/components/editor_state_observer.vue'; +import eventHubFactory from '~/helpers/event_hub_factory'; +import { + LOADING_CONTENT_EVENT, + LOADING_SUCCESS_EVENT, + LOADING_ERROR_EVENT, + ALERT_EVENT, +} from '~/content_editor/constants'; import { createTestEditor } from '../test_utils'; describe('content_editor/components/editor_state_observer', () => { @@ -11,19 +18,29 @@ describe('content_editor/components/editor_state_observer', () => { let onDocUpdateListener; let onSelectionUpdateListener; let onTransactionListener; + let onLoadingContentListener; + let onLoadingSuccessListener; + let onLoadingErrorListener; + let onAlertListener; + let eventHub; const buildEditor = () => { tiptapEditor = createTestEditor(); + eventHub = eventHubFactory(); jest.spyOn(tiptapEditor, 'on'); }; const buildWrapper = () => { wrapper = shallowMount(EditorStateObserver, { - provide: { tiptapEditor }, + provide: { tiptapEditor, eventHub }, listeners: { docUpdate: onDocUpdateListener, selectionUpdate: onSelectionUpdateListener, transaction: onTransactionListener, + [ALERT_EVENT]: onAlertListener, + [LOADING_CONTENT_EVENT]: onLoadingContentListener, + [LOADING_SUCCESS_EVENT]: onLoadingSuccessListener, + [LOADING_ERROR_EVENT]: onLoadingErrorListener, }, }); }; @@ -32,8 +49,11 @@ describe('content_editor/components/editor_state_observer', () => { onDocUpdateListener = jest.fn(); onSelectionUpdateListener = jest.fn(); onTransactionListener = jest.fn(); + onAlertListener = jest.fn(); + onLoadingSuccessListener = jest.fn(); + onLoadingContentListener = jest.fn(); + onLoadingErrorListener = jest.fn(); buildEditor(); - buildWrapper(); }); afterEach(() => { @@ -44,6 +64,8 @@ describe('content_editor/components/editor_state_observer', () => { it('emits update, selectionUpdate, and transaction events', () => { const content = '

My paragraph

'; + buildWrapper(); + tiptapEditor.commands.insertContent(content); expect(onDocUpdateListener).toHaveBeenCalledWith( @@ -58,10 +80,27 @@ describe('content_editor/components/editor_state_observer', () => { }); }); + it.each` + event | listener + ${ALERT_EVENT} | ${() => onAlertListener} + ${LOADING_CONTENT_EVENT} | ${() => onLoadingContentListener} + ${LOADING_SUCCESS_EVENT} | ${() => onLoadingSuccessListener} + ${LOADING_ERROR_EVENT} | ${() => onLoadingErrorListener} + `('listens to $event event in the eventBus object', ({ event, listener }) => { + const args = {}; + + buildWrapper(); + + eventHub.$emit(event, args); + expect(listener()).toHaveBeenCalledWith(args); + }); + describe('when component is destroyed', () => { it('removes onTiptapDocUpdate and onTiptapSelectionUpdate hooks', () => { jest.spyOn(tiptapEditor, 'off'); + buildWrapper(); + wrapper.destroy(); each(tiptapToComponentMap, (_, tiptapEvent) => { @@ -71,5 +110,25 @@ describe('content_editor/components/editor_state_observer', () => { ); }); }); + + it.each` + event + ${ALERT_EVENT} + ${LOADING_CONTENT_EVENT} + ${LOADING_SUCCESS_EVENT} + ${LOADING_ERROR_EVENT} + `('removes $event event hook from eventHub', ({ event }) => { + jest.spyOn(eventHub, '$off'); + jest.spyOn(eventHub, '$on'); + + buildWrapper(); + + wrapper.destroy(); + + expect(eventHub.$off).toHaveBeenCalledWith( + event, + eventHub.$on.mock.calls.find(([eventName]) => eventName === event)[1], + ); + }); }); }); diff --git a/spec/frontend/content_editor/components/loading_indicator_spec.js b/spec/frontend/content_editor/components/loading_indicator_spec.js new file mode 100644 index 00000000000..e4fb09b70a4 --- /dev/null +++ b/spec/frontend/content_editor/components/loading_indicator_spec.js @@ -0,0 +1,71 @@ +import { GlLoadingIcon } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import LoadingIndicator from '~/content_editor/components/loading_indicator.vue'; +import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; +import { + LOADING_CONTENT_EVENT, + LOADING_SUCCESS_EVENT, + LOADING_ERROR_EVENT, +} from '~/content_editor/constants'; + +describe('content_editor/components/loading_indicator', () => { + let wrapper; + + const findEditorStateObserver = () => wrapper.findComponent(EditorStateObserver); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + + const createWrapper = () => { + wrapper = shallowMountExtended(LoadingIndicator); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when loading content', () => { + beforeEach(async () => { + createWrapper(); + + findEditorStateObserver().vm.$emit(LOADING_CONTENT_EVENT); + + await nextTick(); + }); + + it('displays loading indicator', () => { + expect(findLoadingIcon().exists()).toBe(true); + }); + }); + + describe('when loading content succeeds', () => { + beforeEach(async () => { + createWrapper(); + + findEditorStateObserver().vm.$emit(LOADING_CONTENT_EVENT); + await nextTick(); + findEditorStateObserver().vm.$emit(LOADING_SUCCESS_EVENT); + await nextTick(); + }); + + it('hides loading indicator', () => { + expect(findLoadingIcon().exists()).toBe(false); + }); + }); + + describe('when loading content fails', () => { + const error = 'error'; + + beforeEach(async () => { + createWrapper(); + + findEditorStateObserver().vm.$emit(LOADING_CONTENT_EVENT); + await nextTick(); + findEditorStateObserver().vm.$emit(LOADING_ERROR_EVENT, error); + await nextTick(); + }); + + it('hides loading indicator', () => { + expect(findLoadingIcon().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/content_editor/components/toolbar_button_spec.js b/spec/frontend/content_editor/components/toolbar_button_spec.js index 60263c46bdd..ce50482302d 100644 --- a/spec/frontend/content_editor/components/toolbar_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_button_spec.js @@ -2,6 +2,7 @@ import { GlButton } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; import ToolbarButton from '~/content_editor/components/toolbar_button.vue'; +import eventHubFactory from '~/helpers/event_hub_factory'; import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_utils'; describe('content_editor/components/toolbar_button', () => { @@ -25,6 +26,7 @@ describe('content_editor/components/toolbar_button', () => { }, provide: { tiptapEditor, + eventHub: eventHubFactory(), }, propsData: { contentType: CONTENT_TYPE, diff --git a/spec/frontend/content_editor/components/toolbar_link_button_spec.js b/spec/frontend/content_editor/components/toolbar_link_button_spec.js index 0cf488260bd..fc26a9da471 100644 --- a/spec/frontend/content_editor/components/toolbar_link_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_link_button_spec.js @@ -1,6 +1,7 @@ import { GlDropdown, GlButton, GlFormInputGroup } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import ToolbarLinkButton from '~/content_editor/components/toolbar_link_button.vue'; +import eventHubFactory from '~/helpers/event_hub_factory'; import Link from '~/content_editor/extensions/link'; import { hasSelection } from '~/content_editor/services/utils'; import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_utils'; @@ -15,6 +16,7 @@ describe('content_editor/components/toolbar_link_button', () => { wrapper = mountExtended(ToolbarLinkButton, { provide: { tiptapEditor: editor, + eventHub: eventHubFactory(), }, }); }; diff --git a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js index 65c1c8c8310..608be1bd693 100644 --- a/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js +++ b/spec/frontend/content_editor/components/toolbar_text_style_dropdown_spec.js @@ -4,6 +4,7 @@ import EditorStateObserver from '~/content_editor/components/editor_state_observ import ToolbarTextStyleDropdown from '~/content_editor/components/toolbar_text_style_dropdown.vue'; import { TEXT_STYLE_DROPDOWN_ITEMS } from '~/content_editor/constants'; import Heading from '~/content_editor/extensions/heading'; +import eventHubFactory from '~/helpers/event_hub_factory'; import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_utils'; describe('content_editor/components/toolbar_text_style_dropdown', () => { @@ -27,6 +28,7 @@ describe('content_editor/components/toolbar_text_style_dropdown', () => { }, provide: { tiptapEditor, + eventHub: eventHubFactory(), }, propsData: { ...propsData, -- cgit v1.2.3