gitlab-org--gitlab-foss/spec/frontend/content_editor/components/wrappers/table_cell_base_spec.js

194 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 tables 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);
});
});
});
});