From c1fed00f68c4a5a4dadac3bc94426d100222b2d0 Mon Sep 17 00:00:00 2001 From: cchitneedi Date: Fri, 19 May 2023 12:54:34 +0530 Subject: [PATCH 01/21] UIREQ-945 create Jest/RTL test for NoteViewRoute.js --- src/routes/NoteViewRoute.test.js | 49 +++++++++++++++++++ .../__mock__/stripesSmartComponents.mock.js | 9 ++++ test/jest/fixtures/historyData.js | 33 +++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 src/routes/NoteViewRoute.test.js create mode 100644 test/jest/fixtures/historyData.js diff --git a/src/routes/NoteViewRoute.test.js b/src/routes/NoteViewRoute.test.js new file mode 100644 index 00000000..8902822f --- /dev/null +++ b/src/routes/NoteViewRoute.test.js @@ -0,0 +1,49 @@ +import '__mock__/'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { historyData } from '../../test/jest/fixtures/historyData'; +import NoteViewRoute from './NoteViewRoute'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + Redirect: () =>
Request
+})); + +const locationData = historyData.location; +const match = { + params: { + noteId: 'viewNoteRouteID' + }, + path: 'viewPath', + url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules' +}; + +const renderNoteViewRoute = (locationProps, historyProps) => render( + +); +describe('NoteViewRoute', () => { + it('NoteViewPage should render when location.state is not empty', () => { + renderNoteViewRoute(locationData, historyData); + expect(screen.getByText('NoteViewPage')).toBeInTheDocument(); + }); + it('history.replace function to be called when onEdit clicked', () => { + renderNoteViewRoute(locationData, historyData); + userEvent.click(screen.getByRole('button', { name: 'onEdit' })); + expect(historyData.replace).toBeCalled(); + }); + it('Request page should render when location.state is empty', () => { + const historyProp = { + ...historyData, + location : { + hash: '', + key: '9pb09t', + pathname: '/users/notes/new', + search: '', + state: '' + }, + }; + const locationProp = historyProp.location; + renderNoteViewRoute(locationProp, historyProp); + expect(screen.getByText('Request')).toBeInTheDocument(); + }); +}); diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index 994b85d2..dcd6d752 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -4,6 +4,15 @@ jest.mock('@folio/stripes/smart-components', () => ({ ClipCopy: jest.fn(() => null), makeQueryFunction: jest.fn((value) => value), CheckboxFilter: jest.fn(() => null), + NoteViewPage: (props) => { + return ( +
+
NoteViewPage
+ {props.renderReferredRecord()} + +
+ ); + }, NotesSmartAccordion: jest.fn(() => null), SearchAndSort: jest.fn(() => null), ViewMetaData: jest.fn(() => null), diff --git a/test/jest/fixtures/historyData.js b/test/jest/fixtures/historyData.js new file mode 100644 index 00000000..53a65f09 --- /dev/null +++ b/test/jest/fixtures/historyData.js @@ -0,0 +1,33 @@ +export const historyData = { + length: 42, + action: 'PUSH', + location: { + hash: '', + key: '9pb09t', + pathname: '/users/notes/new', + search: '', + state: { + entityId: '2205005b-ca51-4a04-87fd-938eefa8f6de', + entityName: 'rick, psych', + entityType: 'user', + referredRecordData: { + instanceId: 'testInstanceId', + instanceTitle: 'testInstanceTitle', + itemBarcode: '90909090', + itemId: 'testItemId', + holdingsRecordId: 'testHoldingsRecordId', + requestCreateDate: '2023-04-05', + requesterId: 'testRequesterId', + requesterName: 'testRequesterName', + } + } + }, + createHref: () => {}, + push: () => {}, + replace: jest.fn(), + go: () => {}, + goBack: () => {}, + goForward: () => {}, + block: () => {}, + listen: () => {}, +}; From e2ffbf5d9404bed68013b26ed67a5f34406d6584 Mon Sep 17 00:00:00 2001 From: KetineniM Date: Fri, 19 May 2023 16:51:54 +0530 Subject: [PATCH 02/21] UIREQ-941 JEST/RTL test cases for SortableList --- CHANGELOG.md | 1 + .../SortableList/SortableList.test.js | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/components/SortableList/SortableList.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ad8991..9652f648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. +* create Jest/RTL test for SortableList.js. Refs UIREQ-941. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/src/components/SortableList/SortableList.test.js b/src/components/SortableList/SortableList.test.js new file mode 100644 index 00000000..4c25f94e --- /dev/null +++ b/src/components/SortableList/SortableList.test.js @@ -0,0 +1,30 @@ +import { render } from '@testing-library/react'; +import '../../../test/jest/__mock__'; +import SortableList from './SortableList'; + +const mockonDragEnd = jest.fn(); +const propsData = { + droppableId: 'droppableId1', + onDragEnd: mockonDragEnd, + rowFormatter: jest.fn(), + isRowDraggable: jest.fn(), + rowProps: {}, + visibleColumns: ['draggable', ''], + columnMapping: {}, + columnWidths: {}, + formatter: {}, +}; + +const renderSortableList = (prop) => { + const Component = () => SortableList(prop); + return ( + render() + ); +}; + +describe('renderSortableList', () => { + it('should render the SortableList component with provided droppableId', () => { + renderSortableList(propsData); + expect(document.querySelector('[data-rbd-droppable-id="droppableId1"]')).toBeInTheDocument(); + }); +}); From 79d27b2ddd06ec97a952dff8026286ecac5e4f2c Mon Sep 17 00:00:00 2001 From: cchitneedi Date: Fri, 19 May 2023 17:34:19 +0530 Subject: [PATCH 03/21] UIREQ-945 create Jest/RTL test for NoteViewRoute.js --- CHANGELOG.md | 1 + .../jest/__mock__/stripesSmartComponents.mock.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ad8991..20ba61c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. +* Create Jest/RTL test for NoteViewRoute.js Refs: UIREQ-945. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index dcd6d752..4304b63d 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -4,6 +4,22 @@ jest.mock('@folio/stripes/smart-components', () => ({ ClipCopy: jest.fn(() => null), makeQueryFunction: jest.fn((value) => value), CheckboxFilter: jest.fn(() => null), + NoteCreatePage: (props) => { + return ( +
+
NoteCreatePage
+ {props.renderReferredRecord()} +
+ ); + }, + NoteEditPage: (props) => { + return ( +
+
NoteEditPage
+ {props.renderReferredRecord()} +
+ ); + }, NoteViewPage: (props) => { return (
From 05618d55b430ca9d48517c0082c6808d8cebd854 Mon Sep 17 00:00:00 2001 From: cchitneedi Date: Thu, 25 May 2023 17:08:31 +0530 Subject: [PATCH 04/21] UIREQ-945 create Jest/RTL test for NoteViewRoute.js --- CHANGELOG.md | 5 +++++ src/routes/NoteViewRoute.test.js | 20 +++++++++++-------- .../__mock__/stripesSmartComponents.mock.js | 16 --------------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ba61c1..fcf15c96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,16 @@ * Cannot save item request from item with status On Order, because need a barcode. Refs UIREQ-924. * Cover `src/components/PrintButton/PrintButton.js` file by RTL/Jest tests. Refs UIREQ-886. * Cover `src/components/Loading/Loading.js` file by RTL/Jest tests. Refs UIREQ-885. +* Create Jest/RTL test for NoteCreateRoute.js Refs: UIREQ-943. * Leverage cookie-based authentication in all API requests. Refs UIREQ-861. * Update `circulation` okapi interface to `14.0` version. Refs UIREQ-954. * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. +* create Jest/RTL test for draggableRowFormatter.js, Refs UIREQ-942 +* UI tests replacement with RTL/Jest for src/UserDetail.js. Refs UIREQ-881. +* TLR: "Create title level request" checkbox not preselected on "New request" page. Refs UIREQ-955. +* Do not publish test artifacts to NPM. Refs STRIPES-865. * Create Jest/RTL test for NoteViewRoute.js Refs: UIREQ-945. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) diff --git a/src/routes/NoteViewRoute.test.js b/src/routes/NoteViewRoute.test.js index 8902822f..4d1e45b0 100644 --- a/src/routes/NoteViewRoute.test.js +++ b/src/routes/NoteViewRoute.test.js @@ -21,15 +21,19 @@ const match = { const renderNoteViewRoute = (locationProps, historyProps) => render( ); + describe('NoteViewRoute', () => { - it('NoteViewPage should render when location.state is not empty', () => { - renderNoteViewRoute(locationData, historyData); - expect(screen.getByText('NoteViewPage')).toBeInTheDocument(); - }); - it('history.replace function to be called when onEdit clicked', () => { - renderNoteViewRoute(locationData, historyData); - userEvent.click(screen.getByRole('button', { name: 'onEdit' })); - expect(historyData.replace).toBeCalled(); + describe('When location.state is not empty', () => { + beforeEach(() => { + renderNoteViewRoute(locationData, historyData); + }); + it('NoteViewPage should render when location.state is not empty', () => { + expect(screen.getByText('NoteViewPage')).toBeInTheDocument(); + }); + it('history.replace function to be called when onEdit clicked', () => { + userEvent.click(screen.getByRole('button', { name: 'onEdit' })); + expect(historyData.replace).toBeCalled(); + }); }); it('Request page should render when location.state is empty', () => { const historyProp = { diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index 4304b63d..dcd6d752 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -4,22 +4,6 @@ jest.mock('@folio/stripes/smart-components', () => ({ ClipCopy: jest.fn(() => null), makeQueryFunction: jest.fn((value) => value), CheckboxFilter: jest.fn(() => null), - NoteCreatePage: (props) => { - return ( -
-
NoteCreatePage
- {props.renderReferredRecord()} -
- ); - }, - NoteEditPage: (props) => { - return ( -
-
NoteEditPage
- {props.renderReferredRecord()} -
- ); - }, NoteViewPage: (props) => { return (
From e27aac09522a73a13d27dc62fad4a6074aedfb93 Mon Sep 17 00:00:00 2001 From: cchitneedi <100114810+cchitneedi@users.noreply.github.com> Date: Thu, 25 May 2023 17:13:00 +0530 Subject: [PATCH 05/21] Update stripesSmartComponents.mock.js --- test/jest/__mock__/stripesSmartComponents.mock.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index dcd6d752..cf6c254d 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -9,7 +9,7 @@ jest.mock('@folio/stripes/smart-components', () => ({
NoteViewPage
{props.renderReferredRecord()} - +
); }, From 748af5295c4ca7a19fb99c7b555e42b87ff8dc44 Mon Sep 17 00:00:00 2001 From: cchitneedi <100114810+cchitneedi@users.noreply.github.com> Date: Thu, 25 May 2023 18:25:23 +0530 Subject: [PATCH 06/21] Update stripesSmartComponents.mock.js resolved syntax error --- test/jest/__mock__/stripesSmartComponents.mock.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index c591d5c8..17b9d74e 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -10,6 +10,7 @@ jest.mock('@folio/stripes/smart-components', () => ({
NoteViewPage
{props.renderReferredRecord()} +
); }, NoteCreatePage: (props) => { From af54d29774168aaa925abf6beeb9e279dd9a6cd1 Mon Sep 17 00:00:00 2001 From: KetineniM Date: Fri, 26 May 2023 10:27:44 +0530 Subject: [PATCH 07/21] Review changes updated --- .../SortableList/SortableList.test.js | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/components/SortableList/SortableList.test.js b/src/components/SortableList/SortableList.test.js index 4c25f94e..2f5f798c 100644 --- a/src/components/SortableList/SortableList.test.js +++ b/src/components/SortableList/SortableList.test.js @@ -1,7 +1,12 @@ -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import '../../../test/jest/__mock__'; import SortableList from './SortableList'; +jest.mock('react-beautiful-dnd', () => ({ + ...jest.requireActual('react-beautiful-dnd'), + Droppable: jest.fn(({ children }) => children({ droppableProps: { droppableid: 'droppableId1', className: 'droppable-area', role: 'list', onDragEnd: jest.fn() }, placeholder:
Placeholder
, innerRef: jest.fn() }, {})) +})); + const mockonDragEnd = jest.fn(); const propsData = { droppableId: 'droppableId1', @@ -22,9 +27,17 @@ const renderSortableList = (prop) => { ); }; -describe('renderSortableList', () => { - it('should render the SortableList component with provided droppableId', () => { +describe('SortableList', () => { + it('Should render the SortableList component with provided droppableId', () => { + renderSortableList(propsData); + expect(document.querySelector('[droppableid="droppableId1"]')).toBeInTheDocument(); + }); + it('Should render the MultiColumnList', () => { + renderSortableList(propsData); + expect(screen.getByText('MultiColumnList')).toBeInTheDocument(); + }); + it('Should render the Provided Placeholder', () => { renderSortableList(propsData); - expect(document.querySelector('[data-rbd-droppable-id="droppableId1"]')).toBeInTheDocument(); + expect(screen.getByText('Placeholder')).toBeInTheDocument(); }); }); From 068f3a5615a3d12a865a2923a92e32fc8dd501f7 Mon Sep 17 00:00:00 2001 From: KetineniM <53168935+KetineniM@users.noreply.github.com> Date: Fri, 26 May 2023 10:29:12 +0530 Subject: [PATCH 08/21] Update CHANGELOG.md Co-authored-by: Artem Blazhko --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9652f648..01724933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. -* create Jest/RTL test for SortableList.js. Refs UIREQ-941. +* Create Jest/RTL test for SortableList.js. Refs UIREQ-941. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) From da428f1848b82a3e6299bb979e9e35f78155b7e9 Mon Sep 17 00:00:00 2001 From: KetineniM Date: Fri, 26 May 2023 10:56:18 +0530 Subject: [PATCH 09/21] StriptesComponents file updated --- test/jest/__mock__/stripesComponents.mock.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jest/__mock__/stripesComponents.mock.js b/test/jest/__mock__/stripesComponents.mock.js index d4b8f25d..65344fe8 100644 --- a/test/jest/__mock__/stripesComponents.mock.js +++ b/test/jest/__mock__/stripesComponents.mock.js @@ -70,6 +70,7 @@ jest.mock('@folio/stripes/components', () => ({ )), MultiColumnList: jest.fn(({ children }) => (
+
MultiColumnList
{children}
)), From 88829f079dc76cb627c31b4a6b1f156fc1d69921 Mon Sep 17 00:00:00 2001 From: KetineniM Date: Mon, 29 May 2023 18:00:21 +0530 Subject: [PATCH 10/21] Review changes updated --- src/components/SortableList/SortableList.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/SortableList/SortableList.test.js b/src/components/SortableList/SortableList.test.js index 2f5f798c..517ae30a 100644 --- a/src/components/SortableList/SortableList.test.js +++ b/src/components/SortableList/SortableList.test.js @@ -28,16 +28,19 @@ const renderSortableList = (prop) => { }; describe('SortableList', () => { - it('Should render the SortableList component with provided droppableId', () => { + beforeEach(() => { renderSortableList(propsData); + }); + + it('Should render the SortableList component with provided droppableId', () => { expect(document.querySelector('[droppableid="droppableId1"]')).toBeInTheDocument(); }); + it('Should render the MultiColumnList', () => { - renderSortableList(propsData); expect(screen.getByText('MultiColumnList')).toBeInTheDocument(); }); + it('Should render the Provided Placeholder', () => { - renderSortableList(propsData); expect(screen.getByText('Placeholder')).toBeInTheDocument(); }); }); From fa272a9e630c3c1305802fd8edfd4a0103a023a2 Mon Sep 17 00:00:00 2001 From: FOLIO Translations Bot <38661258+folio-translations@users.noreply.github.com> Date: Wed, 31 May 2023 16:49:53 -0400 Subject: [PATCH 11/21] Lokalise: updates --- translations/ui-requests/cs_CZ.json | 14 +++++++------- translations/ui-requests/zh_CN.json | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/translations/ui-requests/cs_CZ.json b/translations/ui-requests/cs_CZ.json index 795ea1d7..4ce596a5 100644 --- a/translations/ui-requests/cs_CZ.json +++ b/translations/ui-requests/cs_CZ.json @@ -37,7 +37,7 @@ "requester.requester": "Čtenář", "requester.pickupLocation": "Místo vyzvednutí", "actions.editRequest": "Upravit žádanku", - "actions.selectAddressType": "Vyberte typ adresy", + "actions.selectAddressType": "Vybrat typ adresy", "actions.selectPickupLoc": "Vyberte místo vyzvednutí", "actions.loading": "Načítání...", "cancel.cancelRequest": "Zrušit žádanku", @@ -87,7 +87,7 @@ "actions.duplicateRequest": "Duplikovat", "actions.cancelNewRequest": "Zrušit", "close": "Zavřít", - "blockedLabel": "Důvod blokování", + "blockedLabel": "Důvod blokace", "blockModal": "Čtenáři je blokováno zadávání žádanek", "detailsButton": "Zobrazit podrobnosti bloku", "enter": "Potvrdit", @@ -96,7 +96,7 @@ "tags.tagList": "Štítky", "item.copyNumbers": "Číslo kopie", "requestNotAllowed": "Žádanka není povolena", - "additionalReasons": "Zobrazit detaily blokování pro zobrazení dodatečných důvodů blokování...", + "additionalReasons": "Zobrazit detaily blokace pro zobrazení dodatečných důvodů blokace...", "pickupServicePoint.name": "Pult služeb pro vyzvednutí", "item.id": "id jednotky", "item.location.libraryName": "Knihovna", @@ -266,8 +266,8 @@ "navigation.keyboardShortcuts": "Klávesové zkratky", "requests.servicePoint": "Pult služeb pro vyzvednutí", "requests.callNumber": "Efektivní signatura", - "fulfillmentPreference": "Request fulfillment preference", - "requestMeta.fulfillment.holdShelf": "Hold Shelf", - "requestMeta.fulfillment.delivery": "Delivery", - "requester.fulfillmentPref": "Fulfillment preference" + "fulfillmentPreference": "Přednostní plnění žádanky", + "requestMeta.fulfillment.holdShelf": "Vyzvednutí z regálu", + "requestMeta.fulfillment.delivery": "Doručení", + "requester.fulfillmentPref": "Preference vyřízení" } \ No newline at end of file diff --git a/translations/ui-requests/zh_CN.json b/translations/ui-requests/zh_CN.json index 930f6033..9d91dce1 100644 --- a/translations/ui-requests/zh_CN.json +++ b/translations/ui-requests/zh_CN.json @@ -266,8 +266,8 @@ "navigation.keyboardShortcuts": "键盘快捷键", "requests.servicePoint": "取件服务点", "requests.callNumber": "有效的索书号字符串", - "fulfillmentPreference": "Request fulfillment preference", - "requestMeta.fulfillment.holdShelf": "Hold Shelf", - "requestMeta.fulfillment.delivery": "Delivery", - "requester.fulfillmentPref": "Fulfillment preference" + "fulfillmentPreference": "请求履行首选项", + "requestMeta.fulfillment.holdShelf": "预约架", + "requestMeta.fulfillment.delivery": "传递", + "requester.fulfillmentPref": "执行偏好" } \ No newline at end of file From 3f66c681147b4fbbdd443ec46cb52344a73836e3 Mon Sep 17 00:00:00 2001 From: KetineniM Date: Wed, 7 Jun 2023 11:14:10 +0530 Subject: [PATCH 12/21] Latest review changes updated --- src/components/SortableList/SortableList.test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/SortableList/SortableList.test.js b/src/components/SortableList/SortableList.test.js index 517ae30a..22d13cb0 100644 --- a/src/components/SortableList/SortableList.test.js +++ b/src/components/SortableList/SortableList.test.js @@ -21,10 +21,7 @@ const propsData = { }; const renderSortableList = (prop) => { - const Component = () => SortableList(prop); - return ( - render() - ); + render(); }; describe('SortableList', () => { From be403bf58e3e21cfafcf30a5965987f8579aa19e Mon Sep 17 00:00:00 2001 From: KetineniM <53168935+KetineniM@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:49:59 +0530 Subject: [PATCH 13/21] UIREQ-936 JEST/RTL test case for ReferredRecord (#1043) * UIREQ-936 JEST/RTL test case for ReferredRecord * Update ReferredRecord.test.js Review changes updated * updated CHANGELOG.md file * Updated the CHANGELOG.md file * Review changes updated * Update CHANGELOG.md --- CHANGELOG.md | 1 + .../ReferredRecord/ReferredRecord.test.js | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/components/ReferredRecord/ReferredRecord.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 8494e515..76399e86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * Cannot save item request from item with status On Order, because need a barcode. Refs UIREQ-924. * Cover `src/components/PrintButton/PrintButton.js` file by RTL/Jest tests. Refs UIREQ-886. * Cover `src/components/Loading/Loading.js` file by RTL/Jest tests. Refs UIREQ-885. +* Create Jest/RTL test for ReferredRecord.js. Refs UIREQ-936. * Create Jest/RTL test for NoteCreateRoute.js Refs: UIREQ-943. * Leverage cookie-based authentication in all API requests. Refs UIREQ-861. * Update `circulation` okapi interface to `14.0` version. Refs UIREQ-954. diff --git a/src/components/ReferredRecord/ReferredRecord.test.js b/src/components/ReferredRecord/ReferredRecord.test.js new file mode 100644 index 00000000..05a0642c --- /dev/null +++ b/src/components/ReferredRecord/ReferredRecord.test.js @@ -0,0 +1,43 @@ +import '../../../test/jest/__mock__'; +import { render, screen } from '@testing-library/react'; +import ReferredRecord from './ReferredRecord'; + +const propsData = { + instanceId: 'testInstanceId', + instanceTitle: 'testInstanceTitle', + itemBarcode: '90909090', + itemId: 'testItemId', + holdingsRecordId: 'testHoldingsRecordId', + requestCreateDate: '2023-04-05', + requesterId: 'testRequesterId', + requesterName: 'testRequesterName', +}; + +const labelIds = { + entityTypeRequest: 'ui-requests.notes.entityType.request', + assignedFor: 'ui-requests.notes.assigned.for', + assignedRequester: 'ui-requests.notes.assigned.requester', + assignedRequestDate: 'ui-requests.notes.assigned.requestDate' +}; + +const renderReferredRecord = (prop) => render(); + +describe('ReferredRecord', () => { + beforeEach(() => renderReferredRecord(propsData)); + + it('entityType.request should render', () => { + expect(screen.getByText(labelIds.entityTypeRequest)).toBeInTheDocument(); + }); + + it('assigned.for should render', () => { + expect(screen.getByText(labelIds.assignedFor)).toBeInTheDocument(); + }); + + it('assigned.requester should render', () => { + expect(screen.getByText(labelIds.assignedRequester)).toBeInTheDocument(); + }); + + it('assigned.requestDate should render', () => { + expect(screen.getByText(labelIds.assignedRequestDate)).toBeInTheDocument(); + }); +}); From 76d155f8e1fbcdb0286744d1bc1979bcc5295ad7 Mon Sep 17 00:00:00 2001 From: cchitneedi <100114810+cchitneedi@users.noreply.github.com> Date: Fri, 9 Jun 2023 15:20:09 +0530 Subject: [PATCH 14/21] UIREQ-944 create Jest/RTL test for NoteEditRoute.js (#1041) * UIREQ-944 create Jest/RTL test for NoteEditRoute.js * UIREQ-944 create Jest/RTL test for NoteEditRoute.js * UIREQ-944 create Jest/RTL test for NoteEditRoute.js * Update stripesSmartComponents.mock.js removed NoteCreatePage * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update NoteEditRoute.test.js removed property of location object --- CHANGELOG.md | 1 + src/routes/NoteEditRoute.test.js | 42 +++++++++++++++++++ .../__mock__/stripesSmartComponents.mock.js | 8 ++++ 3 files changed, 51 insertions(+) create mode 100644 src/routes/NoteEditRoute.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 76399e86..d73c79d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * Create Jest/RTL test for ReferredRecord.js. Refs UIREQ-936. * Create Jest/RTL test for NoteCreateRoute.js Refs: UIREQ-943. * Leverage cookie-based authentication in all API requests. Refs UIREQ-861. +* Create Jest/RTL test for NoteEditRoute.js Refs: UIREQ-944. * Update `circulation` okapi interface to `14.0` version. Refs UIREQ-954. * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. diff --git a/src/routes/NoteEditRoute.test.js b/src/routes/NoteEditRoute.test.js new file mode 100644 index 00000000..9fc1407f --- /dev/null +++ b/src/routes/NoteEditRoute.test.js @@ -0,0 +1,42 @@ +import '__mock__/'; +import { render, screen } from '@testing-library/react'; +import { historyData } from '../../test/jest/fixtures/historyData'; +import NoteEditRoute from './NoteEditRoute'; + +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + Redirect: () =>
Request
+})); + +const locationData = historyData.location; +const match = { + params: { + noteId: 'editNoteRouteID' + }, + path: 'editPath', + url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules' +}; + +const renderNoteEditRoute = (locationProps, historyProps) => render( + +); +describe('NoteEditRoute', () => { + it('NoteEditPage should render when location.state is not empty', () => { + renderNoteEditRoute(locationData, historyData); + expect(screen.getByText('NoteEditPage')).toBeInTheDocument(); + }); + it('Request page should render when location.state is empty', () => { + const historyProp = { + ...historyData, + location : { + hash: '', + pathname: '/users/notes/new', + search: '', + state: '' + }, + }; + const locationProp = historyProp.location; + renderNoteEditRoute(locationProp, historyProp); + expect(screen.getByText('Request')).toBeInTheDocument(); + }); +}); diff --git a/test/jest/__mock__/stripesSmartComponents.mock.js b/test/jest/__mock__/stripesSmartComponents.mock.js index 17b9d74e..6e9e1fca 100644 --- a/test/jest/__mock__/stripesSmartComponents.mock.js +++ b/test/jest/__mock__/stripesSmartComponents.mock.js @@ -4,6 +4,14 @@ jest.mock('@folio/stripes/smart-components', () => ({ ClipCopy: jest.fn(() => null), makeQueryFunction: jest.fn((value) => value), CheckboxFilter: jest.fn(() => null), + NoteEditPage: (props) => { + return ( +
+
NoteEditPage
+ {props.renderReferredRecord()} +
+ ); + }, NoteViewPage: (props) => { return (
From d3cdb630314f8da3387d4b6ada81aa3257ed5de2 Mon Sep 17 00:00:00 2001 From: VSnehalatha <53073086+VSnehalatha@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:29:39 +0530 Subject: [PATCH 15/21] UIREQ-938 Create Jest\RTL test for RequestsFiltersConfig.js (#1040) * Create Jest\RTL test for RequestsFiltersConfig.js * Update to CHANGELOG.md and RequestsFiltersConfig.test.js * Individual tests for each parse in RequestsFiltersConfig.test.js file * Update RequestsFiltersConfig.test.js * Update RequestsFiltersConfig.test.js --- CHANGELOG.md | 1 + .../RequestsFiltersConfig.test.js | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/components/RequestsFilters/RequestsFiltersConfig.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d73c79d8..cde95e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. +* Create Jest/RTL test for RequestsFiltersConfig.js. Refs: UIREQ-938 * Create Jest/RTL test for SortableList.js. Refs UIREQ-941. * create Jest/RTL test for draggableRowFormatter.js, Refs UIREQ-942 * UI tests replacement with RTL/Jest for src/UserDetail.js. Refs UIREQ-881. diff --git a/src/components/RequestsFilters/RequestsFiltersConfig.test.js b/src/components/RequestsFilters/RequestsFiltersConfig.test.js new file mode 100644 index 00000000..a0b244ef --- /dev/null +++ b/src/components/RequestsFilters/RequestsFiltersConfig.test.js @@ -0,0 +1,71 @@ +import { requestFilterTypes } from '../../constants'; +import filtersConfig from './RequestsFiltersConfig'; + +describe('RequestsFiltersConfig', () => { + it('should have a filter for requestType', () => { + const requestTypeFilter = filtersConfig.find(f => f.name === 'requestType'); + const expectedResult = { + name: 'requestType', + cql: 'requestType', + values: [], + operator: '==', + }; + expect(requestTypeFilter).toEqual(expectedResult); + }); + + it('should have a filter for requestStatus', () => { + const requestStatusFilter = filtersConfig.find(f => f.name === 'requestStatus'); + const expectedResult = { + name: 'requestStatus', + cql: 'status', + values: [], + operator: '==', + label: 'ui-requests.requestMeta.status' + }; + expect(requestStatusFilter).toEqual(expectedResult); + }); + + it('should have a filter for request levels', () => { + const requestLevelsFilter = filtersConfig.find(f => f.name === requestFilterTypes.REQUEST_LEVELS); + const expectedResult = { + name: 'requestLevels', + cql: 'requestLevel', + values: [], + operator: '==', + }; + expect(requestLevelsFilter).toEqual(expectedResult); + }); + + it('should return the expected query string for a single tag', () => { + const tagsFilter = filtersConfig.find(f => f.name === 'tags'); + const expectedResult = { + name: 'tags', + cql: 'tags.tagList', + values: [], + operator: '==', + parse: expect.any(Function), + }; + expect(tagsFilter).toEqual(expectedResult); + }); + + it('should return the expected query string for a single tag', () => { + const tagsFilter = filtersConfig.find(f => f.name === 'tags'); + expect(tagsFilter.parse('tag1')).toEqual('tags.tagList==*"*tag1*"*'); + }); + + it('should return the expected query string for an array of tags', () => { + const tagsFilter = filtersConfig.find(f => f.name === 'tags'); + expect(tagsFilter.parse(['tag1', 'tag2'])).toEqual('tags.tagList==(*"*tag1*"* or *"*tag2*"*)'); + }); + + it('should have a filter for pickup service point', () => { + const pickupServicePointFilter = filtersConfig.find(f => f.name === requestFilterTypes.PICKUP_SERVICE_POINT); + const expectedResult = { + name: 'pickupServicePoints', + cql: 'pickupServicePointId', + values: [], + operator: '==', + }; + expect(pickupServicePointFilter).toEqual(expectedResult); + }); +}); From b2eb03809c16461a5887e20a3fd181aeadebf96c Mon Sep 17 00:00:00 2001 From: FOLIO Translations Bot <38661258+folio-translations@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:44:40 -0400 Subject: [PATCH 16/21] Lokalise: updates --- translations/ui-requests/en_GB.json | 6 +++--- translations/ui-requests/en_SE.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/translations/ui-requests/en_GB.json b/translations/ui-requests/en_GB.json index 5cdc90f0..189fed1f 100644 --- a/translations/ui-requests/en_GB.json +++ b/translations/ui-requests/en_GB.json @@ -174,9 +174,9 @@ "notes.assigned.requestDate": "Request date: {requestCreateDate}", "pickSlipsLoading": "Pick slips are loading, please wait", "printInProgress": "Print options loading in progress. It might take a few seconds, please be patient.", - "requestDate": "requestDate", - "holdShelfExpirationTime": "holdShelfExpirationTime", - "csvReportPending": "csvReportPending", + "requestDate": "Request date", + "holdShelfExpirationTime": "Hold shelf expiration time", + "csvReportPending": "CSV report is being generated. Please wait.", "csvReportInProgress": "A CSV results report is being generated. This may take some time for larger result sets. Please be patient.", "patronComments": "Patron comments", "override": "Override", diff --git a/translations/ui-requests/en_SE.json b/translations/ui-requests/en_SE.json index 5cdc90f0..189fed1f 100644 --- a/translations/ui-requests/en_SE.json +++ b/translations/ui-requests/en_SE.json @@ -174,9 +174,9 @@ "notes.assigned.requestDate": "Request date: {requestCreateDate}", "pickSlipsLoading": "Pick slips are loading, please wait", "printInProgress": "Print options loading in progress. It might take a few seconds, please be patient.", - "requestDate": "requestDate", - "holdShelfExpirationTime": "holdShelfExpirationTime", - "csvReportPending": "csvReportPending", + "requestDate": "Request date", + "holdShelfExpirationTime": "Hold shelf expiration time", + "csvReportPending": "CSV report is being generated. Please wait.", "csvReportInProgress": "A CSV results report is being generated. This may take some time for larger result sets. Please be patient.", "patronComments": "Patron comments", "override": "Override", From 5915be18f94214a9140be1745923cbb4bc643925 Mon Sep 17 00:00:00 2001 From: Artem Blazhko Date: Wed, 14 Jun 2023 17:43:49 +0300 Subject: [PATCH 17/21] UIREQ-949: Cover ItemInformation by jest/RTL tests (#1063) --- CHANGELOG.md | 1 + .../ItemInformation/ItemInformation.test.js | 591 ++++++++++++++++++ .../jest/__mock__/finalFormComponents.mock.js | 30 + test/jest/__mock__/index.js | 1 + test/jest/__mock__/stripesComponents.mock.js | 34 +- 5 files changed, 653 insertions(+), 4 deletions(-) create mode 100644 src/components/ItemInformation/ItemInformation.test.js create mode 100644 test/jest/__mock__/finalFormComponents.mock.js diff --git a/CHANGELOG.md b/CHANGELOG.md index cde95e38..4806372f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * TLR: "Create title level request" checkbox not preselected on "New request" page. Refs UIREQ-955. * Do not publish test artifacts to NPM. Refs STRIPES-865. * Create Jest/RTL test for NoteViewRoute.js Refs: UIREQ-945. +* Cover ItemInformation by jest/RTL tests. Refs UIREQ-949. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/src/components/ItemInformation/ItemInformation.test.js b/src/components/ItemInformation/ItemInformation.test.js new file mode 100644 index 00000000..2ced285c --- /dev/null +++ b/src/components/ItemInformation/ItemInformation.test.js @@ -0,0 +1,591 @@ +import { useState } from 'react'; +import { + render, + screen, + fireEvent, + cleanup, + waitFor, +} from '@testing-library/react'; + +import '../../../test/jest/__mock__'; + +import { Field } from 'react-final-form'; +import { + Icon, + TextField, +} from '@folio/stripes-components'; + +import ItemInformation from './ItemInformation'; +import ItemDetail from '../../ItemDetail'; +import { isFormEditing } from '../../utils'; +import { + REQUEST_FORM_FIELD_NAMES, + RESOURCE_KEYS, + ENTER_EVENT_KEY, + BASE_SPINNER_PROPS, +} from '../../constants'; + +jest.mock('../../utils', () => ({ + isFormEditing: jest.fn(() => false), + memoizeValidation: (fn) => () => fn, +})); +jest.mock('../../ItemDetail', () => jest.fn(() =>
Item Details
)); + +const basicProps = { + triggerValidation: jest.fn(), + findItem: jest.fn(() => null), + onSetSelectedItem: jest.fn(), + form: { + change: jest.fn(), + }, + values: { + item: { + barcode: 'itemBarcode', + }, + keyOfItemBarcodeField: 1, + }, + request: { + id: 'requestId', + }, + selectedLoan: {}, + selectedItem: {}, + itemRequestCount: 1, + instanceId: 'instanceId', + isLoading: false, + submitting: false, + isItemIdRequest: true, +}; +const labelIds = { + scanOrEnterBarcode: 'ui-requests.item.scanOrEnterBarcode', + itemBarcode: 'ui-requests.item.barcode', + enterButton: 'ui-requests.enter', + selectItemRequired: 'ui-requests.errors.selectItemRequired', + itemBarcodeDoesNotExist: 'ui-requests.errors.itemBarcodeDoesNotExist', +}; +const testIds = { + itemBarcodeField: 'itemBarcodeField', + errorMessage: 'errorMessage', +}; +const renderItemInfoWithBarcode = (onBlur) => { + Field.mockImplementation(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: {}, + input: { + validate, + 'data-testid': testId, + value: 'itemBarcode', + onBlur, + }, + }); + })); + + render( + + ); +}; + +describe('ItemInformation', () => { + afterEach(() => { + basicProps.onSetSelectedItem.mockClear(); + Field.mockClear(); + cleanup(); + }); + + describe('when "isFormEditing" returns false', () => { + beforeEach(() => { + render( + + ); + }); + + it('should render "scanOrEnterBarcode" placeholder', () => { + const scanOrEnterBarcodePlaceholder = screen.getByPlaceholderText(labelIds.scanOrEnterBarcode); + + expect(scanOrEnterBarcodePlaceholder).toBeVisible(); + }); + + it('should render item barcode field', () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + expect(itemBarcodeField).toBeVisible(); + }); + + it('should render item barcode "Field" with correct props', () => { + const expectedProps = { + name: REQUEST_FORM_FIELD_NAMES.ITEM_BARCODE, + validate: expect.any(Function), + validateFields: [], + }; + + expect(Field).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render item barcode label', () => { + const itemBarcodeLabel = screen.getByText(labelIds.itemBarcode); + + expect(itemBarcodeLabel).toBeVisible(); + }); + + it('should trigger "findItem" when Enter key is pressed', () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.keyDown(itemBarcodeField, { key: ENTER_EVENT_KEY }); + + expect(basicProps.findItem).toHaveBeenCalledWith(RESOURCE_KEYS.barcode, basicProps.values.item.barcode); + }); + + it('should not trigger "findItem" when Control key is pressed', () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.keyDown(itemBarcodeField, { key: 'Control' }); + + expect(basicProps.findItem).not.toHaveBeenCalledWith(); + }); + + it('should trigger "form.change" with correct arguments', () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + const event = { + target: { + value: 'itemBarcode', + }, + }; + + fireEvent.change(itemBarcodeField, event); + + expect(basicProps.form.change).toHaveBeenCalledWith(REQUEST_FORM_FIELD_NAMES.ITEM_BARCODE, event.target.value); + }); + + it('should render "TextField" with correct props', () => { + const expectedProps = { + required: true, + error: null, + onChange: expect.any(Function), + onBlur: expect.any(Function), + onKeyDown: expect.any(Function), + }; + + expect(TextField).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render "TextField" with validation error', () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + const enterButton = screen.getByText(labelIds.enterButton); + const event = { + target: { + value: 'itemBarcode', + }, + }; + const error = 'error'; + + Field.mockImplementationOnce(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: { + error: 'error', + touched: true, + }, + input: { + validate, + 'data-testid': testId, + }, + }); + })); + + fireEvent.click(enterButton); + fireEvent.change(itemBarcodeField, event); + + expect(TextField).toHaveBeenCalledWith(expect.objectContaining({ error }), {}); + }); + }); + + describe('when "isFormEditing" returns true', () => { + beforeEach(() => { + isFormEditing.mockReturnValueOnce(true); + + render( + + ); + }); + + it('should not render "scanOrEnterBarcode" placeholder', () => { + const scanOrEnterBarcodePlaceholder = screen.queryByPlaceholderText(labelIds.scanOrEnterBarcode); + + expect(scanOrEnterBarcodePlaceholder).not.toBeInTheDocument(); + }); + + it('should not render item barcode field', () => { + const itemBarcodeField = screen.queryByTestId(testIds.itemBarcodeField); + + expect(itemBarcodeField).not.toBeInTheDocument(); + }); + + it('should not render item barcode label', () => { + const itemBarcodeLabel = screen.queryByText(labelIds.itemBarcode); + + expect(itemBarcodeLabel).not.toBeInTheDocument(); + }); + }); + + describe('handleBlur', () => { + const onBlur = jest.fn(); + + afterEach(() => { + onBlur.mockClear(); + }); + + it('should trigger "input.onBlur" if item barcode is presented', () => { + renderItemInfoWithBarcode(onBlur); + + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.click(itemBarcodeField); + fireEvent.blur(itemBarcodeField); + + expect(onBlur).toHaveBeenCalled(); + }); + + it('should trigger "input.onBlur" if there is no item barcode', () => { + Field.mockImplementation(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: {}, + input: { + validate, + 'data-testid': testId, + value: '', + onBlur, + }, + }); + })); + + render( + + ); + + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.click(itemBarcodeField); + fireEvent.blur(itemBarcodeField); + + expect(onBlur).toHaveBeenCalled(); + }); + + it('should not trigger "input.onBlur" if item barcode was validated previously', () => { + renderItemInfoWithBarcode(onBlur); + + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + // first input focus + fireEvent.click(itemBarcodeField); + fireEvent.blur(itemBarcodeField); + onBlur.mockClear(); + + // second input focus after validation of initial value + fireEvent.click(itemBarcodeField); + fireEvent.blur(itemBarcodeField); + + expect(onBlur).not.toHaveBeenCalled(); + }); + }); + + describe('Validation', () => { + afterEach(() => { + TextField.mockClear(); + basicProps.findItem.mockClear(); + }); + + beforeEach(() => { + TextField.mockImplementation(jest.fn(({ + onChange, + validate, + ...rest + }) => { + const [error, setError] = useState(''); + const handleChange = async (e) => { + setError(await validate(e.target.value)); + onChange(e); + }; + + return ( +
+ + {error} +
+ ); + })); + }); + + describe('when "barcode" is not presented', () => { + const event = { + target: { + value: '', + }, + }; + + it('should not render error message', async () => { + render( + + ); + + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.change(itemBarcodeField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + + it('should render "selectItemRequired" error message', async () => { + const props = { + ...basicProps, + isItemIdRequest: false, + }; + + render( + + ); + + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.change(itemBarcodeField, event); + + await waitFor(() => { + const errorMessage = screen.queryByText(labelIds.selectItemRequired); + + expect(errorMessage).toBeVisible(); + }); + }); + }); + + describe('when "barcode" is presented', () => { + const event = { + target: { + value: 'barcode', + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not render error message', async () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.change(itemBarcodeField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + + it('should render "itemBarcodeDoesNotExist" error message', async () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + fireEvent.keyDown(itemBarcodeField, { key: ENTER_EVENT_KEY }); + fireEvent.change(itemBarcodeField, event); + + await waitFor(() => { + const errorMessage = screen.queryByText(labelIds.itemBarcodeDoesNotExist); + + expect(errorMessage).toBeVisible(); + }); + }); + + it('should not render error message if item found', async () => { + const itemBarcodeField = screen.getByTestId(testIds.itemBarcodeField); + + basicProps.findItem.mockReturnValue({}); + fireEvent.keyDown(itemBarcodeField, { key: ENTER_EVENT_KEY }); + fireEvent.change(itemBarcodeField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + }); + }); + + describe('"Enter" button', () => { + describe('when barcode is presented', () => { + beforeEach(() => { + render( + + ); + }); + + it('should render "Enter" button', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + expect(enterButton).toBeVisible(); + }); + + it('should trigger "onSetSelectedItem" with correct argument', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.onSetSelectedItem).toHaveBeenCalledWith(null); + }); + + it('should trigger "findItem" with correct arguments', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.findItem).toHaveBeenCalledWith(RESOURCE_KEYS.barcode, basicProps.values.item.barcode); + }); + }); + + describe('when barcode is not presented', () => { + const props = { + ...basicProps, + values: { + item: { + barcode: '', + }, + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not trigger "onSetSelectedItem"', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.onSetSelectedItem).not.toHaveBeenCalled(); + }); + }); + }); + + describe('Spinner', () => { + afterEach(() => { + Icon.mockClear(); + }); + + describe('when data is loading', () => { + const props = { + ...basicProps, + isLoading: true, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should render loading "Icon" with correct props', () => { + expect(Icon).toHaveBeenCalledWith(BASE_SPINNER_PROPS, {}); + }); + }); + + describe('when data is not loading', () => { + beforeEach(() => { + render( + + ); + }); + + it('should not render loading "Icon"', () => { + expect(Icon).not.toHaveBeenCalled(); + }); + }); + }); + + describe('ItemDetails', () => { + afterEach(() => { + ItemDetail.mockClear(); + }); + + describe('when item is selected', () => { + beforeEach(() => { + render( + + ); + }); + + it('should render "ItemDetail" with correct props', () => { + const expectedProps = { + request: basicProps.request, + currentInstanceId: basicProps.instanceId, + item: basicProps.selectedItem, + loan: basicProps.selectedLoan, + requestCount: basicProps.itemRequestCount, + }; + + expect(ItemDetail).toHaveBeenCalledWith(expectedProps, {}); + }); + }); + + describe('when item is not selected', () => { + const props = { + ...basicProps, + selectedItem: undefined, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not render "ItemDetail"', () => { + expect(ItemDetail).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/test/jest/__mock__/finalFormComponents.mock.js b/test/jest/__mock__/finalFormComponents.mock.js new file mode 100644 index 00000000..46feac58 --- /dev/null +++ b/test/jest/__mock__/finalFormComponents.mock.js @@ -0,0 +1,30 @@ +jest.mock('react-final-form', () => ({ + ...jest.requireActual('react-final-form'), + Field: jest.fn(({ + label, + children, + component: Component, + 'data-testid': testId, + validate = jest.fn(), + ...rest + }) => { + if (Component) { + return ( + + ); + } else { + return children({ + meta: {}, + input: { + validate, + 'data-testid': testId, + }, + }); + } + }), +})); diff --git a/test/jest/__mock__/index.js b/test/jest/__mock__/index.js index 2ec179ca..a1807092 100644 --- a/test/jest/__mock__/index.js +++ b/test/jest/__mock__/index.js @@ -7,3 +7,4 @@ import './stripesIcon.mock'; import './stripesCore.mock'; import './stripesSmartComponents.mock'; import './reactToPrint.mock'; +import './finalFormComponents.mock'; diff --git a/test/jest/__mock__/stripesComponents.mock.js b/test/jest/__mock__/stripesComponents.mock.js index 65344fe8..b25def2b 100644 --- a/test/jest/__mock__/stripesComponents.mock.js +++ b/test/jest/__mock__/stripesComponents.mock.js @@ -1,7 +1,7 @@ import React from 'react'; -jest.mock('@folio/stripes/components', () => ({ - ...jest.requireActual('@folio/stripes/components'), +jest.mock('@folio/stripes-components', () => ({ + ...jest.requireActual('@folio/stripes-components'), Accordion: jest.fn(({ children, label }) => (
{label} @@ -27,7 +27,12 @@ jest.mock('@folio/stripes/components', () => ({ )), Callout: jest.fn(() =>
Callout
), - Checkbox: jest.fn(() =>
Checkbox
), + Checkbox: jest.fn((props) => ( + + )), Col: jest.fn(({ children }) => (
{children} @@ -125,6 +130,27 @@ jest.mock('@folio/stripes/components', () => ({ )), Select: jest.fn(() =>
Select
), TextArea: jest.fn(() =>
TextArea
), - TextField: jest.fn(() =>
TextField
), + TextField: jest.fn(({ + label, + onChange, + validate = jest.fn(), + ...rest + }) => { + const handleChange = (e) => { + validate(e.target.value); + onChange(e); + }; + + return ( +
+ + +
+ ); + }), Timepicker: jest.fn(() =>
Timepicker
), })); From e351e84fcc80a4f3b40156ba9e69dd0bce67555d Mon Sep 17 00:00:00 2001 From: Artem Blazhko Date: Fri, 16 Jun 2023 16:13:21 +0300 Subject: [PATCH 18/21] Cover InstanceInformation by jest/RTL tests (#1065) --- CHANGELOG.md | 1 + .../InstanceInformation.js | 3 +- .../InstanceInformation.test.js | 671 ++++++++++++++++++ test/jest/__mock__/stripesCore.mock.js | 15 +- 4 files changed, 688 insertions(+), 2 deletions(-) create mode 100644 src/components/InstanceInformation/InstanceInformation.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 4806372f..2902c010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ * Do not publish test artifacts to NPM. Refs STRIPES-865. * Create Jest/RTL test for NoteViewRoute.js Refs: UIREQ-945. * Cover ItemInformation by jest/RTL tests. Refs UIREQ-949. +* Cover InstanceInformation by jest/RTL tests. Refs UIREQ-950. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/src/components/InstanceInformation/InstanceInformation.js b/src/components/InstanceInformation/InstanceInformation.js index 14dde401..b08acaca 100644 --- a/src/components/InstanceInformation/InstanceInformation.js +++ b/src/components/InstanceInformation/InstanceInformation.js @@ -26,7 +26,7 @@ import { import css from '../../requests.css'; -const INSTANCE_SEGMENT_FOR_PLUGIN = 'instances'; +export const INSTANCE_SEGMENT_FOR_PLUGIN = 'instances'; class InstanceInformation extends Component { static propTypes = { @@ -183,6 +183,7 @@ class InstanceInformation extends Component { return ( ({ + memoizeValidation: (fn) => () => fn, + isFormEditing: jest.fn(() => false), +})); +jest.mock('..', () => ({ + TitleInformation: jest.fn(() =>
TitleInformation
), +})); + +const basicProps = { + triggerValidation: jest.fn(), + findInstance: jest.fn(() => null), + onSetSelectedInstance: jest.fn(), + form: { + change: jest.fn(), + }, + values: { + instance: { + hrid: 'hrid', + }, + keyOfInstanceIdField: 1, + }, + request: { + id: 'requestId', + }, + selectedInstance: { + title: 'instance title', + contributors: {}, + publication: {}, + editions: {}, + identifiers: {}, + }, + instanceRequestCount: 1, + instanceId: 'instanceId', + isLoading: false, + submitting: false, +}; +const labelIds = { + scanOrEnterBarcode: 'ui-requests.instance.scanOrEnterBarcode', + instanceHrid: 'ui-requests.instance.value', + enterButton: 'ui-requests.enter', + selectInstanceRequired: 'ui-requests.errors.selectInstanceRequired', + instanceUuidOrHridDoesNotExist: 'ui-requests.errors.instanceUuidOrHridDoesNotExist', + titleLookupPlugin: 'ui-requests.titleLookupPlugin', +}; +const testIds = { + instanceHridField: 'instanceHridField', + errorMessage: 'errorMessage', +}; +const renderInstanceInfoWithHrid = (onBlur) => { + Field.mockImplementation(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: {}, + input: { + validate, + 'data-testid': testId, + value: 'hrid', + onBlur, + }, + }); + })); + + render( + + ); +}; + +describe('InstanceInformation', () => { + afterEach(() => { + basicProps.onSetSelectedInstance.mockClear(); + Field.mockClear(); + cleanup(); + }); + + describe('when "isFormEditing" returns false', () => { + beforeEach(() => { + render( + + ); + }); + + it('should render "scanOrEnterBarcode" placeholder', () => { + const scanOrEnterBarcodePlaceholder = screen.getByPlaceholderText(labelIds.scanOrEnterBarcode); + + expect(scanOrEnterBarcodePlaceholder).toBeVisible(); + }); + + it('should render instance hrid "Field" with correct props', () => { + const expectedProps = { + name: REQUEST_FORM_FIELD_NAMES.INSTANCE_HRID, + validate: expect.any(Function), + validateFields: [], + }; + + expect(Field).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render instance hrid label', () => { + const instanceHridLabel = screen.getByText(labelIds.instanceHrid); + + expect(instanceHridLabel).toBeVisible(); + }); + + it('should trigger "findInstance" when Enter key is pressed', () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.keyDown(instanceHridField, { key: ENTER_EVENT_KEY }); + + expect(basicProps.findInstance).toHaveBeenCalledWith(basicProps.values.instance.hrid); + }); + + it('should not trigger "findInstance" when Control key is pressed', () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.keyDown(instanceHridField, { key: 'Control' }); + + expect(basicProps.findInstance).not.toHaveBeenCalledWith(); + }); + + it('should trigger "form.change" with correct arguments', () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + const event = { + target: { + value: 'instanceHrid', + }, + }; + + fireEvent.change(instanceHridField, event); + + expect(basicProps.form.change).toHaveBeenCalledWith(REQUEST_FORM_FIELD_NAMES.INSTANCE_HRID, event.target.value); + }); + + it('should render "TextField" with correct props', () => { + const expectedProps = { + required: true, + error: null, + placeholder: [labelIds.scanOrEnterBarcode], + onChange: expect.any(Function), + onBlur: expect.any(Function), + onKeyDown: expect.any(Function), + }; + + expect(TextField).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render "TextField" with validation error', () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + const enterButton = screen.getByText(labelIds.enterButton); + const event = { + target: { + value: 'instanceHrid', + }, + }; + const error = 'error'; + + Field.mockImplementationOnce(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: { + error, + touched: true, + }, + input: { + validate, + 'data-testid': testId, + }, + }); + })); + + fireEvent.click(enterButton); + fireEvent.change(instanceHridField, event); + + expect(TextField).toHaveBeenCalledWith(expect.objectContaining({ error }), {}); + }); + + it('should render "Pluggable" with correct props', () => { + const expectedProps = { + searchButtonStyle: 'link', + type: 'find-instance', + selectInstance: expect.any(Function), + config: { + availableSegments: [{ + name: INSTANCE_SEGMENT_FOR_PLUGIN, + }], + }, + }; + + expect(Pluggable).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render title lookup plugin label', () => { + const titleLookupPluginLabel = screen.getByText(labelIds.titleLookupPlugin); + + expect(titleLookupPluginLabel).toBeVisible(); + }); + + it('should trigger "findInstance" with correct argument', () => { + const hrid = 'hrid'; + const searchButton = screen.getByText('Search Instance'); + + fireEvent.click(searchButton); + + expect(basicProps.findInstance).toHaveBeenCalledWith(hrid); + }); + }); + + describe('when "isFormEditing" returns true', () => { + beforeEach(() => { + isFormEditing.mockReturnValueOnce(true); + + render( + + ); + }); + + it('should not render "scanOrEnterBarcode" placeholder', () => { + const scanOrEnterBarcodePlaceholder = screen.queryByPlaceholderText(labelIds.scanOrEnterBarcode); + + expect(scanOrEnterBarcodePlaceholder).not.toBeInTheDocument(); + }); + + it('should not render instance hrid field', () => { + const instanceHridField = screen.queryByTestId(testIds.instanceHridField); + + expect(instanceHridField).not.toBeInTheDocument(); + }); + + it('should not render instance hrid label', () => { + const instanceHridLabel = screen.queryByText(labelIds.instanceHrid); + + expect(instanceHridLabel).not.toBeInTheDocument(); + }); + }); + + describe('handleBlur', () => { + const onBlur = jest.fn(); + + afterEach(() => { + onBlur.mockClear(); + }); + + it('should trigger "input.onBlur" if instance hrid is presented', () => { + renderInstanceInfoWithHrid(onBlur); + + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.click(instanceHridField); + fireEvent.blur(instanceHridField); + + expect(onBlur).toHaveBeenCalled(); + }); + + it('should trigger "input.onBlur" if there is no instance hrid', () => { + Field.mockImplementation(jest.fn(({ + children, + 'data-testid': testId, + validate, + }) => { + return children({ + meta: {}, + input: { + validate, + 'data-testid': testId, + value: '', + onBlur, + }, + }); + })); + + render( + + ); + + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.click(instanceHridField); + fireEvent.blur(instanceHridField); + + expect(onBlur).toHaveBeenCalled(); + }); + + it('should not trigger "input.onBlur" if instance hrid was validated previously', () => { + renderInstanceInfoWithHrid(onBlur); + + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + // first input focus + fireEvent.click(instanceHridField); + fireEvent.blur(instanceHridField); + onBlur.mockClear(); + + // second input focus after validation of initial value + fireEvent.click(instanceHridField); + fireEvent.blur(instanceHridField); + + expect(onBlur).not.toHaveBeenCalled(); + }); + }); + + describe('Validation', () => { + afterEach(() => { + basicProps.findInstance.mockClear(); + TextField.mockClear(); + }); + + beforeEach(() => { + TextField.mockImplementation(({ + onChange, + validate, + ...rest + }) => { + const [error, setError] = useState(''); + const handleChange = async (e) => { + setError(await validate(e.target.value)); + onChange(e); + }; + + return ( +
+ + {error} +
+ ); + }); + }); + + describe('when instance hrid is not presented', () => { + const event = { + target: { + value: '', + }, + }; + + it('should not render error message', async () => { + render( + + ); + + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.change(instanceHridField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + + it('should render "selectInstanceRequired" error message', async () => { + const props = { + ...basicProps, + selectedInstance: { + id: 'hrid', + }, + }; + + render( + + ); + + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.change(instanceHridField, event); + + await waitFor(() => { + const errorMessage = screen.queryByText(labelIds.selectInstanceRequired); + + expect(errorMessage).toBeVisible(); + }); + }); + }); + + describe('when instance hrid is presented', () => { + const event = { + target: { + value: 'instanceId', + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not render error message', async () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.change(instanceHridField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + + it('should render "instanceUuidOrHridDoesNotExist" error message', async () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + fireEvent.keyDown(instanceHridField, { key: ENTER_EVENT_KEY }); + fireEvent.change(instanceHridField, event); + + await waitFor(() => { + const errorMessage = screen.queryByText(labelIds.instanceUuidOrHridDoesNotExist); + + expect(errorMessage).toBeVisible(); + }); + }); + + it('should not render error message if instance found', async () => { + const instanceHridField = screen.getByTestId(testIds.instanceHridField); + + basicProps.findInstance.mockReturnValue({}); + fireEvent.keyDown(instanceHridField, { key: ENTER_EVENT_KEY }); + fireEvent.change(instanceHridField, event); + + await waitFor(() => { + const errorMessage = screen.getByTestId(testIds.errorMessage); + + expect(errorMessage).toBeEmpty(); + }); + }); + }); + }); + + describe('"Enter" button', () => { + describe('when instance hrid is presented', () => { + beforeEach(() => { + render( + + ); + }); + + it('should render "Enter" button', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + expect(enterButton).toBeVisible(); + }); + + it('should trigger "onSetSelectedInstance" with correct argument', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.onSetSelectedInstance).toHaveBeenCalledWith(null); + }); + + it('should trigger "findInstance" with correct argument', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.findInstance).toHaveBeenCalledWith(basicProps.values.instance.hrid); + }); + }); + + describe('when instance hrid is not presented', () => { + const props = { + ...basicProps, + values: { + instance: { + hrid: '', + }, + }, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not trigger "onSetSelectedInstance"', () => { + const enterButton = screen.getByText(labelIds.enterButton); + + fireEvent.click(enterButton); + + expect(basicProps.onSetSelectedInstance).not.toHaveBeenCalled(); + }); + }); + }); + + describe('Spinner', () => { + afterEach(() => { + Icon.mockClear(); + }); + + describe('when data is loading', () => { + const props = { + ...basicProps, + isLoading: true, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should render loading "Icon" with correct props', () => { + expect(Icon).toHaveBeenCalledWith(BASE_SPINNER_PROPS, {}); + }); + }); + + describe('when data is not loading', () => { + beforeEach(() => { + render( + + ); + }); + + it('should not render loading "Icon"', () => { + expect(Icon).not.toHaveBeenCalled(); + }); + }); + }); + + describe('TitleInformation', () => { + afterEach(() => { + TitleInformation.mockClear(); + }); + + describe('when instance is selected', () => { + it('should render "TitleInformation" with correct props', () => { + render( + + ); + + const expectedProps = { + instanceId: basicProps.instanceId, + titleLevelRequestsCount: basicProps.instanceRequestCount, + title: basicProps.selectedInstance.title, + contributors: basicProps.selectedInstance.contributors, + publications: basicProps.selectedInstance.publication, + editions: basicProps.selectedInstance.editions, + identifiers: basicProps.selectedInstance.identifiers, + }; + + expect(TitleInformation).toHaveBeenCalledWith(expectedProps, {}); + }); + + it('should render "TitleInformation" with "request.instanceId"', () => { + const instanceId = 'instanceId'; + const props = { + ...basicProps, + request: { + ...basicProps.request, + instanceId, + }, + }; + const expectedProps = { + instanceId, + }; + + render( + + ); + + expect(TitleInformation).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + + it('should render "TitleInformation" with "selectedInstance.id"', () => { + const selectedInstanceId = 'selectedInstanceId'; + const props = { + ...basicProps, + selectedInstance: { + ...basicProps.selectedInstance, + id: selectedInstanceId, + }, + }; + const expectedProps = { + instanceId: selectedInstanceId, + }; + + render( + + ); + + expect(TitleInformation).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {}); + }); + }); + + describe('when instance is not selected', () => { + const props = { + ...basicProps, + selectedInstance: undefined, + }; + + beforeEach(() => { + render( + + ); + }); + + it('should not render "TitleInformation"', () => { + expect(TitleInformation).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/test/jest/__mock__/stripesCore.mock.js b/test/jest/__mock__/stripesCore.mock.js index 4cdca697..c3b2c690 100644 --- a/test/jest/__mock__/stripesCore.mock.js +++ b/test/jest/__mock__/stripesCore.mock.js @@ -23,7 +23,20 @@ jest.mock('@folio/stripes/core', () => ({ /> ), stripesConnect: Component => props => , - Pluggable: jest.fn(() => null), + Pluggable: jest.fn(({ + searchLabel, + selectInstance, + }) => ( + <> +
{searchLabel}
+ + + )), IfPermission: jest.fn(({ children }) =>
{children}
), TitleManager: jest.fn(jest.fn(() => null)), })); From bdf219b6e11fe9d82109a940f7c8443c5e470f76 Mon Sep 17 00:00:00 2001 From: Dmitriy-Litvinenko Date: Wed, 21 Jun 2023 16:49:54 +0300 Subject: [PATCH 19/21] UIREQ-979: Fix inconsistency in RTL/Jest tests --- CHANGELOG.md | 7 ++-- .../ReferredRecord/ReferredRecord.test.js | 19 ++++++----- .../RequestsFiltersConfig.test.js | 14 ++++++-- .../SortableList/SortableList.test.js | 24 +++++++++++--- .../draggableRowFormatter.test.js | 24 +++++++++----- src/routes/NoteEditRoute.test.js | 27 ++++++++++----- src/routes/NoteViewRoute.test.js | 33 ++++++++++++++----- src/utils.test.js | 8 ++--- 8 files changed, 109 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2902c010..17916e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,15 +27,16 @@ * Added requestDate token. Refs UIREQ-962. * Update `request-storage` okapi interface to `6.0` version. Refs UIREQ-963. * UI tests replacement with RTL/Jest for src/PatronBlockModal.js. Refs UIREQ-878. -* Create Jest/RTL test for RequestsFiltersConfig.js. Refs: UIREQ-938 +* Create Jest/RTL test for RequestsFiltersConfig.js. Refs UIREQ-938. * Create Jest/RTL test for SortableList.js. Refs UIREQ-941. -* create Jest/RTL test for draggableRowFormatter.js, Refs UIREQ-942 +* Create Jest/RTL test for draggableRowFormatter.js. Refs UIREQ-942. * UI tests replacement with RTL/Jest for src/UserDetail.js. Refs UIREQ-881. * TLR: "Create title level request" checkbox not preselected on "New request" page. Refs UIREQ-955. * Do not publish test artifacts to NPM. Refs STRIPES-865. -* Create Jest/RTL test for NoteViewRoute.js Refs: UIREQ-945. +* Create Jest/RTL test for NoteViewRoute.js. Refs UIREQ-945. * Cover ItemInformation by jest/RTL tests. Refs UIREQ-949. * Cover InstanceInformation by jest/RTL tests. Refs UIREQ-950. +* Fix inconsistency in RTL/Jest tests. Refs UIREQ-979. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/src/components/ReferredRecord/ReferredRecord.test.js b/src/components/ReferredRecord/ReferredRecord.test.js index 05a0642c..26d7e54c 100644 --- a/src/components/ReferredRecord/ReferredRecord.test.js +++ b/src/components/ReferredRecord/ReferredRecord.test.js @@ -1,5 +1,10 @@ import '../../../test/jest/__mock__'; -import { render, screen } from '@testing-library/react'; + +import { + render, + screen, +} from '@testing-library/react'; + import ReferredRecord from './ReferredRecord'; const propsData = { @@ -12,32 +17,30 @@ const propsData = { requesterId: 'testRequesterId', requesterName: 'testRequesterName', }; - const labelIds = { entityTypeRequest: 'ui-requests.notes.entityType.request', assignedFor: 'ui-requests.notes.assigned.for', assignedRequester: 'ui-requests.notes.assigned.requester', - assignedRequestDate: 'ui-requests.notes.assigned.requestDate' + assignedRequestDate: 'ui-requests.notes.assigned.requestDate', }; - const renderReferredRecord = (prop) => render(); describe('ReferredRecord', () => { beforeEach(() => renderReferredRecord(propsData)); - it('entityType.request should render', () => { + it('should render entityType.request', () => { expect(screen.getByText(labelIds.entityTypeRequest)).toBeInTheDocument(); }); - it('assigned.for should render', () => { + it('should render assigned.for', () => { expect(screen.getByText(labelIds.assignedFor)).toBeInTheDocument(); }); - it('assigned.requester should render', () => { + it('should render assigned.requester', () => { expect(screen.getByText(labelIds.assignedRequester)).toBeInTheDocument(); }); - it('assigned.requestDate should render', () => { + it('should render assigned.requestDate', () => { expect(screen.getByText(labelIds.assignedRequestDate)).toBeInTheDocument(); }); }); diff --git a/src/components/RequestsFilters/RequestsFiltersConfig.test.js b/src/components/RequestsFilters/RequestsFiltersConfig.test.js index a0b244ef..c5a94cb4 100644 --- a/src/components/RequestsFilters/RequestsFiltersConfig.test.js +++ b/src/components/RequestsFilters/RequestsFiltersConfig.test.js @@ -1,6 +1,9 @@ -import { requestFilterTypes } from '../../constants'; import filtersConfig from './RequestsFiltersConfig'; +import { + requestFilterTypes, +} from '../../constants'; + describe('RequestsFiltersConfig', () => { it('should have a filter for requestType', () => { const requestTypeFilter = filtersConfig.find(f => f.name === 'requestType'); @@ -10,6 +13,7 @@ describe('RequestsFiltersConfig', () => { values: [], operator: '==', }; + expect(requestTypeFilter).toEqual(expectedResult); }); @@ -20,8 +24,9 @@ describe('RequestsFiltersConfig', () => { cql: 'status', values: [], operator: '==', - label: 'ui-requests.requestMeta.status' + label: 'ui-requests.requestMeta.status', }; + expect(requestStatusFilter).toEqual(expectedResult); }); @@ -33,6 +38,7 @@ describe('RequestsFiltersConfig', () => { values: [], operator: '==', }; + expect(requestLevelsFilter).toEqual(expectedResult); }); @@ -45,16 +51,19 @@ describe('RequestsFiltersConfig', () => { operator: '==', parse: expect.any(Function), }; + expect(tagsFilter).toEqual(expectedResult); }); it('should return the expected query string for a single tag', () => { const tagsFilter = filtersConfig.find(f => f.name === 'tags'); + expect(tagsFilter.parse('tag1')).toEqual('tags.tagList==*"*tag1*"*'); }); it('should return the expected query string for an array of tags', () => { const tagsFilter = filtersConfig.find(f => f.name === 'tags'); + expect(tagsFilter.parse(['tag1', 'tag2'])).toEqual('tags.tagList==(*"*tag1*"* or *"*tag2*"*)'); }); @@ -66,6 +75,7 @@ describe('RequestsFiltersConfig', () => { values: [], operator: '==', }; + expect(pickupServicePointFilter).toEqual(expectedResult); }); }); diff --git a/src/components/SortableList/SortableList.test.js b/src/components/SortableList/SortableList.test.js index 22d13cb0..2f10fee4 100644 --- a/src/components/SortableList/SortableList.test.js +++ b/src/components/SortableList/SortableList.test.js @@ -1,10 +1,24 @@ -import { render, screen } from '@testing-library/react'; +import { + render, + screen, +} from '@testing-library/react'; + import '../../../test/jest/__mock__'; + import SortableList from './SortableList'; jest.mock('react-beautiful-dnd', () => ({ ...jest.requireActual('react-beautiful-dnd'), - Droppable: jest.fn(({ children }) => children({ droppableProps: { droppableid: 'droppableId1', className: 'droppable-area', role: 'list', onDragEnd: jest.fn() }, placeholder:
Placeholder
, innerRef: jest.fn() }, {})) + Droppable: jest.fn(({ children }) => children({ + droppableProps: { + droppableid: 'droppableId1', + className: 'droppable-area', + role: 'list', + onDragEnd: jest.fn(), + }, + placeholder:
Placeholder
, + innerRef: jest.fn(), + }, {})), })); const mockonDragEnd = jest.fn(); @@ -29,15 +43,15 @@ describe('SortableList', () => { renderSortableList(propsData); }); - it('Should render the SortableList component with provided droppableId', () => { + it('should render the SortableList component with provided droppableId', () => { expect(document.querySelector('[droppableid="droppableId1"]')).toBeInTheDocument(); }); - it('Should render the MultiColumnList', () => { + it('should render the MultiColumnList', () => { expect(screen.getByText('MultiColumnList')).toBeInTheDocument(); }); - it('Should render the Provided Placeholder', () => { + it('should render the Provided Placeholder', () => { expect(screen.getByText('Placeholder')).toBeInTheDocument(); }); }); diff --git a/src/components/SortableList/draggableRowFormatter.test.js b/src/components/SortableList/draggableRowFormatter.test.js index 7dbe0a2a..9d659299 100644 --- a/src/components/SortableList/draggableRowFormatter.test.js +++ b/src/components/SortableList/draggableRowFormatter.test.js @@ -1,4 +1,8 @@ -import { render, screen } from '@testing-library/react'; +import { + render, + screen, +} from '@testing-library/react'; + import draggableRowFormatter from './draggableRowFormatter'; jest.mock('react-beautiful-dnd', () => ({ @@ -9,7 +13,7 @@ jest.mock('react-beautiful-dnd', () => ({
{prop.children()}
); - } + }, })); const cells = [ @@ -23,33 +27,35 @@ const propsData = { rowData: 'rowData', rowProps: { isRowDraggable: jest.fn(), - additionalClasses: ['my-additional-class'] + additionalClasses: ['my-additional-class'], }, snapshot: { - isDragging: false + isDragging: false, }, provided: { draggableProps: { style: { - backgroundColor: 'white' - } + backgroundColor: 'white', + }, }, dragHandleProps: '', - innerRef: () => {} + innerRef: () => {}, }, - cells + cells, }; const renderDraggableRowFormatter = (prop) => { const Component = () => draggableRowFormatter(prop); + return ( render() ); }; describe('draggableRowFormatter', () => { - it('draggableRowFormatter component should render correctly', () => { + it('should render correctly draggableRowFormatter component', () => { renderDraggableRowFormatter(propsData); + expect(screen.getByRole('row', { name: /Cell 1 Cell 2 Cell 3/i })).toBeInTheDocument(); }); }); diff --git a/src/routes/NoteEditRoute.test.js b/src/routes/NoteEditRoute.test.js index 9fc1407f..c9a96ea8 100644 --- a/src/routes/NoteEditRoute.test.js +++ b/src/routes/NoteEditRoute.test.js @@ -1,31 +1,40 @@ import '__mock__/'; -import { render, screen } from '@testing-library/react'; -import { historyData } from '../../test/jest/fixtures/historyData'; + +import { + render, + screen, +} from '@testing-library/react'; + +import { + historyData, +} from '../../test/jest/fixtures/historyData'; import NoteEditRoute from './NoteEditRoute'; jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), - Redirect: () =>
Request
+ Redirect: () =>
Request
, })); const locationData = historyData.location; const match = { params: { - noteId: 'editNoteRouteID' + noteId: 'editNoteRouteID', }, path: 'editPath', - url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules' + url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules', }; - const renderNoteEditRoute = (locationProps, historyProps) => render( ); + describe('NoteEditRoute', () => { - it('NoteEditPage should render when location.state is not empty', () => { + it('should render NoteEditPage when location.state is not empty', () => { renderNoteEditRoute(locationData, historyData); + expect(screen.getByText('NoteEditPage')).toBeInTheDocument(); }); - it('Request page should render when location.state is empty', () => { + + it('should render request page when location.state is empty', () => { const historyProp = { ...historyData, location : { @@ -36,7 +45,9 @@ describe('NoteEditRoute', () => { }, }; const locationProp = historyProp.location; + renderNoteEditRoute(locationProp, historyProp); + expect(screen.getByText('Request')).toBeInTheDocument(); }); }); diff --git a/src/routes/NoteViewRoute.test.js b/src/routes/NoteViewRoute.test.js index 4d1e45b0..086df576 100644 --- a/src/routes/NoteViewRoute.test.js +++ b/src/routes/NoteViewRoute.test.js @@ -1,25 +1,36 @@ -import '__mock__/'; -import { render, screen } from '@testing-library/react'; +import { + render, + screen, +} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { historyData } from '../../test/jest/fixtures/historyData'; + +import '__mock__/'; + import NoteViewRoute from './NoteViewRoute'; +import { + historyData, +} from '../../test/jest/fixtures/historyData'; jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), - Redirect: () =>
Request
+ Redirect: () =>
Request
, })); const locationData = historyData.location; const match = { params: { - noteId: 'viewNoteRouteID' + noteId: 'viewNoteRouteID', }, path: 'viewPath', - url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules' + url: '{{ env.FOLIO_MD_REGISTRY }}/_/proxy/modules', }; const renderNoteViewRoute = (locationProps, historyProps) => render( - + ); describe('NoteViewRoute', () => { @@ -27,15 +38,19 @@ describe('NoteViewRoute', () => { beforeEach(() => { renderNoteViewRoute(locationData, historyData); }); + it('NoteViewPage should render when location.state is not empty', () => { expect(screen.getByText('NoteViewPage')).toBeInTheDocument(); }); + it('history.replace function to be called when onEdit clicked', () => { userEvent.click(screen.getByRole('button', { name: 'onEdit' })); + expect(historyData.replace).toBeCalled(); }); }); - it('Request page should render when location.state is empty', () => { + + it('should render request page when location.state is empty', () => { const historyProp = { ...historyData, location : { @@ -47,7 +62,9 @@ describe('NoteViewRoute', () => { }, }; const locationProp = historyProp.location; + renderNoteViewRoute(locationProp, historyProp); + expect(screen.getByText('Request')).toBeInTheDocument(); }); }); diff --git a/src/utils.test.js b/src/utils.test.js index e025cfff..c333aeaa 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -232,7 +232,7 @@ describe('getInstanceQueryString', () => { }); describe('generateUserName', () => { - it('Should return full name', () => { + it('should return full name', () => { const firstName = 'Bob'; const lastName = 'Marley'; const middleName = 'Test'; @@ -241,7 +241,7 @@ describe('generateUserName', () => { .toEqual(`${lastName}, ${firstName} ${middleName}`); }); - it('Should return last name and first name', () => { + it('should return last name and first name', () => { const firstName = 'Bob'; const lastName = 'Marley'; const middleName = undefined; @@ -250,7 +250,7 @@ describe('generateUserName', () => { .toEqual(`${lastName}, ${firstName}`); }); - it('Should return last name only', () => { + it('should return last name only', () => { const firstName = undefined; const lastName = 'Marley'; const middleName = undefined; @@ -259,7 +259,7 @@ describe('generateUserName', () => { .toEqual(lastName); }); - it('Should return last name only if lastName and middleName presented', () => { + it('should return last name only if lastName and middleName presented', () => { const firstName = undefined; const lastName = 'Marley'; const middleName = 'Test'; From ad5d669b99f0eb3f4bbce3be1752350c8ec1a45a Mon Sep 17 00:00:00 2001 From: FOLIO Translations Bot <38661258+folio-translations@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:27:40 -0400 Subject: [PATCH 20/21] Lokalise: updates --- translations/ui-requests/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/ui-requests/de.json b/translations/ui-requests/de.json index d2acc40f..8e64a046 100644 --- a/translations/ui-requests/de.json +++ b/translations/ui-requests/de.json @@ -95,7 +95,7 @@ "showTags": "Tags anzeigen", "tags.tagList": "Tags", "item.copyNumbers": "Exemplarnummer", - "requestNotAllowed": "Bestandsanfrage nicht erlaubt", + "requestNotAllowed": "Bestandsanfrage nicht zulässig", "additionalReasons": "Details der Sperre anzeigen, um zusätzliche Gründe für die Sperre anzuzeigen...", "pickupServicePoint.name": "Abholservicestelle", "item.id": "Exemplar-ID", From 1012387964faadf7c9dea09df29c7395ce21dcba Mon Sep 17 00:00:00 2001 From: Artem Blazhko Date: Wed, 5 Jul 2023 15:38:24 +0300 Subject: [PATCH 21/21] Remove redundant ariaLabel prop (#1071) --- CHANGELOG.md | 1 + src/ItemsDialog.js | 1 - src/ItemsDialog.test.js | 3 --- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17916e23..f04d2682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ * Cover ItemInformation by jest/RTL tests. Refs UIREQ-949. * Cover InstanceInformation by jest/RTL tests. Refs UIREQ-950. * Fix inconsistency in RTL/Jest tests. Refs UIREQ-979. +* Remove redundant ariaLabel prop. Refs UIREQ-972. ## [8.0.2](https://github.com/folio-org/ui-requests/tree/v8.0.2) (2023-03-29) [Full Changelog](https://github.com/folio-org/ui-requests/compare/v8.0.1...v8.0.2) diff --git a/src/ItemsDialog.js b/src/ItemsDialog.js index 0444d865..77d3e3d3 100644 --- a/src/ItemsDialog.js +++ b/src/ItemsDialog.js @@ -212,7 +212,6 @@ const ItemsDialog = ({ : { expect.objectContaining({ id: 'instance-items-list', interactive: true, - ariaLabel: labelIds.instanceItems, contentData: [], visibleColumns: COLUMN_NAMES, columnMapping: COLUMN_MAP, @@ -236,7 +235,6 @@ describe('ItemsDialog', () => { { id: 'instance-items-list', interactive: true, - ariaLabel: labelIds.instanceItems, contentData: [{ id: '2', status: { @@ -397,7 +395,6 @@ describe('ItemsDialog', () => { { id: 'instance-items-list', interactive: true, - ariaLabel: labelIds.instanceItems, contentData: [], visibleColumns: COLUMN_NAMES, columnMapping: COLUMN_MAP,