diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 40bb6caf..f41b19eb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
run: yarn run test
- name: Update Coveralls
- uses: coverallsapp/github-action@main
+ uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/package.json b/package.json
index 3739f4b9..619704b1 100644
--- a/package.json
+++ b/package.json
@@ -135,8 +135,8 @@
],
"coverageThreshold": {
"global": {
- "branches": 80,
- "functions": 88,
+ "branches": 81,
+ "functions": 89,
"lines": 89,
"statements": 89
}
diff --git a/src/components/Filters/Aggregation.less b/src/components/Filters/Aggregation/Aggregation.less
similarity index 100%
rename from src/components/Filters/Aggregation.less
rename to src/components/Filters/Aggregation/Aggregation.less
diff --git a/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.js b/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.js
new file mode 100644
index 00000000..5930e6a0
--- /dev/null
+++ b/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.js
@@ -0,0 +1,143 @@
+import './AggregationBranch.less';
+import { useState } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import PropTypes from 'prop-types';
+import { FormattedNumber } from 'react-intl';
+import {
+ coalesce,
+ getAllFilters,
+ sanitizeHtmlId,
+ slugify,
+} from '../../../../utils';
+import {
+ removeMultipleFilters,
+ replaceFilters,
+} from '../../../../actions/filter';
+import { selectQueryState } from '../../../../reducers/query/selectors';
+import AggregationItem from '../AggregationItem/AggregationItem';
+import getIcon from '../../../iconMap';
+import { SLUG_SEPARATOR } from '../../../../constants';
+
+export const UNCHECKED = 'UNCHECKED';
+export const INDETERMINATE = 'INDETERMINATE';
+export const CHECKED = 'CHECKED';
+
+export const AggregationBranch = ({ fieldName, item, subitems }) => {
+ const query = useSelector(selectQueryState);
+ const dispatch = useDispatch();
+ const [isOpen, setOpen] = useState(false);
+
+ // Find all query filters that refer to the field name
+ const allFilters = coalesce(query, fieldName, []);
+
+ // Do any of these values start with the key?
+ const keyFilters = allFilters.filter(
+ (aFilter) => aFilter.indexOf(item.key) === 0,
+ );
+
+ // Does the key contain the separator?
+ const activeChildren = keyFilters.filter(
+ (key) => key.indexOf(SLUG_SEPARATOR) !== -1,
+ );
+
+ const activeParent = keyFilters.filter((key) => key === item.key);
+
+ let checkedState = UNCHECKED;
+ if (activeParent.length === 0 && activeChildren.length > 0) {
+ checkedState = INDETERMINATE;
+ } else if (activeParent.length > 0) {
+ checkedState = CHECKED;
+ }
+
+ // Fix up the subitems to prepend the current item key
+ const buckets = subitems.map((sub) => ({
+ disabled: item.isDisabled,
+ key: slugify(item.key, sub.key),
+ value: sub.key,
+ // eslint-disable-next-line camelcase
+ doc_count: sub.doc_count,
+ }));
+
+ const liStyle = 'parent m-form-field m-form-field--checkbox body-copy';
+ const id = sanitizeHtmlId(`${fieldName} ${item.key}`);
+
+ const toggleParent = () => {
+ const subItemFilters = getAllFilters(item.key, subitems);
+
+ // Add the active filters (that might be hidden)
+ activeChildren.forEach((child) => subItemFilters.add(child));
+
+ if (checkedState === CHECKED) {
+ dispatch(removeMultipleFilters(fieldName, [...subItemFilters]));
+ } else {
+ // remove all of the child filters
+ const replacementFilters = allFilters.filter(
+ (filter) => filter.indexOf(item.key + SLUG_SEPARATOR) === -1,
+ );
+ // add self/ parent filter
+ replacementFilters.push(item.key);
+ dispatch(replaceFilters(fieldName, [...replacementFilters]));
+ }
+ };
+
+ if (buckets.length === 0) {
+ return ;
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ {isOpen ? (
+
+ {buckets.map((bucket) => (
+
+ ))}
+
+ ) : null}
+ >
+ );
+};
+
+AggregationBranch.propTypes = {
+ fieldName: PropTypes.string.isRequired,
+ item: PropTypes.shape({
+ // eslint-disable-next-line camelcase
+ doc_count: PropTypes.number.isRequired,
+ key: PropTypes.string.isRequired,
+ value: PropTypes.string,
+ isDisabled: PropTypes.bool,
+ }).isRequired,
+ subitems: PropTypes.array.isRequired,
+};
diff --git a/src/components/Filters/AggregationBranch.less b/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.less
similarity index 100%
rename from src/components/Filters/AggregationBranch.less
rename to src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.less
diff --git a/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.spec.js b/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.spec.js
new file mode 100644
index 00000000..568993f1
--- /dev/null
+++ b/src/components/Filters/Aggregation/AggregationBranch/AggregationBranch.spec.js
@@ -0,0 +1,144 @@
+import { testRender as render, screen } from '../../../../testUtils/test-utils';
+import userEvent from '@testing-library/user-event';
+import { merge } from '../../../../testUtils/functionHelpers';
+import { defaultQuery } from '../../../../reducers/query/query';
+import * as filter from '../../../../actions/filter';
+import { AggregationBranch } from './AggregationBranch';
+
+const fieldName = 'abc';
+
+const item = {
+ key: 'foo',
+ doc_count: 99,
+};
+
+const subitems = [
+ { key: 'bar', doc_count: 90 },
+ { key: 'baz', doc_count: 5 },
+ { key: 'qaz', doc_count: 4 },
+];
+
+const renderComponent = (props, newQueryState) => {
+ merge(newQueryState, defaultQuery);
+
+ const data = {
+ query: newQueryState,
+ };
+
+ return render(, {
+ preloadedState: data,
+ });
+};
+
+let props;
+
+describe('component::AggregationBranch', () => {
+ beforeEach(() => {
+ props = {
+ fieldName,
+ item,
+ subitems,
+ };
+ });
+
+ describe('initial state', () => {
+ test('renders as list item button with unchecked state when one or more subitems are present', () => {
+ renderComponent(props);
+
+ expect(screen.getByRole('checkbox')).not.toBeChecked();
+ expect(screen.getByLabelText(props.item.key)).toBeInTheDocument();
+ expect(
+ screen.getByText(props.item.key, { selector: 'button' }),
+ ).toBeInTheDocument();
+ expect(screen.getByText(props.item.doc_count)).toBeInTheDocument();
+ expect(screen.queryByRole('list')).not.toBeInTheDocument();
+ });
+
+ test('renders list item button with disabled checkbox when item property is disabled', () => {
+ const aitem = { ...item, isDisabled: true };
+ props.item = aitem;
+
+ renderComponent(props);
+
+ expect(screen.getByRole('checkbox')).toBeDisabled();
+ });
+
+ test('renders AggregationItem when no subitems are present', () => {
+ props.subitems = [];
+
+ renderComponent(props);
+
+ //list item doesn't render with toggle button;
+ //no need to test rendering of values, since it's covered by AggregationItem tests
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
+ });
+
+ test('renders with checkbox in checked state', () => {
+ const query = {
+ abc: [props.item.key],
+ };
+
+ renderComponent(props, query);
+ expect(screen.getByRole('checkbox')).toBeChecked();
+ });
+
+ test('renders with checkbox in indeterminate state', () => {
+ const query = {
+ abc: [`${props.item.key}•${props.subitems[0].key}`],
+ };
+
+ renderComponent(props, query);
+ expect(
+ screen.getByRole('checkbox', { indeterminate: true }),
+ ).toBeInTheDocument();
+ });
+ });
+
+ describe('toggle states', () => {
+ const user = userEvent.setup({ delay: null });
+
+ let replaceFiltersFn, removeMultipleFiltersFn;
+
+ beforeEach(() => {
+ replaceFiltersFn = jest.spyOn(filter, 'replaceFilters');
+ removeMultipleFiltersFn = jest.spyOn(filter, 'removeMultipleFilters');
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ test('should properly check the component', async () => {
+ renderComponent(props);
+
+ await user.click(screen.getByRole('checkbox'));
+
+ expect(replaceFiltersFn).toHaveBeenCalledWith(props.fieldName, ['foo']);
+ });
+
+ test('should properly uncheck the component', async () => {
+ const query = {
+ abc: [props.item.key],
+ };
+
+ renderComponent(props, query);
+
+ await user.click(screen.getByRole('checkbox'));
+
+ expect(removeMultipleFiltersFn).toHaveBeenCalledWith(props.fieldName, [
+ 'foo',
+ 'foo•bar',
+ 'foo•baz',
+ 'foo•qaz',
+ ]);
+ });
+
+ test('should show children list items on button click', async () => {
+ renderComponent(props);
+
+ await user.click(screen.getByRole('button'));
+
+ expect(screen.getByRole('list')).toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/components/Filters/indeterminate.png b/src/components/Filters/Aggregation/AggregationBranch/indeterminate.png
similarity index 100%
rename from src/components/Filters/indeterminate.png
rename to src/components/Filters/Aggregation/AggregationBranch/indeterminate.png
diff --git a/src/components/Filters/AggregationItem/AggregationItem.js b/src/components/Filters/Aggregation/AggregationItem/AggregationItem.js
similarity index 88%
rename from src/components/Filters/AggregationItem/AggregationItem.js
rename to src/components/Filters/Aggregation/AggregationItem/AggregationItem.js
index d7382b9e..b15430a4 100644
--- a/src/components/Filters/AggregationItem/AggregationItem.js
+++ b/src/components/Filters/Aggregation/AggregationItem/AggregationItem.js
@@ -1,13 +1,13 @@
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { FormattedNumber } from 'react-intl';
-import { filterPatch, SLUG_SEPARATOR } from '../../../constants';
-import { coalesce, sanitizeHtmlId } from '../../../utils';
-import { arrayEquals } from '../../../utils/compare';
-import { replaceFilters, toggleFilter } from '../../../actions/filter';
-import { getUpdatedFilters } from '../../../utils/filters';
-import { selectAggsState } from '../../../reducers/aggs/selectors';
-import { selectQueryState } from '../../../reducers/query/selectors';
+import { filterPatch, SLUG_SEPARATOR } from '../../../../constants';
+import { coalesce, sanitizeHtmlId } from '../../../../utils';
+import { arrayEquals } from '../../../../utils/compare';
+import { replaceFilters, toggleFilter } from '../../../../actions/filter';
+import { getUpdatedFilters } from '../../../../utils/filters';
+import { selectAggsState } from '../../../../reducers/aggs/selectors';
+import { selectQueryState } from '../../../../reducers/query/selectors';
const appliedFilters = ({ fieldName, item, aggs, filters }) => {
// We should find the parent
diff --git a/src/components/Filters/AggregationItem/AggregationItem.spec.js b/src/components/Filters/Aggregation/AggregationItem/AggregationItem.spec.js
similarity index 95%
rename from src/components/Filters/AggregationItem/AggregationItem.spec.js
rename to src/components/Filters/Aggregation/AggregationItem/AggregationItem.spec.js
index 9afc2e0f..e0137256 100644
--- a/src/components/Filters/AggregationItem/AggregationItem.spec.js
+++ b/src/components/Filters/Aggregation/AggregationItem/AggregationItem.spec.js
@@ -1,11 +1,11 @@
-import { testRender as render, screen } from '../../../testUtils/test-utils';
-import { merge } from '../../../testUtils/functionHelpers';
+import { testRender as render, screen } from '../../../../testUtils/test-utils';
+import { merge } from '../../../../testUtils/functionHelpers';
import userEvent from '@testing-library/user-event';
-import * as filter from '../../../actions/filter';
-import * as utils from '../../../utils';
-import { slugify } from '../../../utils';
-import { defaultAggs } from '../../../reducers/aggs/aggs';
-import { defaultQuery } from '../../../reducers/query/query';
+import * as filter from '../../../../actions/filter';
+import * as utils from '../../../../utils';
+import { slugify } from '../../../../utils';
+import { defaultAggs } from '../../../../reducers/aggs/aggs';
+import { defaultQuery } from '../../../../reducers/query/query';
import AggregationItem from './AggregationItem';
const defaultTestProps = {
diff --git a/src/components/Filters/AggregationBranch.js b/src/components/Filters/AggregationBranch.js
deleted file mode 100644
index 49048684..00000000
--- a/src/components/Filters/AggregationBranch.js
+++ /dev/null
@@ -1,213 +0,0 @@
-import './AggregationBranch.less';
-import {
- bindAll,
- coalesce,
- getAllFilters,
- sanitizeHtmlId,
- slugify,
-} from '../../utils';
-import { removeMultipleFilters, replaceFilters } from '../../actions/filter';
-import AggregationItem from './AggregationItem/AggregationItem';
-import { connect } from 'react-redux';
-import { FormattedNumber } from 'react-intl';
-import getIcon from '../iconMap';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { SLUG_SEPARATOR } from '../../constants';
-
-export const UNCHECKED = 'UNCHECKED';
-export const INDETERMINATE = 'INDETERMINATE';
-export const CHECKED = 'CHECKED';
-
-// ----------------------------------------------------------------------------
-// Class
-
-export class AggregationBranch extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = { hasChildren: props.hasChildren };
-
- bindAll(this, ['_decideClickAction', '_toggleChildDisplay']);
- }
-
- _decideClickAction() {
- const { activeChildren, item, subitems, filters, fieldName, checkedState } =
- this.props;
-
- const values = getAllFilters(item.key, subitems);
- // Add the active filters (that might be hidden)
- activeChildren.forEach((child) => values.add(child));
-
- if (checkedState === CHECKED) {
- this.props.uncheckParent(fieldName, [...values]);
- } else {
- this.props.checkParent({ fieldName, filters, item });
- }
- }
-
- _toggleChildDisplay() {
- this.setState({
- hasChildren: !this.state.hasChildren,
- });
- }
-
- render() {
- const { item, subitems, fieldName, checkedState } = this.props;
-
- // Fix up the subitems to prepend the current item key
- const buckets = subitems.map((sub) => ({
- disabled: item.isDisabled,
- key: slugify(item.key, sub.key),
- value: sub.key,
- // eslint-disable-next-line camelcase
- doc_count: sub.doc_count,
- }));
-
- // Special returns
- if (buckets.length === 0) {
- return (
-
- );
- }
-
- const liStyle = 'parent m-form-field m-form-field--checkbox body-copy';
- const id = sanitizeHtmlId(fieldName + '-' + item.key);
-
- let chevronIcon;
- if (this.state.hasChildren) {
- chevronIcon = getIcon('up');
- } else {
- chevronIcon = getIcon('down');
- }
-
- return (
- <>
-
-
-
-
-
-
-
-
- {this.state.hasChildren === false ? null : (
-
- {buckets.map((bucket) => (
-
- ))}
-
- )}
- >
- );
- }
-
- // --------------------------------------------------------------------------
- // Properties
-
- get _labelStyle() {
- let str = 'toggle a-label';
- if (this.props.checkedState === INDETERMINATE) {
- str += ' indeterminate';
- }
-
- return str;
- }
-}
-
-export const mapStateToProps = (state, ownProps) => {
- // Find all query filters that refer to the field name
- const candidates = coalesce(state.query, ownProps.fieldName, []);
-
- // Do any of these values start with the key?
- const hasKey = candidates.filter(
- (candidate) => candidate.indexOf(ownProps.item.key) === 0,
- );
-
- // Does the key contain the separator?
- const activeChildren = hasKey.filter(
- (key) => key.indexOf(SLUG_SEPARATOR) !== -1,
- );
- const activeParent = hasKey.filter((key) => key === ownProps.item.key);
-
- let checkedState = UNCHECKED;
- if (activeParent.length === 0 && activeChildren.length > 0) {
- checkedState = INDETERMINATE;
- } else if (activeParent.length > 0) {
- checkedState = CHECKED;
- }
-
- return {
- activeChildren,
- checkedState,
- filters: candidates,
- focus: state.query.focus,
- hasChildren: activeChildren.length > 0,
- };
-};
-
-export const mapDispatchToProps = (dispatch) => ({
- uncheckParent: (fieldName, values) => {
- dispatch(removeMultipleFilters(fieldName, values));
- },
- checkParent: (props) => {
- const { fieldName, filters, item } = props;
- // remove all of the child filters
- const replacementFilters = filters.filter(
- (filter) => filter.indexOf(item.key + SLUG_SEPARATOR) === -1,
- );
- // add self/ parent filter
- replacementFilters.push(item.key);
- dispatch(replaceFilters(fieldName, replacementFilters));
- },
-});
-
-// eslint-disable-next-line react-redux/prefer-separate-component-file
-export default connect(mapStateToProps, mapDispatchToProps)(AggregationBranch);
-
-AggregationBranch.propTypes = {
- activeChildren: PropTypes.array,
- checkParent: PropTypes.func.isRequired,
- checkedState: PropTypes.string,
- fieldName: PropTypes.string.isRequired,
- item: PropTypes.shape({
- // eslint-disable-next-line camelcase
- doc_count: PropTypes.number.isRequired,
- key: PropTypes.string.isRequired,
- value: PropTypes.string,
- isDisabled: PropTypes.bool,
- }).isRequired,
- hasChildren: PropTypes.bool,
- subitems: PropTypes.array.isRequired,
- uncheckParent: PropTypes.func.isRequired,
- filters: PropTypes.array.isRequired,
-};
-
-AggregationBranch.defaultProps = {
- checkedState: UNCHECKED,
- hasChildren: false,
-};
diff --git a/src/components/Filters/CollapsibleFilter/CollapsibleFilter.spec.js b/src/components/Filters/CollapsibleFilter/CollapsibleFilter.spec.js
index 589f85fc..17c5bf71 100644
--- a/src/components/Filters/CollapsibleFilter/CollapsibleFilter.spec.js
+++ b/src/components/Filters/CollapsibleFilter/CollapsibleFilter.spec.js
@@ -45,13 +45,13 @@ describe('component::CollapsibleFilter', () => {
test('shows children when Show button is clicked', async () => {
renderComponent(props);
- await user.click(screen.getByRole('button'));
- await user.click(screen.getByRole('button'));
+ const buttonBefore = screen.getByRole('button');
+ await user.click(buttonBefore);
+ await user.click(buttonBefore);
const buttonAfter = screen.getByRole('button', {
expanded: true,
});
-
expect(buttonAfter).toBeInTheDocument();
expect(screen.getByText(props.desc)).toBeInTheDocument();
expect(screen.getByText('test child element')).toBeInTheDocument();
diff --git a/src/components/Filters/Issue.js b/src/components/Filters/Issue.js
index 2837f0d9..03fffcfb 100644
--- a/src/components/Filters/Issue.js
+++ b/src/components/Filters/Issue.js
@@ -8,7 +8,7 @@ import { selectQueryState } from '../../reducers/query/selectors';
import { Typeahead } from '../Typeahead/Typeahead/Typeahead';
import { selectAggsState } from '../../reducers/aggs/selectors';
import MoreOrLess from './MoreOrLess/MoreOrLess';
-import AggregationBranch from './AggregationBranch';
+import { AggregationBranch } from './Aggregation/AggregationBranch/AggregationBranch';
export const Issue = () => {
const dispatch = useDispatch();
diff --git a/src/components/Filters/MoreOrLess/MoreOrLess.spec.js b/src/components/Filters/MoreOrLess/MoreOrLess.spec.js
index e94c8901..145ec9d3 100644
--- a/src/components/Filters/MoreOrLess/MoreOrLess.spec.js
+++ b/src/components/Filters/MoreOrLess/MoreOrLess.spec.js
@@ -1,7 +1,7 @@
import { testRender as render, screen } from '../../../testUtils/test-utils';
import userEvent from '@testing-library/user-event';
import MoreOrLess from './MoreOrLess';
-import AggregationItem from '../AggregationItem/AggregationItem';
+import AggregationItem from '../Aggregation/AggregationItem/AggregationItem';
const fixture = [
{ key: 'alpha', doc_count: 99 },
diff --git a/src/components/Filters/Product.js b/src/components/Filters/Product.js
index 347be322..ff78f2f8 100644
--- a/src/components/Filters/Product.js
+++ b/src/components/Filters/Product.js
@@ -1,5 +1,6 @@
import { MODE_TRENDS, SLUG_SEPARATOR } from '../../constants';
-import AggregationBranch from './AggregationBranch';
+import { AggregationBranch } from './Aggregation/AggregationBranch/AggregationBranch';
+
import CollapsibleFilter from './CollapsibleFilter/CollapsibleFilter';
import { useSelector } from 'react-redux';
import { sortSelThenCount } from '../../utils';
diff --git a/src/components/Filters/SimpleFilter/SimpleFilter.js b/src/components/Filters/SimpleFilter/SimpleFilter.js
index e83f6555..254ff88e 100644
--- a/src/components/Filters/SimpleFilter/SimpleFilter.js
+++ b/src/components/Filters/SimpleFilter/SimpleFilter.js
@@ -4,8 +4,9 @@ import { selectAggsState } from '../../../reducers/aggs/selectors';
import { coalesce } from '../../../utils';
import CollapsibleFilter from '../CollapsibleFilter/CollapsibleFilter';
import MoreOrLess from '../MoreOrLess/MoreOrLess';
-import AggregationItem from '../AggregationItem/AggregationItem';
-import '../Aggregation.less';
+import AggregationItem from '../Aggregation/AggregationItem/AggregationItem';
+
+import '../Aggregation/Aggregation.less';
const SimpleFilter = ({ fieldName, title, desc }) => {
const aggs = useSelector(selectAggsState);
diff --git a/src/components/Filters/StickyOptions/StickyOptions.js b/src/components/Filters/StickyOptions/StickyOptions.js
index f7fa9d14..aeba5a68 100644
--- a/src/components/Filters/StickyOptions/StickyOptions.js
+++ b/src/components/Filters/StickyOptions/StickyOptions.js
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import AggregationItem from '../AggregationItem/AggregationItem';
+import AggregationItem from '../Aggregation/AggregationItem/AggregationItem';
import { isEqual } from '../../../utils/compare';
const mapOfOptions = (options) => {
return options.reduce((map, opt) => {
diff --git a/src/components/Filters/__tests__/AggregationBranch.spec.js b/src/components/Filters/__tests__/AggregationBranch.spec.js
deleted file mode 100644
index 9f0ecf5a..00000000
--- a/src/components/Filters/__tests__/AggregationBranch.spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import React from 'react';
-import { IntlProvider } from 'react-intl';
-import { Provider } from 'react-redux';
-//import { shallow } from 'enzyme';
-import configureMockStore from 'redux-mock-store';
-import thunk from 'redux-thunk';
-import renderer from 'react-test-renderer';
-import ReduxAggregationBranch /*, {
- AggregationBranch,
- CHECKED,
- mapDispatchToProps,
- UNCHECKED,
-} */ from '../AggregationBranch';
-import { slugify } from '../../../utils';
-
-// ----------------------------------------------------------------------------
-// Setup
-
-const item = {
- key: 'foo',
- doc_count: 99,
-};
-
-const subitems = [
- { key: 'bar', doc_count: 90 },
- { key: 'baz', doc_count: 5 },
- { key: 'qaz', doc_count: 4 },
-];
-
-// /**
-// *
-// * @param {string} checkedState - The checked state
-// * @returns {object} - Props and the component
-// */
-// function setupEnzyme(checkedState = UNCHECKED) {
-// const props = {
-// activeChildren: [
-// // not hidden
-// slugify('foo', 'bar'),
-// // hidden
-// slugify('foo', 'quux'),
-// ],
-// checkedState,
-// checkParent: jest.fn(),
-// fieldName: 'issue',
-// filters: [],
-// item: item,
-// subitems: subitems,
-// uncheckParent: jest.fn(),
-// };
-
-// const target = shallow();
-
-// return {
-// props,
-// target,
-// };
-// }
-
-/**
- *
- * @param {Array} selections - Array of selections
- * @returns {Function} - Rendering function
- */
-function setupSnapshot(selections) {
- const middlewares = [thunk];
- const mockStore = configureMockStore(middlewares);
- const store = mockStore({
- query: {
- issue: selections,
- },
- });
-
- return renderer.create(
-
-
-
-
- ,
- );
-}
-
-// ----------------------------------------------------------------------------
-// Test
-
-describe('component::AggregationBranch', () => {
- describe('snapshots', () => {
- it('renders with all checked', () => {
- const selections = [
- 'foo',
- slugify('foo', 'bar'),
- slugify('foo', 'baz'),
- slugify('foo', 'qaz'),
- ];
- const target = setupSnapshot(selections);
- const tree = target.toJSON();
- expect(tree).toMatchSnapshot();
- });
-
- it('renders with indeterminate', () => {
- const selections = [slugify('foo', 'bar')];
- const target = setupSnapshot(selections);
- const tree = target.toJSON();
- expect(tree).toMatchSnapshot();
- });
-
- it('renders with none checked', () => {
- const target = setupSnapshot([]);
- const tree = target.toJSON();
- expect(tree).toMatchSnapshot();
- });
- });
- // TODO: rewrite these tests with testing library
- /*describe('toggle behavior', () => {
- it('shows the children when the label is clicked', () => {
- const { target } = setupEnzyme();
- const theButton = target.find('button');
-
- expect(target.state('hasChildren')).toEqual(false);
- theButton.simulate('click');
- expect(target.state('hasChildren')).toEqual(true);
- });
- });
-
- describe('parent checkbox logic', () => {
- it('calls one action when the checkbox is already selected', () => {
- const { target, props } = setupEnzyme(CHECKED);
- const checkbox = target.find('li.parent input[type="checkbox"]');
- checkbox.simulate('change');
- expect(props.uncheckParent).toHaveBeenCalledWith('issue', [
- 'foo',
- 'foo•bar',
- 'foo•baz',
- 'foo•qaz',
- 'foo•quux',
- ]);
- expect(props.checkParent).not.toHaveBeenCalled();
- });
-
- it('calls another action when the checkbox is not selected', () => {
- const { target, props } = setupEnzyme();
- const checkbox = target.find('li.parent input[type="checkbox"]');
- checkbox.simulate('change');
- expect(props.uncheckParent).not.toHaveBeenCalled();
- expect(props.checkParent).toHaveBeenCalledWith({
- fieldName: 'issue',
- filters: [],
- item: { doc_count: 99, key: 'foo' },
- });
- });
- });
-
- describe('mapDispatchToProps', () => {
- it('hooks into replaceFilters', () => {
- const dispatch = jest.fn();
- mapDispatchToProps(dispatch).checkParent({
- fieldName: 'foo',
- filters: [
- slugify('bay', 'bee'),
- slugify('bay', 'ah'),
- 'another filter',
- ],
- item: { key: 'bay' },
- values: ['bar', 'baz'],
- });
- expect(dispatch.mock.calls).toEqual([
- [
- {
- filterName: 'foo',
- requery: 'REQUERY_ALWAYS',
- type: 'FILTER_REPLACED',
- values: ['another filter', 'bay'],
- },
- ],
- ]);
- });
-
- it('hooks into removeMultipleFilters', () => {
- const dispatch = jest.fn();
- mapDispatchToProps(dispatch).uncheckParent({
- fieldName: 'foo',
- values: ['bar', 'baz'],
- });
- expect(dispatch.mock.calls.length).toEqual(1);
- });
- });*/
-});
diff --git a/src/components/Filters/__tests__/__snapshots__/AggregationBranch.spec.js.snap b/src/components/Filters/__tests__/__snapshots__/AggregationBranch.spec.js.snap
deleted file mode 100644
index 98317002..00000000
--- a/src/components/Filters/__tests__/__snapshots__/AggregationBranch.spec.js.snap
+++ /dev/null
@@ -1,274 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`component::AggregationBranch snapshots renders with all checked 1`] = `
-Array [
-
-
-
-
-
- 99
-
- ,
- ,
-]
-`;
-
-exports[`component::AggregationBranch snapshots renders with indeterminate 1`] = `
-Array [
-
-
-
-
-
- 99
-
- ,
- ,
-]
-`;
-
-exports[`component::AggregationBranch snapshots renders with none checked 1`] = `
-
-
-
-
-
- 99
-
-
-`;
diff --git a/src/reducers/query/query.js b/src/reducers/query/query.js
index 05207843..8286f503 100644
--- a/src/reducers/query/query.js
+++ b/src/reducers/query/query.js
@@ -640,17 +640,19 @@ function replaceFilters(state, action) {
*/
function removeMultipleFilters(state, action) {
const newState = { ...state };
- const obj = newState[action.filterName];
+
// remove the focus if it exists in one of the filter values we are removing
newState.focus = action.values.includes(state.focus) ? '' : state.focus || '';
+ let obj = newState[action.filterName];
if (obj) {
action.values.forEach((val) => {
const idx = obj.indexOf(val);
if (idx !== -1) {
- obj.splice(idx, 1);
+ obj = [...obj.slice(0, idx), ...obj.slice(idx + 1)];
}
});
+ newState[action.filterName] = obj;
}
return newState;