Commit a2d4cb8e authored by Enrique Alcantara's avatar Enrique Alcantara Committed by Enrique Alcántara

Use consistent approach to create tiptap editor

Refactor Content Editor unit tests to use the same
set of utility tools to mock editor commands and
create instances of the the TipTap editor class
for testing purposes
parent 7a26a7c1
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { Extension } from '@tiptap/core';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import ToolbarButton from '~/content_editor/components/toolbar_button.vue'; import ToolbarButton from '~/content_editor/components/toolbar_button.vue';
import { createContentEditor } from '~/content_editor/services/create_content_editor'; import { createTestEditor, mockChainedCommands } from '../test_utils';
describe('content_editor/components/toolbar_button', () => { describe('content_editor/components/toolbar_button', () => {
let wrapper; let wrapper;
let tiptapEditor; let tiptapEditor;
let toggleFooSpy;
const CONTENT_TYPE = 'bold'; const CONTENT_TYPE = 'bold';
const ICON_NAME = 'bold'; const ICON_NAME = 'bold';
const LABEL = 'Bold'; const LABEL = 'Bold';
const buildEditor = () => { const buildEditor = () => {
toggleFooSpy = jest.fn(); tiptapEditor = createTestEditor();
tiptapEditor = createContentEditor({
extensions: [
{
tiptapExtension: Extension.create({
addCommands() {
return {
toggleFoo: () => toggleFooSpy,
};
},
}),
},
],
renderMarkdown: () => true,
}).tiptapEditor;
jest.spyOn(tiptapEditor, 'isActive'); jest.spyOn(tiptapEditor, 'isActive');
}; };
...@@ -78,20 +62,28 @@ describe('content_editor/components/toolbar_button', () => { ...@@ -78,20 +62,28 @@ describe('content_editor/components/toolbar_button', () => {
describe('when button is clicked', () => { describe('when button is clicked', () => {
it('executes the content type command when executeCommand = true', async () => { it('executes the content type command when executeCommand = true', async () => {
buildWrapper({ editorCommand: 'toggleFoo' }); const editorCommand = 'toggleFoo';
const mockCommands = mockChainedCommands(tiptapEditor, [editorCommand, 'focus', 'run']);
buildWrapper({ editorCommand });
await findButton().trigger('click'); await findButton().trigger('click');
expect(toggleFooSpy).toHaveBeenCalled(); expect(mockCommands[editorCommand]).toHaveBeenCalled();
expect(mockCommands.focus).toHaveBeenCalled();
expect(mockCommands.run).toHaveBeenCalled();
expect(wrapper.emitted().execute).toHaveLength(1); expect(wrapper.emitted().execute).toHaveLength(1);
}); });
it('does not executes the content type command when executeCommand = false', async () => { it('does not executes the content type command when executeCommand = false', async () => {
const editorCommand = 'toggleFoo';
const mockCommands = mockChainedCommands(tiptapEditor, [editorCommand, 'run']);
buildWrapper(); buildWrapper();
await findButton().trigger('click'); await findButton().trigger('click');
expect(toggleFooSpy).not.toHaveBeenCalled(); expect(mockCommands[editorCommand]).not.toHaveBeenCalled();
expect(wrapper.emitted().execute).toHaveLength(1); expect(wrapper.emitted().execute).toHaveLength(1);
}); });
}); });
......
...@@ -2,21 +2,16 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; ...@@ -2,21 +2,16 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ToolbarTextStyleDropdown from '~/content_editor/components/toolbar_text_style_dropdown.vue'; import ToolbarTextStyleDropdown from '~/content_editor/components/toolbar_text_style_dropdown.vue';
import { TEXT_STYLE_DROPDOWN_ITEMS } from '~/content_editor/constants'; import { TEXT_STYLE_DROPDOWN_ITEMS } from '~/content_editor/constants';
import { createTestContentEditorExtension, createTestEditor } from '../test_utils'; import { tiptapExtension as Heading } from '~/content_editor/extensions/heading';
import { createTestEditor, mockChainedCommands } from '../test_utils';
describe('content_editor/components/toolbar_headings_dropdown', () => { describe('content_editor/components/toolbar_headings_dropdown', () => {
let wrapper; let wrapper;
let tiptapEditor; let tiptapEditor;
let commandMocks;
const buildEditor = () => { const buildEditor = () => {
const testExtension = createTestContentEditorExtension({
commands: TEXT_STYLE_DROPDOWN_ITEMS.map((item) => item.editorCommand),
});
commandMocks = testExtension.commandMocks;
tiptapEditor = createTestEditor({ tiptapEditor = createTestEditor({
extensions: [testExtension.tiptapExtension], extensions: [Heading],
}); });
jest.spyOn(tiptapEditor, 'isActive'); jest.spyOn(tiptapEditor, 'isActive');
...@@ -104,9 +99,12 @@ describe('content_editor/components/toolbar_headings_dropdown', () => { ...@@ -104,9 +99,12 @@ describe('content_editor/components/toolbar_headings_dropdown', () => {
TEXT_STYLE_DROPDOWN_ITEMS.forEach((textStyle, index) => { TEXT_STYLE_DROPDOWN_ITEMS.forEach((textStyle, index) => {
const { editorCommand, commandParams } = textStyle; const { editorCommand, commandParams } = textStyle;
const commands = mockChainedCommands(tiptapEditor, [editorCommand, 'focus', 'run']);
wrapper.findAllComponents(GlDropdownItem).at(index).vm.$emit('click'); wrapper.findAllComponents(GlDropdownItem).at(index).vm.$emit('click');
expect(commandMocks[editorCommand]).toHaveBeenCalledWith(commandParams || {}); expect(commands[editorCommand]).toHaveBeenCalledWith(commandParams || {});
expect(commands.focus).toHaveBeenCalled();
expect(commands.run).toHaveBeenCalled();
}); });
}); });
......
import { BulletList } from '@tiptap/extension-bullet-list';
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
import { Document } from '@tiptap/extension-document';
import { Heading } from '@tiptap/extension-heading';
import { ListItem } from '@tiptap/extension-list-item';
import { Paragraph } from '@tiptap/extension-paragraph';
import { Text } from '@tiptap/extension-text';
import { Editor } from '@tiptap/vue-2';
import { mockTracking } from 'helpers/tracking_helper'; import { mockTracking } from 'helpers/tracking_helper';
import { import {
KEYBOARD_SHORTCUT_TRACKING_ACTION, KEYBOARD_SHORTCUT_TRACKING_ACTION,
INPUT_RULE_TRACKING_ACTION, INPUT_RULE_TRACKING_ACTION,
CONTENT_EDITOR_TRACKING_LABEL, CONTENT_EDITOR_TRACKING_LABEL,
} from '~/content_editor/constants'; } from '~/content_editor/constants';
import { tiptapExtension as BulletList } from '~/content_editor/extensions/bullet_list';
import { tiptapExtension as CodeBlockLowlight } from '~/content_editor/extensions/code_block_highlight';
import { tiptapExtension as Heading } from '~/content_editor/extensions/heading';
import { tiptapExtension as ListItem } from '~/content_editor/extensions/list_item';
import trackInputRulesAndShortcuts from '~/content_editor/services/track_input_rules_and_shortcuts'; import trackInputRulesAndShortcuts from '~/content_editor/services/track_input_rules_and_shortcuts';
import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys'; import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys';
import { createTestEditor } from '../test_utils';
describe('content_editor/services/track_input_rules_and_shortcuts', () => { describe('content_editor/services/track_input_rules_and_shortcuts', () => {
let trackingSpy; let trackingSpy;
let editor; let editor;
let trackedExtensions; let trackedExtensions;
const HEADING_TEXT = 'Heading text'; const HEADING_TEXT = 'Heading text';
const extensions = [Document, Paragraph, Text, Heading, CodeBlockLowlight, BulletList, ListItem]; const extensions = [Heading, CodeBlockLowlight, BulletList, ListItem];
beforeEach(() => { beforeEach(() => {
trackingSpy = mockTracking(undefined, null, jest.spyOn); trackingSpy = mockTracking(undefined, null, jest.spyOn);
...@@ -29,7 +26,7 @@ describe('content_editor/services/track_input_rules_and_shortcuts', () => { ...@@ -29,7 +26,7 @@ describe('content_editor/services/track_input_rules_and_shortcuts', () => {
describe('given the heading extension is instrumented', () => { describe('given the heading extension is instrumented', () => {
beforeEach(() => { beforeEach(() => {
trackedExtensions = extensions.map(trackInputRulesAndShortcuts); trackedExtensions = extensions.map(trackInputRulesAndShortcuts);
editor = new Editor({ editor = createTestEditor({
extensions: extensions.map(trackInputRulesAndShortcuts), extensions: extensions.map(trackInputRulesAndShortcuts),
}); });
}); });
......
...@@ -15,7 +15,7 @@ import { Editor } from '@tiptap/vue-2'; ...@@ -15,7 +15,7 @@ import { Editor } from '@tiptap/vue-2';
* include in the editor * include in the editor
* @returns An instance of a Tiptap’s Editor class * @returns An instance of a Tiptap’s Editor class
*/ */
export const createTestEditor = ({ extensions = [] }) => { export const createTestEditor = ({ extensions = [] } = {}) => {
return new Editor({ return new Editor({
extensions: [Document, Text, Paragraph, ...extensions], extensions: [Document, Text, Paragraph, ...extensions],
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment