mirror of https://github.com/apache/superset.git
test: Adds tests to the filter scope components (#13887)
This commit is contained in:
parent
3b11654c5a
commit
4602ead10c
|
@ -19,8 +19,8 @@
|
|||
/* eslint-disable no-unused-expressions */
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow, mount } from 'enzyme';
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import { ThemeProvider, supersetTheme } from '@superset-ui/core';
|
||||
import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
|
||||
import ControlHeader from 'src/explore/components/ControlHeader';
|
||||
import Checkbox from 'src/components/Checkbox';
|
||||
|
@ -36,20 +36,21 @@ describe('CheckboxControl', () => {
|
|||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<CheckboxControl {...defaultProps} />);
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<CheckboxControl {...defaultProps} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
});
|
||||
|
||||
it('renders a Checkbox', () => {
|
||||
const controlHeader = wrapper.find(ControlHeader);
|
||||
const controlHeader = wrapper.childAt(0).find(ControlHeader);
|
||||
expect(controlHeader).toHaveLength(1);
|
||||
|
||||
const headerWrapper = controlHeader.shallow();
|
||||
expect(headerWrapper.find(Checkbox)).toHaveLength(1);
|
||||
expect(controlHeader.find(Checkbox)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('Checks the box when the label is clicked', () => {
|
||||
const fullComponent = mount(<CheckboxControl {...defaultProps} />);
|
||||
|
||||
const fullComponent = wrapper.childAt(0);
|
||||
const spy = sinon.spy(fullComponent.instance(), 'onChange');
|
||||
|
||||
fullComponent.instance().forceUpdate();
|
||||
|
|
|
@ -17,51 +17,64 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useTheme } from '@superset-ui/core';
|
||||
|
||||
export const CheckboxChecked = () => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.89 0 0 0.9 0 2V16C0 17.1 0.89 18 2 18H16C17.11 18 18 17.1 18 16V2C18 0.9 17.11 0 16 0Z"
|
||||
fill="#20A7C9"
|
||||
/>
|
||||
<path d="M7 14L2 9L3.41 7.59L7 11.17L14.59 3.58L16 5L7 14Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
export const CheckboxChecked = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.89 0 0 0.9 0 2V16C0 17.1 0.89 18 2 18H16C17.11 18 18 17.1 18 16V2C18 0.9 17.11 0 16 0Z"
|
||||
fill={theme.colors.primary.base}
|
||||
/>
|
||||
<path
|
||||
d="M7 14L2 9L3.41 7.59L7 11.17L14.59 3.58L16 5L7 14Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CheckboxHalfChecked = () => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.9 0 0 0.9 0 2V16C0 17.1 0.9 18 2 18H16C17.1 18 18 17.1 18 16V2C18 0.9 17.1 0 16 0Z"
|
||||
fill="#999999"
|
||||
/>
|
||||
<path d="M14 10H4V8H14V10Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
export const CheckboxHalfChecked = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.9 0 0 0.9 0 2V16C0 17.1 0.9 18 2 18H16C17.1 18 18 17.1 18 16V2C18 0.9 17.1 0 16 0Z"
|
||||
fill={theme.colors.grayscale.light1}
|
||||
/>
|
||||
<path d="M14 10H4V8H14V10Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CheckboxUnchecked = () => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.9 0 0 0.9 0 2V16C0 17.1 0.9 18 2 18H16C17.1 18 18 17.1 18 16V2C18 0.9 17.1 0 16 0Z"
|
||||
fill="#CCCCCC"
|
||||
/>
|
||||
<path d="M16 2V16H2V2H16V2Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
export const CheckboxUnchecked = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 0H2C0.9 0 0 0.9 0 2V16C0 17.1 0.9 18 2 18H16C17.1 18 18 17.1 18 16V2C18 0.9 17.1 0 16 0Z"
|
||||
fill={theme.colors.grayscale.light2}
|
||||
/>
|
||||
<path d="M16 2V16H2V2H16V2Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
|
||||
import FormLabel from 'src/components/FormLabel';
|
||||
|
||||
const propTypes = {
|
||||
|
|
|
@ -19,10 +19,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CheckboxTree from 'react-checkbox-tree';
|
||||
|
||||
import { filterScopeSelectorTreeNodePropShape } from 'src/dashboard/util/propShapes';
|
||||
import treeIcons from './treeIcons';
|
||||
import renderFilterFieldTreeNodes from './renderFilterFieldTreeNodes';
|
||||
import { filterScopeSelectorTreeNodePropShape } from '../../util/propShapes';
|
||||
|
||||
const propTypes = {
|
||||
activeKey: PropTypes.string,
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
/**
|
||||
* 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 { supersetTheme } from '@superset-ui/core';
|
||||
import { render, screen } from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import FilterScopeSelector from './FilterScopeSelector';
|
||||
|
||||
const ROOT_ID = 'ROOT_ID';
|
||||
const GRID = 'GRID';
|
||||
const TABS = 'TABS';
|
||||
const TAB = 'TAB';
|
||||
const FILTER_A = 'FILTER_A';
|
||||
const FILTER_B = 'FILTER_B';
|
||||
const FILTER_C = 'FILTER_C';
|
||||
const TAB_A = 'TAB_A';
|
||||
const TAB_B = 'TAB_B';
|
||||
const CHART_A = 'CHART_A';
|
||||
const CHART_B = 'CHART_B';
|
||||
const CHART_C = 'CHART_C';
|
||||
const CHART_D = 'CHART_D';
|
||||
|
||||
const EXPAND_ALL = 'Expand all';
|
||||
const COLLAPSE_ALL = 'Collapse all';
|
||||
const CHECKED = 'checked';
|
||||
const UNCHECKED = 'unchecked';
|
||||
const INDETERMINATE = 'indeterminate';
|
||||
const ALL_FILTERS = 'All filters';
|
||||
const ALL_CHARTS = 'All charts';
|
||||
|
||||
const createProps = () => ({
|
||||
dashboardFilters: {
|
||||
1: {
|
||||
chartId: 1,
|
||||
componentId: 'component-id',
|
||||
datasourceId: 'datasource-id',
|
||||
directPathToFilter: [],
|
||||
isDateFilter: false,
|
||||
isInstantFilter: false,
|
||||
filterName: FILTER_A,
|
||||
columns: { column_b: undefined, column_c: undefined },
|
||||
labels: { column_b: FILTER_B, column_c: FILTER_C },
|
||||
scopes: {
|
||||
column_b: { immune: [], scope: [ROOT_ID] },
|
||||
column_c: { immune: [], scope: [ROOT_ID] },
|
||||
},
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
ROOT_ID: { children: [GRID], id: ROOT_ID, type: 'ROOT' },
|
||||
GRID: {
|
||||
children: [TABS],
|
||||
id: GRID,
|
||||
type: GRID,
|
||||
parents: [ROOT_ID],
|
||||
},
|
||||
TABS: {
|
||||
children: [TAB_A, TAB_B],
|
||||
id: TABS,
|
||||
type: TABS,
|
||||
parents: [ROOT_ID, GRID],
|
||||
},
|
||||
TAB_A: {
|
||||
meta: { text: TAB_A },
|
||||
children: [CHART_A, CHART_B],
|
||||
id: TAB_A,
|
||||
type: TAB,
|
||||
parents: [ROOT_ID, GRID, TABS],
|
||||
},
|
||||
TAB_B: {
|
||||
meta: { text: TAB_B },
|
||||
children: [CHART_C, CHART_D],
|
||||
id: TAB_B,
|
||||
type: TAB,
|
||||
parents: [ROOT_ID, GRID, TABS],
|
||||
},
|
||||
CHART_A: {
|
||||
meta: {
|
||||
chartId: 2,
|
||||
sliceName: CHART_A,
|
||||
},
|
||||
children: [],
|
||||
id: CHART_A,
|
||||
type: 'CHART',
|
||||
parents: [ROOT_ID, GRID, TABS, TAB_A],
|
||||
},
|
||||
CHART_B: {
|
||||
meta: {
|
||||
chartId: 3,
|
||||
sliceName: CHART_B,
|
||||
},
|
||||
children: [],
|
||||
id: CHART_B,
|
||||
type: 'CHART',
|
||||
parents: [ROOT_ID, GRID, TABS, TAB_A],
|
||||
},
|
||||
CHART_C: {
|
||||
meta: {
|
||||
chartId: 4,
|
||||
sliceName: CHART_C,
|
||||
},
|
||||
children: [],
|
||||
id: CHART_C,
|
||||
type: 'CHART',
|
||||
parents: [ROOT_ID, GRID, TABS, TAB_B],
|
||||
},
|
||||
CHART_D: {
|
||||
meta: {
|
||||
chartId: 5,
|
||||
sliceName: CHART_D,
|
||||
},
|
||||
children: [],
|
||||
id: CHART_D,
|
||||
type: 'CHART',
|
||||
parents: [ROOT_ID, GRID, TABS, TAB_B],
|
||||
},
|
||||
},
|
||||
updateDashboardFiltersScope: jest.fn(),
|
||||
setUnsavedChanges: jest.fn(),
|
||||
onCloseModal: jest.fn(),
|
||||
});
|
||||
|
||||
type CheckboxState = 'checked' | 'unchecked' | 'indeterminate';
|
||||
|
||||
/**
|
||||
* Unfortunatelly react-checkbox-tree doesn't provide an easy way to
|
||||
* access the checkbox icon. We need this function to find the element.
|
||||
*/
|
||||
function getCheckboxIcon(element: HTMLElement): Element {
|
||||
const parent = element.parentElement!;
|
||||
if (parent.classList.contains('rct-text')) {
|
||||
return parent.children[1];
|
||||
}
|
||||
return getCheckboxIcon(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfortunatelly when using react-checkbox-tree, the only perceived change of a
|
||||
* checkbox state change is the fill color of the SVG icon.
|
||||
*/
|
||||
function getCheckboxState(name: string): CheckboxState {
|
||||
const element = screen.getByRole('link', { name });
|
||||
const svgPath = getCheckboxIcon(element).children[1].children[0].children[0];
|
||||
const fill = svgPath.getAttribute('fill');
|
||||
return fill === supersetTheme.colors.primary.base
|
||||
? CHECKED
|
||||
: fill === supersetTheme.colors.grayscale.light1
|
||||
? INDETERMINATE
|
||||
: UNCHECKED;
|
||||
}
|
||||
|
||||
function clickCheckbox(name: string) {
|
||||
const element = screen.getByRole('link', { name });
|
||||
const checkboxLabel = getCheckboxIcon(element);
|
||||
userEvent.click(checkboxLabel);
|
||||
}
|
||||
|
||||
test('renders with empty filters', () => {
|
||||
render(<FilterScopeSelector {...createProps()} dashboardFilters={{}} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
expect(screen.getByText('Configure filter scopes')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('There are no filters in this dashboard.'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole('button', { name: 'Save' }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders with filters values', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, { useRedux: true });
|
||||
expect(screen.getByRole('link', { name: FILTER_A })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: FILTER_B })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: FILTER_C })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: TAB_A })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: TAB_B })).toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_A)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_B)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_C)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_D)).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Save' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('collapses/expands all filters', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.click(screen.getAllByRole('button', { name: COLLAPSE_ALL })[0]);
|
||||
expect(screen.getByRole('link', { name: ALL_FILTERS })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole('link', { name: FILTER_A }),
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole('link', { name: FILTER_B }),
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole('link', { name: FILTER_C }),
|
||||
).not.toBeInTheDocument();
|
||||
userEvent.click(screen.getAllByRole('button', { name: EXPAND_ALL })[0]);
|
||||
expect(screen.getByRole('link', { name: ALL_FILTERS })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: FILTER_A })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: FILTER_B })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: FILTER_C })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('collapses/expands all charts', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.click(screen.getAllByRole('button', { name: COLLAPSE_ALL })[1]);
|
||||
expect(screen.getByText(ALL_CHARTS)).toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_A)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_B)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_C)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(CHART_D)).not.toBeInTheDocument();
|
||||
userEvent.click(screen.getAllByRole('button', { name: EXPAND_ALL })[1]);
|
||||
expect(screen.getByText(ALL_CHARTS)).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: CHART_A })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: CHART_B })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: CHART_C })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: CHART_D })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('searches for a chart', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.type(screen.getByPlaceholderText('Search...'), CHART_C);
|
||||
expect(screen.queryByRole('link', { name: CHART_A })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('link', { name: CHART_B })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: CHART_C })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('selects a leaf filter', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
expect(getCheckboxState(FILTER_C)).toBe(UNCHECKED);
|
||||
clickCheckbox(FILTER_C);
|
||||
expect(getCheckboxState(FILTER_C)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('selects a leaf chart', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.click(screen.getAllByRole('button', { name: EXPAND_ALL })[1]);
|
||||
expect(getCheckboxState(CHART_D)).toBe(UNCHECKED);
|
||||
clickCheckbox(CHART_D);
|
||||
expect(getCheckboxState(CHART_D)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('selects a branch of filters', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
expect(getCheckboxState(FILTER_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(FILTER_B)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(FILTER_C)).toBe(UNCHECKED);
|
||||
clickCheckbox(FILTER_A);
|
||||
expect(getCheckboxState(FILTER_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(FILTER_B)).toBe(CHECKED);
|
||||
expect(getCheckboxState(FILTER_C)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('selects a branch of charts', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
|
||||
const tabA = screen.getByText(TAB_A);
|
||||
userEvent.click(tabA);
|
||||
|
||||
expect(getCheckboxState(TAB_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_B)).toBe(UNCHECKED);
|
||||
clickCheckbox(TAB_A);
|
||||
expect(getCheckboxState(TAB_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_B)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('selects all filters', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.click(screen.getAllByRole('button', { name: EXPAND_ALL })[0]);
|
||||
expect(getCheckboxState(ALL_FILTERS)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(FILTER_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(FILTER_B)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(FILTER_C)).toBe(UNCHECKED);
|
||||
clickCheckbox(ALL_FILTERS);
|
||||
expect(getCheckboxState(ALL_FILTERS)).toBe(CHECKED);
|
||||
expect(getCheckboxState(FILTER_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(FILTER_B)).toBe(CHECKED);
|
||||
expect(getCheckboxState(FILTER_C)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('selects all charts', () => {
|
||||
render(<FilterScopeSelector {...createProps()} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
userEvent.click(screen.getAllByRole('button', { name: EXPAND_ALL })[1]);
|
||||
expect(getCheckboxState(TAB_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_A)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_B)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(TAB_B)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_C)).toBe(UNCHECKED);
|
||||
expect(getCheckboxState(CHART_D)).toBe(UNCHECKED);
|
||||
clickCheckbox(ALL_CHARTS);
|
||||
expect(getCheckboxState(TAB_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_A)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_B)).toBe(CHECKED);
|
||||
expect(getCheckboxState(TAB_B)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_C)).toBe(CHECKED);
|
||||
expect(getCheckboxState(CHART_D)).toBe(CHECKED);
|
||||
});
|
||||
|
||||
test('triggers onClose', () => {
|
||||
const onCloseModal = jest.fn();
|
||||
render(
|
||||
<FilterScopeSelector {...createProps()} onCloseModal={onCloseModal} />,
|
||||
{
|
||||
useRedux: true,
|
||||
},
|
||||
);
|
||||
expect(onCloseModal).toHaveBeenCalledTimes(0);
|
||||
userEvent.click(screen.getByRole('button', { name: 'Close' }));
|
||||
expect(onCloseModal).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('triggers onSave', () => {
|
||||
const updateDashboardFiltersScope = jest.fn();
|
||||
const setUnsavedChanges = jest.fn();
|
||||
const onCloseModal = jest.fn();
|
||||
render(
|
||||
<FilterScopeSelector
|
||||
{...createProps()}
|
||||
updateDashboardFiltersScope={updateDashboardFiltersScope}
|
||||
setUnsavedChanges={setUnsavedChanges}
|
||||
onCloseModal={onCloseModal}
|
||||
/>,
|
||||
{
|
||||
useRedux: true,
|
||||
},
|
||||
);
|
||||
expect(updateDashboardFiltersScope).toHaveBeenCalledTimes(0);
|
||||
expect(setUnsavedChanges).toHaveBeenCalledTimes(0);
|
||||
expect(onCloseModal).toHaveBeenCalledTimes(0);
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(updateDashboardFiltersScope).toHaveBeenCalledTimes(1);
|
||||
expect(setUnsavedChanges).toHaveBeenCalledTimes(1);
|
||||
expect(onCloseModal).toHaveBeenCalledTimes(1);
|
||||
});
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
import React, { RefObject } from 'react';
|
||||
import { styled } from '@superset-ui/core';
|
||||
|
||||
import ModalTrigger from 'src/components/ModalTrigger';
|
||||
import FilterScope from 'src/dashboard/containers/FilterScope';
|
||||
|
||||
|
|
|
@ -22,23 +22,23 @@ import cx from 'classnames';
|
|||
import Button from 'src/components/Button';
|
||||
import { t, styled } from '@superset-ui/core';
|
||||
|
||||
import buildFilterScopeTreeEntry from '../../util/buildFilterScopeTreeEntry';
|
||||
import getFilterScopeNodesTree from '../../util/getFilterScopeNodesTree';
|
||||
import getFilterFieldNodesTree from '../../util/getFilterFieldNodesTree';
|
||||
import getFilterScopeParentNodes from '../../util/getFilterScopeParentNodes';
|
||||
import getKeyForFilterScopeTree from '../../util/getKeyForFilterScopeTree';
|
||||
import getSelectedChartIdForFilterScopeTree from '../../util/getSelectedChartIdForFilterScopeTree';
|
||||
import getFilterScopeFromNodesTree from '../../util/getFilterScopeFromNodesTree';
|
||||
import getRevertedFilterScope from '../../util/getRevertedFilterScope';
|
||||
import FilterScopeTree from './FilterScopeTree';
|
||||
import FilterFieldTree from './FilterFieldTree';
|
||||
import { getChartIdsInFilterScope } from '../../util/activeDashboardFilters';
|
||||
import buildFilterScopeTreeEntry from 'src/dashboard/util/buildFilterScopeTreeEntry';
|
||||
import getFilterScopeNodesTree from 'src/dashboard/util/getFilterScopeNodesTree';
|
||||
import getFilterFieldNodesTree from 'src/dashboard/util/getFilterFieldNodesTree';
|
||||
import getFilterScopeParentNodes from 'src/dashboard/util/getFilterScopeParentNodes';
|
||||
import getKeyForFilterScopeTree from 'src/dashboard/util/getKeyForFilterScopeTree';
|
||||
import getSelectedChartIdForFilterScopeTree from 'src/dashboard/util/getSelectedChartIdForFilterScopeTree';
|
||||
import getFilterScopeFromNodesTree from 'src/dashboard/util/getFilterScopeFromNodesTree';
|
||||
import getRevertedFilterScope from 'src/dashboard/util/getRevertedFilterScope';
|
||||
import { getChartIdsInFilterScope } from 'src/dashboard/util/activeDashboardFilters';
|
||||
import {
|
||||
getChartIdAndColumnFromFilterKey,
|
||||
getDashboardFilterKey,
|
||||
} from '../../util/getDashboardFilterKey';
|
||||
import { ALL_FILTERS_ROOT } from '../../util/constants';
|
||||
import { dashboardFilterPropShape } from '../../util/propShapes';
|
||||
} from 'src/dashboard/util/getDashboardFilterKey';
|
||||
import { ALL_FILTERS_ROOT } from 'src/dashboard/util/constants';
|
||||
import { dashboardFilterPropShape } from 'src/dashboard/util/propShapes';
|
||||
import FilterScopeTree from './FilterScopeTree';
|
||||
import FilterFieldTree from './FilterFieldTree';
|
||||
|
||||
const propTypes = {
|
||||
dashboardFilters: PropTypes.objectOf(dashboardFilterPropShape).isRequired,
|
||||
|
|
|
@ -19,10 +19,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CheckboxTree from 'react-checkbox-tree';
|
||||
|
||||
import { filterScopeSelectorTreeNodePropShape } from 'src/dashboard/util/propShapes';
|
||||
import renderFilterScopeTreeNodes from './renderFilterScopeTreeNodes';
|
||||
import treeIcons from './treeIcons';
|
||||
import { filterScopeSelectorTreeNodePropShape } from '../../util/propShapes';
|
||||
|
||||
const propTypes = {
|
||||
nodes: PropTypes.arrayOf(filterScopeSelectorTreeNodePropShape).isRequired,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
import FilterFieldItem from './FilterFieldItem';
|
||||
|
||||
export default function renderFilterFieldTreeNodes({ nodes, activeKey }) {
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
|
||||
import ChartIcon from '../../../components/ChartIcon';
|
||||
import { CHART_TYPE } from '../../util/componentTypes';
|
||||
import ChartIcon from 'src/components/ChartIcon';
|
||||
import { CHART_TYPE } from 'src/dashboard/util/componentTypes';
|
||||
|
||||
function traverse({ currentNode = {}, selectedChartId }) {
|
||||
if (!currentNode) {
|
||||
|
|
|
@ -98,10 +98,14 @@ const Header: FC<HeaderProps> = ({
|
|||
<span>{t('Filters')}</span>
|
||||
{canEdit && (
|
||||
<FilterConfigurationLink createNewOnOpen={filterValues.length === 0}>
|
||||
<Icon name="edit" data-test="create-filter" />
|
||||
<Icon name="edit" role="button" data-test="create-filter" />
|
||||
</FilterConfigurationLink>
|
||||
)}
|
||||
<Icon name="expand" onClick={() => toggleFiltersBar(false)} />
|
||||
<Icon
|
||||
name="expand"
|
||||
role="button"
|
||||
onClick={() => toggleFiltersBar(false)}
|
||||
/>
|
||||
</TitleArea>
|
||||
<ActionButtons>
|
||||
<Button
|
||||
|
|
Loading…
Reference in New Issue