Skip to content

Commit d5d4406

Browse files
abid-nhsJuttonSoliverbeumkes-nhsmark-start-nhs
authored
PRMP-1292: Download LG Record Screen | Add file size column (#493)
* adds fileSize to document reference * PRMP-1292 - comment out as its breaking tests * PRMP-1292 - ensure files table includes a file size information such as file size measure units * PRMP-1292 - lower case size and fix test * [PRMP-1292] Updated Document Search to include file size in response as well as update tests * PRMP-1292 fix unhandled error with invalid argument name * PRMP-1292 fix broken cypress tests * increase test coverage: missing formatFileSize test --------- Co-authored-by: Jack Sutton <[email protected]> Co-authored-by: Ollie Beumkes <[email protected]> Co-authored-by: mark start <[email protected]>
1 parent c9304b0 commit d5d4406

File tree

8 files changed

+90
-7
lines changed

8 files changed

+90
-7
lines changed

app/cypress/e2e/0-ndr-core-tests/gp_user_workflows/download_lloyd_george_workflow.cy.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ const testFiles = [
1919
created: '2024-05-07T14:52:00.827602Z',
2020
virusScannerResult: 'Clean',
2121
id: 'test-id',
22+
fileSize: 200,
2223
},
2324
{
2425
fileName: '2of2_testy_test.pdf',
2526
created: '2024-05-07T14:52:00.827602Z',
2627
virusScannerResult: 'Clean',
2728
id: 'test-id-2',
29+
fileSize: 200,
2830
},
2931
{
3032
fileName: '1of1_lone_test_file.pdf',
3133
created: '2024-01-01T14:52:00.827602Z',
3234
virusScannerResult: 'Clean',
3335
id: 'test-id-3',
36+
fileSize: 200,
3437
},
3538
];
3639

@@ -40,6 +43,7 @@ const singleTestFile = [
4043
created: '2024-01-01T14:52:00.827602Z',
4144
virusScannerResult: 'Clean',
4245
id: 'test-id-3',
46+
fileSize: 200,
4347
},
4448
];
4549

app/src/components/blocks/_lloydGeorge/lloydGeorgeSelectSearchResults/LloydGeorgeSelectSearchResults.test.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import usePatient from '../../../../helpers/hooks/usePatient';
55
import { LinkProps } from 'react-router-dom';
66
import LloydGeorgeSelectSearchResults, { Props } from './LloydGeorgeSelectSearchResults';
77
import userEvent from '@testing-library/user-event';
8-
import { routes } from '../../../../types/generic/routes';
98
import { SEARCH_AND_DOWNLOAD_STATE } from '../../../../types/pages/documentSearchResultsPage/types';
109
import { runAxeTest } from '../../../../helpers/test/axeTestHelper';
1110

@@ -57,6 +56,20 @@ describe('LloydGeorgeSelectSearchResults', () => {
5756
expect(screen.getByTestId('toggle-selection-btn')).toBeInTheDocument();
5857
});
5958

