chore: Create a generic header component for Explore and Dashboard (#20044)

* chore: Create a generic header component for Explore and Dashboard

* Add tests

* Fix undefined error

* Remove duplicate code

* Fix cypress test
This commit is contained in:
Kamil Gabryjelski
2022-05-13 15:36:18 +02:00
committed by GitHub
parent b53daa91ec
commit 1cd002e801
13 changed files with 730 additions and 685 deletions

View File

@@ -18,10 +18,13 @@
*/
import React from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import sinon from 'sinon';
import { render, screen, waitFor } from 'spec/helpers/testing-library';
import userEvent from '@testing-library/user-event';
import fetchMock from 'fetch-mock';
import * as chartAction from 'src/components/Chart/chartAction';
import * as downloadAsImage from 'src/utils/downloadAsImage';
import * as exploreUtils from 'src/explore/exploreUtils';
import ExploreHeader from '.';
const chartEndpoint = 'glob:*api/v1/chart/*';
@@ -30,6 +33,7 @@ fetchMock.get(chartEndpoint, { json: 'foo' });
const createProps = () => ({
chart: {
id: 1,
latestQueryFormData: {
viz_type: 'histogram',
datasource: '49__table',
@@ -88,17 +92,29 @@ const createProps = () => ({
},
slice_name: 'Age distribution of respondents',
actions: {
postChartFormData: () => null,
updateChartTitle: () => null,
fetchFaveStar: () => null,
saveFaveStar: () => null,
postChartFormData: jest.fn(),
updateChartTitle: jest.fn(),
fetchFaveStar: jest.fn(),
saveFaveStar: jest.fn(),
redirectSQLLab: jest.fn(),
},
user: {
userId: 1,
},
onSaveChart: jest.fn(),
canOverwrite: false,
canDownload: false,
isStarred: false,
});
fetchMock.post(
'http://api/v1/chart/data?form_data=%7B%22slice_id%22%3A318%7D',
{ body: {} },
{
sendAsJson: false,
},
);
test('Cancelling changes to the properties should reset previous properties', () => {
const props = createProps();
render(<ExploreHeader {...props} />, { useRedux: true });
@@ -136,3 +152,208 @@ test('Save disabled', () => {
userEvent.click(screen.getByText('Save'));
expect(props.onSaveChart).not.toHaveBeenCalled();
});
describe('Additional actions tests', () => {
test('Should render a button', () => {
const props = createProps();
render(<ExploreHeader {...props} />, { useRedux: true });
expect(screen.getByLabelText('Menu actions trigger')).toBeInTheDocument();
});
test('Should open a menu', () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(screen.getByText('Edit chart properties')).toBeInTheDocument();
expect(screen.getByText('Download')).toBeInTheDocument();
expect(screen.getByText('Share')).toBeInTheDocument();
expect(screen.getByText('View query')).toBeInTheDocument();
expect(screen.getByText('Run in SQL Lab')).toBeInTheDocument();
expect(
screen.queryByText('Set up an email report'),
).not.toBeInTheDocument();
expect(screen.queryByText('Manage email report')).not.toBeInTheDocument();
});
test('Should open download submenu', async () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(screen.queryByText('Export to .CSV')).not.toBeInTheDocument();
expect(screen.queryByText('Export to .JSON')).not.toBeInTheDocument();
expect(screen.queryByText('Download as image')).not.toBeInTheDocument();
expect(screen.getByText('Download')).toBeInTheDocument();
userEvent.hover(screen.getByText('Download'));
expect(await screen.findByText('Export to .CSV')).toBeInTheDocument();
expect(await screen.findByText('Export to .JSON')).toBeInTheDocument();
expect(await screen.findByText('Download as image')).toBeInTheDocument();
});
test('Should open share submenu', async () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(
screen.queryByText('Copy permalink to clipboard'),
).not.toBeInTheDocument();
expect(screen.queryByText('Embed code')).not.toBeInTheDocument();
expect(screen.queryByText('Share chart by email')).not.toBeInTheDocument();
expect(screen.getByText('Share')).toBeInTheDocument();
userEvent.hover(screen.getByText('Share'));
expect(
await screen.findByText('Copy permalink to clipboard'),
).toBeInTheDocument();
expect(await screen.findByText('Embed code')).toBeInTheDocument();
expect(await screen.findByText('Share chart by email')).toBeInTheDocument();
});
test('Should call onOpenPropertiesModal when click on "Edit chart properties"', async () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
expect(props.actions.redirectSQLLab).toBeCalledTimes(0);
userEvent.click(screen.getByLabelText('Menu actions trigger'));
userEvent.click(
screen.getByRole('menuitem', { name: 'Edit chart properties' }),
);
expect(await screen.findByText('Edit Chart Properties')).toBeVisible();
});
test('Should call getChartDataRequest when click on "View query"', async () => {
const props = createProps();
const getChartDataRequest = jest.spyOn(chartAction, 'getChartDataRequest');
render(<ExploreHeader {...props} />, {
useRedux: true,
});
expect(getChartDataRequest).toBeCalledTimes(0);
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(getChartDataRequest).toBeCalledTimes(0);
const menuItem = screen.getByText('View query').parentElement!;
userEvent.click(menuItem);
await waitFor(() => expect(getChartDataRequest).toBeCalledTimes(1));
});
test('Should call onOpenInEditor when click on "Run in SQL Lab"', () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
expect(props.actions.redirectSQLLab).toBeCalledTimes(0);
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(props.actions.redirectSQLLab).toBeCalledTimes(0);
userEvent.click(screen.getByRole('menuitem', { name: 'Run in SQL Lab' }));
expect(props.actions.redirectSQLLab).toBeCalledTimes(1);
});
describe('Download', () => {
let spyDownloadAsImage = sinon.spy();
let spyExportChart = sinon.spy();
beforeEach(() => {
spyDownloadAsImage = sinon.spy(downloadAsImage, 'default');
spyExportChart = sinon.spy(exploreUtils, 'exportChart');
});
afterEach(() => {
spyDownloadAsImage.restore();
spyExportChart.restore();
});
test('Should call downloadAsImage when click on "Download as image"', async () => {
const props = createProps();
const spy = jest.spyOn(downloadAsImage, 'default');
render(<ExploreHeader {...props} />, {
useRedux: true,
});
expect(spy).toBeCalledTimes(0);
userEvent.click(screen.getByLabelText('Menu actions trigger'));
expect(spy).toBeCalledTimes(0);
userEvent.hover(screen.getByText('Download'));
const downloadAsImageElement = await screen.findByText(
'Download as image',
);
userEvent.click(downloadAsImageElement);
expect(spy).toBeCalledTimes(1);
});
test('Should not export to CSV if canDownload=false', async () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
userEvent.hover(screen.getByText('Download'));
const exportCSVElement = await screen.findByText('Export to .CSV');
userEvent.click(exportCSVElement);
expect(spyExportChart.callCount).toBe(0);
spyExportChart.restore();
});
test('Should export to CSV if canDownload=true', async () => {
const props = createProps();
props.canDownload = true;
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
userEvent.hover(screen.getByText('Download'));
const exportCSVElement = await screen.findByText('Export to .CSV');
userEvent.click(exportCSVElement);
expect(spyExportChart.callCount).toBe(1);
spyExportChart.restore();
});
test('Should export to JSON', async () => {
const props = createProps();
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
userEvent.hover(screen.getByText('Download'));
const exportJsonElement = await screen.findByText('Export to .JSON');
userEvent.click(exportJsonElement);
expect(spyExportChart.callCount).toBe(1);
});
test('Should export to pivoted CSV if canDownloadCSV=true and viz_type=pivot_table_v2', async () => {
const props = createProps();
props.canDownload = true;
props.chart.latestQueryFormData.viz_type = 'pivot_table_v2';
render(<ExploreHeader {...props} />, {
useRedux: true,
});
userEvent.click(screen.getByLabelText('Menu actions trigger'));
userEvent.hover(screen.getByText('Download'));
const exportCSVElement = await screen.findByText(
'Export to pivoted .CSV',
);
userEvent.click(exportCSVElement);
expect(spyExportChart.callCount).toBe(1);
});
});
});