From cc80015e844e7a512fdaf348ad92cd9290d72ac2 Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Thu, 4 Jan 2024 18:04:29 +0400 Subject: [PATCH 1/5] UIREC-303 UIREC-304 Implementation of the claim send and claim delay actions --- CHANGELOG.md | 2 + .../AddPieceModal/AddPieceModal.js | 62 ++++++++++- .../ModalActionButtons/ModalActionButtons.js | 14 ++- .../ModalActionButtons/constants.js | 7 +- .../DelayClaimModal/DelayClaimModal.js | 82 ++++++++++++++ src/TitleDetails/DelayClaimModal/index.js | 1 + .../SendClaimModal/SendClaimModal.js | 102 ++++++++++++++++++ src/TitleDetails/SendClaimModal/index.js | 1 + .../FieldClaimingDate/FieldClaimingDate.js | 45 ++++++++ .../components/FieldClaimingDate/index.js | 1 + .../components/FieldClaimingDate/utils.js | 18 ++++ src/common/components/index.js | 1 + .../utils/getClaimingIntervalFromDate.js | 7 ++ src/common/utils/index.js | 1 + translations/ui-receiving/en.json | 9 ++ 15 files changed, 345 insertions(+), 8 deletions(-) create mode 100644 src/TitleDetails/DelayClaimModal/DelayClaimModal.js create mode 100644 src/TitleDetails/DelayClaimModal/index.js create mode 100644 src/TitleDetails/SendClaimModal/SendClaimModal.js create mode 100644 src/TitleDetails/SendClaimModal/index.js create mode 100644 src/common/components/FieldClaimingDate/FieldClaimingDate.js create mode 100644 src/common/components/FieldClaimingDate/index.js create mode 100644 src/common/components/FieldClaimingDate/utils.js create mode 100644 src/common/utils/getClaimingIntervalFromDate.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 552b3d15..b853df64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ * View piece status change log. Refs UIREC-305. * Add CSV export options for new piece statuses. Refs UIREC-306. * Add the "Acquisition units" protected field to the receiving title form. Refs UIREC-295. +* Delay claim action for piece record. Refs UIREC-303. +* Send claim action for piece record. Refs UIREC-304. ## [4.0.0](https://github.com/folio-org/ui-receiving/tree/v4.0.0) (2023-10-12) [Full Changelog](https://github.com/folio-org/ui-receiving/compare/v3.0.0...v4.0.0) diff --git a/src/TitleDetails/AddPieceModal/AddPieceModal.js b/src/TitleDetails/AddPieceModal/AddPieceModal.js index 07ab56a0..5d3ce792 100644 --- a/src/TitleDetails/AddPieceModal/AddPieceModal.js +++ b/src/TitleDetails/AddPieceModal/AddPieceModal.js @@ -49,12 +49,15 @@ import { LineLocationsView, } from '../../common/components'; import { HOLDINGS_API } from '../../common/constants'; +import { getClaimingIntervalFromDate } from '../../common/utils'; import { PIECE_MODAL_ACCORDION, PIECE_MODAL_ACCORDION_LABELS, } from '../constants'; +import { DelayClaimModal } from '../DelayClaimModal'; import { DeletePieceModal } from '../DeletePieceModal'; import { DeleteHoldingsModal } from '../DeleteHoldingsModal'; +import { SendClaimModal } from '../SendClaimModal'; import { ModalActionButtons } from './ModalActionButtons'; import { ReceivingStatusChangeLog } from './ReceivingStatusChangeLog'; @@ -63,7 +66,7 @@ const AddPieceModal = ({ createInventoryValues, deletePiece, canDeletePiece, - form: { mutators, change, getState }, + form, initialValues, handleSubmit, hasValidationErrors, @@ -77,10 +80,18 @@ const AddPieceModal = ({ poLine, getHoldingsItemsAndPieces, }) => { + const { + batch, + change, + getState, + mutators, + } = form; const { enumeration, + externalNote, format, id, + internalNote, itemId, isCreateAnother, metadata, @@ -90,8 +101,11 @@ const AddPieceModal = ({ const isLocationRequired = includes(createInventoryValues[format], INVENTORY_RECORDS_TYPE.instanceAndHolding); const isNotReceived = receivingStatus !== PIECE_STATUS.received; const labelId = id ? 'ui-receiving.piece.addPieceModal.editTitle' : 'ui-receiving.piece.addPieceModal.title'; + const [isDeleteConfirmation, toggleDeleteConfirmation] = useModalToggle(); const [isDeleteHoldingsConfirmation, toggleDeleteHoldingsConfirmation] = useModalToggle(); + const [isClaimDelayModalOpen, toggleClaimDelayModal] = useModalToggle(); + const [isClaimSendModalOpen, toggleClaimSendModal] = useModalToggle(); const stripes = useStripes(); const ky = useOkapiKy(); @@ -169,6 +183,19 @@ const AddPieceModal = ({ onSave(); }, [change, onSave]); + const onClaimDelay = useCallback(({ claimingDate }) => { + change('claimingInterval', getClaimingIntervalFromDate(claimingDate)); + onStatusChange(PIECE_STATUS.claimDelayed); + }, [change, onStatusChange]); + + const onClaimSend = useCallback(({ claimingDate, ...rest }) => { + batch(() => { + change('claimingInterval', getClaimingIntervalFromDate(claimingDate)); + Object.entries(rest).forEach(([field, value]) => change(field, value)); + }); + onStatusChange(PIECE_STATUS.claimSent); + }, [batch, change, onStatusChange]); + const start = ( + ); + const end = ( + <> + + + ); + + const footer = ( + + ); + + return ( + +
+ + + } /> + + +
+
+ ); +}; + +DelayClaimModal.propTypes = { + handleSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + open: PropTypes.bool, +}; + +export default stripesFinalForm({ + navigationCheck: true, + subscription: { values: true }, +})(DelayClaimModal); diff --git a/src/TitleDetails/DelayClaimModal/index.js b/src/TitleDetails/DelayClaimModal/index.js new file mode 100644 index 00000000..974c50e9 --- /dev/null +++ b/src/TitleDetails/DelayClaimModal/index.js @@ -0,0 +1 @@ +export { default as DelayClaimModal } from './DelayClaimModal'; diff --git a/src/TitleDetails/SendClaimModal/SendClaimModal.js b/src/TitleDetails/SendClaimModal/SendClaimModal.js new file mode 100644 index 00000000..9c6f040a --- /dev/null +++ b/src/TitleDetails/SendClaimModal/SendClaimModal.js @@ -0,0 +1,102 @@ +import PropTypes from 'prop-types'; +import { Field } from 'react-final-form'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; + +import { + Button, + Col, + Modal, + Row, + TextArea, +} from '@folio/stripes/components'; +import stripesFinalForm from '@folio/stripes/final-form'; +import { ModalFooter } from '@folio/stripes-acq-components'; + +import { FieldClaimingDate } from '../../common/components'; + +const SendClaimModal = ({ + handleSubmit, + onCancel, + open, +}) => { + const intl = useIntl(); + const modalLabel = intl.formatMessage({ id: 'ui-receiving.modal.sendClaim.heading' }); + + const start = ( + + ); + const end = ( + <> + + + ); + + const footer = ( + + ); + + return ( + +
+ + + } /> + + + + + + } + name="internalNote" + /> + + + } + name="externalNote" + /> + + +
+
+ ); +}; + +SendClaimModal.propTypes = { + handleSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + open: PropTypes.bool, +}; + +export default stripesFinalForm({ + navigationCheck: true, + subscription: { values: true }, +})(SendClaimModal); diff --git a/src/TitleDetails/SendClaimModal/index.js b/src/TitleDetails/SendClaimModal/index.js new file mode 100644 index 00000000..f44d666e --- /dev/null +++ b/src/TitleDetails/SendClaimModal/index.js @@ -0,0 +1 @@ +export { default as SendClaimModal } from './SendClaimModal'; diff --git a/src/common/components/FieldClaimingDate/FieldClaimingDate.js b/src/common/components/FieldClaimingDate/FieldClaimingDate.js new file mode 100644 index 00000000..bdedda56 --- /dev/null +++ b/src/common/components/FieldClaimingDate/FieldClaimingDate.js @@ -0,0 +1,45 @@ +import PropTypes from 'prop-types'; + +import { + FieldDatepickerFinal, + validateRequired, +} from '@folio/stripes-acq-components'; + +import { + excludePreviousDays, + validateClaimingDate, +} from './utils'; + +export const FieldClaimingDate = ({ + name, + required, + ...props +}) => { + const validate = (value) => { + return ( + (required && validateRequired(value)) + || validateClaimingDate(value) + ); + }; + + return ( + + ); +}; + +FieldClaimingDate.propTypes = { + name: PropTypes.string, + required: PropTypes.bool, +}; + +FieldClaimingDate.defaultProps = { + name: 'claimingDate', + required: true, +}; diff --git a/src/common/components/FieldClaimingDate/index.js b/src/common/components/FieldClaimingDate/index.js new file mode 100644 index 00000000..b3918dee --- /dev/null +++ b/src/common/components/FieldClaimingDate/index.js @@ -0,0 +1 @@ +export { FieldClaimingDate } from './FieldClaimingDate'; diff --git a/src/common/components/FieldClaimingDate/utils.js b/src/common/components/FieldClaimingDate/utils.js new file mode 100644 index 00000000..51a2db5d --- /dev/null +++ b/src/common/components/FieldClaimingDate/utils.js @@ -0,0 +1,18 @@ +import moment from 'moment'; +import { FormattedMessage } from 'react-intl'; + +const isSameOrBeforeDay = (day) => { + const today = moment().startOf('day'); + + return day.isSameOrBefore(today, 'day'); +}; + +export const validateClaimingDate = (value) => { + return isSameOrBeforeDay(moment(value)) + ? + : undefined; +}; + +export const excludePreviousDays = (day) => { + return isSameOrBeforeDay(day); +}; diff --git a/src/common/components/index.js b/src/common/components/index.js index af628f9a..71df10b5 100644 --- a/src/common/components/index.js +++ b/src/common/components/index.js @@ -1,2 +1,3 @@ export * from './CreateItemField'; +export * from './FieldClaimingDate'; export * from './LineLocationsView'; diff --git a/src/common/utils/getClaimingIntervalFromDate.js b/src/common/utils/getClaimingIntervalFromDate.js new file mode 100644 index 00000000..5eb9407c --- /dev/null +++ b/src/common/utils/getClaimingIntervalFromDate.js @@ -0,0 +1,7 @@ +import moment from 'moment'; + +export const getClaimingIntervalFromDate = (date) => { + const currentDay = moment().startOf('day'); + + return moment(date).diff(currentDay, 'days'); +}; diff --git a/src/common/utils/index.js b/src/common/utils/index.js index 87d55925..f73618d9 100644 --- a/src/common/utils/index.js +++ b/src/common/utils/index.js @@ -1,3 +1,4 @@ +export * from './getClaimingIntervalFromDate'; export * from './getDehydratedPiece'; export * from './getItemById'; export * from './getReceivingPieceItemStatus'; diff --git a/translations/ui-receiving/en.json b/translations/ui-receiving/en.json index bd25eb9b..1b074f34 100644 --- a/translations/ui-receiving/en.json +++ b/translations/ui-receiving/en.json @@ -192,6 +192,7 @@ "piece.confirmReceiving.message": "The order linked to this Title is closed. Are you sure you want to receive this piece(s)?", "piece.connectedItem": "Connected", "piece.createItem": "Create item", + "piece.externalNote": "External note", "piece.format": "Piece format", "piece.itemStatus.Available": "Available", "piece.itemStatus.In process": "In process", @@ -201,6 +202,7 @@ "piece.itemStatus.Undefined": "Undefined", "piece.itemStatus": "Item status", "piece.itemStatus.info": "When receiving pieces that have connected items. A connected item with the status of \"Order closed\" or \"On order\" will be updated to a status of \"In process\". Items in other statuses will not have their status changed.", + "piece.internalNote": "Internal note", "piece.lineLocations": "Order line locations", "piece.location": "Select location", "piece.locationLookup": "Assign a different location", @@ -230,9 +232,16 @@ "requests.message.itemId": "Item ({itemId})", "requests.footer.close": "Close", + "modal.delayClaim.heading": "Delay piece", + "modal.delayClaim.field.delayTo": "Delay to", + "modal.sendClaim.heading": "Send claim", + "modal.sendClaim.field.claimExpiryDate": "Claim expiry date", + "shortcut.receive": "Receive pieces/Quick receive", "shortcut.piece.saveAndCreateAnother": "Save a piece and create another", + "validation.dateAfter": "Selected date must be later than the current date", + "permission.view": "Receiving: View", "permission.edit": "Receiving: View, edit", "permission.create": "Receiving: View, edit, create", From 1b02c3a081b74f390a92d04d0c32e26d900a90d8 Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Thu, 4 Jan 2024 18:21:43 +0400 Subject: [PATCH 2/5] UIREC-291 Provide actions for pieces in the rest statuses --- .../ModalActionButtons/constants.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js b/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js index 7bde463d..dd6e3b34 100644 --- a/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js +++ b/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js @@ -17,15 +17,20 @@ export const PIECE_ACTION_NAMES = { delete: 'delete', }; +export const EXPECTED_PIECES_ACTIONS = [ + PIECE_ACTION_NAMES.saveAndCreate, + PIECE_ACTION_NAMES.quickReceive, + PIECE_ACTION_NAMES.sendClaim, + PIECE_ACTION_NAMES.delayClaim, + PIECE_ACTION_NAMES.unReceivable, + PIECE_ACTION_NAMES.delete, +]; + export const PIECE_ACTIONS_BY_STATUS = { - [PIECE_STATUS.expected]: [ - PIECE_ACTION_NAMES.saveAndCreate, - PIECE_ACTION_NAMES.quickReceive, - PIECE_ACTION_NAMES.sendClaim, - PIECE_ACTION_NAMES.delayClaim, - PIECE_ACTION_NAMES.unReceivable, - PIECE_ACTION_NAMES.delete, - ], + [PIECE_STATUS.expected]: EXPECTED_PIECES_ACTIONS, + [PIECE_STATUS.claimDelayed]: EXPECTED_PIECES_ACTIONS, + [PIECE_STATUS.claimSent]: EXPECTED_PIECES_ACTIONS, + [PIECE_STATUS.late]: EXPECTED_PIECES_ACTIONS, [PIECE_STATUS.received]: [ PIECE_ACTION_NAMES.saveAndCreate, PIECE_ACTION_NAMES.unReceive, From 718a9c5ba8878414803b5e0b39397a707f0146fa Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Fri, 5 Jan 2024 12:17:12 +0400 Subject: [PATCH 3/5] UIREC-303 UIREC-304 Unit tests (p.1) --- .../DelayClaimModal/DelayClaimModal.js | 18 ++--- .../DelayClaimModal/DelayClaimModal.test.js | 73 +++++++++++++++++ .../SendClaimModal/SendClaimModal.js | 16 ++-- .../SendClaimModal/SendClaimModal.test.js | 81 +++++++++++++++++++ .../FieldClaimingDate.test.js | 33 ++++++++ .../utils/getClaimingIntervalFromDate.test.js | 12 +++ 6 files changed, 214 insertions(+), 19 deletions(-) create mode 100644 src/TitleDetails/DelayClaimModal/DelayClaimModal.test.js create mode 100644 src/TitleDetails/SendClaimModal/SendClaimModal.test.js create mode 100644 src/common/components/FieldClaimingDate/FieldClaimingDate.test.js create mode 100644 src/common/utils/getClaimingIntervalFromDate.test.js diff --git a/src/TitleDetails/DelayClaimModal/DelayClaimModal.js b/src/TitleDetails/DelayClaimModal/DelayClaimModal.js index 1f3a6a26..0a7688e9 100644 --- a/src/TitleDetails/DelayClaimModal/DelayClaimModal.js +++ b/src/TitleDetails/DelayClaimModal/DelayClaimModal.js @@ -15,7 +15,7 @@ import { ModalFooter } from '@folio/stripes-acq-components'; import { FieldClaimingDate } from '../../common/components'; -export const DelayClaimModal = ({ +const DelayClaimModal = ({ onCancel, handleSubmit, open, @@ -32,15 +32,13 @@ export const DelayClaimModal = ({ ); const end = ( - <> - - + ); const footer = ( diff --git a/src/TitleDetails/DelayClaimModal/DelayClaimModal.test.js b/src/TitleDetails/DelayClaimModal/DelayClaimModal.test.js new file mode 100644 index 00000000..f784d351 --- /dev/null +++ b/src/TitleDetails/DelayClaimModal/DelayClaimModal.test.js @@ -0,0 +1,73 @@ +import moment from 'moment'; +import { MemoryRouter } from 'react-router-dom'; + +import user from '@folio/jest-config-stripes/testing-library/user-event'; +import { render, screen } from '@folio/jest-config-stripes/testing-library/react'; + +import DelayClaimModal from './DelayClaimModal'; + +const FORMAT = 'MM/DD/YYYY'; +const today = moment(); + +const defaultProps = { + onCancel: jest.fn(), + onSubmit: jest.fn(), + open: true, +}; + +const renderDelayClaimModal = (props = {}) => render( + , + { wrapper: MemoryRouter }, +); + +describe('DelayClaimModal', () => { + beforeEach(() => { + defaultProps.onCancel.mockClear(); + defaultProps.onSubmit.mockClear(); + }); + + it('should render delay claim modal', () => { + renderDelayClaimModal(); + + expect(screen.getByText('ui-receiving.modal.delayClaim.heading')).toBeInTheDocument(); + }); + + it('should validate "Delay to" field', async () => { + renderDelayClaimModal(); + + const saveBtn = screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' }); + + await user.click(saveBtn); + expect(screen.getByText('stripes-acq-components.validation.required')).toBeInTheDocument(); + + await user.type(screen.getByPlaceholderText(FORMAT), today.format(FORMAT)); + await user.click(saveBtn); + expect(screen.getByText('ui-receiving.validation.dateAfter')).toBeInTheDocument(); + }); + + it('should submit valid form', async () => { + renderDelayClaimModal(); + + const date = today.add(3, 'days'); + + await user.type(screen.getByPlaceholderText(FORMAT), date.format(FORMAT)); + await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' })); + + expect(defaultProps.onSubmit).toHaveBeenCalledWith( + { claimingDate: date.format('YYYY-MM-DD') }, + expect.anything(), + expect.anything(), + ); + }); + + it('should call "onCancel" when the modal dismissed', async () => { + renderDelayClaimModal(); + + await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.cancel' })); + + expect(defaultProps.onCancel).toHaveBeenCalled(); + }); +}); diff --git a/src/TitleDetails/SendClaimModal/SendClaimModal.js b/src/TitleDetails/SendClaimModal/SendClaimModal.js index 9c6f040a..0a661b04 100644 --- a/src/TitleDetails/SendClaimModal/SendClaimModal.js +++ b/src/TitleDetails/SendClaimModal/SendClaimModal.js @@ -34,15 +34,13 @@ const SendClaimModal = ({ ); const end = ( - <> - - + ); const footer = ( diff --git a/src/TitleDetails/SendClaimModal/SendClaimModal.test.js b/src/TitleDetails/SendClaimModal/SendClaimModal.test.js new file mode 100644 index 00000000..6d510184 --- /dev/null +++ b/src/TitleDetails/SendClaimModal/SendClaimModal.test.js @@ -0,0 +1,81 @@ +import moment from 'moment'; +import { MemoryRouter } from 'react-router-dom'; + +import user from '@folio/jest-config-stripes/testing-library/user-event'; +import { render, screen } from '@folio/jest-config-stripes/testing-library/react'; + +import SendClaimModal from './SendClaimModal'; + +const FORMAT = 'MM/DD/YYYY'; +const today = moment(); + +const defaultProps = { + onCancel: jest.fn(), + onSubmit: jest.fn(), + open: true, +}; + +const renderSendClaimModal = (props = {}) => render( + , + { wrapper: MemoryRouter }, +); + +describe('SendClaimModal', () => { + beforeEach(() => { + defaultProps.onCancel.mockClear(); + defaultProps.onSubmit.mockClear(); + }); + + it('should render send claim modal', () => { + renderSendClaimModal(); + + expect(screen.getByText('ui-receiving.modal.sendClaim.heading')).toBeInTheDocument(); + }); + + it('should validate "Claim expiry date" field', async () => { + renderSendClaimModal(); + + const saveBtn = screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' }); + + await user.click(saveBtn); + expect(screen.getByText('stripes-acq-components.validation.required')).toBeInTheDocument(); + + await user.type(screen.getByPlaceholderText(FORMAT), today.format(FORMAT)); + await user.click(saveBtn); + expect(screen.getByText('ui-receiving.validation.dateAfter')).toBeInTheDocument(); + }); + + it('should submit valid form', async () => { + renderSendClaimModal(); + + const date = today.add(5, 'days'); + const internalNote = 'Internal'; + const externalNote = 'External'; + + await user.type(screen.getByPlaceholderText(FORMAT), date.format(FORMAT)); + await user.type(screen.getByLabelText('ui-receiving.piece.internalNote'), internalNote); + await user.type(screen.getByLabelText('ui-receiving.piece.externalNote'), externalNote); + await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' })); + + expect(defaultProps.onSubmit).toHaveBeenCalledWith( + { + claimingDate: date.format('YYYY-MM-DD'), + internalNote, + externalNote, + }, + expect.anything(), + expect.anything(), + ); + }); + + it('should call "onCancel" when the modal dismissed', async () => { + renderSendClaimModal(); + + await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.cancel' })); + + expect(defaultProps.onCancel).toHaveBeenCalled(); + }); +}); diff --git a/src/common/components/FieldClaimingDate/FieldClaimingDate.test.js b/src/common/components/FieldClaimingDate/FieldClaimingDate.test.js new file mode 100644 index 00000000..1c4fb25e --- /dev/null +++ b/src/common/components/FieldClaimingDate/FieldClaimingDate.test.js @@ -0,0 +1,33 @@ +import { MemoryRouter } from 'react-router-dom'; + +import { render, screen } from '@folio/jest-config-stripes/testing-library/react'; +import stripesFinalForm from '@folio/stripes/final-form'; + +import { FieldClaimingDate } from './FieldClaimingDate'; + +const defaultProps = { + label: 'Label', +}; + +const FormComponent = stripesFinalForm({})(({ children }) =>
{children}
); + +const renderFieldClaimingDate = (props = {}, formProps = {}) => render( + + + , + { wrapper: MemoryRouter }, +); + +describe('FieldClaimingDate', () => { + it('should render field', () => { + renderFieldClaimingDate(); + + expect(screen.getByText(defaultProps.label)).toBeInTheDocument(); + }); +}); diff --git a/src/common/utils/getClaimingIntervalFromDate.test.js b/src/common/utils/getClaimingIntervalFromDate.test.js new file mode 100644 index 00000000..2abf7b24 --- /dev/null +++ b/src/common/utils/getClaimingIntervalFromDate.test.js @@ -0,0 +1,12 @@ +import moment from 'moment'; + +import { getClaimingIntervalFromDate } from './getClaimingIntervalFromDate'; + +describe('getClaimingIntervalFromDate', () => { + it('should return claiming interval calculated based on provided date', () => { + const today = moment().startOf('day'); + + expect(getClaimingIntervalFromDate(today)).toEqual(0); + expect(getClaimingIntervalFromDate(today.add(5, 'days'))).toEqual(5); + }); +}); From 775020310d07ccc40a093a3d3df476d7d23f96e9 Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Fri, 5 Jan 2024 13:28:44 +0400 Subject: [PATCH 4/5] UIREC-303 UIREC-304 Unit tests (p.2) --- .../AddPieceModal/AddPieceModal.test.js | 55 ++++++++++++++++--- .../ModalActionButtons/constants.js | 2 + 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/TitleDetails/AddPieceModal/AddPieceModal.test.js b/src/TitleDetails/AddPieceModal/AddPieceModal.test.js index 027cc61f..a03ca718 100644 --- a/src/TitleDetails/AddPieceModal/AddPieceModal.test.js +++ b/src/TitleDetails/AddPieceModal/AddPieceModal.test.js @@ -1,3 +1,4 @@ +import moment from 'moment'; import { MemoryRouter } from 'react-router-dom'; import user from '@folio/jest-config-stripes/testing-library/user-event'; @@ -81,6 +82,9 @@ const kyMock = { })), }; +const DATE_FORMAT = 'MM/DD/YYYY'; +const today = moment(); + const renderAddPieceModal = (props = {}) => render( { const format = PIECE_FORMAT.electronic; renderAddPieceModal({ - ...defaultProps, createInventoryValues: { [format]: INVENTORY_RECORDS_TYPE.instanceAndHolding }, initialValues: { format, @@ -144,7 +147,6 @@ describe('AddPieceModal', () => { it('should not be visible when create inventory does not include holding', () => { renderAddPieceModal({ - ...defaultProps, initialValues: { format: INVENTORY_RECORDS_TYPE.instance, }, @@ -159,7 +161,6 @@ describe('AddPieceModal', () => { const format = PIECE_FORMAT.electronic; renderAddPieceModal({ - ...defaultProps, createInventoryValues: { [format]: INVENTORY_RECORDS_TYPE.instanceAndHolding }, initialValues: { format, @@ -180,7 +181,6 @@ describe('AddPieceModal', () => { }); renderAddPieceModal({ - ...defaultProps, initialValues: { id: 'pieceId', format: PIECE_FORMAT.physical, @@ -199,7 +199,6 @@ describe('AddPieceModal', () => { kyMock.get.mockReturnValue(({ json: () => Promise.reject(new Error('404')) })); renderAddPieceModal({ - ...defaultProps, initialValues: { id: 'pieceId', format: PIECE_FORMAT.physical, @@ -219,7 +218,6 @@ describe('AddPieceModal', () => { describe('Create another piece', () => { it('should update footer button when \'Create another\' is active', async () => { renderAddPieceModal({ - ...defaultProps, initialValues: { isCreateAnother: true, receivingStatus: PIECE_STATUS.expected, @@ -236,7 +234,6 @@ describe('AddPieceModal', () => { const onChange = jest.fn(); renderAddPieceModal({ - ...defaultProps, form: { ...defaultProps.form, change: onChange, @@ -264,4 +261,48 @@ describe('AddPieceModal', () => { expect(defaultProps.onSubmit).toHaveBeenCalled(); }); + + describe('Actions', () => { + const initialValues = { + format: PIECE_FORMAT.other, + holdingId: '60c67dc5-b646-425e-bf08-a8bf2d0681fb', + }; + const date = today.add(3, 'days'); + + beforeEach(async () => { + renderAddPieceModal({ initialValues }); + + await user.click(screen.getByTestId('dropdown-trigger-button')); + }); + + it('should handle "Delay claim" action', async () => { + await user.click(screen.getByTestId('delay-claim-button')); + await user.type(screen.getByRole('textbox', { name: 'ui-receiving.modal.delayClaim.field.delayTo' }), date.format(DATE_FORMAT)); + await user.click(await findButton('stripes-acq-components.FormFooter.save')); + + expect(defaultProps.onSubmit).toHaveBeenCalledWith( + expect.objectContaining({ + claimingInterval: 3, + receivingStatus: PIECE_STATUS.claimDelayed, + }), + expect.anything(), + expect.anything(), + ); + }); + + it('should handle "Send claim" action', async () => { + await user.click(screen.getByTestId('send-claim-button')); + await user.type(screen.getByRole('textbox', { name: 'ui-receiving.modal.sendClaim.field.claimExpiryDate' }), date.format(DATE_FORMAT)); + await user.click(await findButton('stripes-acq-components.FormFooter.save')); + + expect(defaultProps.onSubmit).toHaveBeenCalledWith( + expect.objectContaining({ + claimingInterval: 3, + receivingStatus: PIECE_STATUS.claimSent, + }), + expect.anything(), + expect.anything(), + ); + }); + }); }); diff --git a/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js b/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js index dd6e3b34..2d760e01 100644 --- a/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js +++ b/src/TitleDetails/AddPieceModal/ModalActionButtons/constants.js @@ -58,6 +58,7 @@ export const PIECE_ACTIONS = ({