diff --git a/app/cypress/e2e/0-ndr-core-tests/pcse_download_workflow_step2_individual_patient_search_and_verify.cy.js b/app/cypress/e2e/0-ndr-core-tests/pcse_download_workflow_step2_individual_patient_search_and_verify.cy.js index 924f29ae8..526530957 100644 --- a/app/cypress/e2e/0-ndr-core-tests/pcse_download_workflow_step2_individual_patient_search_and_verify.cy.js +++ b/app/cypress/e2e/0-ndr-core-tests/pcse_download_workflow_step2_individual_patient_search_and_verify.cy.js @@ -10,8 +10,6 @@ describe('PCSE Download Workflow: Access and download found files', () => { PCSE: 'pcse', }); - const noPatientError = 400; - const testNotFoundPatient = '1000000001'; const testPatient = '9000000009'; const patient = { birthDate: new Date('1970-01-01'), @@ -23,6 +21,19 @@ describe('PCSE Download Workflow: Access and download found files', () => { restricted: false, }; + const searchDocumentReferencesResponse = [ + { + fileName: 'Screenshot 2023-09-11 at 16.06.40.png', + virusScannerResult: 'Not Scanned', + created: new Date('2023-09-12T10:41:41.747836Z'), + }, + { + fileName: 'Screenshot 2023-09-08 at 14.53.47.png', + virusScannerResult: 'Not Scanned', + created: new Date('2023-09-12T10:41:41.749341Z'), + }, + ]; + beforeEach(() => { cy.visit(baseUrl); }); @@ -75,7 +86,7 @@ describe('PCSE Download Workflow: Access and download found files', () => { day: '2-digit', month: 'long', year: 'numeric', - }), + }) ); cy.get('#patient-summary-postcode').should('have.text', patient.postalCode); }); @@ -93,24 +104,11 @@ describe('PCSE Download Workflow: Access and download found files', () => { cy.get('#no-files-message').should('have.length', 1); cy.get('#no-files-message').should( 'have.text', - 'There are no documents available for this patient.', + 'There are no documents available for this patient.' ); }); it('(Smoke test) shows avaliable files to download on 200 success', () => { - const searchDocumentReferencesResponse = [ - { - fileName: 'Screenshot 2023-09-11 at 16.06.40.png', - virusScannerResult: 'Not Scanned', - created: new Date('2023-09-12T10:41:41.747836Z'), - }, - { - fileName: 'Screenshot 2023-09-08 at 14.53.47.png', - virusScannerResult: 'Not Scanned', - created: new Date('2023-09-12T10:41:41.749341Z'), - }, - ]; - if (!smokeTest) { cy.intercept('GET', '/SearchDocumentReferences*', { statusCode: 200, @@ -125,11 +123,11 @@ describe('PCSE Download Workflow: Access and download found files', () => { cy.get('.available-files-row').should('have.length', 2); cy.get('#available-files-row-0-filename').should( 'have.text', - searchDocumentReferencesResponse[1].fileName, + searchDocumentReferencesResponse[1].fileName ); cy.get('#available-files-row-1-filename').should( 'have.text', - searchDocumentReferencesResponse[0].fileName, + searchDocumentReferencesResponse[0].fileName ); cy.get('#available-files-row-0-created-date').should('exist'); @@ -148,7 +146,7 @@ describe('PCSE Download Workflow: Access and download found files', () => { hour: 'numeric', minute: 'numeric', second: 'numeric', - }), + }) ); cy.get('#available-files-row-1-created-date').should( 'have.text', @@ -159,14 +157,67 @@ describe('PCSE Download Workflow: Access and download found files', () => { hour: 'numeric', minute: 'numeric', second: 'numeric', - }), + }) ); } }); - it('Shows service error box on Search Docuement Reference 500 response', () => { - const searchDocumentReferencesResponse = []; + it('Shows spinner button while waiting for Download Document Manifest response', () => { + if (!smokeTest) { + cy.intercept('GET', '/SearchDocumentReferences*', { + statusCode: 200, + body: searchDocumentReferencesResponse, + }).as('search'); + } + + navigateToDownload(roles.PCSE); + + const documentManifestResponse = 'test-s3-url'; + + cy.get('#download-documents').click(); + + cy.intercept({ url: '/DocumentManifest*', middleware: true }, (req) => { + req.reply({ + statusCode: 200, + body: documentManifestResponse, + delay: 1500, + }); + }).as('search'); + + cy.get('#download-spinner').should('exist'); + }); + + it('Downloads file from the correct s3 url during Download Document Manifest', () => { + if (!smokeTest) { + cy.intercept('GET', '/SearchDocumentReferences*', { + statusCode: 200, + body: searchDocumentReferencesResponse, + }).as('search'); + } + + navigateToDownload(roles.PCSE); + + const documentManifestResponse = 'test-s3-url'; + + cy.get('#download-link').invoke('attr', 'href').should('eq', ''); + cy.get('#download-link').invoke('attr', 'download').should('eq', ''); + + cy.get('#download-documents').click(); + + cy.intercept({ url: '/DocumentManifest*', middleware: true }, (req) => { + req.reply({ + statusCode: 200, + body: documentManifestResponse, + }); + }).as('search'); + + cy.get('#download-link').invoke('attr', 'href').should('eq', 'test-s3-url'); + cy.get('#download-link') + .invoke('attr', 'download') + .should('eq', `patient-record-${testPatient}`); + }); + it('Shows service error box on Search Document Reference 500 response', () => { cy.intercept('GET', '/SearchDocumentReferences*', { statusCode: 500, }).as('search'); @@ -176,7 +227,7 @@ describe('PCSE Download Workflow: Access and download found files', () => { cy.get('#service-error').should('exist'); }); - it('Shows progress bar while waiting for response', () => { + it('Shows progress bar while waiting for Search Document Reference response', () => { const searchDocumentReferencesResponse = []; cy.intercept({ url: '/SearchDocumentReferences*', middleware: true }, (req) => { diff --git a/app/package-lock.json b/app/package-lock.json index 61de8c660..c1513a074 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -16,7 +16,6 @@ "dotenv": "^16.3.1", "eslint-plugin-legacy-decorators": "^1.0.0", "history": "^5.3.0", - "jsdom": "^22.1.0", "nhsuk-frontend": "^7.0.0", "nhsuk-react-components": "^2.2.2", "pdfobject": "^2.2.12", @@ -44,7 +43,6 @@ "@storybook/react-webpack5": "^7.4.0", "@storybook/testing-library": "^0.2.0", "@types/jest": "^27.5.2", - "@types/jsdom": "^21.1.3", "@types/node": "^16.18.40", "@types/react": "^18.2.19", "@types/react-dom": "^18.2.7", @@ -7907,14 +7905,6 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -8145,17 +8135,6 @@ "pretty-format": "^27.0.0" } }, - "node_modules/@types/jsdom": { - "version": "21.1.3", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.3.tgz", - "integrity": "sha512-1zzqSP+iHJYV4lB3lZhNBa012pubABkj9yG/GuXuf6LZH1cSPIJBqFDrm5JX65HHt6VOnNYdTui/0ySerRbMgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -8345,12 +8324,6 @@ "@types/jest": "*" } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", - "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", - "dev": true - }, "node_modules/@types/trusted-types": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", @@ -11399,17 +11372,6 @@ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -11637,19 +11599,6 @@ "node": ">=0.10" } }, - "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", @@ -12157,17 +12106,6 @@ } ] }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", @@ -14832,17 +14770,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/html-entities": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", @@ -14973,19 +14900,6 @@ "node": ">=8.0.0" } }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/http-proxy-middleware": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", @@ -18319,60 +18233,6 @@ "signal-exit": "^3.0.2" } }, - "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -20305,28 +20165,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -23381,11 +23219,6 @@ "node": ">=8" } }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" - }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -23548,17 +23381,6 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -25195,17 +25017,6 @@ "node": ">= 4.0.0" } }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", @@ -25844,17 +25655,6 @@ "browser-process-hrtime": "^1.0.0" } }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -25897,14 +25697,6 @@ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, "node_modules/webpack": { "version": "5.88.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", @@ -26230,42 +26022,11 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/whatwg-fetch": { "version": "3.6.17", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.17.tgz", "integrity": "sha512-c4ghIvG6th0eudYwKZY5keb81wtFz9/WeAHAoy8+r18kcWlitUIrmGFQ2rWEl4UCKUilD3zCLHOIPheHx5ypRQ==" }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -26816,14 +26577,6 @@ } } }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "engines": { - "node": ">=12" - } - }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", diff --git a/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.test.tsx b/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.test.tsx index 40475cee2..34a5fa833 100644 --- a/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.test.tsx +++ b/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.test.tsx @@ -1,6 +1,6 @@ import { createMemoryHistory } from 'history'; import * as ReactRouter from 'react-router'; -import { buildPatientDetails } from '../../../helpers/test/testBuilders'; +import { buildPatientDetails, buildUserAuth } from '../../../helpers/test/testBuilders'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import axios from 'axios'; @@ -9,6 +9,7 @@ import DocumentSearchResultsOptions from './DocumentSearchResultsOptions'; import { SUBMISSION_STATE } from '../../../types/pages/documentSearchResultsPage/types'; import { PatientDetails } from '../../../types/generic/patientDetails'; import { routes } from '../../../types/generic/routes'; +import SessionProvider, { Session } from '../../../providers/sessionProvider/SessionProvider'; jest.mock('axios'); const mockedAxios = axios as jest.Mocked; @@ -28,20 +29,19 @@ describe('DocumentSearchResultsOptions', () => { expect( screen.getByText( - 'Only permanently delete all documents for this patient if you have a valid reason to. For example, if the retention period of these documents has been reached.', - ), + 'Only permanently delete all documents for this patient if you have a valid reason to. For example, if the retention period of these documents has been reached.' + ) ).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'Download All Documents' }), + screen.getByRole('button', { name: 'Download All Documents' }) ).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'Delete All Documents' }), + screen.getByRole('button', { name: 'Delete All Documents' }) ).toBeInTheDocument(); }); - it.skip('calls parent callback function to pass successful state after a successful response from api', async () => { - // Currently errors, needs to be revisited + it('calls parent callback function to pass successful state after a successful response from api', async () => { mockedAxios.get.mockResolvedValue(async () => { return Promise.resolve({ data: 'test-presigned-url' }); }); @@ -56,7 +56,7 @@ describe('DocumentSearchResultsOptions', () => { it('renders success message when the download state is successful', async () => { renderDocumentSearchResultsOptions(SUBMISSION_STATE.SUCCEEDED); expect( - screen.getByText('All documents have been successfully downloaded.'), + screen.getByText('All documents have been successfully downloaded.') ).toBeInTheDocument(); }); @@ -74,10 +74,10 @@ describe('DocumentSearchResultsOptions', () => { renderDocumentSearchResultsOptions(SUBMISSION_STATE.INITIAL); expect( - screen.getByRole('button', { name: 'Download All Documents' }), + screen.getByRole('button', { name: 'Download All Documents' }) ).toBeInTheDocument(); expect( - screen.getByRole('button', { name: 'Delete All Documents' }), + screen.getByRole('button', { name: 'Delete All Documents' }) ).toBeInTheDocument(); userEvent.click(screen.getByRole('button', { name: 'Download All Documents' })); @@ -93,7 +93,7 @@ describe('DocumentSearchResultsOptions', () => { }); expect( - screen.queryByRole('button', { name: 'Download All Documents' }), + screen.queryByRole('button', { name: 'Download All Documents' }) ).not.toBeInTheDocument(); }); @@ -168,8 +168,12 @@ const renderDocumentSearchResultsOptions = ( history = createMemoryHistory({ initialEntries: [homeRoute], initialIndex: 1, - }), + }) ) => { + const auth: Session = { + auth: buildUserAuth(), + isLoggedIn: true, + }; const patient: PatientDetails = { ...buildPatientDetails(), ...patientOverride, @@ -177,13 +181,15 @@ const renderDocumentSearchResultsOptions = ( render( - - - - , + + + + + + ); }; diff --git a/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.tsx b/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.tsx index 96c2eeb94..3d2d98eb6 100644 --- a/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.tsx +++ b/app/src/components/blocks/documentSearchResultsOptions/DocumentSearchResultsOptions.tsx @@ -6,6 +6,8 @@ import { Link, useNavigate } from 'react-router-dom'; import getPresignedUrlForZip from '../../../helpers/requests/getPresignedUrlForZip'; import { AxiosError } from 'axios'; import { useBaseAPIUrl } from '../../../providers/configProvider/ConfigProvider'; +import { useEffect, useRef, useState } from 'react'; +import useBaseAPIHeaders from '../../../helpers/hooks/useBaseAPIHeaders'; type Props = { nhsNumber: string; @@ -13,9 +15,26 @@ type Props = { updateDownloadState: (newState: SUBMISSION_STATE) => void; }; +interface DownloadLinkAttributes { + url: string; + filename: string; +} + const DocumentSearchResultsOptions = (props: Props) => { const navigate = useNavigate(); const baseUrl = useBaseAPIUrl(); + const baseHeaders = useBaseAPIHeaders(); + const [linkAttributes, setLinkAttributes] = useState({ + url: '', + filename: '', + }); + const linkRef = useRef(null); + + useEffect(() => { + if (linkRef.current && linkAttributes.url) { + linkRef.current.click(); + } + }, [linkAttributes]); const downloadAll = async () => { props.updateDownloadState(SUBMISSION_STATE.PENDING); @@ -23,9 +42,12 @@ const DocumentSearchResultsOptions = (props: Props) => { const preSignedUrl = await getPresignedUrlForZip({ nhsNumber: props.nhsNumber, baseUrl: baseUrl, + baseHeaders, }); - downloadFile(preSignedUrl, `patient-record-${props.nhsNumber}`); + const filename = `patient-record-${props.nhsNumber}`; + + setLinkAttributes({ url: preSignedUrl, filename: filename }); props.updateDownloadState(SUBMISSION_STATE.SUCCEEDED); } catch (e) { @@ -37,15 +59,6 @@ const DocumentSearchResultsOptions = (props: Props) => { } }; - const downloadFile = (url: string, filename: string) => { - const downloadLink = document.createElement('a'); - downloadLink.href = url; - downloadLink.download = filename; - - downloadLink.click(); - downloadLink.remove(); - }; - return ( <>

