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:
Diffstat (limited to 'spec/frontend/vue_shared/components/rich_content_editor')
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js214
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal_spec.js73
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js41
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js44
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js69
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js222
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/build_custom_renderer_spec.js32
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js218
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token_spec.js88
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js54
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition_spec.js25
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline_spec.js33
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_heading_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js37
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js55
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js84
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_list_item_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js23
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_utils_spec.js109
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js11
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js57
22 files changed, 0 insertions, 1537 deletions
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js
deleted file mode 100644
index ce2b0d1ddc1..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import buildCustomRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
-import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer';
-import {
- generateToolbarItem,
- addCustomEventListener,
- removeCustomEventListener,
- registerHTMLToMarkdownRenderer,
- addImage,
- insertVideo,
- getMarkdown,
- getEditorOptions,
-} from '~/vue_shared/components/rich_content_editor/services/editor_service';
-import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
-
-jest.mock('~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer');
-jest.mock('~/vue_shared/components/rich_content_editor/services/build_custom_renderer');
-jest.mock('~/vue_shared/components/rich_content_editor/services/sanitize_html');
-
-describe('Editor Service', () => {
- let mockInstance;
- let event;
- let handler;
- const parseHtml = (str) => {
- const wrapper = document.createElement('div');
- wrapper.innerHTML = str;
- return wrapper.firstChild;
- };
-
- beforeEach(() => {
- mockInstance = {
- eventManager: { addEventType: jest.fn(), removeEventHandler: jest.fn(), listen: jest.fn() },
- editor: {
- exec: jest.fn(),
- isWysiwygMode: jest.fn(),
- getSquire: jest.fn(),
- insertText: jest.fn(),
- },
- invoke: jest.fn(),
- toMarkOptions: {
- renderer: {
- constructor: {
- factory: jest.fn(),
- },
- },
- },
- };
- event = 'someCustomEvent';
- handler = jest.fn();
- });
-
- describe('generateToolbarItem', () => {
- const config = {
- icon: 'bold',
- command: 'some-command',
- tooltip: 'Some Tooltip',
- event: 'some-event',
- };
-
- const generatedItem = generateToolbarItem(config);
-
- it('generates the correct command', () => {
- expect(generatedItem.options.command).toBe(config.command);
- });
-
- it('generates the correct event', () => {
- expect(generatedItem.options.event).toBe(config.event);
- });
-
- it('generates a divider when isDivider is set to true', () => {
- const isDivider = true;
-
- expect(generateToolbarItem({ isDivider })).toBe('divider');
- });
- });
-
- describe('addCustomEventListener', () => {
- it('registers an event type on the instance and adds an event handler', () => {
- addCustomEventListener(mockInstance, event, handler);
-
- expect(mockInstance.eventManager.addEventType).toHaveBeenCalledWith(event);
- expect(mockInstance.eventManager.listen).toHaveBeenCalledWith(event, handler);
- });
- });
-
- describe('removeCustomEventListener', () => {
- it('removes an event handler from the instance', () => {
- removeCustomEventListener(mockInstance, event, handler);
-
- expect(mockInstance.eventManager.removeEventHandler).toHaveBeenCalledWith(event, handler);
- });
- });
-
- describe('addImage', () => {
- const file = new File([], 'some-file.jpg');
- const mockImage = { imageUrl: 'some/url.png', altText: 'some alt text' };
-
- it('calls the insertElement method on the squire instance when in WYSIWYG mode', () => {
- jest.spyOn(URL, 'createObjectURL');
- mockInstance.editor.isWysiwygMode.mockReturnValue(true);
- mockInstance.editor.getSquire.mockReturnValue({ insertElement: jest.fn() });
-
- addImage(mockInstance, mockImage, file);
-
- expect(mockInstance.editor.getSquire().insertElement).toHaveBeenCalled();
- expect(global.URL.createObjectURL).toHaveBeenLastCalledWith(file);
- });
-
- it('calls the insertText method on the instance when in Markdown mode', () => {
- mockInstance.editor.isWysiwygMode.mockReturnValue(false);
- addImage(mockInstance, mockImage, file);
-
- expect(mockInstance.editor.insertText).toHaveBeenCalledWith('![some alt text](some/url.png)');
- });
- });
-
- describe('insertVideo', () => {
- const mockUrl = 'some/url';
- const htmlString = `<figure contenteditable="false" class="gl-relative gl-h-0 video_container"><iframe class="gl-absolute gl-top-0 gl-left-0 gl-w-full gl-h-full" width="560" height="315" frameborder="0" src="some/url"></iframe></figure>`;
- const mockInsertElement = jest.fn();
-
- beforeEach(() =>
- mockInstance.editor.getSquire.mockReturnValue({ insertElement: mockInsertElement }),
- );
-
- describe('WYSIWYG mode', () => {
- it('calls the insertElement method on the squire instance with an iFrame element', () => {
- mockInstance.editor.isWysiwygMode.mockReturnValue(true);
-
- insertVideo(mockInstance, mockUrl);
-
- expect(mockInstance.editor.getSquire().insertElement).toHaveBeenCalledWith(
- parseHtml(htmlString),
- );
- });
- });
-
- describe('Markdown mode', () => {
- it('calls the insertText method on the editor instance with the iFrame element HTML', () => {
- mockInstance.editor.isWysiwygMode.mockReturnValue(false);
-
- insertVideo(mockInstance, mockUrl);
-
- expect(mockInstance.editor.insertText).toHaveBeenCalledWith(htmlString);
- });
- });
- });
-
- describe('getMarkdown', () => {
- it('calls the invoke method on the instance', () => {
- getMarkdown(mockInstance);
-
- expect(mockInstance.invoke).toHaveBeenCalledWith('getMarkdown');
- });
- });
-
- describe('registerHTMLToMarkdownRenderer', () => {
- let baseRenderer;
- const htmlToMarkdownRenderer = {};
- const extendedRenderer = {};
-
- beforeEach(() => {
- baseRenderer = mockInstance.toMarkOptions.renderer;
- buildHTMLToMarkdownRenderer.mockReturnValueOnce(htmlToMarkdownRenderer);
- baseRenderer.constructor.factory.mockReturnValueOnce(extendedRenderer);
-
- registerHTMLToMarkdownRenderer(mockInstance);
- });
-
- it('builds a new instance of the HTML to Markdown renderer', () => {
- expect(buildHTMLToMarkdownRenderer).toHaveBeenCalledWith(baseRenderer);
- });
-
- it('extends base renderer with the HTML to Markdown renderer', () => {
- expect(baseRenderer.constructor.factory).toHaveBeenCalledWith(
- baseRenderer,
- htmlToMarkdownRenderer,
- );
- });
-
- it('replaces the default renderer with extended renderer', () => {
- expect(mockInstance.toMarkOptions.renderer).toBe(extendedRenderer);
- });
- });
-
- describe('getEditorOptions', () => {
- const externalOptions = {
- customRenderers: {},
- };
- const renderer = {};
-
- beforeEach(() => {
- buildCustomRenderer.mockReturnValueOnce(renderer);
- });
-
- it('generates a configuration object with a custom HTML renderer and toolbarItems', () => {
- expect(getEditorOptions()).toHaveProp('customHTMLRenderer', renderer);
- expect(getEditorOptions()).toHaveProp('toolbarItems');
- });
-
- it('passes external renderers to the buildCustomRenderers function', () => {
- getEditorOptions(externalOptions);
- expect(buildCustomRenderer).toHaveBeenCalledWith(externalOptions.customRenderers);
- });
-
- it('uses the internal sanitizeHTML service for HTML sanitization', () => {
- const options = getEditorOptions();
- const html = '<div></div>';
-
- options.customHTMLSanitizer(html);
-
- expect(sanitizeHTML).toHaveBeenCalledWith(html);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal_spec.js
deleted file mode 100644
index 97aecda97d2..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal_spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { GlModal, GlTabs } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { IMAGE_TABS } from '~/vue_shared/components/rich_content_editor/constants';
-import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue';
-import UploadImageTab from '~/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab.vue';
-
-describe('Add Image Modal', () => {
- let wrapper;
- const propsData = { imageRoot: 'path/to/root/' };
-
- const findModal = () => wrapper.find(GlModal);
- const findTabs = () => wrapper.find(GlTabs);
- const findUploadImageTab = () => wrapper.find(UploadImageTab);
- const findUrlInput = () => wrapper.find({ ref: 'urlInput' });
- const findDescriptionInput = () => wrapper.find({ ref: 'descriptionInput' });
-
- beforeEach(() => {
- wrapper = shallowMount(AddImageModal, { propsData });
- });
-
- describe('when content is loaded', () => {
- it('renders a modal component', () => {
- expect(findModal().exists()).toBe(true);
- });
-
- it('renders a Tabs component', () => {
- expect(findTabs().exists()).toBe(true);
- });
-
- it('renders an upload image tab', () => {
- expect(findUploadImageTab().exists()).toBe(true);
- });
-
- it('renders an input to add an image URL', () => {
- expect(findUrlInput().exists()).toBe(true);
- });
-
- it('renders an input to add an image description', () => {
- expect(findDescriptionInput().exists()).toBe(true);
- });
- });
-
- describe('add image', () => {
- describe('Upload', () => {
- it('validates the file', () => {
- const preventDefault = jest.fn();
- const description = 'some description';
- const file = { name: 'some_file.png' };
-
- wrapper.vm.$refs.uploadImageTab = { validateFile: jest.fn() };
- wrapper.setData({ file, description, tabIndex: IMAGE_TABS.UPLOAD_TAB });
-
- findModal().vm.$emit('ok', { preventDefault });
-
- expect(wrapper.vm.$refs.uploadImageTab.validateFile).toHaveBeenCalled();
- });
- });
-
- describe('URL', () => {
- it('emits an addImage event when a valid URL is specified', () => {
- const preventDefault = jest.fn();
- const mockImage = { imageUrl: '/some/valid/url.png', description: 'some description' };
- wrapper.setData({ ...mockImage, tabIndex: IMAGE_TABS.URL_TAB });
-
- findModal().vm.$emit('ok', { preventDefault });
- expect(preventDefault).not.toHaveBeenCalled();
- expect(wrapper.emitted('addImage')).toEqual([
- [{ imageUrl: mockImage.imageUrl, altText: mockImage.description }],
- ]);
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js
deleted file mode 100644
index 81fd059ce4f..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import UploadImageTab from '~/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab.vue';
-
-describe('Upload Image Tab', () => {
- let wrapper;
-
- beforeEach(() => {
- wrapper = shallowMount(UploadImageTab);
- });
-
- afterEach(() => wrapper.destroy());
-
- const triggerInputEvent = (size) => {
- const file = { size, name: 'file-name.png' };
- const mockEvent = new Event('input');
-
- Object.defineProperty(mockEvent, 'target', { value: { files: [file] } });
-
- wrapper.find({ ref: 'fileInput' }).element.dispatchEvent(mockEvent);
-
- return file;
- };
-
- describe('onInput', () => {
- it.each`
- size | fileError
- ${2000000000} | ${'Maximum file size is 2MB. Please select a smaller file.'}
- ${200} | ${null}
- `('validates the file correctly', ({ size, fileError }) => {
- triggerInputEvent(size);
-
- expect(wrapper.vm.fileError).toBe(fileError);
- });
- });
-
- it('emits input event when file is valid', () => {
- const file = triggerInputEvent(200);
-
- expect(wrapper.emitted('input')).toEqual([[file]]);
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js
deleted file mode 100644
index 3e9eaf58181..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
-
-describe('Insert Video Modal', () => {
- let wrapper;
-
- const findModal = () => wrapper.find(GlModal);
- const findUrlInput = () => wrapper.find({ ref: 'urlInput' });
-
- const triggerInsertVideo = (url) => {
- const preventDefault = jest.fn();
- findUrlInput().vm.$emit('input', url);
- findModal().vm.$emit('primary', { preventDefault });
- };
-
- beforeEach(() => {
- wrapper = shallowMount(InsertVideoModal);
- });
-
- afterEach(() => wrapper.destroy());
-
- describe('when content is loaded', () => {
- it('renders a modal component', () => {
- expect(findModal().exists()).toBe(true);
- });
-
- it('renders an input to add a URL', () => {
- expect(findUrlInput().exists()).toBe(true);
- });
- });
-
- describe('insert video', () => {
- it.each`
- url | emitted
- ${'https://www.youtube.com/embed/someId'} | ${[['https://www.youtube.com/embed/someId']]}
- ${'https://www.youtube.com/watch?v=1234'} | ${[['https://www.youtube.com/embed/1234']]}
- ${'::youtube.com/invalid/url'} | ${undefined}
- `('formats the url correctly', ({ url, emitted }) => {
- triggerInsertVideo(url);
- expect(wrapper.emitted('insertVideo')).toEqual(emitted);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js
deleted file mode 100644
index 47b1abd2ad2..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_integration_spec.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Editor from '@toast-ui/editor';
-import buildMarkdownToHTMLRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
-import { registerHTMLToMarkdownRenderer } from '~/vue_shared/components/rich_content_editor/services/editor_service';
-
-describe('vue_shared/components/rich_content_editor', () => {
- let editor;
-
- const buildEditor = () => {
- editor = new Editor({
- el: document.body,
- customHTMLRenderer: buildMarkdownToHTMLRenderer(),
- });
-
- registerHTMLToMarkdownRenderer(editor);
- };
-
- beforeEach(() => {
- buildEditor();
- });
-
- describe('HTML to Markdown', () => {
- it('uses "-" character list marker in unordered lists', () => {
- editor.setHtml('<ul><li>List item 1</li><li>List item 2</li></ul>');
-
- const markdown = editor.getMarkdown();
-
- expect(markdown).toBe('- List item 1\n- List item 2');
- });
-
- it('does not increment the list marker in ordered lists', () => {
- editor.setHtml('<ol><li>List item 1</li><li>List item 2</li></ol>');
-
- const markdown = editor.getMarkdown();
-
- expect(markdown).toBe('1. List item 1\n1. List item 2');
- });
-
- it('indents lists using four spaces', () => {
- editor.setHtml('<ul><li>List item 1</li><ul><li>List item 2</li></ul></ul>');
-
- const markdown = editor.getMarkdown();
-
- expect(markdown).toBe('- List item 1\n - List item 2');
- });
-
- it('uses * for strong and _ for emphasis text', () => {
- editor.setHtml('<strong>strong text</strong><i>emphasis text</i>');
-
- const markdown = editor.getMarkdown();
-
- expect(markdown).toBe('**strong text**_emphasis text_');
- });
- });
-
- describe('Markdown to HTML', () => {
- it.each`
- input | output
- ${'markdown with _emphasized\ntext_'} | ${'<p>markdown with <em>emphasized text</em></p>\n'}
- ${'markdown with **strong\ntext**'} | ${'<p>markdown with <strong>strong text</strong></p>\n'}
- `(
- 'does not transform softbreaks inside (_) and strong (**) nodes into <br/> tags',
- ({ input, output }) => {
- editor.setMarkdown(input);
-
- expect(editor.getHtml()).toBe(output);
- },
- );
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
deleted file mode 100644
index 8eb880b3984..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import { Editor, mockEditorApi } from '@toast-ui/vue-editor';
-import { shallowMount } from '@vue/test-utils';
-import {
- EDITOR_TYPES,
- EDITOR_HEIGHT,
- EDITOR_PREVIEW_STYLE,
- CUSTOM_EVENTS,
-} from '~/vue_shared/components/rich_content_editor/constants';
-import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue';
-import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
-import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
-
-import {
- addCustomEventListener,
- removeCustomEventListener,
- addImage,
- insertVideo,
- registerHTMLToMarkdownRenderer,
- getEditorOptions,
- getMarkdown,
-} from '~/vue_shared/components/rich_content_editor/services/editor_service';
-
-jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service', () => ({
- addCustomEventListener: jest.fn(),
- removeCustomEventListener: jest.fn(),
- addImage: jest.fn(),
- insertVideo: jest.fn(),
- registerHTMLToMarkdownRenderer: jest.fn(),
- getEditorOptions: jest.fn(),
- getMarkdown: jest.fn(),
-}));
-
-describe('Rich Content Editor', () => {
- let wrapper;
-
- const content = '## Some Markdown';
- const imageRoot = 'path/to/root/';
- const findEditor = () => wrapper.find({ ref: 'editor' });
- const findAddImageModal = () => wrapper.find(AddImageModal);
- const findInsertVideoModal = () => wrapper.find(InsertVideoModal);
-
- const buildWrapper = async () => {
- wrapper = shallowMount(RichContentEditor, {
- propsData: { content, imageRoot },
- stubs: {
- ToastEditor: Editor,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when content is loaded', () => {
- const editorOptions = {};
-
- beforeEach(() => {
- getEditorOptions.mockReturnValueOnce(editorOptions);
- buildWrapper();
- });
-
- it('renders an editor', () => {
- expect(findEditor().exists()).toBe(true);
- });
-
- it('renders the correct content', () => {
- expect(findEditor().props().initialValue).toBe(content);
- });
-
- it('provides options generated by the getEditorOptions service', () => {
- expect(findEditor().props().options).toBe(editorOptions);
- });
-
- it('has the correct preview style', () => {
- expect(findEditor().props().previewStyle).toBe(EDITOR_PREVIEW_STYLE);
- });
-
- it('has the correct initial edit type', () => {
- expect(findEditor().props().initialEditType).toBe(EDITOR_TYPES.wysiwyg);
- });
-
- it('has the correct height', () => {
- expect(findEditor().props().height).toBe(EDITOR_HEIGHT);
- });
- });
-
- describe('when content is changed', () => {
- beforeEach(() => {
- buildWrapper();
- });
-
- it('emits an input event with the changed content', () => {
- const changedMarkdown = '## Changed Markdown';
- getMarkdown.mockReturnValueOnce(changedMarkdown);
-
- findEditor().vm.$emit('change');
-
- expect(wrapper.emitted().input[0][0]).toBe(changedMarkdown);
- });
- });
-
- describe('when content is reset', () => {
- beforeEach(() => {
- buildWrapper();
- });
-
- it('should reset the content via setMarkdown', () => {
- const newContent = 'Just the body content excluding the front matter for example';
- const mockInstance = { invoke: jest.fn() };
- wrapper.vm.$refs.editor = mockInstance;
-
- wrapper.vm.resetInitialValue(newContent);
-
- expect(mockInstance.invoke).toHaveBeenCalledWith('setMarkdown', newContent);
- });
- });
-
- describe('when editor is loaded', () => {
- const formattedMarkdown = 'formatted markdown';
-
- beforeEach(() => {
- mockEditorApi.getMarkdown.mockReturnValueOnce(formattedMarkdown);
- buildWrapper();
- });
-
- afterEach(() => {
- mockEditorApi.getMarkdown.mockReset();
- });
-
- it('adds the CUSTOM_EVENTS.openAddImageModal custom event listener', () => {
- expect(addCustomEventListener).toHaveBeenCalledWith(
- wrapper.vm.editorApi,
- CUSTOM_EVENTS.openAddImageModal,
- wrapper.vm.onOpenAddImageModal,
- );
- });
-
- it('adds the CUSTOM_EVENTS.openInsertVideoModal custom event listener', () => {
- expect(addCustomEventListener).toHaveBeenCalledWith(
- wrapper.vm.editorApi,
- CUSTOM_EVENTS.openInsertVideoModal,
- wrapper.vm.onOpenInsertVideoModal,
- );
- });
-
- it('registers HTML to markdown renderer', () => {
- expect(registerHTMLToMarkdownRenderer).toHaveBeenCalledWith(wrapper.vm.editorApi);
- });
-
- it('emits load event with the markdown formatted by Toast UI', () => {
- mockEditorApi.getMarkdown.mockReturnValueOnce(formattedMarkdown);
- expect(mockEditorApi.getMarkdown).toHaveBeenCalled();
- expect(wrapper.emitted('load')[0]).toEqual([{ formattedMarkdown }]);
- });
- });
-
- describe('when editor is destroyed', () => {
- beforeEach(() => {
- buildWrapper();
- });
-
- it('removes the CUSTOM_EVENTS.openAddImageModal custom event listener', () => {
- wrapper.vm.$destroy();
-
- expect(removeCustomEventListener).toHaveBeenCalledWith(
- wrapper.vm.editorApi,
- CUSTOM_EVENTS.openAddImageModal,
- wrapper.vm.onOpenAddImageModal,
- );
- });
-
- it('removes the CUSTOM_EVENTS.openInsertVideoModal custom event listener', () => {
- wrapper.vm.$destroy();
-
- expect(removeCustomEventListener).toHaveBeenCalledWith(
- wrapper.vm.editorApi,
- CUSTOM_EVENTS.openInsertVideoModal,
- wrapper.vm.onOpenInsertVideoModal,
- );
- });
- });
-
- describe('add image modal', () => {
- beforeEach(() => {
- buildWrapper();
- });
-
- it('renders an addImageModal component', () => {
- expect(findAddImageModal().exists()).toBe(true);
- });
-
- it('calls the onAddImage method when the addImage event is emitted', () => {
- const mockImage = { imageUrl: 'some/url.png', altText: 'some description' };
- const mockInstance = { exec: jest.fn() };
- wrapper.vm.$refs.editor = mockInstance;
-
- findAddImageModal().vm.$emit('addImage', mockImage);
- expect(addImage).toHaveBeenCalledWith(mockInstance, mockImage, undefined);
- });
- });
-
- describe('insert video modal', () => {
- beforeEach(() => {
- buildWrapper();
- });
-
- it('renders an insertVideoModal component', () => {
- expect(findInsertVideoModal().exists()).toBe(true);
- });
-
- it('calls the onInsertVideo method when the insertVideo event is emitted', () => {
- const mockUrl = 'https://www.youtube.com/embed/someId';
- const mockInstance = { exec: jest.fn() };
- wrapper.vm.$refs.editor = mockInstance;
-
- findInsertVideoModal().vm.$emit('insertVideo', mockUrl);
- expect(insertVideo).toHaveBeenCalledWith(mockInstance, mockUrl);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/build_custom_renderer_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/build_custom_renderer_spec.js
deleted file mode 100644
index a823d04024d..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/build_custom_renderer_spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import buildCustomHTMLRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
-
-describe('Build Custom Renderer Service', () => {
- describe('buildCustomHTMLRenderer', () => {
- it('should return an object with the default renderer functions when lacking arguments', () => {
- expect(buildCustomHTMLRenderer()).toEqual(
- expect.objectContaining({
- htmlBlock: expect.any(Function),
- htmlInline: expect.any(Function),
- heading: expect.any(Function),
- item: expect.any(Function),
- paragraph: expect.any(Function),
- text: expect.any(Function),
- softbreak: expect.any(Function),
- }),
- );
- });
-
- it('should return an object with both custom and default renderer functions when passed customRenderers', () => {
- const mockHtmlCustomRenderer = jest.fn();
- const customRenderers = {
- html: [mockHtmlCustomRenderer],
- };
-
- expect(buildCustomHTMLRenderer(customRenderers)).toEqual(
- expect.objectContaining({
- html: expect.any(Function),
- }),
- );
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
deleted file mode 100644
index 3caf03dabba..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
+++ /dev/null
@@ -1,218 +0,0 @@
-import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer';
-import { attributeDefinition } from './renderers/mock_data';
-
-describe('rich_content_editor/services/html_to_markdown_renderer', () => {
- let baseRenderer;
- let htmlToMarkdownRenderer;
- let fakeNode;
-
- beforeEach(() => {
- baseRenderer = {
- trim: jest.fn((input) => `trimmed ${input}`),
- getSpaceCollapsedText: jest.fn((input) => `space collapsed ${input}`),
- getSpaceControlled: jest.fn((input) => `space controlled ${input}`),
- convert: jest.fn(),
- };
-
- fakeNode = { nodeValue: 'mock_node', dataset: {} };
- });
-
- afterEach(() => {
- htmlToMarkdownRenderer = null;
- });
-
- describe('TEXT_NODE visitor', () => {
- it('composes getSpaceControlled, getSpaceCollapsedText, and trim services', () => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
-
- expect(htmlToMarkdownRenderer.TEXT_NODE(fakeNode)).toBe(
- `space controlled trimmed space collapsed ${fakeNode.nodeValue}`,
- );
- });
- });
-
- describe('LI OL, LI UL visitor', () => {
- const oneLevelNestedList = '\n * List item 1\n * List item 2';
- const twoLevelNestedList = '\n * List item 1\n * List item 2';
- const spaceInContentList = '\n * List item 1\n * List item 2';
-
- it.each`
- list | indentSpaces | result
- ${oneLevelNestedList} | ${2} | ${'\n * List item 1\n * List item 2'}
- ${oneLevelNestedList} | ${3} | ${'\n * List item 1\n * List item 2'}
- ${oneLevelNestedList} | ${6} | ${'\n * List item 1\n * List item 2'}
- ${twoLevelNestedList} | ${4} | ${'\n * List item 1\n * List item 2'}
- ${spaceInContentList} | ${1} | ${'\n * List item 1\n * List item 2'}
- `('changes the list indentation to $indentSpaces spaces', ({ list, indentSpaces, result }) => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer, {
- subListIndentSpaces: indentSpaces,
- });
-
- baseRenderer.convert.mockReturnValueOnce(list);
-
- expect(htmlToMarkdownRenderer['LI OL, LI UL'](fakeNode, list)).toBe(result);
- expect(baseRenderer.convert).toHaveBeenCalledWith(fakeNode, list);
- });
- });
-
- describe('UL LI visitor', () => {
- it.each`
- listItem | unorderedListBulletChar | result | bulletChar
- ${'* list item'} | ${undefined} | ${'- list item'} | ${'default'}
- ${' - list item'} | ${'*'} | ${' * list item'} | ${'*'}
- ${' * list item'} | ${'-'} | ${' - list item'} | ${'-'}
- `(
- 'uses $bulletChar bullet char in unordered list items when $unorderedListBulletChar is set in config',
- ({ listItem, unorderedListBulletChar, result }) => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer, {
- unorderedListBulletChar,
- });
- baseRenderer.convert.mockReturnValueOnce(listItem);
-
- expect(htmlToMarkdownRenderer['UL LI'](fakeNode, listItem)).toBe(result);
- expect(baseRenderer.convert).toHaveBeenCalledWith(fakeNode, listItem);
- },
- );
-
- it('detects attribute definitions and attaches them to the list item', () => {
- const listItem = '- list item';
- const result = `${listItem}\n${attributeDefinition}\n`;
-
- fakeNode.dataset.attributeDefinition = attributeDefinition;
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
- baseRenderer.convert.mockReturnValueOnce(`${listItem}\n`);
-
- expect(htmlToMarkdownRenderer['UL LI'](fakeNode, listItem)).toBe(result);
- });
- });
-
- describe('OL LI visitor', () => {
- it.each`
- listItem | result | incrementListMarker | action
- ${'2. list item'} | ${'1. list item'} | ${false} | ${'increments'}
- ${' 3. list item'} | ${' 1. list item'} | ${false} | ${'increments'}
- ${' 123. list item'} | ${' 1. list item'} | ${false} | ${'increments'}
- ${'3. list item'} | ${'3. list item'} | ${true} | ${'does not increment'}
- `(
- '$action a list item counter when incrementListMaker is $incrementListMarker',
- ({ listItem, result, incrementListMarker }) => {
- const subContent = null;
-
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer, {
- incrementListMarker,
- });
- baseRenderer.convert.mockReturnValueOnce(listItem);
-
- expect(htmlToMarkdownRenderer['OL LI'](fakeNode, subContent)).toBe(result);
- expect(baseRenderer.convert).toHaveBeenCalledWith(fakeNode, subContent);
- },
- );
- });
-
- describe('STRONG, B visitor', () => {
- it.each`
- input | strongCharacter | result
- ${'**strong text**'} | ${'_'} | ${'__strong text__'}
- ${'__strong text__'} | ${'*'} | ${'**strong text**'}
- `(
- 'converts $input to $result when strong character is $strongCharacter',
- ({ input, strongCharacter, result }) => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer, {
- strong: strongCharacter,
- });
-
- baseRenderer.convert.mockReturnValueOnce(input);
-
- expect(htmlToMarkdownRenderer['STRONG, B'](fakeNode, input)).toBe(result);
- expect(baseRenderer.convert).toHaveBeenCalledWith(fakeNode, input);
- },
- );
- });
-
- describe('EM, I visitor', () => {
- it.each`
- input | emphasisCharacter | result
- ${'*strong text*'} | ${'_'} | ${'_strong text_'}
- ${'_strong text_'} | ${'*'} | ${'*strong text*'}
- `(
- 'converts $input to $result when emphasis character is $emphasisCharacter',
- ({ input, emphasisCharacter, result }) => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer, {
- emphasis: emphasisCharacter,
- });
-
- baseRenderer.convert.mockReturnValueOnce(input);
-
- expect(htmlToMarkdownRenderer['EM, I'](fakeNode, input)).toBe(result);
- expect(baseRenderer.convert).toHaveBeenCalledWith(fakeNode, input);
- },
- );
- });
-
- describe('H1, H2, H3, H4, H5, H6 visitor', () => {
- it('detects attribute definitions and attaches them to the heading', () => {
- const heading = 'heading text';
- const result = `${heading.trimRight()}\n${attributeDefinition}\n\n`;
-
- fakeNode.dataset.attributeDefinition = attributeDefinition;
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
- baseRenderer.convert.mockReturnValueOnce(`${heading}\n\n`);
-
- expect(htmlToMarkdownRenderer['H1, H2, H3, H4, H5, H6'](fakeNode, heading)).toBe(result);
- });
- });
-
- describe('PRE CODE', () => {
- let node;
- const subContent = 'sub content';
- const originalConverterResult = 'base result';
-
- beforeEach(() => {
- node = document.createElement('PRE');
-
- node.innerText = 'reference definition content';
- node.dataset.sseReferenceDefinition = true;
-
- baseRenderer.convert.mockReturnValueOnce(originalConverterResult);
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
- });
-
- it('returns raw text when pre node has sse-reference-definitions class', () => {
- expect(htmlToMarkdownRenderer['PRE CODE'](node, subContent)).toBe(
- `\n\n${node.innerText}\n\n`,
- );
- });
-
- it('returns base result when pre node does not have sse-reference-definitions class', () => {
- delete node.dataset.sseReferenceDefinition;
-
- expect(htmlToMarkdownRenderer['PRE CODE'](node, subContent)).toBe(originalConverterResult);
- });
- });
-
- describe('IMG', () => {
- const originalSrc = 'path/to/image.png';
- const alt = 'alt text';
- let node;
-
- beforeEach(() => {
- node = document.createElement('img');
- node.alt = alt;
- node.src = originalSrc;
- });
-
- it('returns an image with its original src of the `original-src` attribute is preset', () => {
- node.dataset.originalSrc = originalSrc;
- node.src = 'modified/path/to/image.png';
-
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
-
- expect(htmlToMarkdownRenderer.IMG(node)).toBe(`![${alt}](${originalSrc})`);
- });
-
- it('fallback to `src` if no `original-src` is specified on the image', () => {
- htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer);
- expect(htmlToMarkdownRenderer.IMG(node)).toBe(`![${alt}](${originalSrc})`);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token_spec.js
deleted file mode 100644
index 7a7e3055520..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token_spec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import {
- buildTextToken,
- buildUneditableOpenTokens,
- buildUneditableCloseToken,
- buildUneditableCloseTokens,
- buildUneditableBlockTokens,
- buildUneditableInlineTokens,
- buildUneditableHtmlAsTextTokens,
-} from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-
-import {
- originInlineToken,
- originToken,
- uneditableOpenTokens,
- uneditableCloseToken,
- uneditableCloseTokens,
- uneditableBlockTokens,
- uneditableInlineTokens,
- uneditableTokens,
-} from './mock_data';
-
-describe('Build Uneditable Token renderer helper', () => {
- describe('buildTextToken', () => {
- it('returns an object literal representing a text token', () => {
- const text = originToken.content;
- expect(buildTextToken(text)).toStrictEqual(originToken);
- });
- });
-
- describe('buildUneditableOpenTokens', () => {
- it('returns a 2-item array of tokens with the originToken appended to an open token', () => {
- const result = buildUneditableOpenTokens(originToken);
-
- expect(result).toHaveLength(2);
- expect(result).toStrictEqual(uneditableOpenTokens);
- });
- });
-
- describe('buildUneditableCloseToken', () => {
- it('returns an object literal representing the uneditable close token', () => {
- expect(buildUneditableCloseToken()).toStrictEqual(uneditableCloseToken);
- });
- });
-
- describe('buildUneditableCloseTokens', () => {
- it('returns a 2-item array of tokens with the originToken prepended to a close token', () => {
- const result = buildUneditableCloseTokens(originToken);
-
- expect(result).toHaveLength(2);
- expect(result).toStrictEqual(uneditableCloseTokens);
- });
- });
-
- describe('buildUneditableBlockTokens', () => {
- it('returns a 3-item array of tokens with the originToken wrapped in the middle of block tokens', () => {
- const result = buildUneditableBlockTokens(originToken);
-
- expect(result).toHaveLength(3);
- expect(result).toStrictEqual(uneditableTokens);
- });
- });
-
- describe('buildUneditableInlineTokens', () => {
- it('returns a 3-item array of tokens with the originInlineToken wrapped in the middle of inline tokens', () => {
- const result = buildUneditableInlineTokens(originInlineToken);
-
- expect(result).toHaveLength(3);
- expect(result).toStrictEqual(uneditableInlineTokens);
- });
- });
-
- describe('buildUneditableHtmlAsTextTokens', () => {
- it('returns a 3-item array of tokens with the htmlBlockNode wrapped as a text token in the middle of block tokens', () => {
- const htmlBlockNode = {
- type: 'htmlBlock',
- literal: '<div data-tomark-pass ><h1>Some header</h1><p>Some paragraph</p></div>',
- };
- const result = buildUneditableHtmlAsTextTokens(htmlBlockNode);
- const { type, content } = result[1];
-
- expect(type).toBe('text');
- expect(content).not.toMatch(/ data-tomark-pass /);
-
- expect(result).toHaveLength(3);
- expect(result).toStrictEqual(uneditableBlockTokens);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js
deleted file mode 100644
index 407072fb596..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Node spec helpers
-
-export const buildMockTextNode = (literal) => ({ literal, type: 'text' });
-
-export const normalTextNode = buildMockTextNode('This is just normal text.');
-
-// Token spec helpers
-
-const buildMockUneditableOpenToken = (type) => {
- return {
- type: 'openTag',
- tagName: type,
- attributes: { contenteditable: false },
- classNames: [
- 'gl-px-4 gl-py-2 gl-my-5 gl-opacity-5 gl-bg-gray-100 gl-user-select-none gl-cursor-not-allowed',
- ],
- };
-};
-
-const buildMockTextToken = (content) => {
- return {
- type: 'text',
- tagName: null,
- content,
- };
-};
-
-const buildMockUneditableCloseToken = (type) => ({ type: 'closeTag', tagName: type });
-
-export const originToken = buildMockTextToken('{:.no_toc .hidden-md .hidden-lg}');
-const uneditableOpenToken = buildMockUneditableOpenToken('div');
-export const uneditableOpenTokens = [uneditableOpenToken, originToken];
-export const uneditableCloseToken = buildMockUneditableCloseToken('div');
-export const uneditableCloseTokens = [originToken, uneditableCloseToken];
-export const uneditableTokens = [...uneditableOpenTokens, uneditableCloseToken];
-
-export const originInlineToken = {
- type: 'text',
- content: '<i>Inline</i> content',
-};
-
-export const uneditableInlineTokens = [
- buildMockUneditableOpenToken('a'),
- originInlineToken,
- buildMockUneditableCloseToken('a'),
-];
-
-export const uneditableBlockTokens = [
- uneditableOpenToken,
- buildMockTextToken('<div><h1>Some header</h1><p>Some paragraph</p></div>'),
- uneditableCloseToken,
-];
-
-export const attributeDefinition = '{:.no_toc .hidden-md .hidden-lg}';
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition_spec.js
deleted file mode 100644
index 69fd9a67a21..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition_spec.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition';
-import { attributeDefinition } from './mock_data';
-
-describe('rich_content_editor/renderers/render_attribute_definition', () => {
- describe('canRender', () => {
- it.each`
- input | result
- ${{ literal: attributeDefinition }} | ${true}
- ${{ literal: `FOO${attributeDefinition}` }} | ${false}
- ${{ literal: `${attributeDefinition}BAR` }} | ${false}
- ${{ literal: 'foobar' }} | ${false}
- `('returns $result when input is $input', ({ input, result }) => {
- expect(renderer.canRender(input)).toBe(result);
- });
- });
-
- describe('render', () => {
- it('returns an empty HTML comment', () => {
- expect(renderer.render()).toEqual({
- type: 'html',
- content: '<!-- sse-attribute-definition -->',
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_spec.js
deleted file mode 100644
index 0c59d9f569b..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_text';
-import { renderUneditableLeaf } from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
-
-import { buildMockTextNode, normalTextNode } from './mock_data';
-
-const embeddedRubyTextNode = buildMockTextNode('<%= partial("some/path") %>');
-
-describe('Render Embedded Ruby Text renderer', () => {
- describe('canRender', () => {
- it('should return true when the argument `literal` has embedded ruby syntax', () => {
- expect(renderer.canRender(embeddedRubyTextNode)).toBe(true);
- });
-
- it('should return false when the argument `literal` lacks embedded ruby syntax', () => {
- expect(renderer.canRender(normalTextNode)).toBe(false);
- });
- });
-
- describe('render', () => {
- it('should delegate rendering to the renderUneditableLeaf util', () => {
- expect(renderer.render).toBe(renderUneditableLeaf);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline_spec.js
deleted file mode 100644
index c1aaed6f0c3..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline_spec.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { buildUneditableInlineTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline';
-
-import { normalTextNode } from './mock_data';
-
-const fontAwesomeInlineHtmlNode = {
- firstChild: null,
- literal: '<i class="far fa-paper-plane" id="biz-tech-icons">',
- type: 'html',
-};
-
-describe('Render Font Awesome Inline HTML renderer', () => {
- describe('canRender', () => {
- it('should return true when the argument `literal` has font awesome inline html syntax', () => {
- expect(renderer.canRender(fontAwesomeInlineHtmlNode)).toBe(true);
- });
-
- it('should return false when the argument `literal` lacks font awesome inline html syntax', () => {
- expect(renderer.canRender(normalTextNode)).toBe(false);
- });
- });
-
- describe('render', () => {
- it('should return uneditable inline tokens', () => {
- const token = { type: 'text', tagName: null, content: fontAwesomeInlineHtmlNode.literal };
- const context = { origin: () => token };
-
- expect(renderer.render(fontAwesomeInlineHtmlNode, context)).toStrictEqual(
- buildUneditableInlineTokens(token),
- );
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_heading_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_heading_spec.js
deleted file mode 100644
index 76abc1ec3d8..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_heading_spec.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_heading';
-import * as renderUtils from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
-
-describe('rich_content_editor/renderers/render_heading', () => {
- it('canRender delegates to renderUtils.willAlwaysRender', () => {
- expect(renderer.canRender).toBe(renderUtils.willAlwaysRender);
- });
-
- it('render delegates to renderUtils.renderWithAttributeDefinitions', () => {
- expect(renderer.render).toBe(renderUtils.renderWithAttributeDefinitions);
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js
deleted file mode 100644
index 234f6a4d4ca..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { buildUneditableHtmlAsTextTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_html_block';
-
-describe('rich_content_editor/services/renderers/render_html_block', () => {
- const htmlBlockNode = {
- literal: '<div><h1>Heading</h1><p>Paragraph.</p></div>',
- type: 'htmlBlock',
- };
-
- describe('canRender', () => {
- it.each`
- input | result
- ${htmlBlockNode} | ${true}
- ${{ literal: '<iframe></iframe>', type: 'htmlBlock' }} | ${true}
- ${{ literal: '<iframe src="https://www.youtube.com"></iframe>', type: 'htmlBlock' }} | ${false}
- ${{ literal: '<iframe></iframe>', type: 'text' }} | ${false}
- `('returns $result when input=$input', ({ input, result }) => {
- expect(renderer.canRender(input)).toBe(result);
- });
- });
-
- describe('render', () => {
- const htmlBlockNodeToMark = {
- firstChild: null,
- literal: '<div data-to-mark ></div>',
- type: 'htmlBlock',
- };
-
- it.each`
- node
- ${htmlBlockNode}
- ${htmlBlockNodeToMark}
- `('should return uneditable tokens wrapping the $node as a token', ({ node }) => {
- expect(renderer.render(node)).toStrictEqual(buildUneditableHtmlAsTextTokens(node));
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js
deleted file mode 100644
index 425d0f41bcd..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import { buildUneditableInlineTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text';
-
-import { buildMockTextNode, normalTextNode } from './mock_data';
-
-const mockTextStart = 'Majority example ';
-const mockTextMiddle = '[environment terraform plans][terraform]';
-const mockTextEnd = '.';
-const identifierInstanceStartTextNode = buildMockTextNode(mockTextStart);
-const identifierInstanceEndTextNode = buildMockTextNode(mockTextEnd);
-
-describe('Render Identifier Instance Text renderer', () => {
- describe('canRender', () => {
- it.each`
- node | target
- ${normalTextNode} | ${false}
- ${identifierInstanceStartTextNode} | ${false}
- ${identifierInstanceEndTextNode} | ${false}
- ${buildMockTextNode(mockTextMiddle)} | ${true}
- ${buildMockTextNode('Minority example [environment terraform plans][]')} | ${true}
- ${buildMockTextNode('Minority example [environment terraform plans]')} | ${true}
- `(
- 'should return $target when the $node validates against identifier instance syntax',
- ({ node, target }) => {
- expect(renderer.canRender(node)).toBe(target);
- },
- );
- });
-
- describe('render', () => {
- it.each`
- start | middle | end
- ${mockTextStart} | ${mockTextMiddle} | ${mockTextEnd}
- ${mockTextStart} | ${'[environment terraform plans][]'} | ${mockTextEnd}
- ${mockTextStart} | ${'[environment terraform plans]'} | ${mockTextEnd}
- `(
- 'should return inline editable, uneditable, and editable tokens in sequence',
- ({ start, middle, end }) => {
- const buildMockTextToken = (content) => ({ type: 'text', tagName: null, content });
-
- const startToken = buildMockTextToken(start);
- const middleToken = buildMockTextToken(middle);
- const endToken = buildMockTextToken(end);
-
- const content = `${start}${middle}${end}`;
- const contentToken = buildMockTextToken(content);
- const contentNode = buildMockTextNode(content);
- const context = { origin: jest.fn().mockReturnValueOnce(contentToken) };
- expect(renderer.render(contentNode, context)).toStrictEqual(
- [startToken, buildUneditableInlineTokens(middleToken), endToken].flat(),
- );
- },
- );
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js
deleted file mode 100644
index 470cf9bddaa..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph';
-
-import { buildMockTextNode } from './mock_data';
-
-const buildMockParagraphNode = (literal) => {
- return {
- firstChild: buildMockTextNode(literal),
- type: 'paragraph',
- };
-};
-
-const normalParagraphNode = buildMockParagraphNode(
- 'This is just normal paragraph. It has multiple sentences.',
-);
-const identifierParagraphNode = buildMockParagraphNode(
- `[another-identifier]: https://example.com "This example has a title" [identifier]: http://example1.com [this link]: http://example2.com`,
-);
-
-describe('rich_content_editor/renderers_render_identifier_paragraph', () => {
- describe('canRender', () => {
- it.each`
- node | paragraph | target
- ${identifierParagraphNode} | ${'[Some text]: https://link.com'} | ${true}
- ${normalParagraphNode} | ${'Normal non-identifier text. Another sentence.'} | ${false}
- `(
- 'should return $target when the $node matches $paragraph syntax',
- ({ node, paragraph, target }) => {
- const context = {
- entering: true,
- getChildrenText: jest.fn().mockReturnValueOnce(paragraph),
- };
-
- expect(renderer.canRender(node, context)).toBe(target);
- },
- );
- });
-
- describe('render', () => {
- let context;
- let result;
-
- beforeEach(() => {
- const node = {
- firstChild: {
- type: 'text',
- literal: '[Some text]: https://link.com',
- next: {
- type: 'linebreak',
- next: {
- type: 'text',
- literal: '[identifier]: http://example1.com "title"',
- },
- },
- },
- };
- context = { skipChildren: jest.fn() };
- result = renderer.render(node, context);
- });
-
- it('renders the reference definitions as a code block', () => {
- expect(result).toEqual([
- {
- type: 'openTag',
- tagName: 'pre',
- classNames: ['code-block', 'language-markdown'],
- attributes: {
- 'data-sse-reference-definition': true,
- },
- },
- { type: 'openTag', tagName: 'code' },
- {
- type: 'text',
- content: '[Some text]: https://link.com\n[identifier]: http://example1.com "title"',
- },
- { type: 'closeTag', tagName: 'code' },
- { type: 'closeTag', tagName: 'pre' },
- ]);
- });
-
- it('skips the reference definition node children from rendering', () => {
- expect(context.skipChildren).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_list_item_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_list_item_spec.js
deleted file mode 100644
index c1ab700535b..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_list_item_spec.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_list_item';
-import * as renderUtils from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
-
-describe('rich_content_editor/renderers/render_list_item', () => {
- it('canRender delegates to renderUtils.willAlwaysRender', () => {
- expect(renderer.canRender).toBe(renderUtils.willAlwaysRender);
- });
-
- it('render delegates to renderUtils.renderWithAttributeDefinitions', () => {
- expect(renderer.render).toBe(renderUtils.renderWithAttributeDefinitions);
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js
deleted file mode 100644
index 3c3d2354cb9..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_softbreak_spec.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_softbreak';
-
-describe('Render softbreak renderer', () => {
- describe('canRender', () => {
- it.each`
- node | parentType | result
- ${{ parent: { type: 'emph' } }} | ${'emph'} | ${true}
- ${{ parent: { type: 'strong' } }} | ${'strong'} | ${true}
- ${{ parent: { type: 'paragraph' } }} | ${'paragraph'} | ${false}
- `('returns $result when node parent type is $parentType ', ({ node, result }) => {
- expect(renderer.canRender(node)).toBe(result);
- });
- });
-
- describe('render', () => {
- it('returns text node with a break line', () => {
- expect(renderer.render()).toEqual({
- type: 'text',
- content: ' ',
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_utils_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_utils_spec.js
deleted file mode 100644
index 7c1809c290c..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_utils_spec.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import {
- buildUneditableBlockTokens,
- buildUneditableOpenTokens,
-} from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-import {
- renderUneditableLeaf,
- renderUneditableBranch,
- renderWithAttributeDefinitions,
- willAlwaysRender,
-} from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
-
-import { originToken, uneditableCloseToken, attributeDefinition } from './mock_data';
-
-describe('rich_content_editor/renderers/render_utils', () => {
- describe('renderUneditableLeaf', () => {
- it('should return uneditable block tokens around an origin token', () => {
- const context = { origin: jest.fn().mockReturnValueOnce(originToken) };
- const result = renderUneditableLeaf({}, context);
-
- expect(result).toStrictEqual(buildUneditableBlockTokens(originToken));
- });
- });
-
- describe('renderUneditableBranch', () => {
- let origin;
-
- beforeEach(() => {
- origin = jest.fn().mockReturnValueOnce(originToken);
- });
-
- it('should return uneditable block open token followed by the origin token when entering', () => {
- const context = { entering: true, origin };
- const result = renderUneditableBranch({}, context);
-
- expect(result).toStrictEqual(buildUneditableOpenTokens(originToken));
- });
-
- it('should return uneditable block closing token when exiting', () => {
- const context = { entering: false, origin };
- const result = renderUneditableBranch({}, context);
-
- expect(result).toStrictEqual(uneditableCloseToken);
- });
- });
-
- describe('willAlwaysRender', () => {
- it('always returns true', () => {
- expect(willAlwaysRender()).toBe(true);
- });
- });
-
- describe('renderWithAttributeDefinitions', () => {
- let openTagToken;
- let closeTagToken;
- let node;
- const attributes = {
- 'data-attribute-definition': attributeDefinition,
- };
-
- beforeEach(() => {
- openTagToken = { type: 'openTag' };
- closeTagToken = { type: 'closeTag' };
- node = {
- next: {
- firstChild: {
- literal: attributeDefinition,
- },
- },
- };
- });
-
- describe('when token type is openTag', () => {
- it('attaches attributes when attributes exist in the node’s next sibling', () => {
- const context = { origin: () => openTagToken };
-
- expect(renderWithAttributeDefinitions(node, context)).toEqual({
- ...openTagToken,
- attributes,
- });
- });
-
- it('attaches attributes when attributes exist in the node’s children', () => {
- const context = { origin: () => openTagToken };
- node = {
- firstChild: {
- firstChild: {
- next: {
- next: {
- literal: attributeDefinition,
- },
- },
- },
- },
- };
-
- expect(renderWithAttributeDefinitions(node, context)).toEqual({
- ...openTagToken,
- attributes,
- });
- });
- });
-
- it('does not attach attributes when token type is "closeTag"', () => {
- const context = { origin: () => closeTagToken };
-
- expect(renderWithAttributeDefinitions({}, context)).toBe(closeTagToken);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js
deleted file mode 100644
index f2182ef60d7..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
-
-describe('rich_content_editor/services/sanitize_html', () => {
- it.each`
- input | result
- ${'<iframe src="https://www.youtube.com"></iframe>'} | ${'<iframe src="https://www.youtube.com"></iframe>'}
- ${'<iframe src="https://gitlab.com"></iframe>'} | ${''}
- `('removes iframes if the iframe source origin is not allowed', ({ input, result }) => {
- expect(sanitizeHTML(input)).toBe(result);
- });
-});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
deleted file mode 100644
index 5a56b499769..00000000000
--- a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import ToolbarItem from '~/vue_shared/components/rich_content_editor/toolbar_item.vue';
-
-describe('Toolbar Item', () => {
- let wrapper;
-
- const findIcon = () => wrapper.find(GlIcon);
- const findButton = () => wrapper.find('button');
-
- const buildWrapper = (propsData) => {
- wrapper = shallowMount(ToolbarItem, {
- propsData,
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- describe.each`
- icon | tooltip
- ${'heading'} | ${'Headings'}
- ${'bold'} | ${'Add bold text'}
- ${'italic'} | ${'Add italic text'}
- ${'strikethrough'} | ${'Add strikethrough text'}
- ${'quote'} | ${'Insert a quote'}
- ${'link'} | ${'Add a link'}
- ${'doc-code'} | ${'Insert a code block'}
- ${'list-bulleted'} | ${'Add a bullet list'}
- ${'list-numbered'} | ${'Add a numbered list'}
- ${'list-task'} | ${'Add a task list'}
- ${'list-indent'} | ${'Indent'}
- ${'list-outdent'} | ${'Outdent'}
- ${'dash'} | ${'Add a line'}
- ${'table'} | ${'Add a table'}
- ${'code'} | ${'Insert an image'}
- ${'code'} | ${'Insert inline code'}
- `('toolbar item component', ({ icon, tooltip }) => {
- beforeEach(() => buildWrapper({ icon, tooltip }));
-
- it('renders a toolbar button', () => {
- expect(findButton().exists()).toBe(true);
- });
-
- it('renders the correct tooltip', () => {
- const buttonTooltip = getBinding(wrapper.element, 'gl-tooltip');
- expect(buttonTooltip).toBeDefined();
- expect(buttonTooltip.value.title).toBe(tooltip);
- });
-
- it(`renders the ${icon} icon`, () => {
- expect(findIcon().exists()).toBe(true);
- expect(findIcon().props().name).toBe(icon);
- });
- });
-});