diff --git a/src/components/Filters/FilterPanel.js b/src/components/Filters/FilterPanel.js
index abd81ba76..7b57d985b 100644
--- a/src/components/Filters/FilterPanel.js
+++ b/src/components/Filters/FilterPanel.js
@@ -10,7 +10,7 @@ import getIcon from '../iconMap';
import { Issue } from './Issue';
import { Product } from './Product';
import React from 'react';
-import SimpleFilter from './SimpleFilter';
+import SimpleFilter from './SimpleFilter/SimpleFilter';
import { ZipCode } from './ZipCode';
import {
selectViewHasFilters,
diff --git a/src/components/Filters/SimpleFilter.js b/src/components/Filters/SimpleFilter.js
deleted file mode 100644
index 733a00fe0..000000000
--- a/src/components/Filters/SimpleFilter.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import './Aggregation.less';
-import AggregationItem from './AggregationItem/AggregationItem';
-import { coalesce } from '../../utils';
-import CollapsibleFilter from './CollapsibleFilter';
-import { connect } from 'react-redux';
-import MoreOrLess from './MoreOrLess';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-export class SimpleFilter extends React.Component {
- render() {
- const listComponentProps = {
- fieldName: this.props.fieldName,
- };
- const { desc, fieldName, options, hasChildren, title } = this.props;
-
- return (
-
-
-
- );
- }
-}
-
-export const mapStateToProps = (state, ownProps) => {
- // Find all query filters that refer to the field name
- const activeChildren = coalesce(state.query, ownProps.fieldName, []);
-
- return {
- options: coalesce(state.aggs, ownProps.fieldName, []),
- hasChildren: activeChildren.length > 0,
- };
-};
-
-// eslint-disable-next-line react-redux/prefer-separate-component-file
-export default connect(mapStateToProps)(SimpleFilter);
-
-SimpleFilter.propTypes = {
- fieldName: PropTypes.string.isRequired,
- desc: PropTypes.string,
- options: PropTypes.array.isRequired,
- hasChildren: PropTypes.bool.isRequired,
- title: PropTypes.string.isRequired,
-};
diff --git a/src/components/Filters/SimpleFilter/SimpleFilter.js b/src/components/Filters/SimpleFilter/SimpleFilter.js
new file mode 100644
index 000000000..6553a14e9
--- /dev/null
+++ b/src/components/Filters/SimpleFilter/SimpleFilter.js
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import { useSelector } from 'react-redux';
+import { selectAggsState } from '../../../reducers/aggs/selectors';
+import { selectQueryState } from '../../../reducers/query/selectors';
+import { coalesce } from '../../../utils';
+import CollapsibleFilter from '../CollapsibleFilter';
+import MoreOrLess from '../MoreOrLess';
+import AggregationItem from '../AggregationItem/AggregationItem';
+
+const SimpleFilter = ({ fieldName, title, desc }) => {
+ const aggs = useSelector(selectAggsState);
+ const query = useSelector(selectQueryState);
+ const activeChildren = coalesce(query, fieldName, []);
+ const options = coalesce(aggs, fieldName, []);
+ const hasChildren = activeChildren.length > 0;
+
+ const listComponentProps = { fieldName };
+
+ return (
+
+
+
+ );
+};
+
+SimpleFilter.propTypes = {
+ fieldName: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ desc: PropTypes.string,
+};
+
+export default SimpleFilter;
diff --git a/src/components/Filters/SimpleFilter/SimpleFilter.spec.js b/src/components/Filters/SimpleFilter/SimpleFilter.spec.js
new file mode 100644
index 000000000..564e51207
--- /dev/null
+++ b/src/components/Filters/SimpleFilter/SimpleFilter.spec.js
@@ -0,0 +1,86 @@
+import { testRender as render, screen } from '../../../testUtils/test-utils';
+import SimpleFilter from './SimpleFilter';
+import { merge } from '../../../testUtils/functionHelpers';
+import { defaultAggs } from '../../../reducers/aggs/aggs';
+import { defaultQuery } from '../../../reducers/query/query';
+
+const renderComponent = (props, newAggsState, newQueryState) => {
+ merge(newAggsState, defaultAggs);
+ merge(newQueryState, defaultQuery);
+
+ const data = {
+ aggs: newAggsState,
+ query: newQueryState,
+ };
+
+ return render(, {
+ preloadedState: data,
+ });
+};
+
+describe('component:SimpleFilter', () => {
+ let props, aggs, query;
+
+ beforeEach(() => {
+ props = {
+ fieldName: 'company_response',
+ desc: 'This is a description',
+ title: 'Title',
+ };
+
+ aggs = {
+ company_response: [
+ { key: 'Closed with non-monetary relief', doc_count: 412732 },
+ { key: 'Closed with explanation', doc_count: 345066 },
+ { key: 'In progress', doc_count: 86400 },
+ { key: 'Closed with monetary relief', doc_count: 244 },
+ { key: 'Untimely response', doc_count: 178 },
+ ],
+ };
+
+ query = {};
+ });
+
+ describe('initial state', () => {
+ props = { title: 'nana', fieldName: 'company_response' };
+
+ test('renders without crashing', () => {
+ renderComponent(props, {}, {});
+ expect(screen.getByRole('button')).toHaveAttribute(
+ 'aria-label',
+ `Hide ${props.title} filter`,
+ );
+ expect(screen.getByText(props.title)).toBeInTheDocument();
+ });
+
+ test('shows if there are any active children', () => {
+ query = {
+ company_response: ['Closed with non-monetary relief'],
+ };
+
+ renderComponent(props, aggs, query);
+
+ expect(screen.getByRole('button')).toHaveAttribute(
+ 'aria-expanded',
+ 'true',
+ );
+
+ aggs.company_response.forEach((response) => {
+ expect(screen.getByText(response.key)).toBeInTheDocument();
+ });
+ });
+
+ test('hides if there are no active children', () => {
+ renderComponent(props, aggs, query);
+
+ expect(screen.getByRole('button')).toHaveAttribute(
+ 'aria-expanded',
+ 'false',
+ );
+
+ aggs.company_response.forEach((response) => {
+ expect(screen.queryByText(response.key)).not.toBeInTheDocument();
+ });
+ });
+ });
+});
diff --git a/src/components/Filters/__tests__/SimpleFilter.spec.js b/src/components/Filters/__tests__/SimpleFilter.spec.js
deleted file mode 100644
index 64a9f24af..000000000
--- a/src/components/Filters/__tests__/SimpleFilter.spec.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import { Provider } from 'react-redux';
-import configureMockStore from 'redux-mock-store';
-import thunk from 'redux-thunk';
-import { IntlProvider } from 'react-intl';
-import ReduxSimpleFilter, { mapStateToProps } from '../SimpleFilter';
-
-import renderer from 'react-test-renderer';
-
-/**
- *
- * @param {object} initialAggs - Aggs state object
- * @returns {Function} - Rendering function
- */
-function setupSnapshot(initialAggs) {
- const middlewares = [thunk];
- const mockStore = configureMockStore(middlewares);
- const store = mockStore({
- query: {},
- aggs: {
- company_response: initialAggs,
- timely: 'yes',
- },
- });
-
- return renderer.create(
-
-
-
-
- ,
- );
-}
-
-describe('initial state', () => {
- it('renders without crashing', () => {
- const target = setupSnapshot([{ key: 'foo', doc_count: 99 }]);
- const tree = target.toJSON();
- expect(tree).toMatchSnapshot();
- });
-});
-
-describe('mapStateToProps', () => {
- let state, ownProps;
- beforeEach(() => {
- state = {
- aggs: {
- foo: [1, 2, 3, 4, 5, 6],
- },
- query: {
- foo: [1],
- },
- };
- ownProps = {
- fieldName: 'foo',
- };
- });
-
- it('shows if there are any active children', () => {
- const actual = mapStateToProps(state, ownProps);
- expect(actual).toEqual({
- options: [1, 2, 3, 4, 5, 6],
- hasChildren: true,
- });
- });
-
- it('hides if there are no active children', () => {
- state.query.foo = [];
-
- const actual = mapStateToProps(state, ownProps);
- expect(actual).toEqual({
- options: [1, 2, 3, 4, 5, 6],
- hasChildren: false,
- });
- });
-});
diff --git a/src/components/Filters/__tests__/__snapshots__/SimpleFilter.spec.js.snap b/src/components/Filters/__tests__/__snapshots__/SimpleFilter.spec.js.snap
deleted file mode 100644
index 03d4df4d6..000000000
--- a/src/components/Filters/__tests__/__snapshots__/SimpleFilter.spec.js.snap
+++ /dev/null
@@ -1,33 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`initial state renders without crashing 1`] = `
-
-
-
-`;
diff --git a/src/utils/index.js b/src/utils/index.js
index dc1458e67..9c3a8b32c 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -103,7 +103,7 @@ export const clampDate = (val, min, max) => {
* @param {object} object - the object being tested
* @param {string} field - the field to check
* @param {string | object} alternateValue - the value to use in absence
- * @returns {string} the value to use
+ * @returns {string | Array | object} the value to use
*/
export const coalesce = (object, field, alternateValue) => {
if (typeof object !== 'object') {