airbnb/caravel

View on GitHub
superset-frontend/src/dashboard/components/gridComponents/Tabs.test.jsx

Summary

Maintainability
C
1 day
Test Coverage
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import { fireEvent, render } from 'spec/helpers/testing-library';

import { AntdModal } from 'src/components';
import fetchMock from 'fetch-mock';
import { Tabs } from 'src/dashboard/components/gridComponents/Tabs';
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
import emptyDashboardLayout from 'src/dashboard/fixtures/emptyDashboardLayout';
import { dashboardLayoutWithTabs } from 'spec/fixtures/mockDashboardLayout';
import { getMockStore } from 'spec/fixtures/mockStore';
import { nativeFilters } from 'spec/fixtures/mockNativeFilters';
import { initialState } from 'src/SqlLab/fixtures';

jest.mock('src/dashboard/components/dnd/DragDroppable', () => ({
  Draggable: ({ children }) => (
    <div data-test="mock-draggable">{children({})}</div>
  ),
  Droppable: ({ children }) => (
    <div data-test="mock-droppable">{children({})}</div>
  ),
}));
jest.mock('src/dashboard/containers/DashboardComponent', () => ({ id }) => (
  <div data-test="mock-dashboard-component">{id}</div>
));

jest.mock(
  'src/dashboard/components/DeleteComponentButton',
  () =>
    ({ onDelete }) => (
      <button
        type="button"
        data-test="mock-delete-component-button"
        onClick={onDelete}
      >
        Delete
      </button>
    ),
);

fetchMock.post('glob:*/r/shortener/', {});

const props = {
  id: 'TABS_ID',
  parentId: DASHBOARD_ROOT_ID,
  component: dashboardLayoutWithTabs.present.TABS_ID,
  parentComponent: dashboardLayoutWithTabs.present[DASHBOARD_ROOT_ID],
  index: 0,
  depth: 1,
  renderTabContent: true,
  editMode: false,
  availableColumnCount: 12,
  columnWidth: 50,
  dashboardId: 1,
  onResizeStart() {},
  onResize() {},
  onResizeStop() {},
  createComponent() {},
  handleComponentDrop() {},
  onChangeTab() {},
  deleteComponent() {},
  updateComponents() {},
  logEvent() {},
  dashboardLayout: emptyDashboardLayout,
  nativeFilters: nativeFilters.filters,
};

const mockStore = getMockStore({
  ...initialState,
  dashboardLayout: dashboardLayoutWithTabs,
  dashboardFilters: {},
});

function setup(overrideProps) {
  return render(<Tabs {...props} {...overrideProps} />, {
    useDnd: true,
    useRouter: true,
    store: mockStore,
  });
}

test('should render a Draggable', () => {
  // test just Tabs with no children Draggable
  const { getByTestId } = setup({
    component: { ...props.component, children: [] },
  });
  expect(getByTestId('mock-draggable')).toBeInTheDocument();
});

test('should render non-editable tabs', () => {
  const { getAllByRole, container } = setup();
  expect(getAllByRole('tab')[0]).toBeInTheDocument();
  expect(container.querySelector('.ant-tabs-nav-add')).not.toBeInTheDocument();
});

test('should render a tab pane for each child', () => {
  const { getAllByRole } = setup();
  expect(getAllByRole('tab')).toHaveLength(props.component.children.length);
});

test('should render editable tabs in editMode', () => {
  const { getAllByRole, container } = setup({ editMode: true });
  expect(getAllByRole('tab')[0]).toBeInTheDocument();
  expect(container.querySelector('.ant-tabs-nav-add')).toBeInTheDocument();
});

test('should render a DashboardComponent for each child', () => {
  // note: this does not test Tab content
  const { getAllByTestId } = setup({ renderTabContent: false });
  expect(getAllByTestId('mock-dashboard-component')).toHaveLength(
    props.component.children.length,
  );
});

test('should call createComponent if the (+) tab is clicked', () => {
  const createComponent = jest.fn();
  const { getAllByRole } = setup({ editMode: true, createComponent });
  const addButtons = getAllByRole('button', { name: 'Add tab' });
  fireEvent.click(addButtons[0]);
  expect(createComponent).toHaveBeenCalledTimes(1);
});

test('should call onChangeTab when a tab is clicked', () => {
  const onChangeTab = jest.fn();
  const { getByRole } = setup({ editMode: true, onChangeTab });
  const newTab = getByRole('tab', { selected: false });
  fireEvent.click(newTab);
  expect(onChangeTab).toHaveBeenCalledTimes(1);
});

test('should not call onChangeTab when anchor link is clicked', () => {
  const onChangeTab = jest.fn();
  const { getByRole } = setup({ editMode: true, onChangeTab });
  const currentTab = getByRole('tab', { selected: true });
  fireEvent.click(currentTab);

  expect(onChangeTab).toHaveBeenCalledTimes(0);
});

test('should render a HoverMenu in editMode', () => {
  const { container } = setup({ editMode: true });
  expect(container.querySelector('.hover-menu')).toBeInTheDocument();
});

test('should render a DeleteComponentButton in editMode', () => {
  const { getByTestId } = setup({ editMode: true });
  expect(getByTestId('mock-delete-component-button')).toBeInTheDocument();
});

test('should call deleteComponent when deleted', () => {
  const deleteComponent = jest.fn();
  const { getByTestId } = setup({ editMode: true, deleteComponent });
  fireEvent.click(getByTestId('mock-delete-component-button'));
  expect(deleteComponent).toHaveBeenCalledTimes(1);
});

test('should direct display direct-link tab', () => {
  // display child in directPathToChild list
  const directPathToChild =
    dashboardLayoutWithTabs.present.ROW_ID2.parents.slice();
  const directLinkProps = {
    ...props,
    directPathToChild,
  };
  const { getByRole } = setup(directLinkProps);
  expect(getByRole('tab', { selected: true })).toHaveTextContent('TAB_ID2');
});

test('should render Modal when clicked remove tab button', () => {
  const deleteComponent = jest.fn();
  const modalMock = jest.spyOn(AntdModal, 'confirm');
  const { container } = setup({ editMode: true, deleteComponent });
  fireEvent.click(container.querySelector('.ant-tabs-tab-remove'));
  expect(modalMock).toHaveBeenCalledTimes(1);
  expect(deleteComponent).toHaveBeenCalledTimes(0);
});

test('should set new tab key if dashboardId was changed', () => {
  const { getByRole } = setup({
    ...props,
    dashboardId: 2,
    component: dashboardLayoutWithTabs.present.TAB_ID,
  });
  expect(getByRole('tab', { selected: true })).toHaveTextContent('ROW_ID');
});