59+
it('renders the correct table headers', () => {
60+
renderComponent({ selectedDocuments: mockSelectedDocuments });
61+
62+
const headers = screen.getAllByRole('columnheader');
63+
const expectedHeaders = ['Selected', 'Filename', 'Upload date', 'File size'];
64+
65+
expectedHeaders.forEach((headerText, index) => {
66+
expect(headers[index]).toHaveTextContent(headerText);
67+
});
68+
69+
const filesTable = screen.getByTestId('available-files-table-title');
70+
expect(filesTable).toHaveTextContent(/bytes|KB|MB|GB/);
71+
});
72+
6073
it('shows error box when download selected files button is clicked but no files selected', async () => {
6174
renderComponent({ selectedDocuments: [] });
6275

app/src/components/blocks/_lloydGeorge/lloydGeorgeSelectSearchResults/LloydGeorgeSelectSearchResults.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { SEARCH_AND_DOWNLOAD_STATE } from '../../../../types/pages/documentSearc
88
import ErrorBox from '../../../layout/errorBox/ErrorBox';
99
import PatientSummary from '../../../generic/patientSummary/PatientSummary';
1010
import BackButton from '../../../generic/backButton/BackButton';
11+
import formatFileSize from '../../../../helpers/utils/formatFileSize';
1112

1213
export type Props = {
1314
searchResults: Array<SearchResult>;
@@ -108,6 +109,7 @@ const AvailableFilesTable = ({
108109
)}
109110
<Table.Cell className={'table-column-header'}>Filename</Table.Cell>
110111
<Table.Cell className={'table-column-header'}>Upload date</Table.Cell>
112+
<Table.Cell className={'table-column-header'}>File size</Table.Cell>
111113
</Table.Row>
112114
</Table.Head>
113115
<Table.Body>
@@ -147,6 +149,12 @@ const AvailableFilesTable = ({
147149
>
148150
{getFormattedDatetime(new Date(result.created))}
149151
</Table.Cell>
152+
<Table.Cell
153+
id={'available-files-row-' + index + '-file-size'}
154+
data-testid="file-size"
155+
>
156+
{formatFileSize(result.fileSize)}
157+
</Table.Cell>
150158
</Table.Row>
151159
))}
152160
</Table.Body>

app/src/helpers/test/testBuilders.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ const buildSearchResult = (searchResultOverride?: Partial<SearchResult>) => {
123123
created: moment().format(),
124124
virusScannerResult: 'Clean',
125125
ID: '1234qwer-241ewewr',
126+
fileSize: 224,
126127
...searchResultOverride,
127128
};
128129
return result;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import formatFileSize from "./formatFileSize";
2+
3+
describe('formatFileSize', () => {
4+
5+
it('returns rounded file size formats for valid inputs', () => {
6+
7+
expect(formatFileSize(0)).toBe('0 bytes');
8+
expect(formatFileSize(-0)).toBe('0 bytes');
9+
expect(formatFileSize(1)).toBe('1 bytes');
10+
expect(formatFileSize(1.5)).toBe('2 bytes');
11+
12+
expect(formatFileSize(1023)).toBe('1023 bytes');
13+
expect(formatFileSize(1024)).toBe('1 KB');
14+
expect(formatFileSize(1025)).toBe('1 KB');
15+
16+
expect(formatFileSize(1535)).toBe('1 KB');
17+
expect(formatFileSize(1536)).toBe('2 KB');
18+
expect(formatFileSize(2048)).toBe('2 KB');
19+
20+
expect(formatFileSize(Math.pow(2, 20) - 1)).toBe('1024 KB');
21+
expect(formatFileSize(Math.pow(2, 20))).toBe('1 MB');
22+
expect(formatFileSize(Math.pow(2, 20) + 1)).toBe('1 MB');
23+
24+
expect(formatFileSize(Math.pow(2, 30) - 1)).toBe('1024 MB');
25+
expect(formatFileSize(Math.pow(2, 30))).toBe('1 GB');
26+
expect(formatFileSize(Math.pow(2, 30) + 1)).toBe('1 GB');
27+
28+
});
29+
30+
it('throws "Invalid file size" exception for invalid inputs', () => {
31+
32+
expect(() => formatFileSize(Number.MIN_SAFE_INTEGER)).toThrow('Invalid file size');
33+
expect(() => formatFileSize(-1)).toThrow('Invalid file size');
34+
expect(() => formatFileSize(NaN)).toThrow('Invalid file size');
35+
expect(() => formatFileSize(undefined as unknown as number)).toThrow('Invalid file size');
36+
expect(() => formatFileSize(Math.pow(2, 40))).toThrow('Invalid file size'); // 1TB
37+
expect(() => formatFileSize(Number.MAX_SAFE_INTEGER)).toThrow('Invalid file size');
38+
39+
});
40+
41+
});

app/src/types/generic/searchResult.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export type SearchResult = {
33
created: string;
44
virusScannerResult: string;
55
ID: string;
6+
fileSize: number;
67
};

lambdas/services/document_reference_search_service.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,21 @@ def get_document_references(self, nhs_number: str):
4949
423, LambdaError.UploadInProgressError
5050
)
5151
results.extend(
52-
document.model_dump(
53-
include={"file_name", "created", "virus_scanner_result", "id"},
54-
by_alias=True,
55-
)
52+
{
53+
**document.model_dump(
54+
include={
55+
"file_name",
56+
"created",
57+
"virus_scanner_result",
58+
"id",
59+
},
60+
by_alias=True,
61+
),
62+
"fileSize": self.s3_service.get_file_size(
63+
s3_bucket_name=document.get_file_bucket(),
64+
object_key=document.get_file_key(),
65+
),
66+
}
5667
for document in documents
5768
)
5869
return results

lambdas/tests/unit/services/test_document_reference_search_service.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@
1212
DocumentReference.model_validate(MOCK_SEARCH_RESPONSE["Items"][0])
1313
]
1414

15+
MOCK_FILE_SIZE = 24000
16+
1517
EXPECTED_RESPONSE = {
1618
"created": "2024-01-01T12:00:00.000Z",
1719
"fileName": "document.csv",
1820
"virusScannerResult": "Clean",
1921
"ID": "3d8683b9-1665-40d2-8499-6e8302d507ff",
22+
"fileSize": MOCK_FILE_SIZE,
2023
}
2124

2225

2326
@pytest.fixture
2427
def patched_service(mocker, set_env):
2528
service = DocumentReferenceSearchService()
26-
mocker.patch.object(service, "s3_service")
29+
mock_s3_service = mocker.patch.object(service, "s3_service")
30+
mocker.patch.object(mock_s3_service, "get_file_size", return_value=MOCK_FILE_SIZE)
2731
mocker.patch.object(service, "dynamo_service")
2832
mocker.patch.object(service, "fetch_documents_from_table_with_filter")
2933
mocker.patch.object(service, "is_upload_in_process", return_value=False)
@@ -83,10 +87,10 @@ def test_get_document_references_dynamo_return_successful_response_single_table(
8387
patched_service, monkeypatch
8488
):
8589
monkeypatch.setenv("DYNAMODB_TABLE_LIST", json.dumps(["test_table"]))
86-
8790
patched_service.fetch_documents_from_table_with_filter.return_value = (
8891
MOCK_DOCUMENT_REFERENCE
8992
)
93+
9094
expected_results = [EXPECTED_RESPONSE]
9195
actual = patched_service.get_document_references("1111111111")
9296

0 commit comments

Comments
 (0)