Skip to content

Commit

Permalink
Merge branch 'main' into auth_login
Browse files Browse the repository at this point in the history
  • Loading branch information
RioKnightleyNHS committed Oct 5, 2023
2 parents bf5287f + a9b2666 commit c501acf
Show file tree
Hide file tree
Showing 19 changed files with 378 additions and 108 deletions.

Large diffs are not rendered by default.

Binary file removed app/cypress/fixtures/test-images/test_image.jpg
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed app/cypress/fixtures/test-images/test_image_five.jpg
Binary file not shown.
Binary file not shown.
Binary file removed app/cypress/fixtures/test-images/test_image_nine.jpg
Binary file not shown.
Binary file not shown.
Binary file removed app/cypress/fixtures/test-images/test_image_six.jpg
Binary file not shown.
Binary file removed app/cypress/fixtures/test-images/test_image_ten.jpg
Binary file not shown.
Binary file not shown.
Binary file removed app/cypress/fixtures/test-images/test_image_two.jpg
Binary file not shown.
15 changes: 13 additions & 2 deletions app/src/components/blocks/documentInputForm/DocumentInputForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,23 @@ const DocumentInputForm = ({
.
</li>
)}
{formType === DOCUMENT_TYPE.LLOYD_GEORGE && (
<>
<li>
Each Lloyd George file uploaded must match the following format:
[PDFnumber]_Lloyd_George_Record_[Patient Name]_[NHS
Number]_[D.O.B]. For example: 1of2_Lloyd_George_Record_[Joe
Bloggs]_[123456789]_[25-12-2019]
</li>
<li>You can only upload PDF files</li>
</>
)}
</ul>
}
/>
<div role="region" aria-live="polite">
{documents && documents.length > 0 && (
<Table caption="Selected documents" id="selected-documents-table">
<Table caption="Chosen files" id="selected-documents-table">
<Table.Head>
<Table.Row>
<Table.Cell>Filename</Table.Cell>
Expand Down Expand Up @@ -111,7 +122,7 @@ const DocumentInputForm = ({
</Table.Body>
</Table>
)}
{hasDuplicateFiles && (
{hasDuplicateFiles && formType === DOCUMENT_TYPE.ARF && (
<WarningCallout>
<WarningCallout.Label>Possible duplicate file</WarningCallout.Label>
<p>There are two or more documents with the same name.</p>
Expand Down
197 changes: 176 additions & 21 deletions app/src/components/blocks/selectStage/SelectStage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/* eslint-disable testing-library/no-unnecessary-act */
import { render, screen, waitFor } from '@testing-library/react';
import SelectStage from './SelectStage';
import { buildPatientDetails, buildTextFile } from '../../../helpers/test/testBuilders';
import {
buildPatientDetails,
buildTextFile,
buildLgFile,
} from '../../../helpers/test/testBuilders';
import userEvent from '@testing-library/user-event';
import { DOCUMENT_UPLOAD_STATE as documentUploadStates } from '../../../types/pages/UploadDocumentsPage/types';
import { act } from 'react-dom/test-utils';
Expand All @@ -19,6 +23,9 @@ describe('<UploadDocumentsPage />', () => {
const documentOne = buildTextFile('one', 100);
const documentTwo = buildTextFile('two', 200);
const documentThree = buildTextFile('three', 100);
const lgDocumentOne = buildLgFile(1, 2);
const lgDocumentTwo = buildLgFile(2, 2);
const arfDocuments = [documentOne, documentTwo, documentThree];

const setDocumentMock = jest.fn();
setDocumentMock.mockImplementation((document) => {
Expand Down Expand Up @@ -58,16 +65,14 @@ describe('<UploadDocumentsPage />', () => {
});

act(() => {
userEvent.upload(screen.getByTestId('LG-input'), [
documentOne,
documentTwo,
documentThree,
]);
userEvent.upload(screen.getByTestId('LG-input'), [lgDocumentOne, lgDocumentTwo]);
});

expect(await screen.findAllByText(documentOne.name)).toHaveLength(2);
expect(await screen.findAllByText(documentTwo.name)).toHaveLength(2);
expect(await screen.findAllByText(documentThree.name)).toHaveLength(2);
expect(await screen.findAllByText(documentOne.name)).toHaveLength(1);
expect(await screen.findAllByText(documentTwo.name)).toHaveLength(1);
expect(await screen.findAllByText(documentThree.name)).toHaveLength(1);
expect(await screen.findAllByText(lgDocumentOne.name)).toHaveLength(1);
expect(await screen.findAllByText(lgDocumentTwo.name)).toHaveLength(1);

expect(screen.getByRole('button', { name: 'Upload' })).toBeEnabled();
});
Expand Down Expand Up @@ -101,20 +106,25 @@ describe('<UploadDocumentsPage />', () => {
},
);

it.each([['ARF'], ['LG']])(
"does not upload either forms if selected file is less than 5GB for '%s' input",
it.each([
{ name: 'ARF', documents: arfDocuments },
{ name: 'LG', documents: [buildLgFile(1, 2)] },
])(
"does not upload either forms if selected file is more than 5GB for '%s' input",
async (inputType) => {
renderSelectStage(setDocumentMock);

const documentBig = buildTextFile('four', 6 * Math.pow(1024, 3));
const documentBig =
inputType.name === 'ARF'
? buildTextFile('four', 6 * Math.pow(1024, 3))
: buildLgFile(3, 2, 6 * Math.pow(1024, 3));
inputType.documents.push(documentBig);

act(() => {
userEvent.upload(screen.getByTestId(`${inputType}-input`), [
documentOne,
documentTwo,
documentThree,
documentBig,
]);
userEvent.upload(
screen.getByTestId(`${inputType.name}-input`),
inputType.documents,
);
});

expect(screen.getByText(documentBig.name)).toBeInTheDocument();
Expand All @@ -131,8 +141,153 @@ describe('<UploadDocumentsPage />', () => {
},
);

it.each([['ARF'], ['LG']])(
"shows a duplicate file warning if two or more files match name/size for '%s' input",
it('does not upload LG form if selected file is not PDF', async () => {
renderSelectStage(setDocumentMock);
const lgFileWithBadType = new File(
['test'],
`1of2000_Lloyd_George_Record_[Joe Bloggs]_[1234567890]_[25-12-2019].pdf`,
{
type: 'text/plain',
},
);

act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), lgFileWithBadType);
});

expect(screen.getByText(lgFileWithBadType.name)).toBeInTheDocument();

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'One or more of the files do not match the required file type. Please check the file(s) and try again',
),
).toBeInTheDocument();
});

it('does not upload LG form if total number of file does not match file name', async () => {
renderSelectStage(setDocumentMock);
const lgExtraFile = buildLgFile(3, 3);

act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), lgExtraFile);
});

expect(screen.getByText(lgExtraFile.name)).toBeInTheDocument();

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'One or more of the files do not match the required filename format. Please check the file(s) and try again',
),
).toBeInTheDocument();
});

