Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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 @@ -61,7 +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
* *Describe bugfix here.*
* [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.

### What's new
* [OSDEV-1662](https://opensupplyhub.atlassian.net/browse/OSDEV-1662) - Added a new field, `action_perform_by`, to the moderation event. This data appears on the Contribution Record page when a moderator perform any actions like `APPROVED` or `REJECTED`.
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,25 @@ describe('ProductionLocationDetails component', () => {
historicalOsIds,
};

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

beforeEach(() => {
jest.clearAllMocks();
});

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(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 +56,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(`Current OS ID: ${osId}`)).toBeInTheDocument();
});
});
40 changes: 40 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,45 @@ 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?foo=bar');
});

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
30 changes: 22 additions & 8 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 @@ -16,6 +18,12 @@ const ProductionLocationDetails = ({
const historicalOsIdsNotEmpty =
Array.isArray(historicalOsIds) && historicalOsIds.length > 0;

const location = useLocation();
let osIdSearchParameter = '';
if (location?.pathname) {
osIdSearchParameter = getLastPathParameter(location.pathname);
}

return (
<div>
<Typography component="h3" className={classes.locationNameStyles}>
Expand All @@ -28,14 +36,20 @@ const ProductionLocationDetails = ({
{historicalOsIdsNotEmpty ? 'Current OS ID:' : 'OS ID:'} {osId}
</Typography>
{historicalOsIdsNotEmpty &&
historicalOsIds.map(historicalOsId => (
<Typography
key={historicalOsId}
className={classes.locationHistoricalOsIdStyles}
>
Previous OS ID: {historicalOsId} <PreviousOsIdTooltip />
</Typography>
))}
historicalOsIds
.filter(
historicalOsId =>
historicalOsId === osIdSearchParameter,
)
.map(historicalOsId => (
<Typography
key={historicalOsId}
className={classes.locationHistoricalOsIdStyles}
>
Previous OS ID: {historicalOsId}{' '}
<PreviousOsIdTooltip />
</Typography>
))}
<div className={classes.locationAddressContainerStyles}>
<Typography className={classes.locationAddressStyles}>
{address}
Expand Down
4 changes: 4 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,5 @@ export const parseContribData = contribData => {
: null,
};
};

export const getLastPathParameter = url => last(split(trimEnd(url, '/'), '/'));
Loading