Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Also was added sanitization on the server side by using the `Django-Bleach` libr

### Bugfix
* [OSDEV-1806](https://opensupplyhub.atlassian.net/browse/OSDEV-1806) - Refactored the Parent Company field validation. The field is now validated as a regular character field.
* [OSDEV-1787](https://opensupplyhub.atlassian.net/browse/OSDEV-1787) - The tooltip messages for the Claim button have been removed for all statuses of moderation events on the `Contribution Record` page and changed according to the design on `Thanks for adding data for this production location` pop-up.
* [OSDEV-1787](https://opensupplyhub.atlassian.net/browse/OSDEV-1787) - The tooltip messages for the Claim button have been removed for all statuses of moderation events on the `Contribution Record` page and changed according to the design on `Thanks for adding data for this production location` pop-up. Changed tooltip text for pending badge if existing production location has pending claim status or has been claimed already.
* [OSDEV-1789](https://opensupplyhub.atlassian.net/browse/OSDEV-1789) - Fixed an issue where the scroll position was not resetting to the top when navigating through SLC workflow pages.
* [OSDEV-1795](https://opensupplyhub.atlassian.net/browse/OSDEV-1795) - Resolved database connection issue after PostgreSQL 16.3 upgrade by upgrading pg8000 module version.
* [OSDEV-1803](https://opensupplyhub.atlassian.net/browse/OSDEV-1803) - Updated text from `Facility Type` to `Location Type` and `Facility Name` to `Location Name` on the SLC `Thank You for Your Submission` page.
Expand Down
218 changes: 194 additions & 24 deletions src/react/src/__tests__/components/ProductionLocationDialog.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, fireEvent } from '@testing-library/react';
import { BrowserRouter as Router, useHistory } from 'react-router-dom';
import ProductionLocationDialog from '../../components/Contribute/ProductionLocationDialog';
import ProductionLocationDialogCloseButton from '../../components/Contribute/ProductionLocationDialogCloseButton';
import {
MODERATION_STATUSES_ENUM,
PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM,
} from '../../util/constants';


jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: jest.fn(),
}));

jest.mock("../../components/Contribute/DialogTooltip", () => {
// eslint-disable-next-line no-shadow, global-require
const React = require('react');
return function MockDialogTooltip({ text, childComponent }) {
const [open, setOpen] = React.useState(false);

const handleMouseOver = () => {
setOpen(true);
};

const handleMouseOut = () => {
setOpen(false);
};

return (
<div
onMouseOver={handleMouseOver}
onFocus={handleMouseOver}
onMouseOut={handleMouseOut}
onBlur={handleMouseOut}
>
{childComponent}
{open && <div>{text}</div>}
</div>
);
};
});

const mockHistoryPush = jest.fn();

describe('ProductionLocationDialog', () => {
Expand Down Expand Up @@ -66,7 +98,7 @@ describe('ProductionLocationDialog', () => {
});

test('renders dialog content', () => {
render(
const { getAllByText, getByText } = render(
<Router>
<ProductionLocationDialog
classes={{}}
Expand All @@ -77,34 +109,34 @@ describe('ProductionLocationDialog', () => {
</Router>
);

expect(screen.getByText(/Thanks for adding data for this production location!/i)).toBeInTheDocument();
expect(getByText(/Thanks for adding data for this production location!/i)).toBeInTheDocument();

expect(screen.getAllByText(/Location name/i)).toHaveLength(2);
expect(screen.getByText(/Production Location Name/i)).toBeInTheDocument();
expect(getAllByText(/Location name/i)).toHaveLength(2);
expect(getByText(/Production Location Name/i)).toBeInTheDocument();

expect(screen.getByText(/Address/i)).toBeInTheDocument();
expect(screen.getByText(/1234 Production Location St, City, State, 12345/i)).toBeInTheDocument();
expect(getByText(/Address/i)).toBeInTheDocument();
expect(getByText(/1234 Production Location St, City, State, 12345/i)).toBeInTheDocument();

expect(screen.getByText(/OS ID/i)).toBeInTheDocument();
expect(screen.getByText(/US2021250D1DTN7/i)).toBeInTheDocument();
expect(getByText(/OS ID/i)).toBeInTheDocument();
expect(getByText(/US2021250D1DTN7/i)).toBeInTheDocument();

expect(screen.getByText(/Pending/i)).toBeInTheDocument();
expect(screen.getByText(/Location Type/i)).toBeInTheDocument();
expect(getByText(/Pending/i)).toBeInTheDocument();
expect(getByText(/Location Type/i)).toBeInTheDocument();

expect(screen.getByText(/Number of workers/i)).toBeInTheDocument();
expect(screen.getByText(/35 - 60/i)).toBeInTheDocument();
expect(getByText(/Number of workers/i)).toBeInTheDocument();
expect(getByText(/35 - 60/i)).toBeInTheDocument();

expect(screen.getByText(/Processing Type/i)).toBeInTheDocument();
expect(screen.getByText(/Assembly, Printing/i)).toBeInTheDocument();
expect(getByText(/Processing Type/i)).toBeInTheDocument();
expect(getByText(/Assembly, Printing/i)).toBeInTheDocument();

expect(screen.getByText(/Parent Company/i)).toBeInTheDocument();
expect(screen.getByText(/ParentCompany1, ParentCompany2/i)).toBeInTheDocument();
expect(getByText(/Parent Company/i)).toBeInTheDocument();
expect(getByText(/ParentCompany1, ParentCompany2/i)).toBeInTheDocument();

expect(screen.getByText(/Country/i)).toBeInTheDocument();
expect(screen.getByText(/BD/i)).toBeInTheDocument();
expect(getByText(/Country/i)).toBeInTheDocument();
expect(getByText(/BD/i)).toBeInTheDocument();

expect(screen.getByText(/Product Type/i)).toBeInTheDocument();
expect(screen.getByText(/Shirts, Pants/i)).toBeInTheDocument();
expect(getByText(/Product Type/i)).toBeInTheDocument();
expect(getByText(/Shirts, Pants/i)).toBeInTheDocument();
});

test.each([
Expand Down Expand Up @@ -191,7 +223,7 @@ describe('ProductionLocationDialog', () => {
});

test('redirect to the main page when clicking close button', () => {
render(
const { getByText, getByRole } = render(
<Router>
<ProductionLocationDialog
classes={{}}
Expand All @@ -207,11 +239,149 @@ describe('ProductionLocationDialog', () => {
</Router>
);

expect(screen.getByText(/Continue to Claim/i)).toBeInTheDocument();
expect(getByText(/Continue to Claim/i)).toBeInTheDocument();

const closeButton = screen.getByRole('button', { name: /close/i });
const closeButton = getByRole('button', { name: /close/i });

fireEvent.click(closeButton);
expect(mockHistoryPush).toHaveBeenCalledWith('/');
});
});

describe('ProductionLocationDialog tooltip messages for PENDING, CLAIMED and UNCLAIMED production locations', () => {
const defaultProps = {
osID: 'US2021250D1DTN7',
data: {
raw_json: {
name: 'Production Location Name',
address: '1234 Production Location St, City, State, 12345',
},
fields: {
country: "BD"
}
}
};

beforeEach(() => {
useHistory.mockReturnValue({
push: mockHistoryPush,
listen: jest.fn(() => jest.fn()),
});
});

test.each([
[PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.CLAIMED,
'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.',
'This location has already been claimed and therefore cannot be claimed again.'],
[PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.PENDING,
'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.',
'This location cannot be claimed because a pending claim already exists.']
])(
'renders claim button and pending badge tooltips when moderation event is pending and production location has status: %s',
async (claimStatus, expectedPendingTooltip, expectedClaimTooltip) => {
const { getAllByTestId, getByRole, findByText } = render(
<Router>
<ProductionLocationDialog
classes={{}}
data={defaultProps.data}
osID={defaultProps.osID}
moderationStatus={MODERATION_STATUSES_ENUM.PENDING}
claimStatus={claimStatus}
/>
</Router>
);

const tooltipIcons = getAllByTestId('tooltip-icon');

// Pending icon tooltip message
fireEvent.mouseOver(tooltipIcons[0]);

const pendingTooltipText = await findByText(expectedPendingTooltip);
expect(pendingTooltipText).toBeInTheDocument();

fireEvent.mouseOut(tooltipIcons[0]);
expect(pendingTooltipText).not.toBeInTheDocument();

// Claim button tooltip message
const claimButton = getByRole('button', { name: /Continue to Claim/i });
expect(claimButton).toHaveAttribute('tabindex', '-1');

fireEvent.mouseOver(claimButton);
const claimTooltipText = await findByText(expectedClaimTooltip);
expect(claimTooltipText).toBeInTheDocument();

fireEvent.mouseOut(claimButton);
expect(claimTooltipText).not.toBeInTheDocument();
}
);

test('renders claim button and pending badge tooltips when moderation event is pending and production location is available for claim', async () => {
const { getAllByTestId, getByRole, findByText } = render(
<Router>
<ProductionLocationDialog
classes={{}}
data={defaultProps.data}
osID={defaultProps.osID}
moderationStatus={MODERATION_STATUSES_ENUM.PENDING}
claimStatus={PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.UNCLAIMED}
/>
</Router>
);

// Pending icon tooltip message
const tooltipIcons = getAllByTestId('tooltip-icon');

fireEvent.mouseOver(tooltipIcons[0]);

const pendingTooltipText = await findByText(
'Your submission is under review. You will receive a notification once the production location is live on OS Hub. You can proceed to submit a claim while your request is pending.'
);
expect(pendingTooltipText).toBeInTheDocument();

fireEvent.mouseOut(tooltipIcons[0]);
expect(pendingTooltipText).not.toBeInTheDocument();

// Claim button
const claimButton = getByRole('button', { name: /Continue to Claim/i });
expect(claimButton).toHaveAttribute('href', `/facilities/${defaultProps.osID}/claim`);
expect(claimButton).not.toBeDisabled();
});

test('renders claim button and pending badge tooltips when moderation event is pending and production location has\'t been created yet', async () => {
const { getAllByTestId, getByRole, findByText } = render(
<Router>
<ProductionLocationDialog
classes={{}}
data={defaultProps.data}
moderationStatus={MODERATION_STATUSES_ENUM.PENDING}
/>
</Router>
);

// Pending icon tooltip message
const tooltipIcons = getAllByTestId('tooltip-icon');

fireEvent.mouseOver(tooltipIcons[0]);

const pendingTooltipText = await findByText(
'Your submission is being reviewed. You will receive an email with your OS ID once the review is complete.'
);
expect(pendingTooltipText).toBeInTheDocument();

fireEvent.mouseOut(tooltipIcons[0]);
expect(pendingTooltipText).not.toBeInTheDocument();

// Claim button tooltip message
const claimButton = getByRole('button', { name: /Continue to Claim/i });
expect(claimButton).toHaveAttribute('tabindex', '-1');

fireEvent.mouseOver(claimButton);
const claimTooltipText = await findByText(
'You will be able to claim this location once the review is complete.'
);
expect(claimTooltipText).toBeInTheDocument();

fireEvent.mouseOut(claimButton);
expect(claimTooltipText).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ jest.mock('@material-ui/core/Tooltip', () => ({ children, title, open, onOpen, o
onMouseOver={onOpen}
onFocus={onOpen}
onMouseOut={onClose}
onBlur={onClose}
onBlur={onClose}
>
{children}
{open && <div data-testid="tooltip">{title}</div>}
</div>
));


describe('RejectModerationEventDialog component', () => {
const defaultProps = {
updateModerationEvent: mockUpdateModerationEvent,
Expand All @@ -66,7 +66,7 @@ describe('RejectModerationEventDialog component', () => {
test('calls closeDialog when "Cancel" button is clicked', () => {
const { getByRole } = renderWithProviders(<RejectModerationEventDialog {...defaultProps} />);
const cancelButton = getByRole('button', {name: /Cancel/i});

fireEvent.click(cancelButton);
expect(mockCloseDialog).toHaveBeenCalledTimes(1);
});
Expand All @@ -76,10 +76,10 @@ describe('RejectModerationEventDialog component', () => {
<RejectModerationEventDialog {...defaultProps} />
);
const rejectButton = getByRole('button', {name: /Reject/i});

expect(rejectButton).toBeDisabled();
});

test('reject button is enabled when editor text is at least 30 characters and calls updateModerationEvent and closeDialog on click', async () => {
const { getByRole, getByTestId } = renderWithProviders(
<RejectModerationEventDialog {...defaultProps} />
Expand All @@ -94,9 +94,9 @@ describe('RejectModerationEventDialog component', () => {
fireEvent.change(fakeEditor, { target: { value: validText } });

expect(rejectButton).toBeEnabled();

fireEvent.click(rejectButton);

expect(mockUpdateModerationEvent).toHaveBeenCalledTimes(1);
expect(mockUpdateModerationEvent).toHaveBeenCalledWith(
MODERATION_STATUSES_ENUM.REJECTED,
Expand Down Expand Up @@ -137,7 +137,7 @@ describe('RejectModerationEventDialog component', () => {
fireEvent.change(fakeEditor, { target: { value: validText } });

expect(rejectButton).toBeEnabled();

fireEvent.mouseOver(rejectButton);
expect(queryByText('Please provide a message with at least 30 characters.')).not.toBeInTheDocument();
});
Expand Down
19 changes: 17 additions & 2 deletions src/react/src/components/Contribute/ProductionLocationDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ import { makeProductionLocationDialogStyles } from '../../util/styles';
import { getIsMobile, makeClaimFacilityLink } from '../../util/util';

const infoIcon = classes => (
<InfoOutlinedIcon className={classes.osIdStatusBadgeIcon} />
<InfoOutlinedIcon
data-testid="tooltip-icon"
className={classes.osIdStatusBadgeIcon}
/>
);

const claimButton = ({ classes, osID = '', isDisabled = true }) => (
Expand Down Expand Up @@ -72,9 +75,21 @@ const getStatusBadgeClass = (classes, status) => {
};

const getPendingTooltipText = claimStatus => {
if (claimStatus === PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.UNCLAIMED) {
const {
PENDING,
CLAIMED,
UNCLAIMED,
} = PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM;

if (claimStatus === PENDING || claimStatus === CLAIMED) {
return 'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.';
}

if (claimStatus === UNCLAIMED) {
return 'Your submission is under review. You will receive a notification once the production location is live on OS Hub. You can proceed to submit a claim while your request is pending.';
}

// Default tooltip text if a production location hasn't been created yet.
return 'Your submission is being reviewed. You will receive an email with your OS ID once the review is complete.';
};

Expand Down