From a846015f4d01c78fe84f78883c0423e5c2d519c6 Mon Sep 17 00:00:00 2001 From: Lyndsi Kay Williams <55605634+lyndsiWilliams@users.noreply.github.com> Date: Tue, 20 Apr 2021 18:59:48 -0500 Subject: [PATCH] fix: Center each import icon and add a tooltip II (#14192) --- .../views/CRUD/chart/ChartList_spec.jsx | 45 +++++++++++++++++++ .../CRUD/dashboard/DashboardList_spec.jsx | 45 +++++++++++++++++++ .../CRUD/data/database/DatabaseList_spec.jsx | 44 ++++++++++++++++++ .../CRUD/data/dataset/DatasetList_spec.jsx | 45 +++++++++++++++++++ .../data/savedquery/SavedQueryList_spec.jsx | 34 +++++++++----- .../src/components/Menu/SubMenu.tsx | 2 + .../src/views/CRUD/chart/ChartList.tsx | 10 ++++- .../views/CRUD/dashboard/DashboardList.tsx | 10 ++++- .../views/CRUD/data/database/DatabaseList.tsx | 10 ++++- .../views/CRUD/data/dataset/DatasetList.tsx | 10 ++++- .../CRUD/data/savedquery/SavedQueryList.tsx | 14 +++++- 11 files changed, 252 insertions(+), 17 deletions(-) diff --git a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx index dfd19b7da3f..00d74033c68 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/chart/ChartList_spec.jsx @@ -24,6 +24,10 @@ import fetchMock from 'fetch-mock'; import * as featureFlags from 'src/featureFlags'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import { styledMount as mount } from 'spec/helpers/theming'; +import { render, screen, cleanup } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { QueryParamProvider } from 'use-query-params'; +import { act } from 'react-dom/test-utils'; import ChartList from 'src/views/CRUD/chart/ChartList'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; @@ -156,3 +160,44 @@ describe('ChartList', () => { expect(wrapper.find(ConfirmStatusChange)).toExist(); }); }); + +describe('RTL', () => { + async function renderAndWait() { + const mounted = act(async () => { + const mockedProps = {}; + render( + + + , + { useRedux: true }, + ); + }); + + return mounted; + } + + let isFeatureEnabledMock; + beforeEach(async () => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(() => true); + await renderAndWait(); + }); + + afterEach(() => { + cleanup(); + isFeatureEnabledMock.mockRestore(); + }); + + it('renders an "Import Chart" tooltip under import button', async () => { + const importButton = screen.getByTestId('import-button'); + userEvent.hover(importButton); + + await screen.findByRole('tooltip'); + const importTooltip = screen.getByRole('tooltip', { + name: 'Import charts', + }); + + expect(importTooltip).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx index c8d26862494..8bb9a48b11d 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/dashboard/DashboardList_spec.jsx @@ -25,6 +25,10 @@ import * as featureFlags from 'src/featureFlags'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; import { styledMount as mount } from 'spec/helpers/theming'; +import { render, screen, cleanup } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { QueryParamProvider } from 'use-query-params'; +import { act } from 'react-dom/test-utils'; import ConfirmStatusChange from 'src/components/ConfirmStatusChange'; import DashboardList from 'src/views/CRUD/dashboard/DashboardList'; @@ -172,3 +176,44 @@ describe('DashboardList', () => { expect(wrapper.find(ConfirmStatusChange)).toExist(); }); }); + +describe('RTL', () => { + async function renderAndWait() { + const mounted = act(async () => { + const mockedProps = {}; + render( + + + , + { useRedux: true }, + ); + }); + + return mounted; + } + + let isFeatureEnabledMock; + beforeEach(async () => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(() => true); + await renderAndWait(); + }); + + afterEach(() => { + cleanup(); + isFeatureEnabledMock.mockRestore(); + }); + + it('renders an "Import Dashboard" tooltip under import button', async () => { + const importButton = screen.getByTestId('import-button'); + userEvent.hover(importButton); + + await screen.findByRole('tooltip'); + const importTooltip = screen.getByRole('tooltip', { + name: 'Import dashboards', + }); + + expect(importTooltip).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx index 56455779d06..eabbc915b0a 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/data/database/DatabaseList_spec.jsx @@ -22,6 +22,10 @@ import configureStore from 'redux-mock-store'; import fetchMock from 'fetch-mock'; import { Provider } from 'react-redux'; import { styledMount as mount } from 'spec/helpers/theming'; +import { render, screen, cleanup } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { QueryParamProvider } from 'use-query-params'; +import * as featureFlags from 'src/featureFlags'; import DatabaseList from 'src/views/CRUD/data/database/DatabaseList'; import DatabaseModal from 'src/views/CRUD/data/database/DatabaseModal'; @@ -178,3 +182,43 @@ describe('DatabaseList', () => { ); }); }); + +describe('RTL', () => { + async function renderAndWait() { + const mounted = act(async () => { + render( + + + , + { useRedux: true }, + ); + }); + + return mounted; + } + + let isFeatureEnabledMock; + beforeEach(async () => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(() => true); + await renderAndWait(); + }); + + afterEach(() => { + cleanup(); + isFeatureEnabledMock.mockRestore(); + }); + + it('renders an "Import Database" tooltip under import button', async () => { + const importButton = screen.getByTestId('import-button'); + userEvent.hover(importButton); + + await screen.findByRole('tooltip'); + const importTooltip = screen.getByRole('tooltip', { + name: 'Import databases', + }); + + expect(importTooltip).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx index a816a60910f..b141da8d302 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/data/dataset/DatasetList_spec.jsx @@ -22,6 +22,10 @@ import configureStore from 'redux-mock-store'; import fetchMock from 'fetch-mock'; import { Provider } from 'react-redux'; import { styledMount as mount } from 'spec/helpers/theming'; +import { render, screen, cleanup } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { QueryParamProvider } from 'use-query-params'; +import * as featureFlags from 'src/featureFlags'; import DatasetList from 'src/views/CRUD/data/dataset/DatasetList'; import ListView from 'src/components/ListView'; @@ -175,3 +179,44 @@ describe('DatasetList', () => { ).toMatchInlineSnapshot(`"3 Selected (2 Physical, 1 Virtual)"`); }); }); + +describe('RTL', () => { + async function renderAndWait() { + const mounted = act(async () => { + const mockedProps = {}; + render( + + + , + { useRedux: true }, + ); + }); + + return mounted; + } + + let isFeatureEnabledMock; + beforeEach(async () => { + isFeatureEnabledMock = jest + .spyOn(featureFlags, 'isFeatureEnabled') + .mockImplementation(() => true); + await renderAndWait(); + }); + + afterEach(() => { + cleanup(); + isFeatureEnabledMock.mockRestore(); + }); + + it('renders an "Import Dataset" tooltip under import button', async () => { + const importButton = screen.getByTestId('import-button'); + userEvent.hover(importButton); + + await screen.findByRole('tooltip'); + const importTooltip = screen.getByRole('tooltip', { + name: 'Import datasets', + }); + + expect(importTooltip).toBeInTheDocument(); + }); +}); diff --git a/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx b/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx index 019c8c3fa8c..ac6f8c293e5 100644 --- a/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx +++ b/superset-frontend/spec/javascripts/views/CRUD/data/savedquery/SavedQueryList_spec.jsx @@ -22,7 +22,7 @@ import configureStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import fetchMock from 'fetch-mock'; import { styledMount as mount } from 'spec/helpers/theming'; -import { render, screen, cleanup } from 'spec/helpers/testing-library'; +import { render, screen, cleanup, waitFor } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; import { QueryParamProvider } from 'use-query-params'; import { act } from 'react-dom/test-utils'; @@ -229,10 +229,9 @@ describe('RTL', () => { const mounted = act(async () => { render( - - - + , + { useRedux: true }, ); }); @@ -296,26 +295,39 @@ describe('RTL', () => { it('renders an import button in the submenu', () => { // Grab and assert that import saved query button is visible - const importSavedQueryButton = screen.getAllByRole('button')[2]; - expect(importSavedQueryButton).toBeVisible(); + const importButton = screen.getByTestId('import-button'); + expect(importButton).toBeVisible(); + }); + + it('renders an "Import Saved Query" tooltip under import button', async () => { + const importButton = screen.getByTestId('import-button'); + userEvent.hover(importButton); + waitFor(() => { + expect(importButton).toHaveClass('ant-tooltip-open'); + screen.findByTestId('import-tooltip-test'); + const importTooltip = screen.getByRole('tooltip', { + name: 'Import queries', + }); + expect(importTooltip).toBeInTheDocument(); + }); }); it('renders an import model when import button is clicked', async () => { // Grab and click import saved query button to reveal modal - const importSavedQueryButton = screen.getAllByRole('button')[2]; - userEvent.click(importSavedQueryButton); + const importButton = screen.getByTestId('import-button'); + userEvent.click(importButton); // Grab and assert that saved query import modal's heading is visible const importSavedQueryModalHeading = screen.getByRole('heading', { - name: /import saved query/i, + name: 'Import queries', }); expect(importSavedQueryModalHeading).toBeVisible(); }); it('imports a saved query', () => { // Grab and click import saved query button to reveal modal - const importSavedQueryButton = screen.getAllByRole('button')[2]; - userEvent.click(importSavedQueryButton); + const importButton = screen.getByTestId('import-button'); + userEvent.click(importButton); // Grab "Choose File" input from import modal const chooseFileInput = screen.getByLabelText(/file\*/i); diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx b/superset-frontend/src/components/Menu/SubMenu.tsx index d109aa7f4c5..f8f9e3a9d34 100644 --- a/superset-frontend/src/components/Menu/SubMenu.tsx +++ b/superset-frontend/src/components/Menu/SubMenu.tsx @@ -33,6 +33,8 @@ const StyledHeader = styled.header` margin-right: ${({ theme }) => theme.gridUnit * 3}px; } .navbar-right { + display: flex; + align-items: center; padding: 8px 0; margin-right: 0; } diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/views/CRUD/chart/ChartList.tsx index 368db789d2b..7667b913e49 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx +++ b/superset-frontend/src/views/CRUD/chart/ChartList.tsx @@ -553,7 +553,15 @@ function ChartList(props: ChartListProps) { } if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) { subMenuButtons.push({ - name: , + name: ( + + + + ), buttonStyle: 'link', onClick: openChartImportModal, }); diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx index 6113ed69c47..28efa59ac2f 100644 --- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx +++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx @@ -500,7 +500,15 @@ function DashboardList(props: DashboardListProps) { } if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) { subMenuButtons.push({ - name: , + name: ( + + + + ), buttonStyle: 'link', onClick: openDashboardImportModal, }); diff --git a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx index 13d2ab8b540..81c99105c8a 100644 --- a/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx +++ b/superset-frontend/src/views/CRUD/data/database/DatabaseList.tsx @@ -184,7 +184,15 @@ function DatabaseList({ addDangerToast, addSuccessToast }: DatabaseListProps) { if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) { menuData.buttons.push({ - name: , + name: ( + + + + ), buttonStyle: 'link', onClick: openDatabaseImportModal, }); diff --git a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx index b6806dd17d3..e37c6fd27f4 100644 --- a/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx +++ b/superset-frontend/src/views/CRUD/data/dataset/DatasetList.tsx @@ -492,7 +492,15 @@ const DatasetList: FunctionComponent = ({ if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) { buttonArr.push({ - name: , + name: ( + + + + ), buttonStyle: 'link', onClick: openDatasetImportModal, }); diff --git a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx index 9f90bf559be..83200bdfef8 100644 --- a/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx +++ b/superset-frontend/src/views/CRUD/data/savedquery/SavedQueryList.tsx @@ -38,6 +38,7 @@ import SubMenu, { import ListView, { ListViewProps, Filters } from 'src/components/ListView'; import DeleteModal from 'src/components/DeleteModal'; import ActionsBar, { ActionProps } from 'src/components/ListView/ActionsBar'; +import { Tooltip } from 'src/common/components/Tooltip'; import { commonMenuData } from 'src/views/CRUD/data/common'; import { SavedQueryObject } from 'src/views/CRUD/types'; import copyTextToClipboard from 'src/utils/copy'; @@ -180,7 +181,16 @@ function SavedQueryList({ if (isFeatureEnabled(FeatureFlag.VERSIONED_EXPORT)) { subMenuButtons.push({ - name: , + name: ( + + + + ), buttonStyle: 'link', onClick: openSavedQueryImportModal, 'data-test': 'import-button', @@ -517,7 +527,7 @@ function SavedQueryList({