diff options
Diffstat (limited to 'spec/frontend/content_editor/components/content_editor_spec.js')
-rw-r--r-- | spec/frontend/content_editor/components/content_editor_spec.js | 166 |
1 files changed, 125 insertions, 41 deletions
diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js index 563e80e04c1..d516baf6f0f 100644 --- a/spec/frontend/content_editor/components/content_editor_spec.js +++ b/spec/frontend/content_editor/components/content_editor_spec.js @@ -1,91 +1,175 @@ -import { GlAlert } from '@gitlab/ui'; +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 ContentEditorError from '~/content_editor/components/content_editor_error.vue'; +import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue'; +import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; import TopToolbar from '~/content_editor/components/top_toolbar.vue'; -import { createContentEditor } from '~/content_editor/services/create_content_editor'; +import { + LOADING_CONTENT_EVENT, + LOADING_SUCCESS_EVENT, + LOADING_ERROR_EVENT, +} from '~/content_editor/constants'; +import { emitEditorEvent } from '../test_utils'; + +jest.mock('~/emoji'); describe('ContentEditor', () => { let wrapper; - let editor; + let contentEditor; + let renderMarkdown; + const uploadsPath = '/uploads'; const findEditorElement = () => wrapper.findByTestId('content-editor'); - const findErrorAlert = () => wrapper.findComponent(GlAlert); + const findEditorContent = () => wrapper.findComponent(EditorContent); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + + const createWrapper = (propsData = {}) => { + renderMarkdown = jest.fn(); - const createWrapper = async (contentEditor) => { wrapper = shallowMountExtended(ContentEditor, { propsData: { - contentEditor, + renderMarkdown, + uploadsPath, + ...propsData, + }, + stubs: { + EditorStateObserver, + ContentEditorProvider, + }, + listeners: { + initialized(editor) { + contentEditor = editor; + }, }, }); }; - beforeEach(() => { - editor = createContentEditor({ renderMarkdown: () => true }); - }); - afterEach(() => { wrapper.destroy(); }); - it('renders editor content component and attaches editor instance', () => { - createWrapper(editor); + it('triggers initialized event and provides contentEditor instance as event data', () => { + createWrapper(); - const editorContent = wrapper.findComponent(EditorContent); + expect(contentEditor).not.toBeFalsy(); + }); + + it('renders EditorContent component and provides tiptapEditor instance', () => { + createWrapper(); + + const editorContent = findEditorContent(); - expect(editorContent.props().editor).toBe(editor.tiptapEditor); + expect(editorContent.props().editor).toBe(contentEditor.tiptapEditor); expect(editorContent.classes()).toContain('md'); }); - it('renders top toolbar component and attaches editor instance', () => { - createWrapper(editor); + it('renders ContentEditorProvider component', () => { + createWrapper(); - expect(wrapper.findComponent(TopToolbar).props().contentEditor).toBe(editor); + expect(wrapper.findComponent(ContentEditorProvider).exists()).toBe(true); }); - it.each` - isFocused | classes - ${true} | ${['md-area', 'is-focused']} - ${false} | ${['md-area']} - `( - 'has $classes class selectors when tiptapEditor.isFocused = $isFocused', - ({ isFocused, classes }) => { - editor.tiptapEditor.isFocused = isFocused; - createWrapper(editor); + it('renders top toolbar component', () => { + createWrapper(); + + expect(wrapper.findComponent(TopToolbar).exists()).toBe(true); + }); - expect(findEditorElement().classes()).toStrictEqual(classes); - }, - ); + it('adds is-focused class when focus event is emitted', async () => { + createWrapper(); - it('adds isFocused class when tiptapEditor is focused', () => { - editor.tiptapEditor.isFocused = true; - createWrapper(editor); + await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'focus' }); expect(findEditorElement().classes()).toContain('is-focused'); }); - describe('displaying error', () => { - const error = 'Content Editor error'; + it('removes is-focused class when blur event is emitted', async () => { + createWrapper(); + + await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'focus' }); + await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'blur' }); + + expect(findEditorElement().classes()).not.toContain('is-focused'); + }); + + it('emits change event when document is updated', async () => { + createWrapper(); + + await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'update' }); + + expect(wrapper.emitted('change')).toEqual([ + [ + { + empty: contentEditor.empty, + }, + ], + ]); + }); + + it('renders content_editor_error component', () => { + createWrapper(); + + expect(wrapper.findComponent(ContentEditorError).exists()).toBe(true); + }); + describe('when loading content', () => { beforeEach(async () => { - createWrapper(editor); + createWrapper(); - editor.tiptapEditor.emit('error', error); + contentEditor.emit(LOADING_CONTENT_EVENT); await nextTick(); }); - it('displays error notifications from the tiptap editor', () => { - expect(findErrorAlert().text()).toBe(error); + it('displays loading indicator', () => { + expect(findLoadingIcon().exists()).toBe(true); }); - it('allows dismissing an error alert', async () => { - findErrorAlert().vm.$emit('dismiss'); + it('hides EditorContent component', () => { + expect(findEditorContent().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('displays EditorContent component', () => { + expect(findEditorContent().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); + }); - expect(findErrorAlert().exists()).toBe(false); + it('displays EditorContent component', () => { + expect(findEditorContent().exists()).toBe(true); }); }); }); |