Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIIN-2664 Jest/RTL: Cover MoveHoldingContext component with unit tests #2469

Merged
merged 4 commits into from Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -17,6 +17,7 @@
* Jest/RTL: Cover ConnectedTitle component with unit tests. Refs UIIN-2666.
* Jest/RTL: Cover InstancePlugin component with unit tests. Refs UIIN-2668.
* Jest/RTL: Cover ImportRecord component with unit test. Refs UIIN-2667.
* Jest/RTL: Cover MoveHoldingContext component with unit tests. Refs UIIN-2664.

## [11.0.3] (IN PROGRESS)

Expand Down
225 changes: 225 additions & 0 deletions src/Instance/MoveHoldingContext/MoveHoldingContext.test.js
@@ -0,0 +1,225 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { keyBy } from 'lodash';

import { screen, waitFor, configure, fireEvent } from '@folio/jest-config-stripes/testing-library/react';
import { within } from '@folio/jest-config-stripes/testing-library/dom';

import { DataContext } from '../../contexts';
import { useHoldings, useInstanceHoldingsQuery } from '../../providers';
import { useLocationsQuery } from '../../hooks';
import { holdingsById, identifierTypes, instanceRelationshipTypes } from '../../../test/fixtures';
import renderWithIntl from '../../../test/jest/helpers/renderWithIntl';
import translationsProperties from '../../../test/jest/helpers/translationsProperties';
import MoveHoldingContext from './MoveHoldingContext';
import { leftInstance, rightInstance } from '../../../test/fixtures/movingInstances';
import { locationsById } from '../../../test/fixtures/locationsById';
import { InstanceMovementDetailsContainer } from '../InstanceMovement';

configure({ testIdAttribute: 'id' });

jest.mock('../../providers', () => ({
...jest.requireActual('../../providers'),
useHoldings: jest.fn(),
useInstanceHoldingsQuery: jest.fn(),
}));

jest.mock('../../hooks', () => ({
...jest.requireActual('../../hooks'),
useHoldingItemsQuery: jest.fn().mockImplementation(() => ({
totalRecords: 1,
isLoading: false,
isFetching: false,
})),
useLocationsQuery: jest.fn()
}));

useHoldings.mockImplementation(() => ({
holdingsById,
}));

useInstanceHoldingsQuery.mockImplementation((id) => ({
holdingsRecords: Object.values(holdingsById).filter(holding => holding.instanceId === id),
isLoading: false,
}));

useLocationsQuery.mockImplementation(() => ({
data: Object.values(locationsById)
}));

const onClose = jest.fn();
const moveHoldings = jest.fn().mockImplementation(() => Promise.resolve());

const renderMoveHoldingContext = () => renderWithIntl(
<Router>
<DataContext.Provider value={{
contributorTypes: [],
identifierTypes,
identifierTypesById: keyBy(identifierTypes, 'id'),
identifierTypesByName: keyBy(identifierTypes, 'name'),
instanceRelationshipTypes,
instanceRelationshipTypesById: keyBy(identifierTypes, 'id'),
instanceFormats: [],
modesOfIssuance: [],
natureOfContentTerms: [],
tagsRecords: [],
locationsById,
}}
>
<MoveHoldingContext
leftInstance={leftInstance}
rightInstance={rightInstance}
moveHoldings={moveHoldings}
>
<InstanceMovementDetailsContainer
instance={leftInstance}
onClose={onClose}
data-test-movement-from-instance-details
id="movement-from-instance-details"
/>

<InstanceMovementDetailsContainer
instance={rightInstance}
onClose={onClose}
data-test-movement-to-instance-details
id="movement-to-instance-details"
/>
</MoveHoldingContext>
</DataContext.Provider>
</Router>,
translationsProperties
);


