Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
All other traffic will be redirected to the React application.

### Bugfix
* [OSDEV-1700](https://opensupplyhub.atlassian.net/browse/OSDEV-1700) - SLC: Keep only one previous OS ID in the search result if it matches the search query.
* [OSDEV-1697](https://opensupplyhub.atlassian.net/browse/OSDEV-1697) - Added a redirect to the main page upon closing the SLC modal window to prevent the creation of multiple moderation events.
* [OSDEV-1695](https://opensupplyhub.atlassian.net/browse/OSDEV-1695) - [SLC] Enabled the claim button for updated production locations when a moderation event has a pending status. Disabled claim button explicitly if production location has pending claim status.
* [OSDEV-1701](https://opensupplyhub.atlassian.net/browse/OSDEV-1701) - Refactored "Go Back" button in production location info page.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import ProductionLocationDetails from '../../components/Contribute/ProductionLocationDetails';
import renderWithProviders from '../../util/testUtils/renderWithProviders';

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

describe('ProductionLocationDetails component', () => {
const osId = 'US2021250D1DTN7';
const name = 'Production Location Name';
Expand All @@ -17,17 +23,26 @@ describe('ProductionLocationDetails component', () => {
historicalOsIds,
};

test('renders the production location details correctly', () => {
const { getByText } = renderWithProviders(<ProductionLocationDetails {...defaultProps}/>);

beforeEach(() => {
jest.clearAllMocks();
useLocation.mockReturnValue({ pathname: '' });
});

test('renders production location details correctly', () => {
useLocation.mockReturnValue({
pathname: '/contribute/production-location/search/id/US2021250D1DTN7',
});

const { getByText } = renderWithProviders(
<ProductionLocationDetails {...defaultProps} />
);

expect(getByText(name)).toBeInTheDocument();
expect(getByText(`Current OS ID: ${osId}`)).toBeInTheDocument();
expect(getByText(`Previous OS ID: ${historicalOsIds[0]}`)).toBeInTheDocument();
expect(getByText(`Previous OS ID: ${historicalOsIds[1]}`)).toBeInTheDocument();
expect(getByText(`OS ID: ${osId}`)).toBeInTheDocument();
expect(getByText(address)).toBeInTheDocument();
expect(getByText(countryName)).toBeInTheDocument();
});

test('does not render historical OS IDs if the array is empty', () => {
const props = { ...defaultProps, historicalOsIds: [] };
const { getByText, queryByText } = renderWithProviders(<ProductionLocationDetails {...props}/>);
Expand All @@ -42,13 +57,54 @@ describe('ProductionLocationDetails component', () => {

expect(getByText(`OS ID: ${osId}`)).toBeInTheDocument();
});

test('renders the tooltip for each historical OS ID', () => {
const { getAllByTestId } = renderWithProviders(<ProductionLocationDetails {...defaultProps}/>);

const tooltips = getAllByTestId('previous-os-id-tooltip');
expect(tooltips.length).toBe(defaultProps.historicalOsIds.length);

test('renders previous OS IDs that match the search parameter', () => {
useLocation.mockReturnValue({
pathname: '/contribute/production-location/search/id/US2020053ZH1RY5',
});

const { getByText } = renderWithProviders(
<ProductionLocationDetails {...defaultProps} />
);

expect(getByText(`Current OS ID: ${osId}`)).toBeInTheDocument();
expect(getByText('Previous OS ID: US2020053ZH1RY5')).toBeInTheDocument();
});
});

test('does not render previous OS IDs if they do not match the search parameter', () => {
useLocation.mockReturnValue({
pathname: '/contribute/production-location/search/id/UNKNOWN_OS_ID',
});

const { queryByText } = renderWithProviders(
<ProductionLocationDetails {...defaultProps} />
);

expect(queryByText(`Previous OS ID: ${osId}`)).not.toBeInTheDocument();
});

test('renders only "OS ID:" if there are no historical OS IDs', () => {
useLocation.mockReturnValue({
pathname: '/contribute/production-location/search/id/US2021250D1DTN7',
});

const { getByText } = renderWithProviders(
<ProductionLocationDetails
{...defaultProps}
historicalOsIds={[]}
/>
);

expect(getByText(`OS ID: ${osId}`)).toBeInTheDocument();
});

test('handles missing location pathname gracefully', () => {
useLocation.mockReturnValue({});

const { getByText } = renderWithProviders(
<ProductionLocationDetails {...defaultProps} />
);

expect(getByText(`OS ID: ${osId}`)).toBeInTheDocument();
});
});
41 changes: 41 additions & 0 deletions src/react/src/__tests__/utils.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const {
createUserDropdownLinks,
createUploadFormErrorMessages,
updateStateFromData,
getLastPathParameter,
generateRangeField,
} = require('../util/util');

Expand Down Expand Up @@ -1874,6 +1875,46 @@ it('should not call setter when dataKey is null', () => {
expect(mockSetter).not.toHaveBeenCalled();
});

it('extracts the ID from a valid URL without a trailing slash', () => {
const url = '/contribute/production-location/search/id/BD202034606B9SA';
expect(getLastPathParameter(url)).toBe('BD202034606B9SA');
});

it('extracts the ID from a valid URL with a trailing slash', () => {
const url = '/contribute/production-location/search/id/BD202034606B9SA/';
expect(getLastPathParameter(url)).toBe('BD202034606B9SA');
});

it('returns id when the URL ends at "id/" with no ID', () => {
const url = '/contribute/production-location/search/id/';
expect(getLastPathParameter(url)).toBe('id');
});

it('returns the correct ID when the URL contains query parameters', () => {
const url = '/contribute/production-location/search/id/BD202034606B9SA?foo=bar';
expect(getLastPathParameter(url)).toBe('BD202034606B9SA');
});

it('returns the correct ID when the URL has multiple segments after "id/"', () => {
const url = '/contribute/production-location/search/id/BD202034606B9SA/extra';
expect(getLastPathParameter(url)).toBe('extra');
});

it('returns the whole string if no slashes exist', () => {
const url = 'BD202034606B9SA';
expect(getLastPathParameter(url)).toBe('BD202034606B9SA');
});

it('returns empty string for an empty string', () => {
const url = '';
expect(getLastPathParameter(url)).toBe('');
});

it('returns empty string for a URL that only contains slashes', () => {
const url = '///';
expect(getLastPathParameter(url)).toBe('');
});

it('should return { min: value, max: value } when value is a number', () => {
expect(generateRangeField(10)).toEqual({ min: 10, max: 10 });
expect(generateRangeField(0)).toEqual({ min: 0, max: 0 });
Expand Down
26 changes: 14 additions & 12 deletions src/react/src/components/Contribute/ProductionLocationDetails.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import { string, arrayOf, object } from 'prop-types';
import { Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import PreviousOsIdTooltip from './PreviousOsIdTooltip';
import { makeProductionLocationDetailsStyles } from '../../util/styles';
import { getLastPathParameter } from '../../util/util';

const ProductionLocationDetails = ({
osId,
Expand All @@ -13,8 +15,12 @@ const ProductionLocationDetails = ({
historicalOsIds,
classes,
}) => {
const historicalOsIdsNotEmpty =
Array.isArray(historicalOsIds) && historicalOsIds.length > 0;
const { pathname = '' } = useLocation();
const osIdSearchParameter = pathname ? getLastPathParameter(pathname) : '';

const previousOsId = historicalOsIds.find(
historicalOsId => historicalOsId === osIdSearchParameter,
);

return (
<div>
Expand All @@ -25,17 +31,13 @@ const ProductionLocationDetails = ({
component="h6"
className={classes.locationCurrentOsIdStyles}
>
{historicalOsIdsNotEmpty ? 'Current OS ID:' : 'OS ID:'} {osId}
{previousOsId ? 'Current OS ID:' : 'OS ID:'} {osId}
</Typography>
{historicalOsIdsNotEmpty &&
historicalOsIds.map(historicalOsId => (
<Typography
key={historicalOsId}
className={classes.locationHistoricalOsIdStyles}
>
Previous OS ID: {historicalOsId} <PreviousOsIdTooltip />
</Typography>
))}
{previousOsId && (
<Typography className={classes.locationHistoricalOsIdStyles}>
Previous OS ID: {previousOsId} <PreviousOsIdTooltip />
</Typography>
)}
<div className={classes.locationAddressContainerStyles}>
<Typography className={classes.locationAddressStyles}>
{address}
Expand Down
3 changes: 3 additions & 0 deletions src/react/src/util/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,9 @@ export const makeProductionLocationDetailsStyles = theme => ({
marginTop: '8px',
}),
locationHistoricalOsIdStyles: Object.freeze({
display: 'flex',
alignItems: 'center',
gap: '5px',
fontSize: '14px',
lineHeight: '20px',
fontWeight: theme.typography.fontWeightBold,
Expand Down
8 changes: 8 additions & 0 deletions src/react/src/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import isArray from 'lodash/isArray';
import isObject from 'lodash/isObject';
import flatten from 'lodash/flatten';
import identity from 'lodash/identity';
import split from 'lodash/split';
import last from 'lodash/last';
import some from 'lodash/some';
import size from 'lodash/size';
import negate from 'lodash/negate';
Expand Down Expand Up @@ -1484,3 +1486,9 @@ export const parseContribData = contribData => {
: null,
};
};

export const getLastPathParameter = url => {
if (typeof url !== 'string') return '';
const cleanUrl = url.split('?')[0];
return last(split(trimEnd(cleanUrl, '/'), '/')) || '';
};