diff options
Diffstat (limited to 'spec/frontend/content_editor/components/bubble_menus/code_block_spec.js')
-rw-r--r-- | spec/frontend/content_editor/components/bubble_menus/code_block_spec.js | 157 |
1 files changed, 145 insertions, 12 deletions
diff --git a/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js index 3a15ea45f40..646d068e795 100644 --- a/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js @@ -1,21 +1,33 @@ import { BubbleMenu } from '@tiptap/vue-2'; -import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; -import Vue from 'vue'; +import { + GlDropdown, + GlDropdownForm, + GlDropdownItem, + GlSearchBoxByType, + GlFormInput, +} from '@gitlab/ui'; +import { nextTick } from 'vue'; import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { stubComponent } from 'helpers/stub_component'; import CodeBlockBubbleMenu from '~/content_editor/components/bubble_menus/code_block.vue'; import eventHubFactory from '~/helpers/event_hub_factory'; import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight'; +import Diagram from '~/content_editor/extensions/diagram'; import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader'; import { createTestEditor, emitEditorEvent } from '../../test_utils'; +const createFakeEvent = () => ({ preventDefault: jest.fn(), stopPropagation: jest.fn() }); + describe('content_editor/components/bubble_menus/code_block', () => { let wrapper; let tiptapEditor; + let contentEditor; let bubbleMenu; let eventHub; const buildEditor = () => { - tiptapEditor = createTestEditor({ extensions: [CodeBlockHighlight] }); + tiptapEditor = createTestEditor({ extensions: [CodeBlockHighlight, Diagram] }); + contentEditor = { renderDiagram: jest.fn() }; eventHub = eventHubFactory(); }; @@ -23,8 +35,12 @@ describe('content_editor/components/bubble_menus/code_block', () => { wrapper = mountExtended(CodeBlockBubbleMenu, { provide: { tiptapEditor, + contentEditor, eventHub, }, + stubs: { + GlDropdownItem: stubComponent(GlDropdownItem), + }, }); }; @@ -36,7 +52,7 @@ describe('content_editor/components/bubble_menus/code_block', () => { checked: x.props('isChecked'), })); - beforeEach(() => { + beforeEach(async () => { buildEditor(); buildWrapper(); }); @@ -73,6 +89,15 @@ describe('content_editor/components/bubble_menus/code_block', () => { expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Javascript'); }); + it('selects diagram sytnax for mermaid', async () => { + tiptapEditor.commands.insertContent('<pre lang="mermaid">test</pre>'); + bubbleMenu = wrapper.findComponent(BubbleMenu); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Diagram (mermaid)'); + }); + 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); @@ -104,22 +129,57 @@ describe('content_editor/components/bubble_menus/code_block', () => { }); }); + describe('preview button', () => { + it('does not appear for a regular code block', async () => { + tiptapEditor.commands.insertContent('<pre lang="javascript">var a = 2;</pre>'); + + expect(wrapper.findByTestId('preview-diagram').exists()).toBe(false); + }); + + it.each` + diagramType | diagramCode + ${'mermaid'} | ${'<pre lang="mermaid">graph TD;\n A-->B;</pre>'} + ${'nomnoml'} | ${'<img data-diagram="nomnoml" data-diagram-src="data:text/plain;base64,WzxmcmFtZT5EZWNvcmF0b3IgcGF0dGVybl0=">'} + `('toggles preview for a $diagramType diagram', async ({ diagramType, diagramCode }) => { + tiptapEditor.commands.insertContent(diagramCode); + + await nextTick(); + await wrapper.findByTestId('preview-diagram').vm.$emit('click'); + + expect(tiptapEditor.getAttributes(Diagram.name)).toEqual({ + isDiagram: true, + language: diagramType, + showPreview: false, + }); + + await wrapper.findByTestId('preview-diagram').vm.$emit('click'); + + expect(tiptapEditor.getAttributes(Diagram.name)).toEqual({ + isDiagram: true, + language: diagramType, + showPreview: true, + }); + }); + }); + 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(); + await 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 }, - ]); + expect(findDropdownItemsData()).toEqual( + expect.arrayContaining([ + { 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', () => { @@ -128,7 +188,7 @@ describe('content_editor/components/bubble_menus/code_block', () => { findDropdownItems().at(1).vm.$emit('click'); - await Vue.nextTick(); + await nextTick(); }); it('loads language', () => { @@ -152,5 +212,78 @@ describe('content_editor/components/bubble_menus/code_block', () => { expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Java'); }); }); + + describe('Create custom type', () => { + beforeEach(async () => { + tiptapEditor.commands.insertContent('<pre lang="javascript">var a = 2;</pre>'); + + await wrapper.findComponent(GlDropdown).vm.show(); + await wrapper.findByTestId('create-custom-type').trigger('click'); + }); + + it('shows custom language input form and hides dropdown items', () => { + expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(false); + expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(false); + expect(wrapper.findComponent(GlDropdownForm).exists()).toBe(true); + }); + + describe('on clicking back', () => { + it('hides the custom language input form and shows dropdown items', async () => { + await wrapper.findByRole('button', { name: 'Go back' }).trigger('click'); + + expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(true); + expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(true); + expect(wrapper.findComponent(GlDropdownForm).exists()).toBe(false); + }); + }); + + describe('on clicking cancel', () => { + it('hides the custom language input form and shows dropdown items', async () => { + await wrapper.findByRole('button', { name: 'Cancel' }).trigger('click'); + + expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(true); + expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(true); + expect(wrapper.findComponent(GlDropdownForm).exists()).toBe(false); + }); + }); + + describe('on dropdown hide', () => { + it('hides the form', async () => { + wrapper.findComponent(GlFormInput).setValue('foobar'); + await wrapper.findComponent(GlDropdown).vm.$emit('hide'); + + expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(true); + expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(true); + expect(wrapper.findComponent(GlDropdownForm).exists()).toBe(false); + }); + }); + + describe('on clicking apply', () => { + beforeEach(async () => { + wrapper.findComponent(GlFormInput).setValue('foobar'); + await wrapper.findComponent(GlDropdownForm).vm.$emit('submit', createFakeEvent()); + + await emitEditorEvent({ event: 'transaction', tiptapEditor }); + }); + + it('hides the custom language input form and shows dropdown items', async () => { + expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(true); + expect(wrapper.findComponent(GlSearchBoxByType).exists()).toBe(true); + expect(wrapper.findComponent(GlDropdownForm).exists()).toBe(false); + }); + + it('updates dropdown value to the custom language type', () => { + expect(wrapper.findComponent(GlDropdown).props('text')).toBe('Custom (foobar)'); + }); + + it('updates tiptap editor to the custom language type', () => { + expect(tiptapEditor.getAttributes(CodeBlockHighlight.name)).toEqual( + expect.objectContaining({ + language: 'foobar', + }), + ); + }); + }); + }); }); }); |