it('does not upload LG form if selected file does not match naming conventions', async () => {
renderSelectStage(setDocumentMock);
const pdfFileWithBadName = new File(['test'], `test_not_up_to_naming_conventions.pdf`, {
type: 'application/pdf',
});
act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), pdfFileWithBadName);
});

expect(screen.getByText(pdfFileWithBadName.name)).toBeInTheDocument();

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'One or more of the files do not match the required filename format. Please check the file(s) and try again',
),
).toBeInTheDocument();
});

it('does not upload LG form if selected file number is bigger than number of total files', async () => {
renderSelectStage(setDocumentMock);
const pdfFileWithBadNumber = buildLgFile(2, 1);
act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), pdfFileWithBadNumber);
});

expect(screen.getByText(pdfFileWithBadNumber.name)).toBeInTheDocument();

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'One or more of the files do not match the required filename format. Please check the file(s) and try again',
),
).toBeInTheDocument();
});

it('does not upload LG form if files do not match each other', async () => {
renderSelectStage(setDocumentMock);
const joeBloggsFile = new File(
['test'],
`1of2_Lloyd_George_Record_[Joe Bloggs]_[1234567890]_[25-12-2019].pdf`,
{
type: 'application/pdf',
},
);
const johnSmithFile = new File(
['test'],
`2of2_Lloyd_George_Record_[John Smith]_[9876543210]_[25-12-2019].pdf`,
{
type: 'application/pdf',
},
);
act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), [joeBloggsFile, johnSmithFile]);
});

expect(screen.getByText(joeBloggsFile.name)).toBeInTheDocument();
expect(screen.getByText(johnSmithFile.name)).toBeInTheDocument();

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'One or more of the files do not match the required filename format. Please check the file(s) and try again',
),
).toBeInTheDocument();
});

it('does not upload LG form if two or more files match name/size', async () => {
renderSelectStage(setDocumentMock);
const duplicateFileWarning = 'There are two or more documents with the same name.';
act(() => {
userEvent.upload(screen.getByTestId(`LG-input`), [lgDocumentTwo, lgDocumentTwo]);
});

expect(screen.getAllByText(lgDocumentTwo.name)).toHaveLength(2);

act(() => {
userEvent.click(screen.getByText('Upload'));
});

expect(
await screen.findByText(
'There are documents chosen that have the same name, a record with duplicate file names can not be uploaded because it does not match the required file format. Please check the files(s) and try again.',
),
).toBeInTheDocument();
expect(screen.queryByText(duplicateFileWarning)).not.toBeInTheDocument();
});

