diff options
Diffstat (limited to 'spec/frontend/content_editor/components')
-rw-r--r-- | spec/frontend/content_editor/components/code_block_bubble_menu_spec.js | 142 | ||||
-rw-r--r-- | spec/frontend/content_editor/components/formatting_bubble_menu_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/content_editor/components/wrappers/media_spec.js (renamed from spec/frontend/content_editor/components/wrappers/image_spec.js) | 21 |
3 files changed, 155 insertions, 10 deletions
diff --git a/spec/frontend/content_editor/components/code_block_bubble_menu_spec.js b/spec/frontend/content_editor/components/code_block_bubble_menu_spec.js new file mode 100644 index 00000000000..074c311495f --- /dev/null +++ b/spec/frontend/content_editor/components/code_block_bubble_menu_spec.js @@ -0,0 +1,142 @@ +import { BubbleMenu } from '@tiptap/vue-2'; +import { GlButton, GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; +import Vue from 'vue'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import CodeBlockBubbleMenu from '~/content_editor/components/code_block_bubble_menu.vue'; +import eventHubFactory from '~/helpers/event_hub_factory'; +import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight'; +import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader'; +import { createTestEditor, emitEditorEvent } from '../test_utils'; + +describe('content_editor/components/code_block_bubble_menu', () => { + let wrapper; + let tiptapEditor; + let bubbleMenu; + let eventHub; + + const buildEditor = () => { + tiptapEditor = createTestEditor({ extensions: [CodeBlockHighlight] }); + eventHub = eventHubFactory(); + }; + + const buildWrapper = () => { + wrapper = mountExtended(CodeBlockBubbleMenu, { + provide: { + tiptapEditor, + eventHub, + }, + }); + }; + + const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); + const findDropdownItemsData = () => + findDropdownItems().wrappers.map((x) => ({ + text: x.text(), + visible: x.isVisible(), + checked: x.props('isChecked'), + })); + + beforeEach(() => { + buildEditor(); + buildWrapper(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders bubble menu component', async () => { + tiptapEditor.commands.insertContent('<pre>test</pre>'); + bubbleMenu = wrapper.findComponent(BubbleMenu); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + + expect(bubbleMenu.props('editor')).toBe(tiptapEditor); + expect(bubbleMenu.classes()).toEqual(['gl-shadow', 'gl-rounded-base']); + }); + + it('selects plaintext language by default', async () => { + tiptapEditor.commands.insertContent('<pre>test</pre>'); + bubbleMenu = wrapper.findComponent(BubbleMenu); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Plain text'); + }); + + it('selects appropriate language based on the code block', async () => { + tiptapEditor.commands.insertContent('<pre lang="javascript">var a = 2;</pre>'); + bubbleMenu = wrapper.findComponent(BubbleMenu); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Javascript'); + }); + + it("selects Custom (syntax) if the language doesn't exist in the list", async () => { + tiptapEditor.commands.insertContent('<pre lang="nomnoml">test</pre>'); + bubbleMenu = wrapper.findComponent(BubbleMenu); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Custom (nomnoml)'); + }); + + it('delete button deletes the code block', async () => { + tiptapEditor.commands.insertContent('<pre lang="javascript">var a = 2;</pre>'); + + await wrapper.findComponent(GlButton).vm.$emit('click'); + + expect(tiptapEditor.getText()).toBe(''); + }); + + describe('when opened and search is changed', () => { + beforeEach(async () => { + tiptapEditor.commands.insertContent('<pre lang="javascript">var a = 2;</pre>'); + + wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', 'js'); + + await Vue.nextTick(); + }); + + it('shows dropdown items', () => { + expect(findDropdownItemsData()).toEqual([ + { text: 'Javascript', visible: true, checked: true }, + { text: 'Java', visible: true, checked: false }, + { text: 'Javascript', visible: false, checked: false }, + { text: 'JSON', visible: true, checked: false }, + ]); + }); + + describe('when dropdown item is clicked', () => { + beforeEach(async () => { + jest.spyOn(codeBlockLanguageLoader, 'loadLanguages').mockResolvedValue(); + + findDropdownItems().at(1).vm.$emit('click'); + + await Vue.nextTick(); + }); + + it('loads language', () => { + expect(codeBlockLanguageLoader.loadLanguages).toHaveBeenCalledWith(['java']); + }); + + it('sets code block', () => { + expect(tiptapEditor.getJSON()).toMatchObject({ + content: [ + { + type: 'codeBlock', + attrs: { + language: 'java', + }, + }, + ], + }); + }); + + it('updates selected dropdown', () => { + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Java'); + }); + }); + }); +}); diff --git a/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js b/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js index e44a7fa4ddb..192ddee78c6 100644 --- a/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js @@ -9,7 +9,7 @@ import { } from '~/content_editor/constants'; import { createTestEditor } from '../test_utils'; -describe('content_editor/components/top_toolbar', () => { +describe('content_editor/components/formatting_bubble_menu', () => { let wrapper; let trackingSpy; let tiptapEditor; diff --git a/spec/frontend/content_editor/components/wrappers/image_spec.js b/spec/frontend/content_editor/components/wrappers/media_spec.js index 7b057f9cabc..3e95e2f3914 100644 --- a/spec/frontend/content_editor/components/wrappers/image_spec.js +++ b/spec/frontend/content_editor/components/wrappers/media_spec.js @@ -1,21 +1,24 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { NodeViewWrapper } from '@tiptap/vue-2'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import ImageWrapper from '~/content_editor/components/wrappers/image.vue'; +import MediaWrapper from '~/content_editor/components/wrappers/media.vue'; -describe('content/components/wrappers/image', () => { +describe('content/components/wrappers/media', () => { let wrapper; const createWrapper = async (nodeAttrs = {}) => { - wrapper = shallowMountExtended(ImageWrapper, { + wrapper = shallowMountExtended(MediaWrapper, { propsData: { node: { attrs: nodeAttrs, + type: { + name: 'image', + }, }, }, }); }; - const findImage = () => wrapper.findByTestId('image'); + const findMedia = () => wrapper.findByTestId('media'); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); afterEach(() => { @@ -33,7 +36,7 @@ describe('content/components/wrappers/image', () => { createWrapper({ src }); - expect(findImage().attributes().src).toBe(src); + expect(findMedia().attributes().src).toBe(src); }); describe('when uploading', () => { @@ -45,8 +48,8 @@ describe('content/components/wrappers/image', () => { expect(findLoadingIcon().exists()).toBe(true); }); - it('adds gl-opacity-5 class selector to image', () => { - expect(findImage().classes()).toContain('gl-opacity-5'); + it('adds gl-opacity-5 class selector to the media tag', () => { + expect(findMedia().classes()).toContain('gl-opacity-5'); }); }); @@ -59,8 +62,8 @@ describe('content/components/wrappers/image', () => { expect(findLoadingIcon().exists()).toBe(false); }); - it('does not add gl-opacity-5 class selector to image', () => { - expect(findImage().classes()).not.toContain('gl-opacity-5'); + it('does not add gl-opacity-5 class selector to the media tag', () => { + expect(findMedia().classes()).not.toContain('gl-opacity-5'); }); }); }); |