mirror of https://github.com/apache/superset.git
chore(explore): migrate enzyme to RTL (#26272)
This commit is contained in:
parent
63ded0fc58
commit
55846992d2
|
@ -16,14 +16,9 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { mount } from 'enzyme';
|
import { ThemeProvider, supersetTheme } from '@superset-ui/core';
|
||||||
import {
|
|
||||||
ThemeProvider,
|
|
||||||
supersetTheme,
|
|
||||||
promiseTimeout,
|
|
||||||
} from '@superset-ui/core';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from 'spec/helpers/testing-library';
|
import { render, screen, waitFor } from 'spec/helpers/testing-library';
|
||||||
import Control, { ControlProps } from 'src/explore/components/Control';
|
import Control, { ControlProps } from 'src/explore/components/Control';
|
||||||
|
|
||||||
const defaultProps: ControlProps = {
|
const defaultProps: ControlProps = {
|
||||||
|
@ -41,54 +36,50 @@ const setup = (overrides = {}) => (
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('Control', () => {
|
test('render a control', () => {
|
||||||
it('render a control', () => {
|
render(setup());
|
||||||
render(setup());
|
|
||||||
|
|
||||||
const checkbox = screen.getByRole('checkbox');
|
const checkbox = screen.getByRole('checkbox');
|
||||||
expect(checkbox).toBeVisible();
|
expect(checkbox).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render null if type is not exit', () => {
|
test('render null if type is not exit', () => {
|
||||||
render(
|
render(
|
||||||
setup({
|
setup({
|
||||||
type: undefined,
|
type: undefined,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render null if type is not valid', () => {
|
test('render null if type is not valid', () => {
|
||||||
render(
|
render(
|
||||||
setup({
|
setup({
|
||||||
type: 'UnknownControl',
|
type: 'UnknownControl',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('render null if isVisible is false', () => {
|
test('render null if isVisible is false', () => {
|
||||||
render(
|
render(
|
||||||
setup({
|
setup({
|
||||||
isVisible: false,
|
isVisible: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('call setControlValue if isVisible is false', () => {
|
test('call setControlValue if isVisible is false', async () => {
|
||||||
const wrapper = mount(
|
const { rerender } = render(
|
||||||
setup({
|
setup({
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
default: false,
|
default: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
wrapper.setProps({
|
expect(defaultProps.actions.setControlValue).not.toBeCalled();
|
||||||
isVisible: false,
|
rerender(setup({ isVisible: false, default: false }));
|
||||||
default: false,
|
await waitFor(() =>
|
||||||
});
|
expect(defaultProps.actions.setControlValue).toBeCalled(),
|
||||||
promiseTimeout(() => {
|
);
|
||||||
expect(defaultProps.actions.setControlValue).toBeCalled();
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,17 +21,26 @@ import configureStore from 'redux-mock-store';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
import { shallow } from 'enzyme';
|
import {
|
||||||
import { Radio } from 'src/components/Radio';
|
fireEvent,
|
||||||
import Button from 'src/components/Button';
|
render,
|
||||||
|
waitFor,
|
||||||
|
within,
|
||||||
|
} from 'spec/helpers/testing-library';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
|
|
||||||
import * as saveModalActions from 'src/explore/actions/saveModalActions';
|
import * as saveModalActions from 'src/explore/actions/saveModalActions';
|
||||||
import SaveModal, {
|
import SaveModal, { PureSaveModal } from 'src/explore/components/SaveModal';
|
||||||
PureSaveModal,
|
|
||||||
StyledModal,
|
jest.mock('src/components', () => ({
|
||||||
} from 'src/explore/components/SaveModal';
|
...jest.requireActual('src/components'),
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
AsyncSelect: ({ onChange }) => (
|
||||||
|
<input
|
||||||
|
data-test="mock-async-select"
|
||||||
|
onChange={({ target: { value } }) => onChange({ label: value, value })}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
const middlewares = [thunk];
|
const middlewares = [thunk];
|
||||||
const mockStore = configureStore(middlewares);
|
const mockStore = configureStore(middlewares);
|
||||||
|
@ -97,141 +106,191 @@ const queryStore = mockStore({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryDefaultProps = {
|
|
||||||
...defaultProps,
|
|
||||||
form_data: { datasource: '107__query', url_params: { foo: 'bar' } },
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`;
|
const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`;
|
||||||
const fetchChartEndpoint = `glob:*/api/v1/chart/${1}*`;
|
const fetchChartEndpoint = `glob:*/api/v1/chart/${1}*`;
|
||||||
|
const fetchDashboardEndpoint = `glob:*/api/v1/dashboard/*`;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
fetchMock.get(fetchDashboardsEndpoint, mockDashboardData);
|
fetchMock.get(fetchDashboardsEndpoint, mockDashboardData);
|
||||||
fetchMock.get(fetchChartEndpoint, { id: 1, dashboards: [1] });
|
fetchMock.get(fetchChartEndpoint, { id: 1, dashboards: [1] });
|
||||||
|
fetchMock.get(fetchDashboardEndpoint, {
|
||||||
|
result: [{ id: 'id', dashboard_title: 'dashboard title' }],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => fetchMock.restore());
|
afterAll(() => fetchMock.restore());
|
||||||
|
|
||||||
const getWrapper = (props = defaultProps, store = initialStore) =>
|
const setup = (props = defaultProps, store = initialStore) =>
|
||||||
shallow(
|
render(<SaveModal {...props} />, {
|
||||||
<BrowserRouter>
|
useRouter: true,
|
||||||
<SaveModal {...props} store={store} />
|
store,
|
||||||
</BrowserRouter>,
|
});
|
||||||
)
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive()
|
|
||||||
.dive();
|
|
||||||
|
|
||||||
test('renders a Modal with the right set of components', () => {
|
test('renders a Modal with the right set of components', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole, getByTestId } = setup();
|
||||||
expect(wrapper.find(StyledModal)).toExist();
|
expect(getByRole('dialog', { name: 'Save chart' })).toBeInTheDocument();
|
||||||
expect(wrapper.find(Radio)).toHaveLength(2);
|
expect(getByRole('radio', { name: 'Save (Overwrite)' })).toBeInTheDocument();
|
||||||
|
expect(getByRole('radio', { name: 'Save as...' })).toBeInTheDocument();
|
||||||
const footerWrapper = shallow(wrapper.find(StyledModal).props().footer);
|
expect(
|
||||||
|
within(getByTestId('save-modal-footer')).getAllByRole('button'),
|
||||||
expect(footerWrapper.find(Button)).toHaveLength(3);
|
).toHaveLength(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders the right footer buttons', () => {
|
test('renders the right footer buttons', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByTestId } = setup();
|
||||||
const footerWrapper = shallow(wrapper.find(StyledModal).props().footer);
|
expect(
|
||||||
const saveAndGoDash = footerWrapper
|
within(getByTestId('save-modal-footer')).getByRole('button', {
|
||||||
.find('#btn_modal_save_goto_dash')
|
name: 'Cancel',
|
||||||
.getElement();
|
}),
|
||||||
const save = footerWrapper.find('#btn_modal_save').getElement();
|
).toBeInTheDocument();
|
||||||
expect(save.props.children).toBe('Save');
|
expect(
|
||||||
expect(saveAndGoDash.props.children).toBe('Save & go to dashboard');
|
within(getByTestId('save-modal-footer')).getByRole('button', {
|
||||||
|
name: 'Save & go to dashboard',
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
within(getByTestId('save-modal-footer')).getByRole('button', {
|
||||||
|
name: 'Save',
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not render a message when overriding', () => {
|
test('does not render a message when overriding', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole, queryByRole } = setup();
|
||||||
wrapper.setState({
|
|
||||||
action: 'overwrite',
|
fireEvent.click(getByRole('radio', { name: 'Save (Overwrite)' }));
|
||||||
});
|
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('[message="A new chart will be created."]'),
|
queryByRole('alert', { name: 'A new chart will be created.' }),
|
||||||
).not.toExist();
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders a message when saving as', () => {
|
test('renders a message when saving as', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole } = setup(
|
||||||
wrapper.setState({
|
{},
|
||||||
action: 'saveas',
|
mockStore({
|
||||||
});
|
...initialState,
|
||||||
expect(wrapper.find('[message="A new chart will be created."]')).toExist();
|
explore: {
|
||||||
|
...initialState.explore,
|
||||||
|
slice: {
|
||||||
|
...initialState.explore.slice,
|
||||||
|
is_managed_externally: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
fireEvent.click(getByRole('radio', { name: 'Save as...' }));
|
||||||
|
expect(getByRole('alert')).toHaveTextContent('A new chart will be created.');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders a message when a new dashboard is selected', () => {
|
test('renders a message when a new dashboard is selected', async () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole, getByTestId } = setup();
|
||||||
wrapper.setState({
|
|
||||||
dashboard: { label: 'Test new dashboard', value: 'Test new dashboard' },
|
const selection = getByTestId('mock-async-select');
|
||||||
});
|
fireEvent.change(selection, { target: { value: 'Test new dashboard' } });
|
||||||
expect(
|
|
||||||
wrapper.find('[message="A new dashboard will be created."]'),
|
expect(getByRole('alert')).toHaveTextContent(
|
||||||
).toExist();
|
'A new dashboard will be created.',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders a message when saving as with new dashboard', () => {
|
test('renders a message when saving as with new dashboard', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole, getByTestId } = setup(
|
||||||
wrapper.setState({
|
{},
|
||||||
action: 'saveas',
|
mockStore({
|
||||||
dashboard: { label: 'Test new dashboard', value: 'Test new dashboard' },
|
...initialState,
|
||||||
});
|
explore: {
|
||||||
expect(
|
...initialState.explore,
|
||||||
wrapper.find('[message="A new chart and dashboard will be created."]'),
|
slice: {
|
||||||
).toExist();
|
...initialState.explore.slice,
|
||||||
|
is_managed_externally: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
fireEvent.click(getByRole('radio', { name: 'Save as...' }));
|
||||||
|
const selection = getByTestId('mock-async-select');
|
||||||
|
fireEvent.change(selection, { target: { value: 'Test new dashboard' } });
|
||||||
|
|
||||||
|
expect(getByRole('alert')).toHaveTextContent(
|
||||||
|
'A new chart and dashboard will be created.',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('disables overwrite option for new slice', () => {
|
test('disables overwrite option for new slice', () => {
|
||||||
const wrapper = getWrapper();
|
const { getByRole } = setup(
|
||||||
wrapper.setProps({ slice: null });
|
{},
|
||||||
expect(wrapper.find('#overwrite-radio').prop('disabled')).toBe(true);
|
mockStore({
|
||||||
|
...initialState,
|
||||||
|
explore: {
|
||||||
|
...initialState.explore,
|
||||||
|
slice: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(getByRole('radio', { name: 'Save (Overwrite)' })).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('disables overwrite option for non-owner', () => {
|
test('disables overwrite option for non-owner', () => {
|
||||||
const wrapperForNonOwner = getWrapper();
|
const { getByRole } = setup(
|
||||||
wrapperForNonOwner.setProps({ user: { userId: 2 } });
|
{},
|
||||||
const overwriteRadio = wrapperForNonOwner.find('#overwrite-radio');
|
mockStore({
|
||||||
expect(overwriteRadio).toHaveLength(1);
|
...initialState,
|
||||||
expect(overwriteRadio.prop('disabled')).toBe(true);
|
user: { userId: 2 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(getByRole('radio', { name: 'Save (Overwrite)' })).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sets action when saving as new slice', () => {
|
test('updates slice name and selected dashboard', async () => {
|
||||||
const wrapperForNewSlice = getWrapper();
|
|
||||||
wrapperForNewSlice.setProps({ can_overwrite: false });
|
|
||||||
wrapperForNewSlice.instance().changeAction('saveas');
|
|
||||||
const saveasRadio = wrapperForNewSlice.find('#saveas-radio');
|
|
||||||
saveasRadio.simulate('click');
|
|
||||||
expect(wrapperForNewSlice.state().action).toBe('saveas');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('sets action when overwriting slice', () => {
|
|
||||||
const wrapperForOverwrite = getWrapper();
|
|
||||||
const overwriteRadio = wrapperForOverwrite.find('#overwrite-radio');
|
|
||||||
overwriteRadio.simulate('click');
|
|
||||||
expect(wrapperForOverwrite.state().action).toBe('overwrite');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('updates slice name and selected dashboard', () => {
|
|
||||||
const wrapper = getWrapper();
|
|
||||||
const dashboardId = mockEvent.value;
|
const dashboardId = mockEvent.value;
|
||||||
|
const saveDataset = jest.fn().mockResolvedValue();
|
||||||
|
const createDashboard = jest.fn().mockResolvedValue({ id: dashboardId });
|
||||||
|
const saveSliceFailed = jest.fn();
|
||||||
|
const setFormData = jest.fn();
|
||||||
|
const createSlice = jest.fn().mockResolvedValue({ id: 1 });
|
||||||
|
|
||||||
wrapper.instance().onSliceNameChange(mockEvent);
|
const { getByRole, getByTestId } = setup(
|
||||||
expect(wrapper.state().newSliceName).toBe(mockEvent.target.value);
|
{
|
||||||
|
actions: {
|
||||||
|
saveDataset,
|
||||||
|
createDashboard,
|
||||||
|
saveSliceFailed,
|
||||||
|
setFormData,
|
||||||
|
createSlice,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
queryStore,
|
||||||
|
);
|
||||||
|
|
||||||
wrapper.instance().onDashboardChange({ value: dashboardId });
|
fireEvent.change(getByTestId('new-chart-name'), mockEvent);
|
||||||
expect(wrapper.state().dashboard.value).toBe(dashboardId);
|
fireEvent.change(getByTestId('new-dataset-name'), mockEvent);
|
||||||
|
const selection = getByTestId('mock-async-select');
|
||||||
|
fireEvent.change(selection, { target: { value: dashboardId } });
|
||||||
|
|
||||||
|
expect(getByRole('button', { name: 'Save' })).toBeEnabled();
|
||||||
|
|
||||||
|
fireEvent.click(getByRole('button', { name: 'Save' }));
|
||||||
|
expect(saveDataset).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
datasourceName: mockEvent.target.value,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(fetchMock.calls(fetchDashboardEndpoint)).toHaveLength(1),
|
||||||
|
);
|
||||||
|
expect(fetchMock.calls(fetchDashboardEndpoint)[0][0]).toEqual(
|
||||||
|
expect.stringContaining(`dashboard/${dashboardId}`),
|
||||||
|
);
|
||||||
|
expect(createSlice).toHaveBeenCalledWith(
|
||||||
|
mockEvent.target.value,
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('set dataset name when chart source is query', () => {
|
test('set dataset name when chart source is query', () => {
|
||||||
const wrapper = getWrapper(queryDefaultProps, queryStore);
|
const { getByTestId } = setup({}, queryStore);
|
||||||
expect(wrapper.find('[data-test="new-dataset-name"]')).toExist();
|
expect(getByTestId('new-dataset-name')).toHaveValue('test');
|
||||||
expect(wrapper.state().datasetName).toBe('test');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('make sure slice_id in the URLSearchParams before the redirect', () => {
|
test('make sure slice_id in the URLSearchParams before the redirect', () => {
|
||||||
|
|
Loading…
Reference in New Issue