describe('MoveHoldingContext', () => {
it('should render correct holdings accordion for left pane', () => {
const { getByTestId } = renderMoveHoldingContext();

const leftPane = getByTestId('movement-from-instance-details');
expect(within(leftPane).getByText(/Holdings: Main Library/)).toBeInTheDocument();
expect(within(leftPane).getByText(/Holdings: Annex/)).toBeInTheDocument();
});

it('should render "Drop holding" area in right pane', () => {
const { getByTestId } = renderMoveHoldingContext();

const leftPane = getByTestId('movement-to-instance-details');
expect(within(leftPane).getByText(/Drop holding/)).toBeInTheDocument();
});

it('"Select holdings" checkbox functionality works as expected', () => {
const { getByTestId } = renderMoveHoldingContext();

const selectHoldingCheckbox = getByTestId('select-holding-c4a15834-0184-4a6f-9c0c-0ca5bad8286d');

fireEvent.click(selectHoldingCheckbox);
expect(selectHoldingCheckbox).toBeChecked();

fireEvent.click(selectHoldingCheckbox);
expect(selectHoldingCheckbox).not.toBeChecked();
});

it('should render confirmation modal with initial state in background', () => {
const { getByText } = renderMoveHoldingContext();

expect(getByText(/ConfirmationModal/)).toBeInTheDocument();
expect(getByText(/0 items will be moved to/)).toBeInTheDocument();
});

it('should render correct list of holdings for Annex with checkbox', async () => {
const { getByTestId } = renderMoveHoldingContext();

const annexSection = getByTestId('c4a15834-0184-4a6f-9c0c-0ca5bad8286d');
const annexHoldingsAccordionBtn = getByTestId('accordion-toggle-button-c4a15834-0184-4a6f-9c0c-0ca5bad8286d');

fireEvent.click(annexHoldingsAccordionBtn);

let grid;
let rows;

await waitFor(() => {
grid = within(annexSection).getByRole('grid');
rows = within(grid).getAllByRole('row');

expect(grid).toBeVisible();
expect(rows).toHaveLength(3);

// render correct table headers
const titles = [
'Item: barcode',
'Status',
'Copy number',
'Loan type',
'Effective location',
'Enumeration',
'Chronology',
'Volume',
'Year, caption',
'Material type'
];

titles.forEach(title => {
expect(within(rows[0]).getByText(title)).toBeInTheDocument();
});

// second row should have 'Inactive' cell
expect(within(rows[1]).getByText('Inactive')).toBeInTheDocument();

// should render 'End of list' indicator
expect(within(grid).getByText('End of list')).toBeInTheDocument();
});

fireEvent.click(within(rows[1]).getByRole('checkbox'));

rows.forEach(row => {
expect(within(row).getByRole('checkbox')).toBeChecked();
});

fireEvent.click(within(rows[1]).getByRole('checkbox'));

rows.forEach(row => {
expect(within(row).getByRole('checkbox')).not.toBeChecked();
});
});

describe('when "Move" button is clicked', () => {
const clickMoveFlow = ({ getByTestId, getByText }) => {
const holdingsAnnex = getByTestId('item-row-c4a15834-0184-4a6f-9c0c-0ca5bad8286d');

const moveToBtn = within(holdingsAnnex).getByText('Move to');

fireEvent.click(moveToBtn);

const dropdownMoveBtn = within(holdingsAnnex).getByText('A journey through Europe Bildtontraeger high-speed lines European Commission, Directorate-General for Mobility and Transport');
expect(dropdownMoveBtn).toBeInTheDocument();

fireEvent.click(dropdownMoveBtn);

expect(getByText('1 holding will be moved to')).toBeInTheDocument();
};

it('should move selected holdings if "Confirm button" is clicked', () => {
const { getByText, getByTestId } = renderMoveHoldingContext();

clickMoveFlow({ getByText, getByTestId });

const confirmBtn = screen.getByRole('button', { name: /confirm/ });

fireEvent.click(confirmBtn);

expect(screen.queryByText('Loading')).toBeInTheDocument();
});

it('should close modal and stop moving when "Cancel" is clicked', () => {
const { getByText, getByTestId } = renderMoveHoldingContext();

clickMoveFlow({ getByText, getByTestId });

const cancelBtn = screen.getByRole('button', { name: /cancel/ });

fireEvent.click(cancelBtn);

expect(screen.queryByText('Loading')).not.toBeInTheDocument();
});
});
});
136 changes: 136 additions & 0 deletions test/fixtures/holdingsById.js
@@ -0,0 +1,136 @@
export const holdingsById = {
'0c45bb50-7c9b-48b0-86eb-178a494e25fe': {
'holdingsItems': [],
'bareHoldingsItems': [],
'id': '0c45bb50-7c9b-48b0-86eb-178a494e25fe',
'_version': 1,
'hrid': 'hold000000000002',
'formerIds': [
'ABW4508',
'442882'
],
'instanceId': '69640328-788e-43fc-9c3c-af39e243f3b7',
'permanentLocationId': 'fcd64ce1-6995-48f0-840e-89ffa2288371',
'effectiveLocationId': 'fcd64ce1-6995-48f0-840e-89ffa2288371',
'electronicAccess': [
{
'uri': 'http://www.ebscohost.com',
'materialsSpecification': '1984-',
'relationshipId': '3b430592-2e09-4b48-9a0c-0636d66b9fb3'
},
{
'uri': 'http://www.jstor.com',
'materialsSpecification': '1984-',
'publicNote': 'Most recent 4 years not available.',
'relationshipId': '3b430592-2e09-4b48-9a0c-0636d66b9fb3'
}
],
'callNumber': 'K1 .M44',
'acquisitionMethod': 'Purchase',
'receiptStatus': 'Not currently received',
'administrativeNotes': [],
'notes': [
{
'holdingsNoteTypeId': 'b160f13a-ddba-4053-b9c4-60ec5ea45d56',
'note': ' Subscription cancelled per Evans Current Periodicals Selector Review. acq',
'staffOnly': true
},
{
'holdingsNoteTypeId': 'b160f13a-ddba-4053-b9c4-60ec5ea45d56',
'note': 'Asked Ebsco to check with publisher and ask what years were paid since we are missing (2001:Oct.-Dec.), (All of 2002), & (2003:Jan.-Feb.). 20030305. evaldez',
'staffOnly': false
},
{
'holdingsNoteTypeId': 'b160f13a-ddba-4053-b9c4-60ec5ea45d56',
'note': 'Backorder:v.87(2001:Oct.-Dec)-v.88(2002). eluza',
'staffOnly': false
},
{
'holdingsNoteTypeId': 'b160f13a-ddba-4053-b9c4-60ec5ea45d56',
'note': 'WITH 2010 TREAT ISSUE S AS DISCARDS. dgill',
'staffOnly': false
}
],
'retentionPolicy': 'Permanently retained.',
'holdingsStatements': [
{
'statement': 'v.70-84 (1984-1998)'
},
{
'statement': 'v.85:no. 1-11 (1999:Jan.-Nov.)'
},
{
'statement': 'v.87:no.1-9 (2001:Jan.-Sept.)'
},
{
'statement': 'v.89:no.2-12 (2003:Feb.-Dec.)'
},
{
'statement': 'v.90-95 (2004-2009)'
}
],
'holdingsStatementsForIndexes': [],
'holdingsStatementsForSupplements': [
{
'statement': 'no.1-23 '
}
],
'copyNumber': '1',
'statisticalCodeIds': [
'775b6ad4-9c35-4d29-bf78-8775a9b42226'
],
'metadata': {
'createdDate': '2024-04-27T13:50:16.043+00:00',
'updatedDate': '2024-04-27T13:50:16.043+00:00'
}
},
'c4a15834-0184-4a6f-9c0c-0ca5bad8286d': {
'holdingsItems': [],
'bareHoldingsItems': [],
'id': 'c4a15834-0184-4a6f-9c0c-0ca5bad8286d',
'_version': 3,
'hrid': 'hold000000000001',
'formerIds': [],
'instanceId': '69640328-788e-43fc-9c3c-af39e243f3b7',
'permanentLocationId': '53cf956f-c1df-410b-8bea-27f712cca7c0',
'effectiveLocationId': '53cf956f-c1df-410b-8bea-27f712cca7c0',
'electronicAccess': [
{
'uri': 'https://search.proquest.com/publication/1396348',
'materialsSpecification': '1.2012 -',
'publicNote': 'via ProQuest, the last 12 months are not available due to an embargo',
'relationshipId': 'f5d0068e-6272-458e-8a81-b85e7b9a14aa'
},
{
'uri': 'https://www.emeraldinsight.com/loi/jepp',
'materialsSpecification': '1.2012 -',
'publicNote': 'via Emerald',
'relationshipId': 'f5d0068e-6272-458e-8a81-b85e7b9a14aa'
},
{
'uri': 'https://www.emeraldinsight.com/journal/jepp',
'materialsSpecification': '1.2012 - 5.2016',
'publicNote': 'via Emerald, national license',
'relationshipId': 'f5d0068e-6272-458e-8a81-b85e7b9a14aa'
}
],
'callNumber': 'K1 .M44',
'administrativeNotes': [
'cataloging note'
],
'notes': [],
'holdingsStatements': [
{
'statement': '1.2012 -'
}
],
'holdingsStatementsForIndexes': [],
'holdingsStatementsForSupplements': [],
'statisticalCodeIds': [],
'metadata': {
'createdDate': '2024-04-27T13:50:16.060+00:00',
'updatedDate': '2024-04-28T12:12:07.062+00:00',
'updatedByUserId': '7e70e5c1-20d1-56aa-8cd7-1d92d9fa83f3'
}
}
};
1 change: 1 addition & 0 deletions test/fixtures/index.js
Expand Up @@ -6,3 +6,4 @@ export { subInstances } from './subInstances';
export { relationshipTypes } from './relationshipTypes';
export { childInstances } from './childInstances';
export { items } from './callNumbers';
export { holdingsById } from './holdingsById';