summaryrefslogtreecommitdiff
path: root/spec/frontend/content_editor
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-08 21:10:05 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-08 21:10:05 +0000
commit9882aeb510f9e3125a6451eb08681ea9d90dd5e2 (patch)
tree02dbb3cb032ee91c50fdccb00893bbc94ec04acc /spec/frontend/content_editor
parent8a03b5424b73679d852fbf43781d9422c83869f7 (diff)
downloadgitlab-ce-9882aeb510f9e3125a6451eb08681ea9d90dd5e2.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/content_editor')
-rw-r--r--spec/frontend/content_editor/components/__snapshots__/toolbar_link_button_spec.js.snap36
-rw-r--r--spec/frontend/content_editor/components/toolbar_link_button_spec.js151
-rw-r--r--spec/frontend/content_editor/test_utils.js18
3 files changed, 205 insertions, 0 deletions
diff --git a/spec/frontend/content_editor/components/__snapshots__/toolbar_link_button_spec.js.snap b/spec/frontend/content_editor/components/__snapshots__/toolbar_link_button_spec.js.snap
new file mode 100644
index 00000000000..4fae9ff932c
--- /dev/null
+++ b/spec/frontend/content_editor/components/__snapshots__/toolbar_link_button_spec.js.snap
@@ -0,0 +1,36 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`content_editor/components/toolbar_link_button renders dropdown component 1`] = `
+"<div class=\\"dropdown b-dropdown gl-new-dropdown btn-group\\">
+ <!----><button aria-haspopup=\\"true\\" aria-expanded=\\"false\\" type=\\"button\\" class=\\"btn dropdown-toggle btn-default btn-sm gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only\\">
+ <!----> <svg data-testid=\\"link-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"dropdown-icon gl-icon s16\\">
+ <use href=\\"#link\\"></use>
+ </svg> <span class=\\"gl-new-dropdown-button-text\\"></span> <svg data-testid=\\"chevron-down-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"gl-button-icon dropdown-chevron gl-icon s16\\">
+ <use href=\\"#chevron-down\\"></use>
+ </svg></button>
+ <ul role=\\"menu\\" tabindex=\\"-1\\" class=\\"dropdown-menu\\">
+ <div class=\\"gl-new-dropdown-inner\\">
+ <!---->
+ <div class=\\"gl-new-dropdown-contents\\">
+ <li role=\\"presentation\\" class=\\"gl-px-3!\\">
+ <form tabindex=\\"-1\\" class=\\"b-dropdown-form gl-p-0\\">
+ <div placeholder=\\"Link URL\\">
+ <div role=\\"group\\" class=\\"input-group\\">
+ <!---->
+ <!----> <input type=\\"text\\" placeholder=\\"Link URL\\" class=\\"gl-form-input form-control\\">
+ <div class=\\"input-group-append\\"><button type=\\"button\\" class=\\"btn btn-confirm btn-md gl-button\\">
+ <!---->
+ <!----> <span class=\\"gl-button-text\\">Apply</span></button></div>
+ <!---->
+ </div>
+ </div>
+ </form>
+ </li>
+ <!---->
+ <!---->
+ </div>
+ <!---->
+ </div>
+ </ul>
+</div>"
+`;
diff --git a/spec/frontend/content_editor/components/toolbar_link_button_spec.js b/spec/frontend/content_editor/components/toolbar_link_button_spec.js
new file mode 100644
index 00000000000..812e769c891
--- /dev/null
+++ b/spec/frontend/content_editor/components/toolbar_link_button_spec.js
@@ -0,0 +1,151 @@
+import { GlDropdown, GlDropdownDivider, GlFormInputGroup, GlButton } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ToolbarLinkButton from '~/content_editor/components/toolbar_link_button.vue';
+import { tiptapExtension as Link } from '~/content_editor/extensions/link';
+import { hasSelection } from '~/content_editor/services/utils';
+import { createTestEditor, mockChainedCommands } from '../test_utils';
+
+jest.mock('~/content_editor/services/utils');
+
+describe('content_editor/components/toolbar_link_button', () => {
+ let wrapper;
+ let editor;
+
+ const buildWrapper = () => {
+ wrapper = mountExtended(ToolbarLinkButton, {
+ propsData: {
+ tiptapEditor: editor,
+ },
+ stubs: {
+ GlFormInputGroup,
+ },
+ });
+ };
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownDivider = () => wrapper.findComponent(GlDropdownDivider);
+ const findLinkURLInput = () => wrapper.findComponent(GlFormInputGroup).find('input[type="text"]');
+ const findApplyLinkButton = () => wrapper.findComponent(GlButton);
+ const findRemoveLinkButton = () => wrapper.findByText('Remove link');
+
+ beforeEach(() => {
+ editor = createTestEditor({
+ extensions: [Link],
+ });
+ });
+
+ afterEach(() => {
+ editor.destroy();
+ wrapper.destroy();
+ });
+
+ it('renders dropdown component', () => {
+ buildWrapper();
+
+ expect(findDropdown().html()).toMatchSnapshot();
+ });
+
+ describe('when there is an active link', () => {
+ beforeEach(() => {
+ jest.spyOn(editor, 'isActive');
+ editor.isActive.mockReturnValueOnce(true);
+ buildWrapper();
+ });
+
+ it('sets dropdown as active when link extension is active', () => {
+ expect(findDropdown().props('toggleClass')).toEqual({ active: true });
+ });
+
+ it('displays a remove link dropdown option', () => {
+ expect(findDropdownDivider().exists()).toBe(true);
+ expect(wrapper.findByText('Remove link').exists()).toBe(true);
+ });
+
+ it('executes removeLink command when the remove link option is clicked', async () => {
+ const commands = mockChainedCommands(editor, ['focus', 'unsetLink', 'run']);
+
+ await findRemoveLinkButton().trigger('click');
+
+ expect(commands.unsetLink).toHaveBeenCalled();
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.run).toHaveBeenCalled();
+ });
+
+ it('updates the link with a new link when "Apply" button is clicked', async () => {
+ const commands = mockChainedCommands(editor, ['focus', 'unsetLink', 'setLink', 'run']);
+
+ await findLinkURLInput().setValue('https://example');
+ await findApplyLinkButton().trigger('click');
+
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.unsetLink).toHaveBeenCalled();
+ expect(commands.setLink).toHaveBeenCalledWith({ href: 'https://example' });
+ expect(commands.run).toHaveBeenCalled();
+ });
+ });
+
+ describe('when there is not an active link', () => {
+ beforeEach(() => {
+ jest.spyOn(editor, 'isActive');
+ editor.isActive.mockReturnValueOnce(false);
+ buildWrapper();
+ });
+
+ it('does not set dropdown as active', () => {
+ expect(findDropdown().props('toggleClass')).toEqual({ active: false });
+ });
+
+ it('does not display a remove link dropdown option', () => {
+ expect(findDropdownDivider().exists()).toBe(false);
+ expect(wrapper.findByText('Remove link').exists()).toBe(false);
+ });
+
+ it('sets the link to the value in the URL input when "Apply" button is clicked', async () => {
+ const commands = mockChainedCommands(editor, ['focus', 'unsetLink', 'setLink', 'run']);
+
+ await findLinkURLInput().setValue('https://example');
+ await findApplyLinkButton().trigger('click');
+
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.setLink).toHaveBeenCalledWith({ href: 'https://example' });
+ expect(commands.run).toHaveBeenCalled();
+ });
+ });
+
+ describe('when the user displays the dropdown', () => {
+ let commands;
+
+ beforeEach(() => {
+ commands = mockChainedCommands(editor, ['focus', 'extendMarkRange', 'run']);
+ });
+
+ describe('given the user has not selected text', () => {
+ beforeEach(() => {
+ hasSelection.mockReturnValueOnce(false);
+ });
+
+ it('the editor selection is extended to the current mark extent', () => {
+ buildWrapper();
+
+ findDropdown().vm.$emit('show');
+ expect(commands.extendMarkRange).toHaveBeenCalledWith(Link.name);
+ expect(commands.focus).toHaveBeenCalled();
+ expect(commands.run).toHaveBeenCalled();
+ });
+ });
+
+ describe('given the user has selected text', () => {
+ beforeEach(() => {
+ hasSelection.mockReturnValueOnce(true);
+ });
+
+ it('the editor does not modify the current selection', () => {
+ buildWrapper();
+
+ findDropdown().vm.$emit('show');
+ expect(commands.extendMarkRange).not.toHaveBeenCalled();
+ expect(commands.focus).not.toHaveBeenCalled();
+ expect(commands.run).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/content_editor/test_utils.js b/spec/frontend/content_editor/test_utils.js
index 3c8474d9f12..8e73aef678b 100644
--- a/spec/frontend/content_editor/test_utils.js
+++ b/spec/frontend/content_editor/test_utils.js
@@ -21,6 +21,24 @@ export const createTestEditor = ({ extensions = [] }) => {
});
};
+export const mockChainedCommands = (editor, commandNames = []) => {
+ const commandMocks = commandNames.reduce(
+ (accum, commandName) => ({
+ ...accum,
+ [commandName]: jest.fn(),
+ }),
+ {},
+ );
+
+ Object.keys(commandMocks).forEach((commandName) => {
+ commandMocks[commandName].mockReturnValue(commandMocks);
+ });
+
+ jest.spyOn(editor, 'chain').mockImplementation(() => commandMocks);
+
+ return commandMocks;
+};
+
/**
* Creates a Content Editor extension for testing
* purposes.