summaryrefslogtreecommitdiff
path: root/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 13:18:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 13:18:24 +0000
commit0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch)
tree4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
parent744144d28e3e7fddc117924fef88de5d9674fe4c (diff)
downloadgitlab-ce-0653e08efd039a5905f3fa4f6e9cef9f5d2f799c.tar.gz
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js')
-rw-r--r--spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js193
1 files changed, 193 insertions, 0 deletions
diff --git a/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js b/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
new file mode 100644
index 00000000000..e48f59f6d9c
--- /dev/null
+++ b/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js
@@ -0,0 +1,193 @@
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { NodeViewWrapper } from '@tiptap/vue-2';
+import { selectedRect as getSelectedRect } from 'prosemirror-tables';
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import TableCellBaseWrapper from '~/content_editor/components/wrappers/table_cell_base.vue';
+import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../../test_utils';
+
+jest.mock('prosemirror-tables');
+
+describe('content/components/wrappers/table_cell_base', () => {
+ let wrapper;
+ let editor;
+ let getPos;
+
+ const createWrapper = async (propsData = { cellType: 'td' }) => {
+ wrapper = shallowMountExtended(TableCellBaseWrapper, {
+ propsData: {
+ editor,
+ getPos,
+ ...propsData,
+ },
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownItemWithLabel = (name) =>
+ wrapper
+ .findAllComponents(GlDropdownItem)
+ .filter((dropdownItem) => dropdownItem.text().includes(name))
+ .at(0);
+ const findDropdownItemWithLabelExists = (name) =>
+ wrapper
+ .findAllComponents(GlDropdownItem)
+ .filter((dropdownItem) => dropdownItem.text().includes(name)).length > 0;
+ const setCurrentPositionInCell = () => {
+ const { $cursor } = editor.state.selection;
+
+ getPos.mockReturnValue($cursor.pos - $cursor.parentOffset - 1);
+ };
+ const mockDropdownHide = () => {
+ /*
+ * TODO: Replace this method with using the scoped hide function
+ * provided by BootstrapVue https://bootstrap-vue.org/docs/components/dropdown.
+ * GitLab UI is not exposing it in the default scope
+ */
+ findDropdown().vm.hide = jest.fn();
+ };
+
+ beforeEach(() => {
+ getPos = jest.fn();
+ editor = createTestEditor({});
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders a td node-view-wrapper with relative position', () => {
+ createWrapper();
+ expect(wrapper.findComponent(NodeViewWrapper).classes()).toContain('gl-relative');
+ expect(wrapper.findComponent(NodeViewWrapper).props().as).toBe('td');
+ });
+
+ it('displays dropdown when selection cursor is on the cell', async () => {
+ setCurrentPositionInCell();
+ createWrapper();
+
+ await nextTick();
+
+ expect(findDropdown().props()).toMatchObject({
+ category: 'tertiary',
+ icon: 'chevron-down',
+ size: 'small',
+ split: false,
+ });
+ expect(findDropdown().attributes()).toMatchObject({
+ boundary: 'viewport',
+ 'no-caret': '',
+ });
+ });
+
+ it('does not display dropdown when selection cursor is not on the cell', async () => {
+ createWrapper();
+
+ await nextTick();
+
+ expect(findDropdown().exists()).toBe(false);
+ });
+
+ describe('when dropdown is visible', () => {
+ beforeEach(async () => {
+ setCurrentPositionInCell();
+ getSelectedRect.mockReturnValue({
+ map: {
+ height: 1,
+ width: 1,
+ },
+ });
+
+ createWrapper();
+ await nextTick();
+
+ mockDropdownHide();
+ });
+
+ it.each`
+ dropdownItemLabel | commandName
+ ${'Insert column before'} | ${'addColumnBefore'}
+ ${'Insert column after'} | ${'addColumnAfter'}
+ ${'Insert row before'} | ${'addRowBefore'}
+ ${'Insert row after'} | ${'addRowAfter'}
+ ${'Delete table'} | ${'deleteTable'}
+ `(
+ 'executes $commandName when $dropdownItemLabel button is clicked',
+ ({ commandName, dropdownItemLabel }) => {
+ const mocks = mockChainedCommands(editor, [commandName, 'run']);
+
+ findDropdownItemWithLabel(dropdownItemLabel).vm.$emit('click');
+
+ expect(mocks[commandName]).toHaveBeenCalled();
+ },
+ );
+
+ it('does not allow deleting rows and columns', async () => {
+ expect(findDropdownItemWithLabelExists('Delete row')).toBe(false);
+ expect(findDropdownItemWithLabelExists('Delete column')).toBe(false);
+ });
+
+ it('allows deleting rows when there are more than 2 rows in the table', async () => {
+ const mocks = mockChainedCommands(editor, ['deleteRow', 'run']);
+
+ getSelectedRect.mockReturnValue({
+ map: {
+ height: 3,
+ },
+ });
+
+ emitEditorEvent({ tiptapEditor: editor, event: 'selectionUpdate' });
+
+ await nextTick();
+
+ findDropdownItemWithLabel('Delete row').vm.$emit('click');
+
+ expect(mocks.deleteRow).toHaveBeenCalled();
+ });
+
+ it('allows deleting columns when there are more than 1 column in the table', async () => {
+ const mocks = mockChainedCommands(editor, ['deleteColumn', 'run']);
+
+ getSelectedRect.mockReturnValue({
+ map: {
+ width: 2,
+ },
+ });
+
+ emitEditorEvent({ tiptapEditor: editor, event: 'selectionUpdate' });
+
+ await nextTick();
+
+ findDropdownItemWithLabel('Delete column').vm.$emit('click');
+
+ expect(mocks.deleteColumn).toHaveBeenCalled();
+ });
+
+ describe('when current row is the table’s header', () => {
+ beforeEach(async () => {
+ // Remove 2 rows condition
+ getSelectedRect.mockReturnValue({
+ map: {
+ height: 3,
+ },
+ });
+
+ createWrapper({ cellType: 'th' });
+
+ await nextTick();
+ });
+
+ it('does not allow adding a row before the header', async () => {
+ expect(findDropdownItemWithLabelExists('Insert row before')).toBe(false);
+ });
+
+ it('does not allow removing the header row', async () => {
+ createWrapper({ cellType: 'th' });
+
+ await nextTick();
+
+ expect(findDropdownItemWithLabelExists('Delete row')).toBe(false);
+ });
+ });
+ });
+});