diff --git a/cypress/e2e/patient_spec/patient_files.cy.ts b/cypress/e2e/patient_spec/patient_files.cy.ts new file mode 100644 index 00000000000..38e587ea789 --- /dev/null +++ b/cypress/e2e/patient_spec/patient_files.cy.ts @@ -0,0 +1,170 @@ +import { PatientEncounter } from "@/pageObject/Patients/PatientEncounter"; +import { PatientFiles } from "@/pageObject/Patients/PatientFiles"; +import { FacilityCreation } from "@/pageObject/facility/FacilityCreation"; + +const facilityCreation = new FacilityCreation(); +const patientEncounter = new PatientEncounter(); +const patientFiles = new PatientFiles(); + +describe("Patient Files", () => { + beforeEach(() => { + cy.loginByApi("nurse"); + cy.visit("/"); + facilityCreation.selectFacility("PHC Angamaly"); + patientEncounter + .navigateToEncounters() + .openFirstEncounterDetails() + .clickPatientDetailsButton(); + patientFiles.clickFilesTab(); + }); + + const validationMessage = "Please give a name for the file"; + const fileUploadSuccessToast = "File Uploaded Successfully"; + const fileArchiveSuccessToast = "File archived successfully"; + const fileRenameSuccessToast = "File name changed successfully"; + const fileDownloadingSuccessToast = "Downloading file..."; + const newFileName = "Renamed Cypress File1"; + const newFileDisplayName = "Renamed Cypress File1.png"; + const archiveReason = "Cypress Archive Reason"; + + // Audio File Upload Setup + + const audioFileName = "Cypress Audio Test"; + const audioDisplayName = audioFileName + ".mp3"; + + // Single File Upload Setup + + const fileName = "sample_img1.png"; + const inputFileName = "Cypress Test File Upload"; + const fileDisplayName = inputFileName + ".png"; + const filePath = (fileName: string) => `cypress/fixtures/${fileName}`; + + // Multiple Files Upload Setup + + const fileNames = ["sample_img1.png", "sample_img2.png", "sample_file.xlsx"]; + const inputFileNames = [ + "Cypress Image Test 1", + "Cypress Image Test 2", + "Cypress File Test 3", + ]; + const fileDisplayNames = [ + "Cypress Image Test 1.png", + "Cypress Image Test 2.png", + "Cypress File Test 3.xlsx", + ]; + const filePaths = (fileNames: string[]) => + fileNames.map((file) => `cypress/fixtures/${file}`); + + // Tests for single and multiple file uploads, rename, download and archive + + it("Add a new patient file", () => { + patientFiles + .clickAddFilesButton() + .uploadSingleFile(filePath(fileName)) + .clickUploadFilesButton() + .verifyValidationErrors(validationMessage) + .fillSingleFileName(inputFileName) + .interceptFileUploadRequest() + .clickUploadFilesButton() + .verifyFileUploadApiCall() + .verifySingleFileUploadSuccess(fileUploadSuccessToast) + .verifyFilesAdded([fileDisplayName]); + }); + + it("Add multiple patient files", () => { + patientFiles + .clickAddFilesButton() + .uploadMultipleFiles(filePaths(fileNames)) + .clickUploadFilesButton() + .verifyValidationErrors(validationMessage) + .fillMultipleFileNames(inputFileNames) + .interceptFileUploadRequest() + .clickUploadFilesButton() + .verifyFileUploadApiCall() + .verifyMultipleFileUploadSuccess(fileUploadSuccessToast) + .verifyFilesAdded(fileDisplayNames); + }); + + it("Record an Audio and download", () => { + patientFiles + .clickAddFilesButton() + .clickRecordAudioButton() + .startRecordingAudio() + .stopRecordingAudio() + + // Test Cancel Audio Button + + .clickCancelAudioButton() + .clickFilesTab() + .clickAddFilesButton() + + // Test Start Again Button + + .clickRecordAudioButton() + .startRecordingAudio() + .stopRecordingAudio() + .clickStartAgainButton() + + // Record and Upload Audio File + + .stopRecordingAudio() + .clickSaveAudioButton() + .clickUploadFilesButton() + .verifyValidationErrors(validationMessage) + .fillSingleFileName(audioFileName) + .interceptFileUploadRequest() + .clickUploadFilesButton() + .verifyFileUploadApiCall() + .verifySingleFileUploadSuccess(fileUploadSuccessToast) + .filterActiveFiles() + .verifyFilesAdded([audioDisplayName]) + + // Download Audio file + + .clickFileDetailsButton(audioDisplayName) + .clickDownloadFile() + .verifySingleFileUploadSuccess(fileDownloadingSuccessToast); + }); + + it("File Modification, Rename and Archive", () => { + // Upload a new file + + patientFiles + .clickAddFilesButton() + .uploadSingleFile(filePath(fileName)) + .clickUploadFilesButton() + .verifyValidationErrors(validationMessage) + .fillSingleFileName(inputFileName) + .interceptFileUploadRequest() + .clickUploadFilesButton() + .verifyFileUploadApiCall() + .verifySingleFileUploadSuccess(fileUploadSuccessToast) + .verifyFilesAdded([fileDisplayName]) + + // Rename the file + + .clickFileDetailsButton(fileDisplayName) + .clickRenameOption() + .fillNewFileName(newFileName) + .interceptFileRenameRequest() + .clickProceedButton() + .verifyFileRenameApiCall() + .verifySingleFileUploadSuccess(fileRenameSuccessToast) + .verifyFilesAdded([newFileDisplayName]) + + // Archive the file + + .clickFileDetailsButton(newFileDisplayName) + .clickArchiveOption() + .fillArchiveReason(archiveReason) + .interceptFileArchiveRequest() + .clickProceedButton() + .verifyFileArchiveApiCall() + .verifySingleFileUploadSuccess(fileArchiveSuccessToast) + .filterArchivedFiles() + .clickViewFile(newFileDisplayName) + .verifyArchiveReason(archiveReason); + }); + + // Cypress test for Convert to PDF +}); diff --git a/cypress/fixtures/sample_file.xlsx b/cypress/fixtures/sample_file.xlsx new file mode 100644 index 00000000000..49421f62bac Binary files /dev/null and b/cypress/fixtures/sample_file.xlsx differ diff --git a/cypress/fixtures/sample_img1.png b/cypress/fixtures/sample_img1.png new file mode 100644 index 00000000000..dfb4ecb2958 Binary files /dev/null and b/cypress/fixtures/sample_img1.png differ diff --git a/cypress/fixtures/sample_img2.png b/cypress/fixtures/sample_img2.png new file mode 100644 index 00000000000..d73e60ebff7 Binary files /dev/null and b/cypress/fixtures/sample_img2.png differ diff --git a/cypress/pageObject/Patients/PatientFiles.ts b/cypress/pageObject/Patients/PatientFiles.ts new file mode 100644 index 00000000000..7f9737f982e --- /dev/null +++ b/cypress/pageObject/Patients/PatientFiles.ts @@ -0,0 +1,238 @@ +export class PatientFiles { + clickFilesTab() { + cy.verifyAndClickElement('[data-cy="tab-files"]', "Files"); + return this; + } + + clickAddFilesButton() { + cy.verifyAndClickElement('[data-cy="add-files-button"]', "Add Files"); + return this; + } + + uploadSingleFile(filePath: string) { + cy.contains("Upload From Device").should("be.visible"); + cy.get('input[type="file"]').selectFile(filePath, { force: true }); + return this; + } + + uploadMultipleFiles(filePaths: string[]) { + cy.contains("Upload From Device").should("be.visible"); + cy.get('input[type="file"]').selectFile( + filePaths.map((file) => ({ + contents: file, + })), + { force: true }, + ); + return this; + } + + clickUploadFilesButton() { + cy.get('[data-cy="upload-files-button"]').click(); + return this; + } + + verifyValidationErrors(errorMessage: string) { + cy.contains(errorMessage).then(($errors) => { + cy.wrap($errors).each(($error) => { + cy.wrap($error).scrollIntoView().should("be.visible"); + }); + }); + return this; + } + + fillMultipleFileNames(fileNames: string[]) { + cy.get("input").each(($input, index) => { + cy.wrap($input).clear(); + cy.wrap($input).type(`${fileNames[index]}`); + }); + return this; + } + + fillSingleFileName(fileName: string) { + cy.get("input").type(fileName); + return this; + } + + interceptFileUploadRequest() { + cy.intercept("POST", "**/api/v1/files/").as("uploadFile"); + return this; + } + + interceptFileRenameRequest() { + cy.intercept("PUT", "**/api/v1/files/**").as("renameFile"); + return this; + } + + interceptFileArchiveRequest() { + cy.intercept("POST", "**/api/v1/files/**").as("archiveFile"); + return this; + } + + interceptFilterRequest() { + cy.intercept("GET", "**/api/v1/files/?**").as("filterFiles"); + return this; + } + + verifyFilterApiCall() { + cy.wait("@filterFiles").then((interception) => { + expect(interception.response?.statusCode).to.equal(200); + }); + return this; + } + + verifyFileUploadApiCall() { + cy.wait("@uploadFile").then((interception) => { + expect(interception.response?.statusCode).to.equal(200); + }); + return this; + } + + verifyFileRenameApiCall() { + cy.wait("@renameFile").then((interception) => { + expect(interception.response?.statusCode).to.equal(200); + }); + return this; + } + + verifyFileArchiveApiCall() { + cy.wait("@archiveFile").then((interception) => { + expect(interception.response?.statusCode).to.equal(200); + }); + return this; + } + + verifySingleFileUploadSuccess(message: string) { + cy.verifyNotification(message); + cy.wait(300); + return this; + } + + verifyMultipleFileUploadSuccess(message: string) { + cy.verifyNotification(message); + cy.wait(200); + cy.verifyNotification(message); + cy.wait(200); + cy.verifyNotification(message); + cy.wait(300); + return this; + } + + verifyFilesAdded(fileNames: string[]) { + fileNames.forEach((fileName) => { + cy.verifyContentPresence(`[data-cy="${fileName}"]`, [fileName]); + }); + return this; + } + + clickRecordAudioButton() { + cy.get('[data-cy="record-audio-button"]').click(); + return this; + } + + startRecordingAudio() { + cy.get('[data-cy="start-recording-button"]') + .should("be.visible") + .should("be.enabled") + .click(); + cy.wait(2000); + return this; + } + + stopRecordingAudio() { + cy.get('[data-cy="stop-recording-button"]') + .should("be.visible") + .should("be.enabled") + .click(); + cy.wait(1000); + return this; + } + + clickCancelAudioButton() { + cy.get('[data-cy="cancel-audio-button"]').click(); + return this; + } + + clickStartAgainButton() { + cy.get('[data-cy="start-again-button"]').click(); + cy.wait(2000); + return this; + } + + clickSaveAudioButton() { + cy.get('[data-cy="save-recording-button"]').click(); + return this; + } + + clickFileDetailsButton(fileName: string) { + cy.get(`[data-cy="${fileName}"] [data-cy="file-options-button"]`).click({ + force: true, + }); + return this; + } + + clickDownloadFile() { + cy.get("button").contains("Download").click(); + return this; + } + + clickRenameOption() { + cy.contains("Rename").click(); + return this; + } + + fillNewFileName(newFileName: string) { + cy.get("input").clear().type(newFileName); + return this; + } + + clickProceedButton() { + cy.contains("button", "Proceed").should("be.enabled").click(); + return this; + } + + clickArchiveOption() { + cy.contains("button", "Archive").should("be.enabled").click(); + return this; + } + + fillArchiveReason(archiveReason: string) { + cy.get("textarea").clear().type(archiveReason); + return this; + } + + clickViewFile(fileName: string) { + cy.get(`[data-cy="${fileName}"]`) + .contains("button", "View") + .click({ force: true }); + return this; + } + + verifyArchiveReason(reason: string) { + cy.contains(reason).should("be.visible"); + return this; + } + + filterActiveFiles() { + this.interceptFilterRequest(); + cy.contains("button", "Filter").click(); + cy.contains("Active Files").click(); + this.verifyFilterApiCall(); + return this; + } + + filterArchivedFiles() { + this.interceptFilterRequest(); + cy.contains("button", "Filter").click(); + cy.contains("Archived Files").click(); + this.verifyFilterApiCall(); + return this; + } + + removeFilter() { + cy.contains("Active Files").click(); + this.verifyFilterApiCall(); + return this; + } + + // CONVERT TO PDF +} diff --git a/src/components/Files/AudioCaptureDialog.tsx b/src/components/Files/AudioCaptureDialog.tsx index 6bbab097435..5a57bb5a74d 100644 --- a/src/components/Files/AudioCaptureDialog.tsx +++ b/src/components/Files/AudioCaptureDialog.tsx @@ -143,6 +143,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) { @@ -165,6 +166,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) { onClick={handleStopRecording} id="stop-recording" className="inline-flex aspect-square w-32 animate-pulse items-center justify-center rounded-full bg-red-500/20 text-2xl text-red-500 hover:bg-red-500/30" + data-cy="stop-recording-button" > {timer.time} @@ -191,6 +193,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) { onClick={handleSubmit} className="rounded-md bg-primary-500 px-4 py-2 text-white transition-all hover:bg-primary-600" id="save-recording" + data-cy="save-recording-button" > {t("done")} @@ -198,6 +201,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) { @@ -395,6 +395,7 @@ export const FilesTab = (props: FilesTabProps) => {