diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-08 21:10:05 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-08 21:10:05 +0000 |
commit | 9882aeb510f9e3125a6451eb08681ea9d90dd5e2 (patch) | |
tree | 02dbb3cb032ee91c50fdccb00893bbc94ec04acc /spec/frontend/content_editor | |
parent | 8a03b5424b73679d852fbf43781d9422c83869f7 (diff) | |
download | gitlab-ce-9882aeb510f9e3125a6451eb08681ea9d90dd5e2.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/content_editor')
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. |