text: 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);
        });
      });
    });
  });
  