mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
test: RTL overhaul - hackathon (#16626)
* CachedLabel_spec fully converted to RTL * ColumnTypeLabel_spec fully converted to RTL * MissingChart_spec fully converted to RTL * RefreshIntervalModal_spec mostly converted to RTL * HoverMenu_spec mostly converted to RTL * ResizableContainer_spec fully converted to RTL * ResizableHandle_spec fully converted to RTL * AggregateOption_spec fully converted to RTL * CheckboxControl_spec fully converted to RTL * ColorPickerControl_spec to RTL * Finished converting ColorPickerControl_spec to RTL/TS, also converted RefreshIntervalModal_spec to TS * Added unknown type to ColumnTypeLabelProps * Fixed ColumnTypeLabel_spec
This commit is contained in:
committed by
GitHub
parent
4af5ae08f9
commit
63aadd3fe4
@@ -17,23 +17,38 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
|
||||
import MissingChart from 'src/dashboard/components/MissingChart';
|
||||
|
||||
describe('MissingChart', () => {
|
||||
function setup(overrideProps) {
|
||||
const wrapper = shallow(<MissingChart height={100} {...overrideProps} />);
|
||||
return wrapper;
|
||||
}
|
||||
type MissingChartProps = {
|
||||
height: number;
|
||||
};
|
||||
|
||||
const setup = (overrides?: MissingChartProps) => (
|
||||
<MissingChart height={100} {...overrides} />
|
||||
);
|
||||
|
||||
describe('MissingChart', () => {
|
||||
it('renders a .missing-chart-container', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find('.missing-chart-container')).toExist();
|
||||
const rendered = render(setup());
|
||||
|
||||
const missingChartContainer = rendered.container.querySelector(
|
||||
'.missing-chart-container',
|
||||
);
|
||||
expect(missingChartContainer).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders a .missing-chart-body', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find('.missing-chart-body')).toExist();
|
||||
const rendered = render(setup());
|
||||
|
||||
const missingChartBody = rendered.container.querySelector(
|
||||
'.missing-chart-body',
|
||||
);
|
||||
const bodyText =
|
||||
'There is no chart definition associated with this component, could it have been deleted?<br><br>Delete this container and save to remove this message.';
|
||||
|
||||
expect(missingChartBody).toBeVisible();
|
||||
expect(missingChartBody?.innerHTML).toMatch(bodyText);
|
||||
});
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* 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 React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import ModalTrigger from 'src/components/ModalTrigger';
|
||||
import RefreshIntervalModal from 'src/dashboard/components/RefreshIntervalModal';
|
||||
import Alert from 'src/components/Alert';
|
||||
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||
|
||||
const getMountWrapper = props =>
|
||||
mount(<RefreshIntervalModal {...props} />, {
|
||||
wrappingComponent: ThemeProvider,
|
||||
wrappingComponentProps: {
|
||||
theme: supersetTheme,
|
||||
},
|
||||
});
|
||||
|
||||
describe('RefreshIntervalModal', () => {
|
||||
const mockedProps = {
|
||||
triggerNode: <i className="fa fa-edit" />,
|
||||
refreshFrequency: 10,
|
||||
onChange: jest.fn(),
|
||||
editMode: true,
|
||||
};
|
||||
it('is valid', () => {
|
||||
expect(
|
||||
React.isValidElement(<RefreshIntervalModal {...mockedProps} />),
|
||||
).toBe(true);
|
||||
});
|
||||
it('renders the trigger node', () => {
|
||||
const wrapper = getMountWrapper(mockedProps);
|
||||
expect(wrapper.find('.fa-edit')).toExist();
|
||||
});
|
||||
it('should render a interval seconds', () => {
|
||||
const wrapper = getMountWrapper(mockedProps);
|
||||
expect(wrapper.prop('refreshFrequency')).toEqual(10);
|
||||
});
|
||||
it('should change refreshFrequency with edit mode', () => {
|
||||
const wrapper = getMountWrapper(mockedProps);
|
||||
wrapper.instance().handleFrequencyChange(30);
|
||||
wrapper.instance().onSave();
|
||||
expect(mockedProps.onChange).toHaveBeenCalled();
|
||||
expect(mockedProps.onChange).toHaveBeenCalledWith(30, mockedProps.editMode);
|
||||
});
|
||||
it('should show warning message', () => {
|
||||
const props = {
|
||||
...mockedProps,
|
||||
refreshLimit: 3600,
|
||||
refreshWarning: 'Show warning',
|
||||
};
|
||||
|
||||
const wrapper = getMountWrapper(props);
|
||||
wrapper.find('span[role="button"]').simulate('click');
|
||||
|
||||
wrapper.instance().handleFrequencyChange(30);
|
||||
wrapper.update();
|
||||
expect(wrapper.find(ModalTrigger).find(Alert)).toExist();
|
||||
|
||||
wrapper.instance().handleFrequencyChange(3601);
|
||||
wrapper.update();
|
||||
expect(wrapper.find(ModalTrigger).find(Alert)).not.toExist();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* 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 React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, screen } from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import fetchMock from 'fetch-mock';
|
||||
|
||||
import ModalTrigger from 'src/components/ModalTrigger';
|
||||
import RefreshIntervalModal from 'src/dashboard/components/RefreshIntervalModal';
|
||||
import HeaderActionsDropdown from 'src/dashboard/components/Header/HeaderActionsDropdown';
|
||||
import Alert from 'src/components/Alert';
|
||||
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||
|
||||
describe('RefreshIntervalModal - Enzyme', () => {
|
||||
const getMountWrapper = (props: any) =>
|
||||
mount(<RefreshIntervalModal {...props} />, {
|
||||
wrappingComponent: ThemeProvider,
|
||||
wrappingComponentProps: {
|
||||
theme: supersetTheme,
|
||||
},
|
||||
});
|
||||
const mockedProps = {
|
||||
triggerNode: <i className="fa fa-edit" />,
|
||||
refreshFrequency: 10,
|
||||
onChange: jest.fn(),
|
||||
editMode: true,
|
||||
};
|
||||
it('should show warning message', () => {
|
||||
const props = {
|
||||
...mockedProps,
|
||||
refreshLimit: 3600,
|
||||
refreshWarning: 'Show warning',
|
||||
};
|
||||
|
||||
const wrapper = getMountWrapper(props);
|
||||
wrapper.find('span[role="button"]').simulate('click');
|
||||
|
||||
// @ts-ignore (for handleFrequencyChange)
|
||||
wrapper.instance().handleFrequencyChange(30);
|
||||
wrapper.update();
|
||||
expect(wrapper.find(ModalTrigger).find(Alert)).toExist();
|
||||
|
||||
// @ts-ignore (for handleFrequencyChange)
|
||||
wrapper.instance().handleFrequencyChange(3601);
|
||||
wrapper.update();
|
||||
expect(wrapper.find(ModalTrigger).find(Alert)).not.toExist();
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
const createProps = () => ({
|
||||
addSuccessToast: jest.fn(),
|
||||
addDangerToast: jest.fn(),
|
||||
customCss: '#save-dash-split-button{margin-left: 100px;}',
|
||||
dashboardId: 1,
|
||||
dashboardInfo: {
|
||||
id: 1,
|
||||
dash_edit_perm: true,
|
||||
dash_save_perm: true,
|
||||
userId: '1',
|
||||
metadata: {},
|
||||
common: {
|
||||
conf: {},
|
||||
},
|
||||
},
|
||||
dashboardTitle: 'Title',
|
||||
editMode: false,
|
||||
expandedSlices: {},
|
||||
forceRefreshAllCharts: jest.fn(),
|
||||
hasUnsavedChanges: false,
|
||||
isLoading: false,
|
||||
layout: {},
|
||||
dataMask: {},
|
||||
onChange: jest.fn(),
|
||||
onSave: jest.fn(),
|
||||
refreshFrequency: 0,
|
||||
setRefreshFrequency: jest.fn(),
|
||||
shouldPersistRefreshFrequency: false,
|
||||
showPropertiesModal: jest.fn(),
|
||||
startPeriodicRender: jest.fn(),
|
||||
updateCss: jest.fn(),
|
||||
userCanEdit: false,
|
||||
userCanSave: false,
|
||||
userCanShare: false,
|
||||
lastModifiedTime: 0,
|
||||
});
|
||||
|
||||
const editModeOnProps = {
|
||||
...createProps(),
|
||||
editMode: true,
|
||||
};
|
||||
|
||||
const setup = (overrides?: any) => (
|
||||
<div className="dashboard-header">
|
||||
<HeaderActionsDropdown {...editModeOnProps} {...overrides} />
|
||||
</div>
|
||||
);
|
||||
|
||||
fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {});
|
||||
|
||||
const openRefreshIntervalModal = async () => {
|
||||
const headerActionsButton = screen.getByRole('img', { name: 'more-horiz' });
|
||||
userEvent.click(headerActionsButton);
|
||||
|
||||
const autoRefreshOption = screen.getByText('Set auto-refresh interval');
|
||||
userEvent.click(autoRefreshOption);
|
||||
};
|
||||
|
||||
const displayOptions = async () => {
|
||||
// Click default refresh interval option to display other options
|
||||
userEvent.click(screen.getByText(/don't refresh/i));
|
||||
};
|
||||
|
||||
const defaultRefreshIntervalModalProps = {
|
||||
triggerNode: <i className="fa fa-edit" />,
|
||||
refreshFrequency: 0,
|
||||
onChange: jest.fn(),
|
||||
editMode: true,
|
||||
};
|
||||
|
||||
describe('RefreshIntervalModal - RTL', () => {
|
||||
it('is valid', () => {
|
||||
expect(
|
||||
React.isValidElement(
|
||||
<RefreshIntervalModal {...defaultRefreshIntervalModalProps} />,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('renders refresh interval modal', async () => {
|
||||
render(setup(editModeOnProps));
|
||||
await openRefreshIntervalModal();
|
||||
|
||||
// Assert that modal exists by checking for the modal title
|
||||
expect(screen.getByText('Refresh interval')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders refresh interval options', async () => {
|
||||
render(setup(editModeOnProps));
|
||||
await openRefreshIntervalModal();
|
||||
await displayOptions();
|
||||
|
||||
// Assert that both "Don't refresh" instances exist
|
||||
// - There will be two at this point, the default option and the dropdown option
|
||||
const dontRefreshInstances = screen.getAllByText(/don't refresh/i);
|
||||
expect(dontRefreshInstances).toHaveLength(2);
|
||||
dontRefreshInstances.forEach(option => {
|
||||
expect(option).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Assert that all the other options exist
|
||||
const options = [
|
||||
screen.getByText(/10 seconds/i),
|
||||
screen.getByText(/30 seconds/i),
|
||||
screen.getByText(/1 minute/i),
|
||||
screen.getByText(/5 minutes/i),
|
||||
screen.getByText(/30 minutes/i),
|
||||
screen.getByText(/1 hour/i),
|
||||
screen.getByText(/6 hours/i),
|
||||
screen.getByText(/12 hours/i),
|
||||
screen.getByText(/24 hours/i),
|
||||
];
|
||||
options.forEach(option => {
|
||||
expect(option).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should change selected value', async () => {
|
||||
render(setup(editModeOnProps));
|
||||
await openRefreshIntervalModal();
|
||||
|
||||
// Initial selected value should be "Don't refresh"
|
||||
const selectedValue = screen.getByText(/don't refresh/i);
|
||||
expect(selectedValue.title).toMatch(/don't refresh/i);
|
||||
|
||||
// Display options and select "10 seconds"
|
||||
await displayOptions();
|
||||
userEvent.click(screen.getByText(/10 seconds/i));
|
||||
|
||||
// Selected value should now be "10 seconds"
|
||||
expect(selectedValue.title).toMatch(/10 seconds/i);
|
||||
expect(selectedValue.title).not.toMatch(/don't refresh/i);
|
||||
});
|
||||
|
||||
it('should save a newly-selected value', async () => {
|
||||
render(setup(editModeOnProps));
|
||||
await openRefreshIntervalModal();
|
||||
await displayOptions();
|
||||
|
||||
screen.logTestingPlaygroundURL();
|
||||
// Select a new interval and click save
|
||||
userEvent.click(screen.getByText(/10 seconds/i));
|
||||
userEvent.click(screen.getByRole('button', { name: /save/i }));
|
||||
|
||||
expect(editModeOnProps.setRefreshFrequency).toHaveBeenCalled();
|
||||
expect(editModeOnProps.setRefreshFrequency).toHaveBeenCalledWith(
|
||||
10,
|
||||
editModeOnProps.editMode,
|
||||
);
|
||||
});
|
||||
|
||||
it('should show warning message', async () => {
|
||||
// TODO (lyndsiWilliams): This test is incomplete
|
||||
const warningProps = {
|
||||
...editModeOnProps,
|
||||
refreshLimit: 3600,
|
||||
refreshWarning: 'Show warning',
|
||||
};
|
||||
|
||||
render(setup(warningProps));
|
||||
await openRefreshIntervalModal();
|
||||
await displayOptions();
|
||||
|
||||
userEvent.click(screen.getByText(/30 seconds/i));
|
||||
userEvent.click(screen.getByRole('button', { name: /save/i }));
|
||||
|
||||
// screen.debug(screen.getByRole('alert'));
|
||||
expect.anything();
|
||||
});
|
||||
});
|
||||
@@ -17,13 +17,14 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
|
||||
import HoverMenu from 'src/dashboard/components/menu/HoverMenu';
|
||||
|
||||
describe('HoverMenu', () => {
|
||||
it('should render a div.hover-menu', () => {
|
||||
const wrapper = shallow(<HoverMenu />);
|
||||
expect(wrapper.find('.hover-menu')).toExist();
|
||||
it('should render a hover menu', () => {
|
||||
const rendered = render(<HoverMenu />);
|
||||
const hoverMenu = rendered.container.querySelector('.hover-menu');
|
||||
expect(hoverMenu).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -17,20 +17,46 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Resizable } from 're-resizable';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
|
||||
import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer';
|
||||
|
||||
interface ResizableContainerProps {
|
||||
id: string;
|
||||
children?: object;
|
||||
adjustableWidth?: boolean;
|
||||
adjustableHeight?: boolean;
|
||||
gutterWidth?: number;
|
||||
widthStep?: number;
|
||||
heightStep?: number;
|
||||
widthMultiple?: number;
|
||||
heightMultiple?: number;
|
||||
minWidthMultiple?: number;
|
||||
maxWidthMultiple?: number;
|
||||
minHeightMultiple?: number;
|
||||
maxHeightMultiple?: number;
|
||||
staticHeight?: number;
|
||||
staticHeightMultiple?: number;
|
||||
staticWidth?: number;
|
||||
staticWidthMultiple?: number;
|
||||
onResizeStop?: () => {};
|
||||
onResize?: () => {};
|
||||
onResizeStart?: () => {};
|
||||
editMode: boolean;
|
||||
}
|
||||
|
||||
describe('ResizableContainer', () => {
|
||||
const props = { editMode: false, id: 'id' };
|
||||
|
||||
function setup(propOverrides) {
|
||||
return shallow(<ResizableContainer {...props} {...propOverrides} />);
|
||||
}
|
||||
const setup = (overrides?: ResizableContainerProps) => (
|
||||
<ResizableContainer {...props} {...overrides} />
|
||||
);
|
||||
|
||||
it('should render a Resizable', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper.find(Resizable)).toExist();
|
||||
it('should render a Resizable container', () => {
|
||||
const rendered = render(setup());
|
||||
const resizableContainer = rendered.container.querySelector(
|
||||
'.resizable-container',
|
||||
);
|
||||
expect(resizableContainer).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -17,29 +17,33 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
|
||||
import ResizableHandle from 'src/dashboard/components/resizable/ResizableHandle';
|
||||
|
||||
/* eslint-disable react/jsx-pascal-case */
|
||||
describe('ResizableHandle', () => {
|
||||
it('should render a right resize handle', () => {
|
||||
const wrapper = shallow(<ResizableHandle.right />);
|
||||
expect(wrapper.find('.resize-handle.resize-handle--right')).toExist();
|
||||
const rendered = render(<ResizableHandle.right />);
|
||||
expect(
|
||||
rendered.container.querySelector('.resize-handle.resize-handle--right'),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('should render a bottom resize handle', () => {
|
||||
const wrapper = shallow(<ResizableHandle.bottom />);
|
||||
expect(wrapper.find('.resize-handle.resize-handle--bottom')).toHaveLength(
|
||||
1,
|
||||
);
|
||||
const rendered = render(<ResizableHandle.bottom />);
|
||||
expect(
|
||||
rendered.container.querySelector('.resize-handle.resize-handle--bottom'),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
it('should render a bottomRight resize handle', () => {
|
||||
const wrapper = shallow(<ResizableHandle.bottomRight />);
|
||||
const rendered = render(<ResizableHandle.bottomRight />);
|
||||
expect(
|
||||
wrapper.find('.resize-handle.resize-handle--bottom-right'),
|
||||
).toHaveLength(1);
|
||||
rendered.container.querySelector(
|
||||
'.resize-handle.resize-handle--bottom-right',
|
||||
),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
/* eslint-enable react/jsx-pascal-case */
|
||||
Reference in New Issue
Block a user