From accf81063333ecfe04026b163805689a9d6bddc7 Mon Sep 17 00:00:00 2001
From: Monireh Rasouli <83644557+MonireRasouli@users.noreply.github.com>
Date: Tue, 19 Nov 2024 16:20:30 +0000
Subject: [PATCH] ERM-3395, Complete absent test cases for
 stripes-erm-components document filter (#709)

* extend DocumentFilter tests

* extend tests

* extend tests for DocumentFilterFieldArray

* extend tests  for DocumentFilterRule

* tweak

* fix tests

* fix tests for DocumentFilterFieldArray

* test: DocumentFilterField test tweaks

* ci: Update centralised workflow to 1.6

* test: DocumentFilterFieldArray test tweaks

* test: Monireh's changes (not pushed originally)

* test: DocumentFilterForm test tweaks

* test: stripes-erm-testing testSelect

Make use of new testSelect feature in stripes-erm-testing (Bump major version of stripes-erm-testing)

* test: DocumentFilterRule test

Tweaked test case for DocumentFilterRule to align with describe-action, test-outcome paradigm

ERM-3395

* chore: Javascript-ify some JSON

---------

Co-authored-by: Ethan Freestone <ethan.freestone@k-int.co.uk>
---
 .github/workflows/ui.yml                      |   2 +-
 lib/DocumentFilter/DocumentFilter.test.js     |  52 +++---
 lib/DocumentFilter/DocumentFilterField.js     |   1 +
 .../DocumentFilterField.test.js               | 158 ++++++++++--------
 .../DocumentFilterFieldArray.js               |   5 +-
 .../DocumentFilterFieldArray.test.js          |  92 +++++++---
 lib/DocumentFilter/DocumentFilterForm.test.js |  73 ++++----
 lib/DocumentFilter/DocumentFilterRule.test.js | 138 +++++++++------
 package.json                                  |   2 +-
 test/jest/resources/categoryValues.js         |  19 +++
 test/jest/resources/index.js                  |   2 +
 11 files changed, 323 insertions(+), 221 deletions(-)
 create mode 100644 test/jest/resources/categoryValues.js
 create mode 100644 test/jest/resources/index.js

diff --git a/.github/workflows/ui.yml b/.github/workflows/ui.yml
index 7fca2ea3..6867a3cd 100644
--- a/.github/workflows/ui.yml
+++ b/.github/workflows/ui.yml
@@ -7,7 +7,7 @@ on:
 jobs:
   ui:
     # Use the shared workflow from https://github.com/folio-org/.github
-    uses: folio-org/.github/.github/workflows/ui.yml@v1
+    uses: folio-org/.github/.github/workflows/ui.yml@v1.6
     with:
       sonar-sources: ./lib
       generate-module-descriptor: false # Shared libraries do not need module descriptors, they're an okapi thing
diff --git a/lib/DocumentFilter/DocumentFilter.test.js b/lib/DocumentFilter/DocumentFilter.test.js
index f2be2941..7fb43be9 100644
--- a/lib/DocumentFilter/DocumentFilter.test.js
+++ b/lib/DocumentFilter/DocumentFilter.test.js
@@ -1,4 +1,6 @@
 import { MemoryRouter } from 'react-router-dom';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
+
 import {
   Button,
   Accordion,
@@ -9,6 +11,7 @@ import { Button as MockStripesButton } from '@folio/stripes/components';
 
 import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
 import { translationsProperties } from '../../test/jest/helpers';
+import { categoryValues } from '../../test/jest/resources';
 import DocumentFilter from './DocumentFilter';
 
 import { documentFilterParsing } from './testResources';
@@ -37,43 +40,22 @@ const filterHandlers = {
   reset: () => {},
 };
 
-
-// Todo these should be centralised
-const categoryValues = [
-  {
-    'id': '2c9180a09262108601926219be050022',
-    'value': 'consortium_negotiation_document',
-    'label': 'Consortium negotiation document',
-  },
-  {
-    'id': '2c9180a09262108601926219bdfc0020',
-    'value': 'license',
-    'label': 'License',
-  },
-  {
-    'id': '2c9180a09262108601926219be010021',
-    'value': 'misc',
-    'label': 'Misc',
-  },
-];
-
-
 let renderComponent;
 
 describe('DocumentFilter', () => {
   describe.each([
-    [
-      'with active filters',
-      documentFilterParsing.find(dfp => dfp.name === 'simple').deparsed,
-      '1 document filters applied',
-      documentFilterParsing.find(dfp => dfp.name === 'simple').parsed,
-    ],
     [
       'without active filters',
       { docs: [] },
       null,
       []
     ],
+    [
+      'with active filters',
+      documentFilterParsing.find(dfp => dfp.name === 'simple').deparsed,
+      '1 document filters applied',
+      documentFilterParsing.find(dfp => dfp.name === 'simple').parsed,
+    ],
     [
       'with multiple active filters',
       documentFilterParsing.find(dfp => dfp.name === 'complex').deparsed,
@@ -101,11 +83,11 @@ describe('DocumentFilter', () => {
         );
       });
 
-      test('renders the document filters accordion', async () => {
+      it('renders the document filters accordion', async () => {
         await Accordion('Documents').exists();
       });
 
-      test('renders expected filters text', async () => {
+      it('renders expected filters text', async () => {
         const baseLayoutText = /document filters applied/;
         const { queryByText } = renderComponent;
         if (expectedLayoutText != null) {
@@ -120,9 +102,14 @@ describe('DocumentFilter', () => {
         expect(getByText('DocumentFilterForm')).toBeInTheDocument();
       });
 
-      // TODO
-      // Add test for clearing accordion, whether clear button exists etc (mock filterHandlers.state)
-      // and check the right value are passed when it's clicked
+      it('should clear the selected document filters by clicking on the clear button', () => {
+        const { getByRole, queryAllByTestId } = renderComponent;
+        if (expectedLayoutText !== null) {
+          expect(getByRole('button', { name: 'stripes-components.filterGroups.clearFilterSetLabel' })).toBeInTheDocument();
+          userEvent.click(getByRole('button', { name: 'stripes-components.filterGroups.clearFilterSetLabel' }));
+          expect(queryAllByTestId(/document filters applied\[.*\]/i).length).toEqual(0);
+        }
+      });
 
       describe('testing parsedFilterData', () => {
         beforeEach(async () => {
@@ -139,7 +126,6 @@ describe('DocumentFilter', () => {
       });
     });
   });
-
   // TODO
   // Add test for passing in/not passing in labels
 });
diff --git a/lib/DocumentFilter/DocumentFilterField.js b/lib/DocumentFilter/DocumentFilterField.js
index f835a68f..2cc8388b 100644
--- a/lib/DocumentFilter/DocumentFilterField.js
+++ b/lib/DocumentFilter/DocumentFilterField.js
@@ -60,6 +60,7 @@ const DocumentFilterField = ({
       </FieldArray>
       <Button
         data-test-add-rule-btn
+        id={`add-rule-button-${name}`}
         onClick={() => push(`${name}.rules`)}
       >
         <FormattedMessage id="stripes-erm-components.documentFilter.addRule" />
diff --git a/lib/DocumentFilter/DocumentFilterField.test.js b/lib/DocumentFilter/DocumentFilterField.test.js
index c4314393..5de4873f 100644
--- a/lib/DocumentFilter/DocumentFilterField.test.js
+++ b/lib/DocumentFilter/DocumentFilterField.test.js
@@ -1,96 +1,112 @@
 import { MemoryRouter } from 'react-router-dom';
 import { FieldArray } from 'react-final-form-arrays';
 
-import { renderWithIntl, Button, TestForm } from '@folio/stripes-erm-testing';
+import { screen, waitFor } from '@folio/jest-config-stripes/testing-library/react';
+import { renderWithIntl, TestForm, Button } from '@folio/stripes-erm-testing';
 
 import { translationsProperties } from '../../test/jest/helpers';
+import { categoryValues } from '../../test/jest/resources';
+
 import DocumentFilterField from './DocumentFilterField';
 import { documentFilterParsing } from './testResources';
 
 const onSubmit = jest.fn();
-
-// These should be centralised
-const categoryValues = [
-  {
-    'id': '2c9180a09262108601926219be050022',
-    'value': 'consortium_negotiation_document',
-    'label': 'Consortium negotiation document',
-  },
-  {
-    'id': '2c9180a09262108601926219bdfc0020',
-    'value': 'license',
-    'label': 'License',
-  },
-  {
-    'id': '2c9180a09262108601926219be010021',
-    'value': 'misc',
-    'label': 'Misc',
-  },
-];
+jest.mock('./DocumentFilterRule', () => () => <div>DocumentFilterRule</div>);
 
 let renderComponent;
 describe('DocumentFilterField', () => {
   describe.each([
     {
-      initalFilters: documentFilterParsing.find(dfp => dfp.name === 'complex').parsed,
-      expectedFields: 2
+      initialFilters: [],
+      expectedFields: 0,
+      expectedRules: 0,
     },
     {
-      initalFilters: documentFilterParsing.find(dfp => dfp.name === 'simple').parsed,
-      expectedFields: 1
+      initialFilters: documentFilterParsing.find((dfp) => dfp.name === 'simple')
+        .parsed,
+      expectedFields: 1,
+      expectedRules: 1,
     },
     {
-      initalFilters: [],
-      expectedFields: 0
-    }
-  ])('Render DocumentFilterField with $expectedFields in the array', ({ initalFilters, expectedFields }) => {
-    beforeEach(() => {
-      renderComponent = renderWithIntl(
-        <MemoryRouter>
-          <TestForm
-            initialValues={{
-              filters: initalFilters
-            }}
-            onSubmit={onSubmit}
-          >
-            <FieldArray name="filters">
-              {({ fields }) => fields.map((name, index) => (
-                <DocumentFilterField
-                  key={`${name}[${index}]`}
-                  categoryValues={categoryValues}
-                  filterName="docs"
-                  index={index}
-                  name={name}
-                />
-              ))}
-            </FieldArray>
-          </TestForm>
-          ,
-        </MemoryRouter>,
-        translationsProperties
-      );
-    });
+      initialFilters: documentFilterParsing.find((dfp) => dfp.name === 'complex')
+        .parsed,
+      expectedFields: 2,
+      expectedRules: 3,
+    },
+  ])(
+    'Render $expectedFields DocumentFilterField component(s)',
+    ({ initialFilters, expectedFields, expectedRules }) => {
+      beforeEach(() => {
+        renderComponent = renderWithIntl(
+          <MemoryRouter>
+            <TestForm
+              initialValues={{
+                filters: initialFilters,
+              }}
+              onSubmit={onSubmit}
+            >
+              <FieldArray name="filters">
+                {({ fields }) => fields.map((name, index) => (
+                  <DocumentFilterField
+                    key={`${name}[${index}]`}
+                    categoryValues={categoryValues}
+                    filterName="docs"
+                    index={index}
+                    name={name}
+                  />
+                ))
+                }
+              </FieldArray>
+            </TestForm>
+            ,
+          </MemoryRouter>,
+          translationsProperties
+        );
+      });
 
-    it('displays attibute label(s)', () => {
-      const { queryAllByText } = renderComponent;
-      expect(queryAllByText('Attribute')).toHaveLength(expectedFields);
-    });
+      it('displays attribute label(s)', () => {
+        const { queryAllByText } = renderComponent;
+        expect(queryAllByText('Attribute')).toHaveLength(expectedFields);
+      });
+
+      it('displays operator label(s)', () => {
+        const { queryAllByText } = renderComponent;
+        expect(queryAllByText('Operator')).toHaveLength(expectedFields);
+      });
+
+      it('displays value label(s)', () => {
+        const { queryAllByText } = renderComponent;
+        expect(queryAllByText('Value')).toHaveLength(expectedFields);
+      });
 
-    it('displays operator label(s)', () => {
-      const { queryAllByText } = renderComponent;
-      expect(queryAllByText('Operator')).toHaveLength(expectedFields);
-    });
+      describe('DocumentFilterRule interactions', () => {
+        it(`renders ${expectedRules} DocumentFilterRule component${expectedRules !== 1 ? 's' : ''}`, () => {
+          const { queryAllByText } = renderComponent;
+          expect(queryAllByText('DocumentFilterRule')).toHaveLength(expectedRules);
+        });
 
-    it('displays value label(s)', () => {
-      const { queryAllByText } = renderComponent;
-      expect(queryAllByText('Value')).toHaveLength(expectedFields);
-    });
+        if (expectedFields === 0) {
+          it('does not render the add rule button', async () => {
+            await Button('Add rule').absent();
+          });
+        } else {
+          describe('clicking add rule button', () => {
+            beforeEach(async () => {
+              await waitFor(async () => {
+                // There will be multiple add rules for multiple DocumentFilterFields
+                await Button({ id: 'add-rule-button-filters[0]' }).click();
+              });
+            });
 
-    if (expectedFields > 0) {
-      test('renders the add rule button', async () => {
-        await Button('Add rule').exists();
+            test('a rule has been added', async () => {
+              const { queryAllByText } = renderComponent;
+              await waitFor(() => {
+                expect(queryAllByText('DocumentFilterRule')).toHaveLength(expectedRules + 1);
+              });
+            });
+          });
+        }
       });
-      // TODO Mock DocumentFilterRule and check that you can add rules, that the right number show up and that they're separated by ANDs
     }
-  });
+  );
 });
diff --git a/lib/DocumentFilter/DocumentFilterFieldArray.js b/lib/DocumentFilter/DocumentFilterFieldArray.js
index a55d9ced..8a826c4d 100644
--- a/lib/DocumentFilter/DocumentFilterFieldArray.js
+++ b/lib/DocumentFilter/DocumentFilterFieldArray.js
@@ -30,9 +30,10 @@ const DocumentFilterFieldArray = ({
       <FieldArray name="filters">
         {({ fields }) => fields.map((name, index) => {
           return (
-            <>
+            <div key={`document-filter-field-array-${name}`}>
               <Card
                 key={`document-filter-card[${index}]`}
+                data-testid={`document-filter-field[${index}]`}
                 headerEnd={
                   fields?.length > 1 ? (
                     <Tooltip
@@ -79,7 +80,7 @@ const DocumentFilterFieldArray = ({
                   <FormattedMessage id="stripes-erm-components.OR" />
                 </Layout>
               )}
-            </>
+            </div>
           );
         })
         }
diff --git a/lib/DocumentFilter/DocumentFilterFieldArray.test.js b/lib/DocumentFilter/DocumentFilterFieldArray.test.js
index 2e74fe0e..455b5d36 100644
--- a/lib/DocumentFilter/DocumentFilterFieldArray.test.js
+++ b/lib/DocumentFilter/DocumentFilterFieldArray.test.js
@@ -1,53 +1,91 @@
 import { MemoryRouter } from 'react-router-dom';
 
+import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
 import { renderWithIntl, Button, TestForm } from '@folio/stripes-erm-testing';
 
 import { translationsProperties } from '../../test/jest/helpers';
+import { categoryValues } from '../../test/jest/resources';
+
 import DocumentFilterFieldArray from './DocumentFilterFieldArray';
 
 const onSubmit = jest.fn();
+jest.mock('./DocumentFilterField', () => () => <div>DocumentFilterField</div>);
 
-const categoryValues = [
-  {
-    'id': '2c9180a09262108601926219be050022',
-    'value': 'consortium_negotiation_document',
-    'label': 'Consortium negotiation document',
-  },
-  {
-    'id': '2c9180a09262108601926219bdfc0020',
-    'value': 'license',
-    'label': 'License',
-  },
-  {
-    'id': '2c9180a09262108601926219be010021',
-    'value': 'misc',
-    'label': 'Misc',
-  },
-];
-
+let renderComponent;
 describe('DocumentFilterFieldArray', () => {
   beforeEach(() => {
-    renderWithIntl(
+    renderComponent = renderWithIntl(
       <MemoryRouter>
         <TestForm onSubmit={onSubmit}>
           <DocumentFilterFieldArray
             categoryValues={categoryValues}
             filterName="docs"
           />
-        </TestForm>
-        ,
+        </TestForm>,
       </MemoryRouter>,
       translationsProperties
     );
   });
 
-  test('renders the document filters button', async () => {
+  it('renders the Add filter button', async () => {
     await Button('Add filter').exists();
   });
 
-  // TODO mock DocumentFilterField
-  // Test adding renders card as expected
-  // Test card delete removes an item
-  // Test card heading shows right label
-  // Test multiples are separated by OR (check this scales with right number of ORs for 2/3/4 items)
+  describe('clicking \'Add filter\' button', () => {
+    beforeEach(async () => {
+      await waitFor(async () => {
+        await Button('Add filter').click();
+      });
+    });
+
+    it('should display Document filter 1', async () => {
+      const { getByText } = renderComponent;
+      expect(getByText('Document filter 1')).toBeInTheDocument();
+    });
+
+    it('should not render a \'Delete filter 1\' button', async () => {
+      const { queryByRole } = renderComponent;
+
+      await waitFor(async () => {
+        // IconButton calls not working right now
+        // await IconButton('Delete filter 1').absent();
+        expect(queryByRole('button', { name: 'Delete filter 1' })).not.toBeInTheDocument();
+      });
+    });
+
+    it('should not display Document filter 2', async () => {
+      const { queryByText } = renderComponent;
+      expect(queryByText('Document filter 2')).not.toBeInTheDocument();
+    });
+
+    it('should render the document filter field component', async () => {
+      const { getByText } = renderComponent;
+      await waitFor(async () => {
+        expect(getByText('DocumentFilterField')).toBeInTheDocument();
+      });
+    });
+
+    describe('clicking \'Add filter\' button again', () => {
+      beforeEach(async () => {
+        await waitFor(async () => {
+          await Button('Add filter').click();
+        });
+      });
+
+      it('should display Document filter 2', async () => {
+        const { getByText } = renderComponent;
+        expect(getByText('Document filter 2')).toBeInTheDocument();
+      });
+
+      it('should render a \'Delete filter 2\' button', async () => {
+        const { queryByRole } = renderComponent;
+
+        await waitFor(async () => {
+          // IconButton calls not working right now
+          // await IconButton('Delete filter 2').exists();
+          expect(queryByRole('button', { name: 'Delete filter 2' })).toBeInTheDocument();
+        });
+      });
+    });
+  });
 });
diff --git a/lib/DocumentFilter/DocumentFilterForm.test.js b/lib/DocumentFilter/DocumentFilterForm.test.js
index 3b3417bc..adaf0d0d 100644
--- a/lib/DocumentFilter/DocumentFilterForm.test.js
+++ b/lib/DocumentFilter/DocumentFilterForm.test.js
@@ -1,15 +1,15 @@
 import { MemoryRouter } from 'react-router-dom';
-
 import {
   Field as MockField,
 } from 'react-final-form';
-
 import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
+
 import { renderWithIntl, Button, TextField } from '@folio/stripes-erm-testing';
 import { TextField as MockStripesTextField } from '@folio/stripes/components';
 
 
 import { translationsProperties } from '../../test/jest/helpers';
+import { categoryValues } from '../../test/jest/resources';
 import DocumentFilterForm from './DocumentFilterForm';
 import { documentFilterParsing } from './testResources';
 
@@ -34,24 +34,6 @@ const handlers = {
 };
 
 const filterModalProps = {};
-// TODO these should be centralised
-const categoryValues = [
-  {
-    'id': '2c9180a09262108601926219be050022',
-    'value': 'consortium_negotiation_document',
-    'label': 'Consortium negotiation document',
-  },
-  {
-    'id': '2c9180a09262108601926219bdfc0020',
-    'value': 'license',
-    'label': 'License',
-  },
-  {
-    'id': '2c9180a09262108601926219be010021',
-    'value': 'misc',
-    'label': 'Misc',
-  },
-];
 
 const filterHandlers = {
   state: jest.fn(),
@@ -87,9 +69,9 @@ describe('DocumentFilterForm', () => {
 
     test('filter form is not open', async () => {
       const { queryByText } = renderComponent;
-      await waitFor(async () => {
-        await expect(queryByText('DocumentFilterFieldArray')).not.toBeInTheDocument();
-      })
+      await waitFor(() => {
+        expect(queryByText('DocumentFilterFieldArray')).not.toBeInTheDocument();
+      });
     });
 
     describe('opening the filter form', () => {
@@ -101,15 +83,13 @@ describe('DocumentFilterForm', () => {
 
       test('filter form is open', async () => {
         const { queryByText } = renderComponent;
-        await waitFor(async () => {
-          await expect(queryByText('DocumentFilterFieldArray')).toBeInTheDocument();
+        await waitFor(() => {
+          expect(queryByText('DocumentFilterFieldArray')).toBeInTheDocument();
         });
       });
     });
   });
 
-  // TODO these are borrowed as outputs from DocumentFilter.test.js... should probs be centralised in a way that makes sense.
-  // Maybe the helper functions live in their own components for testing?
   describe.each([
     {
       filtersInfo: 'simple filters',
@@ -148,10 +128,10 @@ describe('DocumentFilterForm', () => {
         });
       });
 
-      test('filter form is open', async () => {
-        const { queryByText } = renderComponent;
-        await waitFor(async () => {
-          await expect(queryByText('DocumentFilterFieldArray')).toBeInTheDocument();
+      it('should render the document filter builder modal', async () => {
+        const { getByText } = renderComponent;
+        await waitFor(() => {
+          expect(getByText('Document filter builder')).toBeInTheDocument();
         });
       });
 
@@ -169,6 +149,27 @@ describe('DocumentFilterForm', () => {
           });
         });
 
+        it('should display the cancel button', async () => {
+          await waitFor(async () => {
+            await Button('ui-test-implementor.cancel').exists();
+          });
+        });
+
+        describe('clicking cancel button', () => {
+          beforeEach(async () => {
+            await waitFor(async () => {
+              await Button('ui-test-implementor.cancel').click();
+            });
+          });
+
+          it('should close the filter form', async () => {
+            const { queryByText } = renderComponent;
+            await waitFor(() => {
+              expect(queryByText('DocumentFilterFieldArray')).not.toBeInTheDocument();
+            });
+          });
+        });
+
         describe('submitting form', () => {
           beforeEach(async () => {
             // Submit form
@@ -179,19 +180,19 @@ describe('DocumentFilterForm', () => {
           });
 
           test(`submit handler acted as expected for ${filtersInfo}`, async () => {
-            await waitFor(async () => {
-              await expect(filterHandlers.state.mock.calls[0][0]).toEqual(expectedSubmit);
+            await waitFor(() => {
+              expect(filterHandlers.state.mock.calls[0][0]).toEqual(expectedSubmit);
             });
           });
 
           test('filter form is not open', async () => {
             const { queryByText } = renderComponent;
-            await waitFor(async () => {
-              await expect(queryByText('DocumentFilterFieldArray')).not.toBeInTheDocument();
+            await waitFor(() => {
+              expect(queryByText('DocumentFilterFieldArray')).not.toBeInTheDocument();
             });
           });
         });
       });
     });
   });
-});
+});
\ No newline at end of file
diff --git a/lib/DocumentFilter/DocumentFilterRule.test.js b/lib/DocumentFilter/DocumentFilterRule.test.js
index 75d1fef3..c5608036 100644
--- a/lib/DocumentFilter/DocumentFilterRule.test.js
+++ b/lib/DocumentFilter/DocumentFilterRule.test.js
@@ -1,18 +1,18 @@
 import { MemoryRouter } from 'react-router-dom';
 import { Field } from 'react-final-form';
+import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
 
 import {
   renderWithIntl,
   Button,
   TestForm,
-  TextArea,
+  testSelect
 } from '@folio/stripes-erm-testing';
 
 import { translationsProperties } from '../../test/jest/helpers';
+import { categoryValues } from '../../test/jest/resources';
 import DocumentFilterRule from './DocumentFilterRule';
 
-TextArea('Name').exists();
-
 const onSubmit = jest.fn();
 const onDelete = jest.fn();
 const value = {
@@ -21,9 +21,10 @@ const value = {
   'value': 'test',
 };
 
+let renderComponent;
 describe('DocumentFilterRule', () => {
   beforeEach(() => {
-    renderWithIntl(
+    renderComponent = renderWithIntl(
       <MemoryRouter>
         <TestForm onSubmit={onSubmit}>
           <Field
@@ -47,56 +48,93 @@ describe('DocumentFilterRule', () => {
     );
   });
 
-  test('renders the submit button', async () => {
+  it('renders the submit button', async () => {
     await Button('Submit').exists();
   });
 
-  it('renders Name option', () => {
-    TextArea('Name').exists();
-  });
-
-  it('renders Note option', () => {
-    TextArea('Note').exists();
-  });
-
-  it('renders Physical location option', () => {
-    TextArea('Physical location').exists();
+  // EXAMPLE testing select options with a centralised testSelect method
+  describe.each([
+    {
+      selector: { name: 'filters[0].rules[0].path' },
+      selectorName: 'Attribute',
+      optionsArray: [
+        'Name',
+        'Note',
+        'Physical location',
+        'URL',
+        'Content type',
+        'File name',
+        ''
+      ]
+    },
+    {
+      selector: { name: 'filters[0].rules[0].comparator' },
+      selectorName: 'Comparator',
+      optionsArray: [
+        'is',
+        'contains',
+        'does not contain',
+        ''
+      ]
+    }
+  ])('$selectorName select', (options) => {
+    testSelect(options);
   });
 
-  // TODO this is not how we check select options
-  it('renders URL option', () => {
-    TextArea('URL').exists();
+  let removeButton;
+  describe('DocumentFilterRule with more than one rule', () => {
+    beforeEach(() => {
+      renderWithIntl(
+        <MemoryRouter>
+          <TestForm onSubmit={onSubmit}>
+            <Field
+              name="filters[0].rules[1]"
+            >
+              {({ input: { name } }) => (
+                <DocumentFilterRule
+                  ariaLabelledby="selected-document-item-name-0"
+                  categoryValues={categoryValues}
+                  index={1}
+                  name={name}
+                  onDelete={onDelete}
+                  value={value}
+                />
+              )}
+            </Field>
+          </TestForm>
+          ,
+        </MemoryRouter>,
+        translationsProperties
+      );
+      const { getByRole } = renderComponent;
+      removeButton = getByRole('button', { name: 'Remove rule 2' });
+    });
+
+    it('renders the submit button', async () => {
+      await Button('Submit').exists();
+    });
+
+    it('renders the \'remove rule 2\' button', async () => {
+      const { getByRole } = renderComponent;
+      // Tooltip calls not working right now
+      // await Tooltip('Remove rule 2').exists();
+      expect(getByRole('tooltip', { name: /remove rule 2/i })).toBeInTheDocument();
+    });
+
+    describe('clicking the remove button', () => {
+      beforeEach(async () => {
+        await waitFor(async () => {
+          removeButton.click();
+        });
+      });
+
+      test('onDelete function got called', async () => {
+        await waitFor(async () => {
+          // Tooltip calls not working right now
+          // await Tooltip('Remove rule 2').click();
+          await expect(onDelete).toHaveBeenCalled();
+        });
+      });
+    });
   });
-
-  it('renders Content type option', () => {
-    TextArea('Content type').exists();
-  });
-
-  it('renders File name option', () => {
-    TextArea('File name').exists();
-  });
-
-  it('renders Category option', () => {
-    TextArea('Category').exists();
-  });
-
-  it('renders is option', () => {
-    TextArea('is').exists();
-  });
-
-  it('renders containes option', () => {
-    TextArea('containes').exists();
-  });
-
-  it('renders does not contain option', () => {
-    TextArea('does not contain').exists();
-  });
-
-  // TODO check Delete button renders for index > 0 and calls onDelete as expected and does NOT render for index 0
-  // Test that value is normally a TextField
-  // Test that selecting category makes:
-  // the comparator a Select with is vs is not
-  // the value a Select with expected options (categoryvalues from some centralised test resources)
-
-  // Also please test DocumentFilterRuleConstants returns what you expect for ALL occasions
 });
diff --git a/package.json b/package.json
index 02140927..2c2503de 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
     "@folio/jest-config-stripes": "^2.0.0",
     "@folio/stripes": "^9.2.0",
     "@folio/stripes-cli": "^3.2.0",
-    "@folio/stripes-erm-testing": "^2.2.0",
+    "@folio/stripes-erm-testing": "^3.0.0",
     "@formatjs/cli": "^6.1.3",
     "classnames": ">=2.2.6",
     "core-js": "^3.6.1",
diff --git a/test/jest/resources/categoryValues.js b/test/jest/resources/categoryValues.js
new file mode 100644
index 00000000..e68edffe
--- /dev/null
+++ b/test/jest/resources/categoryValues.js
@@ -0,0 +1,19 @@
+const categoryValues = [
+  {
+    id: '2c9180a09262108601926219be050022',
+    value: 'consortium_negotiation_document',
+    label: 'Consortium negotiation document',
+  },
+  {
+    id: '2c9180a09262108601926219bdfc0020',
+    value: 'license',
+    label: 'License',
+  },
+  {
+    id: '2c9180a09262108601926219be010021',
+    value: 'misc',
+    label: 'Misc',
+  },
+];
+
+export default categoryValues;
diff --git a/test/jest/resources/index.js b/test/jest/resources/index.js
new file mode 100644
index 00000000..fb1ec3f1
--- /dev/null
+++ b/test/jest/resources/index.js
@@ -0,0 +1,2 @@
+export { default as categoryValues } from './categoryValues';
+