@@ -55,15 +68,24 @@ const DocumentSearchResultsOptions = (props: Props) => {

{props.downloadState === SUBMISSION_STATE.PENDING ? ( ) : ( - )} + ', () => { const triggerUploadStateChange = ( document: UploadDocument, state: DOCUMENT_UPLOAD_STATE, - progress: number, + progress: number ) => { act(() => { document.state = state; @@ -48,20 +56,15 @@ describe('', () => { docType: DOCUMENT_TYPE.ARF, }; - render( - , - ); + renderUploadingStage([documentOne, documentTwo, documentThree]); triggerUploadStateChange(documentOne, documentUploadStates.UPLOADING, 0); expect(screen.queryByTestId('upload-document-form')).not.toBeInTheDocument(); expect( screen.getByText( - 'Do not close or navigate away from this browser until upload is complete.', - ), + 'Do not close or navigate away from this browser until upload is complete.' + ) ).toBeInTheDocument(); }); @@ -92,7 +95,7 @@ describe('', () => { , + /> ); const getProgressBarValue = (document: UploadDocument) => { const progressBar: HTMLProgressElement = screen.getByRole('progressbar', { @@ -111,7 +114,7 @@ describe('', () => { , + /> ); expect(getProgressBarValue(documentOne)).toEqual(10); expect(getProgressText(documentOne)).toContain('10% uploaded...'); @@ -121,7 +124,7 @@ describe('', () => { , + /> ); expect(getProgressBarValue(documentOne)).toEqual(70); expect(getProgressText(documentOne)).toContain('70% uploaded...'); @@ -131,7 +134,7 @@ describe('', () => { , + /> ); expect(getProgressBarValue(documentTwo)).toEqual(20); expect(getProgressText(documentTwo)).toContain('20% uploaded...'); @@ -141,7 +144,7 @@ describe('', () => { , + /> ); expect(getProgressBarValue(documentTwo)).toEqual(100); expect(getProgressText(documentTwo)).toContain('Uploaded'); @@ -151,10 +154,36 @@ describe('', () => { , + /> ); expect(getProgressBarValue(documentOne)).toEqual(0); expect(getProgressText(documentOne)).toContain('Upload failed'); }); }); }); + +const homeRoute = '/example'; +const renderUploadingStage = ( + documents: Array, + patientOverride: Partial = {}, + history = createMemoryHistory({ + initialEntries: [homeRoute], + initialIndex: 1, + }) +) => { + const auth: Session = { + auth: buildUserAuth(), + isLoggedIn: true, + }; + const patient: PatientDetails = { + ...buildPatientDetails(), + ...patientOverride, + }; + render( + + + + + + ); +}; diff --git a/app/src/components/generic/spinnerButton/SpinnerButton.story.tsx b/app/src/components/generic/spinnerButton/SpinnerButton.story.tsx index 67544b2aa..76134d953 100644 --- a/app/src/components/generic/spinnerButton/SpinnerButton.story.tsx +++ b/app/src/components/generic/spinnerButton/SpinnerButton.story.tsx @@ -14,6 +14,7 @@ type Story = StoryObj; export const OrgSelectPage: Story = { args: { + id: 'spinner-button', status: 'Loading...', disabled: false, }, diff --git a/app/src/components/generic/spinnerButton/SpinnerButton.test.tsx b/app/src/components/generic/spinnerButton/SpinnerButton.test.tsx index 28160e210..050e353ae 100644 --- a/app/src/components/generic/spinnerButton/SpinnerButton.test.tsx +++ b/app/src/components/generic/spinnerButton/SpinnerButton.test.tsx @@ -5,7 +5,7 @@ describe('SpinnerButton', () => { it('displays status text for the spinner button', () => { const status = 'Loading...'; - render(); + render(); expect(screen.getByRole('SpinnerButton', { name: 'SpinnerButton' })).toBeInTheDocument(); expect(screen.getByRole('status')).toBeInTheDocument(); diff --git a/app/src/components/generic/spinnerButton/SpinnerButton.tsx b/app/src/components/generic/spinnerButton/SpinnerButton.tsx index d0ca9f61d..a0ec1c8a8 100644 --- a/app/src/components/generic/spinnerButton/SpinnerButton.tsx +++ b/app/src/components/generic/spinnerButton/SpinnerButton.tsx @@ -2,13 +2,15 @@ import React from 'react'; import { Button } from 'nhsuk-react-components'; export type Props = { + id: string; status: string; disabled?: boolean; }; -const SpinnerButton = ({ status, disabled }: Props) => { +const SpinnerButton = ({ id, status, disabled }: Props) => { return (