it.each([['ARF']])(
'shows a duplicate file warning if two or more files match name/size for ARF input only',
async (inputType) => {
const duplicateFileWarning = 'There are two or more documents with the same name.';

Expand Down Expand Up @@ -165,7 +320,7 @@ describe('<UploadDocumentsPage />', () => {
async (inputType) => {
renderSelectStage(setDocumentMock);

const selectFilesLabel = screen.getByTestId('ARF-input');
const selectFilesLabel = screen.getByTestId(`${inputType}-input`);

act(() => {
userEvent.upload(selectFilesLabel, documentOne);
Expand Down
68 changes: 59 additions & 9 deletions app/src/components/blocks/selectStage/SelectStage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ function SelectStage({ uploadDocuments, setDocuments, patientDetails }: Props) {

const mergedDocuments = [...arfDocuments, ...lgDocuments];
const hasFileInput = mergedDocuments.length;

const lgRegex =
/[0-9]+of[0-9]+_Lloyd_George_Record_\[[A-Za-z]+\s[A-Za-z]+]_\[[0-9]{10}]_\[\d\d-\d\d-\d\d\d\d].pdf/; // eslint-disable-line
const lgFilesNumber = /of[0-9]+/;
const FIVEGB = 5 * Math.pow(1024, 3);
const { handleSubmit, control, formState } = useForm();
const formConfig = (name: string) => ({
Expand All @@ -39,18 +41,63 @@ function SelectStage({ uploadDocuments, setDocuments, patientDetails }: Props) {
isFile: () => {
return !!hasFileInput || 'Please select a file';
},
isLessThan5GB: (value?: Array<UploadDocument>) => {
perFileValidation: (value?: Array<UploadDocument>) => {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if (value[i].file.size > FIVEGB) {
const currentFile = value[i].file;
if (currentFile.size > FIVEGB) {
return 'Please ensure that all files are less than 5GB in size';
}
if (name === 'lg-documents') {
if (currentFile.type !== 'application/pdf') {
return 'One or more of the files do not match the required file type. Please check the file(s) and try again';
}
const expectedNumberOfFiles = currentFile.name.match(lgFilesNumber);
const doesPassRegex = lgRegex.exec(currentFile.name);
const doFilesTotalMatch =
expectedNumberOfFiles &&
value.length === parseInt(expectedNumberOfFiles[0].slice(2));
const isFileNumberBiggerThanTotal =
expectedNumberOfFiles &&
parseInt(currentFile.name.split(lgFilesNumber)[0]) >
parseInt(expectedNumberOfFiles[0].slice(2));
const isFileNumberZero =
currentFile.name.split(lgFilesNumber)[0] === '0';
const doesFileNameMatchEachOther =
currentFile.name.split(lgFilesNumber)[1] ===
value[0].file.name.split(lgFilesNumber)[1];
if (
!doesPassRegex ||
!doFilesTotalMatch ||
isFileNumberBiggerThanTotal ||
isFileNumberZero ||
!doesFileNameMatchEachOther
) {
return 'One or more of the files do not match the required filename format. Please check the file(s) and try again';
}
}
}
}
},
hasDuplicateFile: (value?: Array<UploadDocument>) => {
if (
name === 'lg-documents' &&
value?.some((doc: UploadDocument) => {
return value?.some(
(compare: UploadDocument) =>
doc.file.name === compare.file.name &&
doc.file.size === compare.file.size &&
doc.id !== compare.id,
);
})
) {
return 'There are documents chosen that have the same name, a record with duplicate file names can not be uploaded because it does not match the required file format. Please check the files(s) and try again.';
}
},
},
},
});

const lgController = useController(formConfig('lg-documents'));
const arfController = useController(formConfig('arf-documents'));

Expand Down Expand Up @@ -87,11 +134,13 @@ function SelectStage({ uploadDocuments, setDocuments, patientDetails }: Props) {
setArfDocuments(updatedDocList);
if (arfInputRef.current) {
arfInputRef.current.files = toFileList(updatedDocList);
arfController.field.onChange(updatedDocList);
}
} else {
setLgDocuments(updatedDocList);
if (lgInputRef.current) {
lgInputRef.current.files = toFileList(updatedDocList);
lgController.field.onChange(updatedDocList);
}
}

Expand All @@ -106,11 +155,12 @@ function SelectStage({ uploadDocuments, setDocuments, patientDetails }: Props) {
noValidate
data-testid="upload-document-form"
>
<Fieldset.Legend headingLevel="h1" isPageHeading>
Upload documents
</Fieldset.Legend>
<PatientSummary patientDetails={patientDetails} />

<Fieldset>
<Fieldset.Legend headingLevel="h1" isPageHeading>
Upload documents
</Fieldset.Legend>
<PatientSummary patientDetails={patientDetails} />
<h2>Electronic health records</h2>
<DocumentInputForm
showHelp
Expand All @@ -121,8 +171,8 @@ function SelectStage({ uploadDocuments, setDocuments, patientDetails }: Props) {
inputRef={arfInputRef}
formType={DOCUMENT_TYPE.ARF}
/>
<br />
<br />
</Fieldset>
<Fieldset>
<h2>Lloyd George records</h2>
<DocumentInputForm
documents={lgDocuments}
Expand Down
Loading

0 comments on commit c501acf

Please sign in to comment.