From 6481de3f3734d79a7c0df5f3fab7276fb5f52ae8 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 12 Oct 2022 13:25:05 +0100 Subject: [PATCH 01/63] move checkResponseOK to api.ts --- src/fhir/api.test.ts | 32 +------------------------------- src/fhir/api.ts | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index c620f8b..6762101 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -1,6 +1,5 @@ import { Fhir } from "fhir/fhir"; -import { BundleResponse } from "../code_systems/types"; -import { createBundle } from "./api"; +import { createBundle, checkResponseOK } from "./api"; import { initialValues, initialWithNoVariant } from "../components/reports/FormDefaults"; import { Observation } from "fhir/r4"; import { geneCoding } from "../code_systems/hgnc"; @@ -13,35 +12,6 @@ const fhir = new Fhir(); const reportedGenes = [geneCoding("HGNC:4389", "GNA01")]; const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; -const checkResponseOK = async (response: Response) => { - const r = await response.json(); - - if (!response.ok) { - console.error(r.body); - throw new Error(response.statusText); - } - if (!(r.type === "bundle-response")) { - return r; - } - - const errors = (r as BundleResponse).entry - .filter((entry) => entry.response.status.toString().startsWith("4")) - .map((entry) => entry.response.outcome.issue); - - if (errors.length > 1) { - errors.forEach((issue) => { - let message = "unknown error in bundle"; - if (issue && issue.length > 0) { - message = issue[0].diagnostics; - } - throw new Error(message); - }); - } - - console.debug(`check response: ${JSON.stringify(r, null, 2)}`); - return r; -}; - const getPatients = async (identifier?: string): Promise => { let url = `${FHIR_URL}/Patient`; if (identifier) url = `${FHIR_URL}/Patient?identifier=${identifier}`; diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 4c44d4f..a4e31de 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -16,7 +16,7 @@ import { } from "./resources"; import { VariantSchema } from "../components/reports/formDataValidation"; import { loincResources } from "../code_systems/loincCodes"; -import { RequiredCoding } from "../code_systems/types"; +import { BundleResponse, RequiredCoding } from "../code_systems/types"; /** * Create a report bundle @@ -128,3 +128,32 @@ const createEntry = (resource: Resource, identifier?: string) => { request: requestInfo, }; }; + +export const checkResponseOK = async (response: Response) => { + const r = await response.json(); + + if (!response.ok) { + console.error(r.body); + throw new Error(response.statusText); + } + if (!(r.type === "bundle-response")) { + return r; + } + + const errors = (r as BundleResponse).entry + .filter((entry) => entry.response.status.toString().startsWith("4")) + .map((entry) => entry.response.outcome.issue); + + if (errors.length > 1) { + errors.forEach((issue) => { + let message = "unknown error in bundle"; + if (issue && issue.length > 0) { + message = issue[0].diagnostics; + } + throw new Error(message); + }); + } + + console.debug(`check response: ${JSON.stringify(r, null, 2)}`); + return r; +}; From 5f375267cb70aee43191bd2f4d2e0c4eefe35a8f Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 12 Oct 2022 14:40:44 +0100 Subject: [PATCH 02/63] adding basic batch-response functionality --- src/fhir/api.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index a4e31de..5e1c653 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -154,6 +154,17 @@ export const checkResponseOK = async (response: Response) => { }); } + if (r.type === "batch-response") { + const notOKs = []; + const responseStatus = (r as BundleResponse).entry.map((entry) => entry.response.status); + if (!responseStatus.toString().startsWith("2")) { + const responseIssue = (r as BundleResponse).entry.map((entry) => entry.response.outcome.issue); + const issueDiagnostics = responseIssue?.map((issue) => issue[0].diagnostics); + + notOKs.push([r.resourceType, responseStatus, issueDiagnostics]); + } + } + console.debug(`check response: ${JSON.stringify(r, null, 2)}`); return r; }; From b9dbaf2633457b1565a9183794186572f312cfce Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 12 Oct 2022 14:49:24 +0100 Subject: [PATCH 03/63] moving bits to testUtilities --- src/fhir/api.test.ts | 62 ++------------------------------------- src/fhir/testUtilities.ts | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 59 deletions(-) create mode 100644 src/fhir/testUtilities.ts diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 6762101..d64b70e 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,68 +6,12 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; +import { sendBundle, deletePatients, getPatients, getObservations } from "./testUtilities"; const fhir = new Fhir(); const reportedGenes = [geneCoding("HGNC:4389", "GNA01")]; -const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; - -const getPatients = async (identifier?: string): Promise => { - let url = `${FHIR_URL}/Patient`; - if (identifier) url = `${FHIR_URL}/Patient?identifier=${identifier}`; - const response = await fetch(url); - return await checkResponseOK(response); -}; - -const getObservations = async (identifier?: string): Promise => { - let url = `${FHIR_URL}/Observation`; - if (identifier) url = `${FHIR_URL}/Observation?identifier=${identifier}`; - const response = await fetch(url); - return await checkResponseOK(response); -}; - -const sendBundle = async (bundle: Bundle) => { - const sentBundle = await fetch(`${FHIR_URL}/`, { - method: "POST", - body: JSON.stringify(bundle), - headers: { - "Content-Type": "application/json", - }, - }); - await new Promise((r) => setTimeout(r, 1500)); - return sentBundle; -}; - -/** - * Given an ID string - * this will delete the chosen patient's records, otherwise it will remove all patients by looping - * through and extracting IDs from the search bundle - */ -const deletePatients = async (patientId?: string) => { - const patientData = await getPatients(); - if (!("entry" in patientData)) { - console.debug("Nothing to delete; no patients in database"); - return; - } - if (patientId) { - await deleteAndCascadeDelete([patientId]); - } else { - const patientIds = patientData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(patientIds); - } - - // await new Promise((r) => setTimeout(r, 1500)); -}; - -const deleteAndCascadeDelete = async (patientIds: string[]) => { - console.debug(`deleting ids: ${patientIds}`); - for (const patientId of patientIds) { - const response = await fetch(`${FHIR_URL}/Patient/${patientId}?_cascade=delete`, { - method: "DELETE", - }); - await checkResponseOK(response); - } -}; +export const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; jest.setTimeout(20000); @@ -113,7 +57,7 @@ describe("FHIR resources", () => { const createPatient = await sendBundle(bundle); // check it's the right patient - await checkResponseOK(createPatient); + const response = await checkResponseOK(createPatient); const patientData = await getPatients(); expect("entry" in patientData).toBeTruthy(); expect(getPatientIdentifier(patientData)).toEqual(initialValues.patient.mrn); diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts new file mode 100644 index 0000000..b66e831 --- /dev/null +++ b/src/fhir/testUtilities.ts @@ -0,0 +1,54 @@ +import { checkResponseOK } from "./api"; +import { FHIR_URL } from "./api.test"; + +export const sendBundle = async (bundle: Bundle) => { + const sentBundle = await fetch(`${FHIR_URL}/`, { + method: "POST", + body: JSON.stringify(bundle), + headers: { + "Content-Type": "application/json", + }, + }); + await new Promise((r) => setTimeout(r, 1500)); + return sentBundle; +}; + +export const getPatients = async (identifier?: string): Promise => { + let url = `${FHIR_URL}/Patient`; + if (identifier) url = `${FHIR_URL}/Patient?identifier=${identifier}`; + const response = await fetch(url); + return await checkResponseOK(response); +}; + +export const getObservations = async (identifier?: string): Promise => { + let url = `${FHIR_URL}/Observation`; + if (identifier) url = `${FHIR_URL}/Observation?identifier=${identifier}`; + const response = await fetch(url); + return await checkResponseOK(response); +}; + +export const deletePatients = async (patientId?: string) => { + const patientData = await getPatients(); + if (!("entry" in patientData)) { + console.debug("Nothing to delete; no patients in database"); + return; + } + if (patientId) { + await deleteAndCascadeDelete([patientId]); + } else { + const patientIds = patientData.entry?.map((entry) => entry.resource?.id) as string[]; + await deleteAndCascadeDelete(patientIds); + } + + // await new Promise((r) => setTimeout(r, 1500)); +}; + +const deleteAndCascadeDelete = async (patientIds: string[]) => { + console.debug(`deleting ids: ${patientIds}`); + for (const patientId of patientIds) { + const response = await fetch(`${FHIR_URL}/Patient/${patientId}?_cascade=delete`, { + method: "DELETE", + }); + await checkResponseOK(response); + } +}; From 43198293debb480e7e7269ad7653342081470ab8 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 12 Oct 2022 14:58:39 +0100 Subject: [PATCH 04/63] adding missing import --- src/fhir/testUtilities.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index b66e831..1606aba 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -1,3 +1,4 @@ +import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { checkResponseOK } from "./api"; import { FHIR_URL } from "./api.test"; From 9e44dc8b275aed9eb23e7fd9be625735867c9e74 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Thu, 13 Oct 2022 10:52:21 +0100 Subject: [PATCH 05/63] fixed issue possibly being undefined? --- src/fhir/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 5e1c653..ab740fb 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -159,7 +159,7 @@ export const checkResponseOK = async (response: Response) => { const responseStatus = (r as BundleResponse).entry.map((entry) => entry.response.status); if (!responseStatus.toString().startsWith("2")) { const responseIssue = (r as BundleResponse).entry.map((entry) => entry.response.outcome.issue); - const issueDiagnostics = responseIssue?.map((issue) => issue[0].diagnostics); + const issueDiagnostics = responseIssue?.map((issue) => issue?.[0].diagnostics); notOKs.push([r.resourceType, responseStatus, issueDiagnostics]); } From 51530c00beb3d97d2fa2be55b1b99cb5e067bef9 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Thu, 13 Oct 2022 11:32:23 +0100 Subject: [PATCH 06/63] added basis for modal test --- src/components/reports/ReportForm.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index bea0ff9..974dc7e 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -142,6 +142,24 @@ describe("Report form", () => { fetchMock.dontMock(); await deletePatients(); }); + + test("Error modal exists", async () => { + // Arrange + render(); + + // Act + await setLabAndPatient(); + await setSample(); + await setVariantFields(); + await setReportFields(); + await act(async () => { + userEvent.click(screen.getByText(/submit/i)); + }); + + // Assert + const modal = await screen.findByRole("modal"); + expect(modal).toContain("error"); + }); /** * Given the report form * When all data filled in From a7905128687f7ff81f73bbb2aacd0b173586b8c3 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 11:22:46 +0100 Subject: [PATCH 07/63] posting duplicate practitioner --- src/components/reports/ReportForm.test.tsx | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 974dc7e..f85c43d 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -2,9 +2,12 @@ import ReportForm from "./ReportForm"; import { render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; -import { noValues } from "./FormDefaults"; +import { initialWithNoVariant, noValues } from "./FormDefaults"; import { act } from "react-dom/test-utils"; import { deletePatients } from "../../fhir/testUtilities"; +import { FHIR_URL } from "../../fhir/api.test"; +import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; +import { createIdentifier } from "../../fhir/resource_helpers"; const clearAndType = (element: Element, value: string) => { userEvent.clear(element); @@ -145,7 +148,26 @@ describe("Report form", () => { test("Error modal exists", async () => { // Arrange - render(); + render(); + const practitioner = new Practitioner(); + practitioner.resourceType = "Practitioner"; + const identifier = createIdentifier("anapietra_report"); + practitioner.identifier = [identifier]; + console.log(practitioner); + + const createPractitioner = async (practitioner: any) => { + const sendPractitioner = await fetch(`${FHIR_URL}/Practitioner`, { + method: "POST", + body: JSON.stringify(practitioner), + headers: { + "Content-Type": "application/json", + }, + }); + await new Promise((r) => setTimeout(r, 1500)); + return sendPractitioner; + }; + createPractitioner(practitioner); + createPractitioner(practitioner); // Act await setLabAndPatient(); From 9394d85ee3b7e725543f9ff41bd3113c07cf6c16 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 11:23:23 +0100 Subject: [PATCH 08/63] updated notOKs name to errorsForModal --- src/fhir/api.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index ab740fb..9115ec3 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -155,14 +155,15 @@ export const checkResponseOK = async (response: Response) => { } if (r.type === "batch-response") { - const notOKs = []; + const errorsForModal = []; const responseStatus = (r as BundleResponse).entry.map((entry) => entry.response.status); if (!responseStatus.toString().startsWith("2")) { const responseIssue = (r as BundleResponse).entry.map((entry) => entry.response.outcome.issue); const issueDiagnostics = responseIssue?.map((issue) => issue?.[0].diagnostics); - notOKs.push([r.resourceType, responseStatus, issueDiagnostics]); + errorsForModal.push([r.resourceType, responseStatus, issueDiagnostics]); // need to make these accessible } + return errorsForModal; } console.debug(`check response: ${JSON.stringify(r, null, 2)}`); From 20b77411a77ae369202cc7f8f072f69d4c9c8394 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 11:35:30 +0100 Subject: [PATCH 09/63] moving fhirURL and related functions to testUtilities --- src/components/reports/ReportForm.test.tsx | 14 +------------- src/fhir/api.test.ts | 1 - src/fhir/testUtilities.ts | 16 ++++++++++++++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index f85c43d..88d213a 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -4,8 +4,7 @@ import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { initialWithNoVariant, noValues } from "./FormDefaults"; import { act } from "react-dom/test-utils"; -import { deletePatients } from "../../fhir/testUtilities"; -import { FHIR_URL } from "../../fhir/api.test"; +import { createPractitioner, deletePatients } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; @@ -155,17 +154,6 @@ describe("Report form", () => { practitioner.identifier = [identifier]; console.log(practitioner); - const createPractitioner = async (practitioner: any) => { - const sendPractitioner = await fetch(`${FHIR_URL}/Practitioner`, { - method: "POST", - body: JSON.stringify(practitioner), - headers: { - "Content-Type": "application/json", - }, - }); - await new Promise((r) => setTimeout(r, 1500)); - return sendPractitioner; - }; createPractitioner(practitioner); createPractitioner(practitioner); diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 16fb408..00f9a81 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -11,7 +11,6 @@ import { sendBundle, deletePatients, getPatients, getObservations } from "./test const fhir = new Fhir(); const reportedGenes = [geneCoding("HGNC:4389", "GNA01")]; -export const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; jest.setTimeout(20000); diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 1606aba..61de707 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -1,6 +1,19 @@ import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { checkResponseOK } from "./api"; -import { FHIR_URL } from "./api.test"; + +const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; + +export const createPractitioner = async (practitioner: any) => { + const sendPractitioner = await fetch(`${FHIR_URL}/Practitioner`, { + method: "POST", + body: JSON.stringify(practitioner), + headers: { + "Content-Type": "application/json", + }, + }); + await new Promise((r) => setTimeout(r, 1500)); + return sendPractitioner; +}; export const sendBundle = async (bundle: Bundle) => { const sentBundle = await fetch(`${FHIR_URL}/`, { @@ -40,7 +53,6 @@ export const deletePatients = async (patientId?: string) => { const patientIds = patientData.entry?.map((entry) => entry.resource?.id) as string[]; await deleteAndCascadeDelete(patientIds); } - // await new Promise((r) => setTimeout(r, 1500)); }; From 7d065ca9885c74a4eb60133159d1e13717c5b388 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 12:04:42 +0100 Subject: [PATCH 10/63] updating fetchMock to be conditional --- src/setupTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setupTests.ts b/src/setupTests.ts index 10d6db4..159c7f8 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -10,7 +10,7 @@ enableFetchMocks(); global.beforeEach(() => { fetchMock.resetMocks(); - fetchMock.mockResponse((request: Request) => { + fetchMock.mockIf(/clinicaltables\.nlm\.nih\.gov\/api\/genes\/v4\/search/, (request: Request) => { let requestData: (number | string[] | string[][] | null)[] = [0, [], null, []]; if (request.url.includes("TW")) { requestData = [2, ["TWO", "TWENTY"], null, [["TWO_SYMBOL"], ["TWENTY_SYMBOL"]]]; From ac7caf5e8f5ef0bb3625c9c0539afe69c28d9801 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 12:09:28 +0100 Subject: [PATCH 11/63] remove not mocking fetch --- src/components/reports/ReportForm.test.tsx | 1 - src/fhir/api.test.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 88d213a..17b4967 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -141,7 +141,6 @@ jest.setTimeout(20000); describe("Report form", () => { beforeEach(async () => { - fetchMock.dontMock(); await deletePatients(); }); diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 00f9a81..4d559d3 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -33,7 +33,6 @@ const getPatientGivenNames = (patientData: Bundle) => { describe("FHIR resources", () => { beforeEach(async () => { - fetchMock.dontMock(); await deletePatients(); }); From 658fbb3b9b0d3f4927a9cb3683357c4ac53e6db7 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 12:11:07 +0100 Subject: [PATCH 12/63] new get/delete practitioners functions --- src/fhir/testUtilities.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 61de707..e4ffc11 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -34,6 +34,13 @@ export const getPatients = async (identifier?: string): Promise => { return await checkResponseOK(response); }; +const getPractitioners = async (id?: string): Promise => { + let url = `${FHIR_URL}/Practitioner`; + if (id) url = `${FHIR_URL}/Practitioner/${id}`; + const response = await fetch(url); + return await checkResponseOK(response); +}; + export const getObservations = async (identifier?: string): Promise => { let url = `${FHIR_URL}/Observation`; if (identifier) url = `${FHIR_URL}/Observation?identifier=${identifier}`; @@ -56,6 +63,20 @@ export const deletePatients = async (patientId?: string) => { // await new Promise((r) => setTimeout(r, 1500)); }; +export const deletePractitioners = async (practitionerId?: string) => { + const practitionerData = await getPractitioners(); + if (!("resource" in practitionerData)) { + console.debug("Nothing to delete; no practitioners in database"); + return; + } + if (practitionerId) { + await deleteAndCascadeDelete([practitionerId]); + } else { + const practitionerIds = practitionerData.entry?.map((entry) => entry.resource?.id) as string[]; + await deleteAndCascadeDelete(practitionerIds); + } +}; + const deleteAndCascadeDelete = async (patientIds: string[]) => { console.debug(`deleting ids: ${patientIds}`); for (const patientId of patientIds) { From 6f06e2abd83e71ac4757edd4a14f2d3952bc0d5c Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 12:12:40 +0100 Subject: [PATCH 13/63] delete patients and practitioners before each test --- src/components/reports/ReportForm.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 17b4967..d090665 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -4,7 +4,7 @@ import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { initialWithNoVariant, noValues } from "./FormDefaults"; import { act } from "react-dom/test-utils"; -import { createPractitioner, deletePatients } from "../../fhir/testUtilities"; +import { createPractitioner, deletePatients, deletePractitioners } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; @@ -142,6 +142,7 @@ jest.setTimeout(20000); describe("Report form", () => { beforeEach(async () => { await deletePatients(); + await deletePractitioners(); }); test("Error modal exists", async () => { From 20a68c9400222ed2a29cc04e7305f2b673811ff9 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 13:04:07 +0100 Subject: [PATCH 14/63] reworked batch-response loop and shuffled process order --- src/fhir/api.ts | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 9115ec3..2ef1215 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -136,7 +136,23 @@ export const checkResponseOK = async (response: Response) => { console.error(r.body); throw new Error(response.statusText); } - if (!(r.type === "bundle-response")) { + if (r.type === "batch-response") { + const errorsForModal: string[] = []; + const errorResponses = (r as BundleResponse).entry + .map((entry) => entry.response) + .filter((response) => !response.status.toString().startsWith("2")); + if (errorResponses.length > 1) { + errorResponses.forEach((error) => { + const errorDetails: any = [ + r.resourceType.toString(), + error.status.toString(), + error.outcome.issue?.[0].diagnostics.toString(), + ]; + errorsForModal.push(errorDetails); //had as string[] but errorDetails claimed it couldn't be assigned to type string + }); + } + return errorsForModal; + } else if (!(r.type === "bundle-response")) { return r; } @@ -154,18 +170,6 @@ export const checkResponseOK = async (response: Response) => { }); } - if (r.type === "batch-response") { - const errorsForModal = []; - const responseStatus = (r as BundleResponse).entry.map((entry) => entry.response.status); - if (!responseStatus.toString().startsWith("2")) { - const responseIssue = (r as BundleResponse).entry.map((entry) => entry.response.outcome.issue); - const issueDiagnostics = responseIssue?.map((issue) => issue?.[0].diagnostics); - - errorsForModal.push([r.resourceType, responseStatus, issueDiagnostics]); // need to make these accessible - } - return errorsForModal; - } - console.debug(`check response: ${JSON.stringify(r, null, 2)}`); return r; }; From a028f521cbc8b1ddfca4793604306a5d8ad70a85 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 14:14:44 +0100 Subject: [PATCH 15/63] new ErrorDetails type --- src/code_systems/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index 18f6209..c1d1820 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -22,6 +22,8 @@ export type BundleResponse = { ]; }; +export type ErrorDetails = [errorCode: string | number, resourceType: string, diagnostics: string]; + /** * FHIR reference with reference and type required. */ From e090ae95c16eafb9abd21282b51d7a89eed0ca0e Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 14:37:23 +0100 Subject: [PATCH 16/63] update checkResponseOK import --- src/fhir/api.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 4d559d3..f3bc52b 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -1,12 +1,12 @@ import { Fhir } from "fhir/fhir"; -import { createBundle, checkResponseOK } from "./api"; +import { createBundle } from "./api"; import { initialValues, initialWithNoVariant } from "../components/reports/FormDefaults"; import { Observation } from "fhir/r4"; import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { sendBundle, deletePatients, getPatients, getObservations } from "./testUtilities"; +import { sendBundle, deletePatients, getPatients, getObservations, checkResponseOK } from "./testUtilities"; const fhir = new Fhir(); From df41716d16bc58d0a7b4ef1e81fb0363b78ba7fa Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 14:41:11 +0100 Subject: [PATCH 17/63] split checkResponseOK - error parsing --- src/fhir/api.ts | 58 ++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 2ef1215..c2868fd 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -16,7 +16,7 @@ import { } from "./resources"; import { VariantSchema } from "../components/reports/formDataValidation"; import { loincResources } from "../code_systems/loincCodes"; -import { BundleResponse, RequiredCoding } from "../code_systems/types"; +import { BundleResponse, ErrorDetails, RequiredCoding } from "../code_systems/types"; /** * Create a report bundle @@ -129,47 +129,21 @@ const createEntry = (resource: Resource, identifier?: string) => { }; }; -export const checkResponseOK = async (response: Response) => { - const r = await response.json(); - - if (!response.ok) { - console.error(r.body); - throw new Error(response.statusText); - } - if (r.type === "batch-response") { - const errorsForModal: string[] = []; - const errorResponses = (r as BundleResponse).entry - .map((entry) => entry.response) - .filter((response) => !response.status.toString().startsWith("2")); - if (errorResponses.length > 1) { - errorResponses.forEach((error) => { - const errorDetails: any = [ - r.resourceType.toString(), - error.status.toString(), - error.outcome.issue?.[0].diagnostics.toString(), - ]; - errorsForModal.push(errorDetails); //had as string[] but errorDetails claimed it couldn't be assigned to type string - }); - } - return errorsForModal; - } else if (!(r.type === "bundle-response")) { - return r; - } - - const errors = (r as BundleResponse).entry - .filter((entry) => entry.response.status.toString().startsWith("4")) - .map((entry) => entry.response.outcome.issue); - - if (errors.length > 1) { - errors.forEach((issue) => { - let message = "unknown error in bundle"; - if (issue && issue.length > 0) { - message = issue[0].diagnostics; - } - throw new Error(message); +export const getErrors = (r: any) => { + //should be result of response.json() + const errorArray: ErrorDetails[] = []; + const errorResponses = (r as BundleResponse).entry + .map((entry) => entry.response) + .filter((response) => !response.status.toString().startsWith("2")); + if (errorResponses.length > 1) { + errorResponses.forEach((error) => { + const errorDetails: ErrorDetails = [ + error.status, + r.resourceType as string, + error.outcome.issue?.[0].diagnostics as string, + ]; + errorArray.push(errorDetails); }); } - - console.debug(`check response: ${JSON.stringify(r, null, 2)}`); - return r; + return errorArray; }; From ea0e4c1da8eba4b5854ba4ebf3f65f4d0f5f02b8 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 15:10:05 +0100 Subject: [PATCH 18/63] updating ErrorDetails type --- src/code_systems/types.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index c1d1820..866a552 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -22,7 +22,11 @@ export type BundleResponse = { ]; }; -export type ErrorDetails = [errorCode: string | number, resourceType: string, diagnostics: string]; +export type ErrorDetails = { + errorCode: string | number; + resourceType: string; + diagnostics: string; +}; /** * FHIR reference with reference and type required. From d8bd73648e591a2bc85ac2794b8775dac3481777 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 15:11:37 +0100 Subject: [PATCH 19/63] update checkResponseOK --- src/fhir/testUtilities.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index e4ffc11..cd10675 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -1,5 +1,5 @@ import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; -import { checkResponseOK } from "./api"; +import { getErrors } from "./api"; const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; @@ -27,6 +27,32 @@ export const sendBundle = async (bundle: Bundle) => { return sentBundle; }; +export const checkResponseOK = async (response: Response) => { + const r = await response.json(); + + if (!response.ok) { + console.error(r.body); + throw new Error(response.statusText); + } + // if (r.type === "batch-response") { + // getErrors(r); + // } else + if (!(r.type === "bundle-response")) { + return r; + } + + const errors = getErrors(r); + if (errors.length > 1) { + errors.forEach((error) => { + const message = error.diagnostics; + throw new Error(message); + }); + } + + console.debug(`check response: ${JSON.stringify(r, null, 2)}`); + return r; +}; + export const getPatients = async (identifier?: string): Promise => { let url = `${FHIR_URL}/Patient`; if (identifier) url = `${FHIR_URL}/Patient?identifier=${identifier}`; From 9638534c58fc3b994b72a71494cf3472f20c766a Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 15:11:52 +0100 Subject: [PATCH 20/63] update getErrors --- src/fhir/api.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index c2868fd..8220122 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -137,11 +137,11 @@ export const getErrors = (r: any) => { .filter((response) => !response.status.toString().startsWith("2")); if (errorResponses.length > 1) { errorResponses.forEach((error) => { - const errorDetails: ErrorDetails = [ - error.status, - r.resourceType as string, - error.outcome.issue?.[0].diagnostics as string, - ]; + const errorDetails: ErrorDetails = { + errorCode: error.status, + resourceType: r.resourceType as string, + diagnostics: error.outcome.issue?.[0].diagnostics as string, + }; errorArray.push(errorDetails); }); } From 6047075c67d04307a4f98c46d0a6d044af31142b Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 15:12:21 +0100 Subject: [PATCH 21/63] making sure to delete all practitioners in fhir api tests (precaution) --- src/fhir/api.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index f3bc52b..1f647ef 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,7 +6,14 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { sendBundle, deletePatients, getPatients, getObservations, checkResponseOK } from "./testUtilities"; +import { + sendBundle, + deletePatients, + getPatients, + getObservations, + checkResponseOK, + deletePractitioners, +} from "./testUtilities"; const fhir = new Fhir(); @@ -34,6 +41,7 @@ const getPatientGivenNames = (patientData: Bundle) => { describe("FHIR resources", () => { beforeEach(async () => { await deletePatients(); + await deletePractitioners(); }); /** From 9025081c9ceacee3864ef72d1f85e67b863beef6 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 15:38:50 +0100 Subject: [PATCH 22/63] updating deleteAndCascadeDelete to take a resource parameter --- src/fhir/testUtilities.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index cd10675..5f2dd14 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -81,10 +81,10 @@ export const deletePatients = async (patientId?: string) => { return; } if (patientId) { - await deleteAndCascadeDelete([patientId]); + await deleteAndCascadeDelete([patientId], "Patient"); } else { const patientIds = patientData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(patientIds); + await deleteAndCascadeDelete(patientIds, "Patient"); } // await new Promise((r) => setTimeout(r, 1500)); }; @@ -96,17 +96,17 @@ export const deletePractitioners = async (practitionerId?: string) => { return; } if (practitionerId) { - await deleteAndCascadeDelete([practitionerId]); + await deleteAndCascadeDelete([practitionerId], "Practitioner"); } else { const practitionerIds = practitionerData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(practitionerIds); + await deleteAndCascadeDelete(practitionerIds, "Practitioner"); } }; -const deleteAndCascadeDelete = async (patientIds: string[]) => { - console.debug(`deleting ids: ${patientIds}`); - for (const patientId of patientIds) { - const response = await fetch(`${FHIR_URL}/Patient/${patientId}?_cascade=delete`, { +const deleteAndCascadeDelete = async (identifiers: string[], resource: string) => { + console.debug(`deleting ids: ${identifiers}`); + for (const id of identifiers) { + const response = await fetch(`${FHIR_URL}/${resource}/${id}?_cascade=delete`, { method: "DELETE", }); await checkResponseOK(response); From 60aeb768b683f6e8a63a43b8ad5a6be8b9eb8941 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Fri, 14 Oct 2022 16:35:49 +0100 Subject: [PATCH 23/63] fixed practitioners not deleting --- src/fhir/testUtilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 5f2dd14..7b3ef68 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -91,7 +91,7 @@ export const deletePatients = async (patientId?: string) => { export const deletePractitioners = async (practitionerId?: string) => { const practitionerData = await getPractitioners(); - if (!("resource" in practitionerData)) { + if (!("entry" in practitionerData)) { console.debug("Nothing to delete; no practitioners in database"); return; } From bc15ac29335596aba39caabbf08b8b09f113f414 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 13:19:58 +0100 Subject: [PATCH 24/63] new deleteFhirData and getResources functions --- src/fhir/testUtilities.ts | 43 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 7b3ef68..604a8ce 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -60,18 +60,45 @@ export const getPatients = async (identifier?: string): Promise => { return await checkResponseOK(response); }; -const getPractitioners = async (id?: string): Promise => { - let url = `${FHIR_URL}/Practitioner`; - if (id) url = `${FHIR_URL}/Practitioner/${id}`; +// const getPractitioners = async (id?: string): Promise => { +// let url = `${FHIR_URL}/Practitioner`; +// if (id) url = `${FHIR_URL}/Practitioner/${id}`; +// const response = await fetch(url); +// return await checkResponseOK(response); +// }; + +export const getResources = async (resource: string, id?: string): Promise => { + let url = `${FHIR_URL}/${resource}`; + if (id) { + if (resource === "Practitioner") { + url = `${FHIR_URL}/Practitioner/${id}`; + } + url = `${FHIR_URL}/${resource}?identifier=${id}`; + } const response = await fetch(url); return await checkResponseOK(response); }; -export const getObservations = async (identifier?: string): Promise => { - let url = `${FHIR_URL}/Observation`; - if (identifier) url = `${FHIR_URL}/Observation?identifier=${identifier}`; - const response = await fetch(url); - return await checkResponseOK(response); +export const deleteFhirData = async (resource?: string, id?: string) => { + let resources = [resource]; + + if (!resource) { + resources = ["Patient", "Practitioner"]; + } + for (const r of resources) { + const fhirData = await getResources(r as string); + if (!("entry" in fhirData)) { + console.debug("Nothing to delete; no data in database"); + return; + } + if (id) { + await deleteAndCascadeDelete([id], r as string); + } else { + const resourceId = fhirData.entry?.map((entry) => entry.resource?.id) as string[]; + await deleteAndCascadeDelete(resourceId, r as string); + } + } + await new Promise((response) => setTimeout(response, 500)); }; export const deletePatients = async (patientId?: string) => { From 998114b86e5ad8fb20effafc94e964da0c9fc887 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 13:20:49 +0100 Subject: [PATCH 25/63] updating api tests for new functions nb: the timing for the clearing/checking might need to be tinkered with --- src/fhir/api.test.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 1f647ef..1340cec 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,14 +6,7 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { - sendBundle, - deletePatients, - getPatients, - getObservations, - checkResponseOK, - deletePractitioners, -} from "./testUtilities"; +import { sendBundle, getPatients, checkResponseOK, deleteFhirData, getResources } from "./testUtilities"; const fhir = new Fhir(); @@ -40,8 +33,8 @@ const getPatientGivenNames = (patientData: Bundle) => { describe("FHIR resources", () => { beforeEach(async () => { - await deletePatients(); - await deletePractitioners(); + await deleteFhirData(); + await new Promise((r) => setTimeout(r, 1500)); }); /** @@ -85,7 +78,7 @@ describe("FHIR resources", () => { // check it has the expected profile await sendBundle(bundle); const expectedProfile = "http://hl7.org/fhir/uv/genomics-reporting/StructureDefinition/variant"; - const obsResponse = await getObservations(); + const obsResponse = await getResources("Observation"); const varProfile = (obsResponse.entry as Array) .filter((entry) => entry.resource?.resourceType === "Observation") @@ -102,7 +95,7 @@ describe("FHIR resources", () => { test("Bundle without variants", async () => { const bundle = createBundle(initialWithNoVariant, []); await sendBundle(bundle); - const obsResponse = await getObservations(); + const obsResponse = await getResources("Observation"); // null variant entry const variantNotes = (obsResponse.entry as Array) From 8959f02ba983bb9c3fc0f61a21125d7bbbde339a Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 13:29:19 +0100 Subject: [PATCH 26/63] using new deleteFhirData function --- src/components/reports/ReportForm.test.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index d090665..c752fbe 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -4,7 +4,7 @@ import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { initialWithNoVariant, noValues } from "./FormDefaults"; import { act } from "react-dom/test-utils"; -import { createPractitioner, deletePatients, deletePractitioners } from "../../fhir/testUtilities"; +import { createPractitioner, deleteFhirData } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; @@ -141,8 +141,7 @@ jest.setTimeout(20000); describe("Report form", () => { beforeEach(async () => { - await deletePatients(); - await deletePractitioners(); + deleteFhirData(); }); test("Error modal exists", async () => { @@ -167,7 +166,7 @@ describe("Report form", () => { }); // Assert - const modal = await screen.findByRole("modal"); + const modal = await screen.findByTitle("modal"); expect(modal).toContain("error"); }); /** From 0510b209db5a86f7bc4f2eee42eab7d095d2e24b Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 13:29:44 +0100 Subject: [PATCH 27/63] updating getPatients to getResources --- src/fhir/api.test.ts | 10 +++++----- src/fhir/testUtilities.ts | 36 ------------------------------------ 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index 1340cec..b1c6993 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,7 +6,7 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { sendBundle, getPatients, checkResponseOK, deleteFhirData, getResources } from "./testUtilities"; +import { sendBundle, checkResponseOK, deleteFhirData, getResources } from "./testUtilities"; const fhir = new Fhir(); @@ -41,7 +41,7 @@ describe("FHIR resources", () => { * Before doing tests on the database, we want to clear all its data */ test("database is clear on setup", async () => { - const postDelete = await getPatients(); + const postDelete = await getResources("Patient"); expect("entry" in postDelete).toBeFalsy(); }); @@ -57,7 +57,7 @@ describe("FHIR resources", () => { // check it's the right patient await checkResponseOK(createPatient); - const patientData = await getPatients(); + const patientData = await getResources("Patient"); expect("entry" in patientData).toBeTruthy(); expect(getPatientIdentifier(patientData)).toEqual(initialValues.patient.mrn); }); @@ -125,14 +125,14 @@ describe("FHIR resources", () => { const originalBundle = createBundle(initialValues, reportedGenes); await sendBundle(originalBundle); - const originalPatient = await getPatients(identifier); + const originalPatient = await getResources("Patient", identifier); const newValues = { ...initialValues }; newValues.patient.firstName = "Daffy"; const updatedBundle = createBundle(newValues, reportedGenes); await sendBundle(updatedBundle); - const updatedPatient = await getPatients(identifier); + const updatedPatient = await getResources("Patient", identifier); // check it's the right patient by identifier expect(getPatientIdentifier(originalPatient)).toEqual(getPatientIdentifier(updatedPatient)); expect(getPatientIdentifier(originalPatient)).toEqual(initialValues.patient.mrn); diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 604a8ce..d4bda92 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -60,13 +60,6 @@ export const getPatients = async (identifier?: string): Promise => { return await checkResponseOK(response); }; -// const getPractitioners = async (id?: string): Promise => { -// let url = `${FHIR_URL}/Practitioner`; -// if (id) url = `${FHIR_URL}/Practitioner/${id}`; -// const response = await fetch(url); -// return await checkResponseOK(response); -// }; - export const getResources = async (resource: string, id?: string): Promise => { let url = `${FHIR_URL}/${resource}`; if (id) { @@ -101,35 +94,6 @@ export const deleteFhirData = async (resource?: string, id?: string) => { await new Promise((response) => setTimeout(response, 500)); }; -export const deletePatients = async (patientId?: string) => { - const patientData = await getPatients(); - if (!("entry" in patientData)) { - console.debug("Nothing to delete; no patients in database"); - return; - } - if (patientId) { - await deleteAndCascadeDelete([patientId], "Patient"); - } else { - const patientIds = patientData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(patientIds, "Patient"); - } - // await new Promise((r) => setTimeout(r, 1500)); -}; - -export const deletePractitioners = async (practitionerId?: string) => { - const practitionerData = await getPractitioners(); - if (!("entry" in practitionerData)) { - console.debug("Nothing to delete; no practitioners in database"); - return; - } - if (practitionerId) { - await deleteAndCascadeDelete([practitionerId], "Practitioner"); - } else { - const practitionerIds = practitionerData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(practitionerIds, "Practitioner"); - } -}; - const deleteAndCascadeDelete = async (identifiers: string[], resource: string) => { console.debug(`deleting ids: ${identifiers}`); for (const id of identifiers) { From ec5d7026bb257e60d2acdad6fd743bcbea0a6458 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 15:15:47 +0100 Subject: [PATCH 28/63] updating error modal test --- src/components/reports/ReportForm.test.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index c752fbe..f93748d 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -141,7 +141,7 @@ jest.setTimeout(20000); describe("Report form", () => { beforeEach(async () => { - deleteFhirData(); + await deleteFhirData(); }); test("Error modal exists", async () => { @@ -151,23 +151,25 @@ describe("Report form", () => { practitioner.resourceType = "Practitioner"; const identifier = createIdentifier("anapietra_report"); practitioner.identifier = [identifier]; - console.log(practitioner); - createPractitioner(practitioner); - createPractitioner(practitioner); + await createPractitioner(practitioner); + await createPractitioner(practitioner); // Act await setLabAndPatient(); await setSample(); await setVariantFields(); await setReportFields(); + await act(async () => { userEvent.click(screen.getByText(/submit/i)); }); // Assert - const modal = await screen.findByTitle("modal"); - expect(modal).toContain("error"); + const debug = screen.debug(); + console.log(debug); + const errorModal = await screen.findByText(/add a new report/i); + expect(errorModal).toBeInTheDocument(); }); /** * Given the report form From f8000a96dd6e51a7ec03d3dec715197e18d3381f Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 15:25:28 +0100 Subject: [PATCH 29/63] trying jsx rendering --- src/components/reports/ReportForm.test.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index f93748d..b5f4be1 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -7,6 +7,7 @@ import { act } from "react-dom/test-utils"; import { createPractitioner, deleteFhirData } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; +import { FhirProvider } from "../fhir/FhirContext"; const clearAndType = (element: Element, value: string) => { userEvent.clear(element); @@ -146,7 +147,13 @@ describe("Report form", () => { test("Error modal exists", async () => { // Arrange - render(); + render( + <> +
+ + + , + ); const practitioner = new Practitioner(); practitioner.resourceType = "Practitioner"; const identifier = createIdentifier("anapietra_report"); @@ -168,7 +175,7 @@ describe("Report form", () => { // Assert const debug = screen.debug(); console.log(debug); - const errorModal = await screen.findByText(/add a new report/i); + const errorModal = await screen.findByText(/error/i); expect(errorModal).toBeInTheDocument(); }); /** From 2dce62da9df6f0eaf55fba5b336e57bc2bdb1aec Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 16:57:13 +0100 Subject: [PATCH 30/63] cleaning up checkResponseOK usage --- src/fhir/api.test.ts | 5 ++--- src/fhir/testUtilities.ts | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index b1c6993..bfec727 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,7 +6,7 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { sendBundle, checkResponseOK, deleteFhirData, getResources } from "./testUtilities"; +import { sendBundle, deleteFhirData, getResources } from "./testUtilities"; const fhir = new Fhir(); @@ -53,10 +53,9 @@ describe("FHIR resources", () => { test("bundle creates patient", async () => { const bundle = createBundle(initialValues, reportedGenes); - const createPatient = await sendBundle(bundle); + await sendBundle(bundle); // check it's the right patient - await checkResponseOK(createPatient); const patientData = await getResources("Patient"); expect("entry" in patientData).toBeTruthy(); expect(getPatientIdentifier(patientData)).toEqual(initialValues.patient.mrn); diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index d4bda92..99178b9 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -12,7 +12,7 @@ export const createPractitioner = async (practitioner: any) => { }, }); await new Promise((r) => setTimeout(r, 1500)); - return sendPractitioner; + return checkResponseOK(sendPractitioner); }; export const sendBundle = async (bundle: Bundle) => { @@ -24,10 +24,10 @@ export const sendBundle = async (bundle: Bundle) => { }, }); await new Promise((r) => setTimeout(r, 1500)); - return sentBundle; + return checkResponseOK(sentBundle); }; -export const checkResponseOK = async (response: Response) => { +const checkResponseOK = async (response: Response) => { const r = await response.json(); if (!response.ok) { From 302aa55c0319477601d046d3bde30248180cb678 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 17 Oct 2022 16:57:37 +0100 Subject: [PATCH 31/63] updating error modal to have table of errors --- src/components/UI/ModalWrapper.tsx | 6 ++--- src/components/reports/ReportForm.tsx | 32 +++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/components/UI/ModalWrapper.tsx b/src/components/UI/ModalWrapper.tsx index 131139c..68d591e 100644 --- a/src/components/UI/ModalWrapper.tsx +++ b/src/components/UI/ModalWrapper.tsx @@ -4,14 +4,14 @@ import Modal from "./Modal"; import classes from "./Modal.module.css"; export interface ModalState { - message: string | null | undefined; + message: string | JSX.Element | null | undefined; isError: boolean | null | undefined; } export interface Props { onClear: () => void; isError: boolean | null | undefined; - modalMessage: string | null | undefined; + modalMessage: string | JSX.Element | null | undefined; } const ModalWrapper: FC = (props: Props) => { @@ -31,7 +31,7 @@ const ModalWrapper: FC = (props: Props) => { } > -

{modalMessage}

+

{modalMessage}

); }; diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index 07fbc3e..d01d709 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -6,7 +6,7 @@ import { FhirContext } from "../fhir/FhirContext"; import Card from "../UI/Card"; import classes from "./ReportForm.module.css"; import { addressSchema, patientSchema, reportDetailSchema, sampleSchema, variantsSchema } from "./formDataValidation"; -import { bundleRequest } from "../../fhir/api"; +import { bundleRequest, getErrors } from "../../fhir/api"; import Patient from "./formSteps/Patient"; import Sample from "./formSteps/Sample"; import Variant from "./formSteps/Variant"; @@ -66,7 +66,35 @@ const ReportForm: FC = (props: Props) => { ctx.client ?.request(bundle) - .then((response) => console.debug("Bundle submitted", bundle, response)) + .then((response) => { + console.debug("Bundle submitted", bundle, response); + const errors = getErrors(response); + if (errors) { + const errorsTable = () => { + return ( + <> + + + + + + + + {errors.map((error) => ( + + + + + + ))} + +
CodeResourceInformation
{error.errorCode}{error.resourceType}{error.diagnostics}
+ + ); + }; + setModal({ message: errorsTable(), isError: true }); + } + }) .catch((error) => { console.error(error); setModal({ From 77aec38bcde36d90de941273a72de01f0b782c46 Mon Sep 17 00:00:00 2001 From: Stef Piatek Date: Tue, 18 Oct 2022 10:51:45 +0100 Subject: [PATCH 32/63] Update dev fhir docker image and use h2 database --- docker-compose.dev.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index afd3c2d..78f037f 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,29 +1,12 @@ version: "3.7" services: fhir: - image: "hapiproject/hapi:v5.6.0" + image: "hapiproject/hapi:v6.1.0" ports: - "8090:8080" environment: - spring.datasource.url: "jdbc:postgresql://fhir-db:5432/hapi_r4" - spring.datasource.username: admin - spring.datasource.password: admin - spring.datasource.driverClassName: org.postgresql.Driver - hapi.fhir.subscription.resthook_enabled: "true" - hapi.fhir.subscription.websocket_enabled: "true" hapi.fhir.client_id_strategy: ANY hapi.fhir.cors.allowed_origin: "*" hapi.fhir.fhir_version: R4 hapi.fhir.allow_cascading_deletes: "true" hapi.fhir.reuse_cached_search_results_millis: -1 - fhir-db: - image: postgres:latest - volumes: - - fhir-db-data:/var/lib/postgresql/data - environment: - POSTGRES_PASSWORD: admin - POSTGRES_USER: admin - POSTGRES_DB: hapi_r4 - -volumes: - fhir-db-data: From 3b761b84ba0be28eefe1b8809608554dfa9ea7b8 Mon Sep 17 00:00:00 2001 From: Stef Piatek Date: Tue, 18 Oct 2022 10:52:14 +0100 Subject: [PATCH 33/63] Run tests sequentially to avoid fhir conflicts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9091016..308a11f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "build": "react-scripts build", "predeploy": "react-scripts build && cp build/index.html build/404.html", "deploy": "COMMIT_MSG=$(git log -1 --pretty=%B | sed 's/ /_/g'); gh-pages -d build --message ${COMMIT_MSG}", - "test": "react-scripts test", + "test": "react-scripts test --runInBand", "eject": "react-scripts eject", "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, From 0bb0337180501a006342caf45694ae1f747c041b Mon Sep 17 00:00:00 2001 From: Stef Piatek Date: Tue, 18 Oct 2022 10:54:02 +0100 Subject: [PATCH 34/63] Update fhir api testing for modal --- src/components/reports/ReportForm.test.tsx | 14 +++--- src/fhir/api.test.ts | 8 ++-- .../{testUtilities.ts => testUtilities.tsx} | 48 +++++++++++++++---- 3 files changed, 48 insertions(+), 22 deletions(-) rename src/fhir/{testUtilities.ts => testUtilities.tsx} (67%) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index c752fbe..4c0919a 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -1,10 +1,8 @@ -import ReportForm from "./ReportForm"; import { render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; -import { initialWithNoVariant, noValues } from "./FormDefaults"; import { act } from "react-dom/test-utils"; -import { createPractitioner, deleteFhirData } from "../../fhir/testUtilities"; +import { createPractitioner, deleteFhirData, TestReportForm } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; @@ -19,7 +17,7 @@ type DropDown = { }; const setDummyValues = (withDates: boolean, dropDowns?: DropDown[]) => { - const dummyValue = "Always the same"; + const dummyValue = "Always_the_same"; const form = screen.getByRole("form"); const textInputs = within(form).getAllByLabelText( /^((?!resultOutput|date|address|gender|specimen type|search|gene symbol|follow up).)*$/i, @@ -146,10 +144,9 @@ describe("Report form", () => { test("Error modal exists", async () => { // Arrange - render(); const practitioner = new Practitioner(); practitioner.resourceType = "Practitioner"; - const identifier = createIdentifier("anapietra_report"); + const identifier = createIdentifier("always_the_same_report"); practitioner.identifier = [identifier]; console.log(practitioner); @@ -157,6 +154,7 @@ describe("Report form", () => { createPractitioner(practitioner); // Act + render(); await setLabAndPatient(); await setSample(); await setVariantFields(); @@ -176,7 +174,7 @@ describe("Report form", () => { */ test("Report with variant", async () => { // Arrange - render(); + render(); // Act await setLabAndPatient(); @@ -199,7 +197,7 @@ describe("Report form", () => { */ test("Report without variant", async () => { // Arrange - render(); + render(); // Act await setLabAndPatient(); diff --git a/src/fhir/api.test.ts b/src/fhir/api.test.ts index b1c6993..0389a1c 100644 --- a/src/fhir/api.test.ts +++ b/src/fhir/api.test.ts @@ -6,7 +6,7 @@ import { geneCoding } from "../code_systems/hgnc"; import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { BundleEntry } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/models-r4"; -import { sendBundle, checkResponseOK, deleteFhirData, getResources } from "./testUtilities"; +import { deleteFhirData, getResources, sendBundle } from "./testUtilities"; const fhir = new Fhir(); @@ -32,9 +32,8 @@ const getPatientGivenNames = (patientData: Bundle) => { }; describe("FHIR resources", () => { - beforeEach(async () => { - await deleteFhirData(); - await new Promise((r) => setTimeout(r, 1500)); + beforeEach(() => { + return deleteFhirData(); }); /** @@ -56,7 +55,6 @@ describe("FHIR resources", () => { const createPatient = await sendBundle(bundle); // check it's the right patient - await checkResponseOK(createPatient); const patientData = await getResources("Patient"); expect("entry" in patientData).toBeTruthy(); expect(getPatientIdentifier(patientData)).toEqual(initialValues.patient.mrn); diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.tsx similarity index 67% rename from src/fhir/testUtilities.ts rename to src/fhir/testUtilities.tsx index d4bda92..cf23a86 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.tsx @@ -1,5 +1,14 @@ import { Bundle } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/bundle"; import { getErrors } from "./api"; +import { FhirContext } from "../components/fhir/FhirContext"; +import ReportForm from "../components/reports/ReportForm"; +import { noValues } from "../components/reports/FormDefaults"; +import FHIR from "fhirclient/lib/entry/browser"; +import React from "react"; + +/** + * Utilities to be used only during testing, no actual tests here. + */ const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; @@ -11,8 +20,8 @@ export const createPractitioner = async (practitioner: any) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 1500)); - return sendPractitioner; + await new Promise((r) => setTimeout(r, 100)); + return checkResponseOK(sendPractitioner); }; export const sendBundle = async (bundle: Bundle) => { @@ -23,15 +32,15 @@ export const sendBundle = async (bundle: Bundle) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 1500)); - return sentBundle; + await new Promise((r) => setTimeout(r, 100)); + return checkResponseOK(sentBundle); }; export const checkResponseOK = async (response: Response) => { const r = await response.json(); if (!response.ok) { - console.error(r.body); + console.error(JSON.stringify(r)); throw new Error(response.statusText); } // if (r.type === "batch-response") { @@ -81,8 +90,8 @@ export const deleteFhirData = async (resource?: string, id?: string) => { for (const r of resources) { const fhirData = await getResources(r as string); if (!("entry" in fhirData)) { - console.debug("Nothing to delete; no data in database"); - return; + console.debug(`No ${r} to delete`); + continue; } if (id) { await deleteAndCascadeDelete([id], r as string); @@ -91,15 +100,36 @@ export const deleteFhirData = async (resource?: string, id?: string) => { await deleteAndCascadeDelete(resourceId, r as string); } } - await new Promise((response) => setTimeout(response, 500)); }; const deleteAndCascadeDelete = async (identifiers: string[], resource: string) => { - console.debug(`deleting ids: ${identifiers}`); + console.debug(`deleting ${identifiers.length}x ids of resource '${resource}'`); for (const id of identifiers) { const response = await fetch(`${FHIR_URL}/${resource}/${id}?_cascade=delete`, { method: "DELETE", }); await checkResponseOK(response); + await new Promise((r) => setTimeout(r, 100)); } }; + +/** + * Report Form setup for testing of the modal output. + * + * Contains hooks for displaying the modal and the fhir client context being set. + * @constructor + */ +export const TestReportForm: React.FC = () => { + const client = FHIR.client(FHIR_URL); + + return ( + <> +
+ +
+ "" }}> + + + + ); +}; From adecd2b5248aa94a447d30aa509c8eb4b3cdf500 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 16:24:40 +0100 Subject: [PATCH 35/63] error modal shows correct resource type --- src/components/UI/ModalWrapper.tsx | 2 +- src/components/reports/ReportForm.tsx | 30 +++++++++++++++++--------- src/fhir/api.ts | 31 ++++++++++++++++----------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/components/UI/ModalWrapper.tsx b/src/components/UI/ModalWrapper.tsx index 68d591e..f881a70 100644 --- a/src/components/UI/ModalWrapper.tsx +++ b/src/components/UI/ModalWrapper.tsx @@ -31,7 +31,7 @@ const ModalWrapper: FC = (props: Props) => { } > -

{modalMessage}

+
{modalMessage}
); }; diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index d01d709..703d28e 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -63,25 +63,35 @@ const ReportForm: FC = (props: Props) => { const bundle = bundleRequest(values, reportedGenes); setResult(JSON.stringify(JSON.parse(bundle.body), null, 2)); + const resourceList = JSON.parse(bundle.body).entry.map((entry: any) => entry.resource.resourceType); ctx.client ?.request(bundle) .then((response) => { console.debug("Bundle submitted", bundle, response); - const errors = getErrors(response); - if (errors) { + const errors = getErrors(response, resourceList); + if (errors.length > 1) { const errorsTable = () => { + //originally had this in ReportForm.module.css but didn't work? + const css = ` + .errors-table { + font: inherit; + font-size: 86%; + }`; return ( <> - - - - - + +
CodeResourceInformation
+ + + + + + - - {errors.map((error) => ( - + + {errors.map((error, i) => ( + diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 8220122..c9cf470 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -129,21 +129,26 @@ const createEntry = (resource: Resource, identifier?: string) => { }; }; -export const getErrors = (r: any) => { +export const getErrors = (r: any, resourceTypes?: string[]) => { //should be result of response.json() const errorArray: ErrorDetails[] = []; - const errorResponses = (r as BundleResponse).entry - .map((entry) => entry.response) - .filter((response) => !response.status.toString().startsWith("2")); - if (errorResponses.length > 1) { - errorResponses.forEach((error) => { - const errorDetails: ErrorDetails = { - errorCode: error.status, - resourceType: r.resourceType as string, - diagnostics: error.outcome.issue?.[0].diagnostics as string, - }; - errorArray.push(errorDetails); - }); + const errorResponses = []; + let count = 0; + for (const entry of r.entry) { + if (!entry.response.status.toString().startsWith("2")) { + entry.count = count; + errorResponses.push(entry); + } + count++; } + errorResponses.forEach((error) => { + const errorDetails: ErrorDetails = { + errorCode: error.response.status, + resourceType: resourceTypes?.[error.count] as string, + diagnostics: error.response.outcome.issue?.[0].diagnostics as string, + }; + errorArray.push(errorDetails); + }); + return errorArray; }; From 2f608a866623773605af0f979ea6beb6512ab0a5 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 16:24:56 +0100 Subject: [PATCH 36/63] cleaning up test utils --- src/fhir/testUtilities.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/fhir/testUtilities.ts b/src/fhir/testUtilities.ts index 99178b9..7ed7b78 100644 --- a/src/fhir/testUtilities.ts +++ b/src/fhir/testUtilities.ts @@ -23,24 +23,20 @@ export const sendBundle = async (bundle: Bundle) => { "Content-Type": "application/json", }, }); + await new Promise((r) => setTimeout(r, 1500)); return checkResponseOK(sentBundle); }; const checkResponseOK = async (response: Response) => { const r = await response.json(); - if (!response.ok) { console.error(r.body); throw new Error(response.statusText); } - // if (r.type === "batch-response") { - // getErrors(r); - // } else if (!(r.type === "bundle-response")) { return r; } - const errors = getErrors(r); if (errors.length > 1) { errors.forEach((error) => { @@ -53,13 +49,6 @@ const checkResponseOK = async (response: Response) => { return r; }; -export const getPatients = async (identifier?: string): Promise => { - let url = `${FHIR_URL}/Patient`; - if (identifier) url = `${FHIR_URL}/Patient?identifier=${identifier}`; - const response = await fetch(url); - return await checkResponseOK(response); -}; - export const getResources = async (resource: string, id?: string): Promise => { let url = `${FHIR_URL}/${resource}`; if (id) { From 6366701611396a6e05417a206434e00efaec75fe Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 16:39:01 +0100 Subject: [PATCH 37/63] cleaning up imports --- src/fhir/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fhir/api.ts b/src/fhir/api.ts index c9cf470..b624c76 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -16,7 +16,7 @@ import { } from "./resources"; import { VariantSchema } from "../components/reports/formDataValidation"; import { loincResources } from "../code_systems/loincCodes"; -import { BundleResponse, ErrorDetails, RequiredCoding } from "../code_systems/types"; +import { ErrorDetails, RequiredCoding } from "../code_systems/types"; /** * Create a report bundle From 1aa338d9e06716295eaaaefc7c342f3743e5593f Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 16:44:03 +0100 Subject: [PATCH 38/63] increasing timeout to help ci --- src/fhir/testUtilities.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fhir/testUtilities.tsx b/src/fhir/testUtilities.tsx index 039edef..617eb13 100644 --- a/src/fhir/testUtilities.tsx +++ b/src/fhir/testUtilities.tsx @@ -20,7 +20,7 @@ export const createPractitioner = async (practitioner: any) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 100)); + await new Promise((r) => setTimeout(r, 500)); return checkResponseOK(sendPractitioner); }; @@ -32,7 +32,7 @@ export const sendBundle = async (bundle: Bundle) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 100)); + await new Promise((r) => setTimeout(r, 500)); return checkResponseOK(sentBundle); }; @@ -97,7 +97,7 @@ const deleteAndCascadeDelete = async (identifiers: string[], resource: string) = method: "DELETE", }); await checkResponseOK(response); - await new Promise((r) => setTimeout(r, 100)); + await new Promise((r) => setTimeout(r, 500)); } }; From f75f290661e7bcb5a114708948f8bda2dfdf602e Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 16:50:28 +0100 Subject: [PATCH 39/63] removing timeouts to see if that helps the socket --- src/fhir/testUtilities.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fhir/testUtilities.tsx b/src/fhir/testUtilities.tsx index 617eb13..34261af 100644 --- a/src/fhir/testUtilities.tsx +++ b/src/fhir/testUtilities.tsx @@ -20,7 +20,7 @@ export const createPractitioner = async (practitioner: any) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 500)); + // await new Promise((r) => setTimeout(r, 500)); return checkResponseOK(sendPractitioner); }; @@ -32,7 +32,7 @@ export const sendBundle = async (bundle: Bundle) => { "Content-Type": "application/json", }, }); - await new Promise((r) => setTimeout(r, 500)); + // await new Promise((r) => setTimeout(r, 500)); return checkResponseOK(sentBundle); }; @@ -97,7 +97,7 @@ const deleteAndCascadeDelete = async (identifiers: string[], resource: string) = method: "DELETE", }); await checkResponseOK(response); - await new Promise((r) => setTimeout(r, 500)); + // await new Promise((r) => setTimeout(r, 500)); } }; From 2a80f6818b61abe7bfd36e838552e155735a922b Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn <72266023+acholyn@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:12:45 +0100 Subject: [PATCH 40/63] add h2 selector Co-authored-by: Stefan Piatek --- src/components/reports/ReportForm.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 27ce88d..39ac298 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -166,7 +166,7 @@ describe("Report form", () => { // Assert const debug = screen.debug(); console.log(debug); - const errorModal = await screen.findByText(/error/i); + const errorModal = await screen.findByText(/error/i, { selector: "h2" }); expect(errorModal).toBeInTheDocument(); }); /** From f38c4a326a884c0271808f3692da0407581de168 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn <72266023+acholyn@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:13:01 +0100 Subject: [PATCH 41/63] Update src/components/reports/ReportForm.tsx Co-authored-by: Stefan Piatek --- src/components/reports/ReportForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index 703d28e..15e3179 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -70,7 +70,7 @@ const ReportForm: FC = (props: Props) => { .then((response) => { console.debug("Bundle submitted", bundle, response); const errors = getErrors(response, resourceList); - if (errors.length > 1) { + if (errors.length > 0) { const errorsTable = () => { //originally had this in ReportForm.module.css but didn't work? const css = ` From e24c98f289887f6843b6e0de2f2dbfca42ea04d6 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn <72266023+acholyn@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:13:23 +0100 Subject: [PATCH 42/63] Update src/code_systems/types.ts Co-authored-by: Stefan Piatek --- src/code_systems/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index 866a552..5276b2c 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -23,7 +23,7 @@ export type BundleResponse = { }; export type ErrorDetails = { - errorCode: string | number; + errorCode: string; resourceType: string; diagnostics: string; }; From ddb8056447158f9cb2fb8bf09bbbf071713446b5 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 17:18:34 +0100 Subject: [PATCH 43/63] return not await deleteFhirData --- src/components/reports/ReportForm.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 39ac298..6f81ecb 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -138,8 +138,8 @@ const setReportFields = async () => { jest.setTimeout(20000); describe("Report form", () => { - beforeEach(async () => { - await deleteFhirData(); + beforeEach(() => { + return deleteFhirData(); }); test("Error modal exists", async () => { From 24ed321e3590fb3ccd1c73f06dd0752b4041aa77 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 17:19:33 +0100 Subject: [PATCH 44/63] remove debug lines --- src/components/reports/ReportForm.test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 6f81ecb..56a3f3f 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -164,8 +164,6 @@ describe("Report form", () => { }); // Assert - const debug = screen.debug(); - console.log(debug); const errorModal = await screen.findByText(/error/i, { selector: "h2" }); expect(errorModal).toBeInTheDocument(); }); From ceb8b83063e4697af36177f51d232495e9de0860 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 17:39:51 +0100 Subject: [PATCH 45/63] giving Fhir more time --- .github/workflows/test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b73aa2..f8684f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,9 +2,9 @@ name: Tests on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: test_fsh: @@ -16,7 +16,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: 17 - cache: 'npm' + cache: "npm" - name: Install sushi run: npm install -g fsh-sushi - name: Run sushi @@ -27,11 +27,13 @@ jobs: steps: - name: Checkout Repo uses: actions/checkout@v3 + - name: Run fake FHIR in docker + run: docker-compose -f docker-compose.dev.yml up -d - name: Use Node and enable cache uses: actions/setup-node@v3 with: node-version: 17 - cache: 'npm' + cache: "npm" - name: Install dependencies run: | npm ci @@ -39,8 +41,6 @@ jobs: run: npm run lint - name: Setup .env file run: cp env/dev.env .env - - name: Run fake FHIR in docker - run: docker-compose -f docker-compose.dev.yml up -d - name: npm build run: npm run build --if-present - name: npm test From eb1a3cf2f51c8818bb8d079a7f3fb20948535bb2 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 18 Oct 2022 18:07:46 +0100 Subject: [PATCH 46/63] new type for retrievable resources --- src/code_systems/types.ts | 1 + src/fhir/testUtilities.tsx | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index 5276b2c..b0337b8 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -27,6 +27,7 @@ export type ErrorDetails = { resourceType: string; diagnostics: string; }; +export type RetrievableResource = "Practitioner" | "Patient" | "Observation"; /** * FHIR reference with reference and type required. diff --git a/src/fhir/testUtilities.tsx b/src/fhir/testUtilities.tsx index 34261af..6dbecbc 100644 --- a/src/fhir/testUtilities.tsx +++ b/src/fhir/testUtilities.tsx @@ -5,6 +5,7 @@ import ReportForm from "../components/reports/ReportForm"; import { noValues } from "../components/reports/FormDefaults"; import FHIR from "fhirclient/lib/entry/browser"; import React from "react"; +import { RetrievableResource } from "../code_systems/types"; /** * Utilities to be used only during testing, no actual tests here. @@ -52,12 +53,14 @@ const checkResponseOK = async (response: Response) => { throw new Error(message); }); } - console.debug(`check response: ${JSON.stringify(r, null, 2)}`); return r; }; -export const getResources = async (resource: string, id?: string): Promise => { +export const getResources = async ( + resource: "Practitioner" | "Patient" | "Observation", + id?: string, +): Promise => { let url = `${FHIR_URL}/${resource}`; if (id) { if (resource === "Practitioner") { @@ -69,28 +72,28 @@ export const getResources = async (resource: string, id?: string): Promise { +export const deleteFhirData = async (resource?: RetrievableResource, id?: string) => { let resources = [resource]; if (!resource) { resources = ["Patient", "Practitioner"]; } - for (const r of resources) { - const fhirData = await getResources(r as string); + for (const res of resources) { + const fhirData = await getResources(res as RetrievableResource); if (!("entry" in fhirData)) { - console.debug(`No ${r} to delete`); + console.debug(`No ${res} to delete`); continue; } if (id) { - await deleteAndCascadeDelete([id], r as string); + await deleteAndCascadeDelete([id], res as RetrievableResource); } else { const resourceId = fhirData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(resourceId, r as string); + await deleteAndCascadeDelete(resourceId, res as RetrievableResource); } } }; -const deleteAndCascadeDelete = async (identifiers: string[], resource: string) => { +const deleteAndCascadeDelete = async (identifiers: string[], resource: RetrievableResource) => { console.debug(`deleting ${identifiers.length}x ids of resource '${resource}'`); for (const id of identifiers) { const response = await fetch(`${FHIR_URL}/${resource}/${id}?_cascade=delete`, { From 98951898c7cc12011905b293051bc57c1442d9e1 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 19 Oct 2022 10:02:11 +0100 Subject: [PATCH 47/63] remove debug line --- src/components/reports/ReportForm.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index 15e3179..c21aba7 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -68,7 +68,6 @@ const ReportForm: FC = (props: Props) => { ctx.client ?.request(bundle) .then((response) => { - console.debug("Bundle submitted", bundle, response); const errors = getErrors(response, resourceList); if (errors.length > 0) { const errorsTable = () => { From b4042337e0430843624eb92c7c7b85625e798ce2 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 19 Oct 2022 10:13:45 +0100 Subject: [PATCH 48/63] r => resourceToDelete --- src/fhir/testUtilities.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fhir/testUtilities.tsx b/src/fhir/testUtilities.tsx index 6dbecbc..87e8c40 100644 --- a/src/fhir/testUtilities.tsx +++ b/src/fhir/testUtilities.tsx @@ -78,17 +78,17 @@ export const deleteFhirData = async (resource?: RetrievableResource, id?: string if (!resource) { resources = ["Patient", "Practitioner"]; } - for (const res of resources) { - const fhirData = await getResources(res as RetrievableResource); + for (const resourceToDelete of resources) { + const fhirData = await getResources(resourceToDelete as RetrievableResource); if (!("entry" in fhirData)) { - console.debug(`No ${res} to delete`); + console.debug(`No ${resourceToDelete} to delete`); continue; } if (id) { - await deleteAndCascadeDelete([id], res as RetrievableResource); + await deleteAndCascadeDelete([id], resourceToDelete as RetrievableResource); } else { const resourceId = fhirData.entry?.map((entry) => entry.resource?.id) as string[]; - await deleteAndCascadeDelete(resourceId, res as RetrievableResource); + await deleteAndCascadeDelete(resourceId, resourceToDelete as RetrievableResource); } } }; From 6dec9338c8869e74d38cbd7c020cf58fb9d8dff8 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 11:25:59 +0000 Subject: [PATCH 49/63] implementing waitfor --- src/components/reports/ReportForm.test.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 56a3f3f..1582aa3 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, within } from "@testing-library/react"; +import { render, screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { act } from "react-dom/test-utils"; @@ -165,7 +165,9 @@ describe("Report form", () => { // Assert const errorModal = await screen.findByText(/error/i, { selector: "h2" }); - expect(errorModal).toBeInTheDocument(); + await waitFor(() => { + expect(errorModal).toBeInTheDocument(); + }); }); /** * Given the report form From 5031602ae8a71501e2aaf6456c20c17ab88da55a Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 12:05:49 +0000 Subject: [PATCH 50/63] rejig --- src/components/reports/ReportForm.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 1582aa3..af16622 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -164,8 +164,9 @@ describe("Report form", () => { }); // Assert - const errorModal = await screen.findByText(/error/i, { selector: "h2" }); - await waitFor(() => { + await waitFor(async () => { + const errorModal = await screen.findByText(/error/i, { selector: "h2" }); + expect(errorModal).toBeInTheDocument(); }); }); From 622beb8c54eb1b3b8fce8347da450c13d235a403 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 13:02:41 +0000 Subject: [PATCH 51/63] checking practitioners --- src/components/reports/ReportForm.test.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index af16622..680d297 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -1,8 +1,8 @@ -import { render, screen, waitFor, within } from "@testing-library/react"; +import { render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { act } from "react-dom/test-utils"; -import { createPractitioner, deleteFhirData, TestReportForm } from "../../fhir/testUtilities"; +import { createPractitioner, deleteFhirData, getResources, TestReportForm } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; @@ -149,8 +149,10 @@ describe("Report form", () => { const identifier = createIdentifier("always_the_same_report"); practitioner.identifier = [identifier]; + console.log("practitioners before:", await (await getResources("Practitioner")).total); await createPractitioner(practitioner); await createPractitioner(practitioner); + console.log("practitioners after:", await (await getResources("Practitioner")).total); // Act render(); @@ -164,11 +166,8 @@ describe("Report form", () => { }); // Assert - await waitFor(async () => { - const errorModal = await screen.findByText(/error/i, { selector: "h2" }); - - expect(errorModal).toBeInTheDocument(); - }); + const errorModal = await screen.findByText(/error/i, { selector: "h2" }); + expect(errorModal).toBeInTheDocument(); }); /** * Given the report form From b00d074eb80826f6a789fbd6fc3294043ede3f88 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 14:17:33 +0000 Subject: [PATCH 52/63] adding verbose to test script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 308a11f..2b7c53c 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "build": "react-scripts build", "predeploy": "react-scripts build && cp build/index.html build/404.html", "deploy": "COMMIT_MSG=$(git log -1 --pretty=%B | sed 's/ /_/g'); gh-pages -d build --message ${COMMIT_MSG}", - "test": "react-scripts test --runInBand", + "test": "react-scripts test --verbose --runInBand", "eject": "react-scripts eject", "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, From ccb811e9d97b437fffe27fc6161d959dc44e9aaa Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 17:18:48 +0000 Subject: [PATCH 53/63] small tweaks to tests error modal should pass, redirect after submission may say conflict --- src/components/reports/ReportForm.test.tsx | 43 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 680d297..20719a4 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -1,10 +1,11 @@ -import { render, screen, within } from "@testing-library/react"; +import { getByText, render, screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { act } from "react-dom/test-utils"; import { createPractitioner, deleteFhirData, getResources, TestReportForm } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; +import { notDeepEqual } from "assert"; const clearAndType = (element: Element, value: string) => { userEvent.clear(element); @@ -142,6 +143,32 @@ describe("Report form", () => { return deleteFhirData(); }); + test("Redirect after submission", async () => { + const practitioner = new Practitioner(); + practitioner.resourceType = "Practitioner"; + const identifier = createIdentifier("always_the_same_report"); + practitioner.identifier = [identifier]; + + await createPractitioner(practitioner); + + // Act + render(); + await setLabAndPatient(); + await setSample(); + await setVariantFields(); + await setReportFields(); + + await act(async () => { + userEvent.click(screen.getByText(/submit/i)); + }); + if (!("error" in screen)) { + window.location.href = "/public/index.html"; + } + await waitFor(() => { + expect(screen.getByText(/form step 1 of 5/i, { selector: "h2" })).toBeInTheDocument(); + }); + }); + test("Error modal exists", async () => { // Arrange const practitioner = new Practitioner(); @@ -149,7 +176,13 @@ describe("Report form", () => { const identifier = createIdentifier("always_the_same_report"); practitioner.identifier = [identifier]; - console.log("practitioners before:", await (await getResources("Practitioner")).total); + console.log( + "practitioners before:", + await ( + await getResources("Practitioner") + ).total, + await getResources("Patient"), + ); await createPractitioner(practitioner); await createPractitioner(practitioner); console.log("practitioners after:", await (await getResources("Practitioner")).total); @@ -166,8 +199,10 @@ describe("Report form", () => { }); // Assert - const errorModal = await screen.findByText(/error/i, { selector: "h2" }); - expect(errorModal).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); + }); }); /** * Given the report form From 4b2e37625d9b78f7c650f77a0b3443b22f67cf81 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Mon, 7 Nov 2022 17:25:47 +0000 Subject: [PATCH 54/63] remove expect from first test --- src/components/reports/ReportForm.test.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 20719a4..8d22aad 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -164,9 +164,9 @@ describe("Report form", () => { if (!("error" in screen)) { window.location.href = "/public/index.html"; } - await waitFor(() => { - expect(screen.getByText(/form step 1 of 5/i, { selector: "h2" })).toBeInTheDocument(); - }); + // await waitFor(() => { + // expect(screen.getByText(/form step 1 of 5/i)).toBeInTheDocument(); + // }); }); test("Error modal exists", async () => { @@ -199,7 +199,6 @@ describe("Report form", () => { }); // Assert - await waitFor(() => { expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); }); From cb24e7440042ad5ae0b23294ea033a3e433131e4 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 8 Nov 2022 10:56:43 +0000 Subject: [PATCH 55/63] sending resource on first fhir load --- src/components/reports/ReportForm.test.tsx | 36 ++-------------------- src/setupTests.ts | 16 +++++++++- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 8d22aad..e631096 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -5,7 +5,7 @@ import { act } from "react-dom/test-utils"; import { createPractitioner, deleteFhirData, getResources, TestReportForm } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; -import { notDeepEqual } from "assert"; +import { enableFetchMocks } from "jest-fetch-mock"; const clearAndType = (element: Element, value: string) => { userEvent.clear(element); @@ -143,32 +143,6 @@ describe("Report form", () => { return deleteFhirData(); }); - test("Redirect after submission", async () => { - const practitioner = new Practitioner(); - practitioner.resourceType = "Practitioner"; - const identifier = createIdentifier("always_the_same_report"); - practitioner.identifier = [identifier]; - - await createPractitioner(practitioner); - - // Act - render(); - await setLabAndPatient(); - await setSample(); - await setVariantFields(); - await setReportFields(); - - await act(async () => { - userEvent.click(screen.getByText(/submit/i)); - }); - if (!("error" in screen)) { - window.location.href = "/public/index.html"; - } - // await waitFor(() => { - // expect(screen.getByText(/form step 1 of 5/i)).toBeInTheDocument(); - // }); - }); - test("Error modal exists", async () => { // Arrange const practitioner = new Practitioner(); @@ -176,13 +150,7 @@ describe("Report form", () => { const identifier = createIdentifier("always_the_same_report"); practitioner.identifier = [identifier]; - console.log( - "practitioners before:", - await ( - await getResources("Practitioner") - ).total, - await getResources("Patient"), - ); + console.log("practitioners before:", await (await getResources("Practitioner")).total); await createPractitioner(practitioner); await createPractitioner(practitioner); console.log("practitioners after:", await (await getResources("Practitioner")).total); diff --git a/src/setupTests.ts b/src/setupTests.ts index 159c7f8..265d241 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -2,11 +2,25 @@ // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom +import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import "@testing-library/jest-dom"; import { enableFetchMocks } from "jest-fetch-mock"; +import { createIdentifier } from "./fhir/resource_helpers"; +import { createPractitioner } from "./fhir/testUtilities"; -enableFetchMocks(); +beforeAll(async () => { + /* + * For some reason on first load of FHIR server, creating a batch of requests doesn't seem to validate + * Sending a resource before any test are run fixed the issue + */ + const practitioner = new Practitioner(); + practitioner.resourceType = "Practitioner"; + practitioner.identifier = [createIdentifier("initial")]; + await createPractitioner(practitioner); + + enableFetchMocks(); +}); global.beforeEach(() => { fetchMock.resetMocks(); From 4d3058e622935982a76c68b697d7c22aa59cc759 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn <72266023+acholyn@users.noreply.github.com> Date: Tue, 8 Nov 2022 11:31:51 +0000 Subject: [PATCH 56/63] remove unused imports --- src/components/reports/ReportForm.test.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index e631096..52dc229 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -1,11 +1,10 @@ -import { getByText, render, screen, waitFor, within } from "@testing-library/react"; +import { render, screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Patient } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/patient"; import { act } from "react-dom/test-utils"; import { createPractitioner, deleteFhirData, getResources, TestReportForm } from "../../fhir/testUtilities"; import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; import { createIdentifier } from "../../fhir/resource_helpers"; -import { enableFetchMocks } from "jest-fetch-mock"; const clearAndType = (element: Element, value: string) => { userEvent.clear(element); From 133f6be3aaae8eda566920ab48d2f6633def6036 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 8 Nov 2022 21:30:23 +0000 Subject: [PATCH 57/63] moving styling to report form module --- src/components/reports/ReportForm.module.css | 5 +++++ src/components/reports/ReportForm.tsx | 13 +++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/reports/ReportForm.module.css b/src/components/reports/ReportForm.module.css index e03874e..4290fc9 100644 --- a/src/components/reports/ReportForm.module.css +++ b/src/components/reports/ReportForm.module.css @@ -43,3 +43,8 @@ text-align: center; text-decoration: underline; } + +.errors-table { + font: inherit; + font-size: 86%; +} diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index c21aba7..de0e885 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -71,24 +71,17 @@ const ReportForm: FC = (props: Props) => { const errors = getErrors(response, resourceList); if (errors.length > 0) { const errorsTable = () => { - //originally had this in ReportForm.module.css but didn't work? - const css = ` - .errors-table { - font: inherit; - font-size: 86%; - }`; return ( <> - -
CodeResourceInformation
{error.errorCode} {error.resourceType} {error.diagnostics}
- +
+ - + {errors.map((error, i) => ( From ac5df81911a1a1fcae0dfed25f9493b591ef8547 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Tue, 8 Nov 2022 21:39:29 +0000 Subject: [PATCH 58/63] updating testUtilities.tsx --- src/fhir/testUtilities.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/fhir/testUtilities.tsx b/src/fhir/testUtilities.tsx index 87e8c40..861f740 100644 --- a/src/fhir/testUtilities.tsx +++ b/src/fhir/testUtilities.tsx @@ -6,6 +6,7 @@ import { noValues } from "../components/reports/FormDefaults"; import FHIR from "fhirclient/lib/entry/browser"; import React from "react"; import { RetrievableResource } from "../code_systems/types"; +import { Practitioner } from "@smile-cdr/fhirts/dist/FHIR-R4/classes/practitioner"; /** * Utilities to be used only during testing, no actual tests here. @@ -13,7 +14,7 @@ import { RetrievableResource } from "../code_systems/types"; const FHIR_URL = process.env.REACT_APP_FHIR_URL || ""; -export const createPractitioner = async (practitioner: any) => { +export const createPractitioner = async (practitioner: Practitioner) => { const sendPractitioner = await fetch(`${FHIR_URL}/Practitioner`, { method: "POST", body: JSON.stringify(practitioner), @@ -38,23 +39,23 @@ export const sendBundle = async (bundle: Bundle) => { }; const checkResponseOK = async (response: Response) => { - const r = await response.json(); + const jsonData = await response.json(); if (!response.ok) { - console.error(JSON.stringify(r)); + console.error(JSON.stringify(jsonData)); throw new Error(response.statusText); } - if (!(r.type === "bundle-response")) { - return r; + if (!(jsonData.type === "bundle-response")) { + return jsonData; } - const errors = getErrors(r); + const errors = getErrors(jsonData); if (errors.length > 1) { errors.forEach((error) => { const message = error.diagnostics; throw new Error(message); }); } - console.debug(`check response: ${JSON.stringify(r, null, 2)}`); - return r; + console.debug(`check response: ${JSON.stringify(jsonData, null, 2)}`); + return jsonData; }; export const getResources = async ( From c50e1fc302941ad3ba36bca5bb8aaa7883795903 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 9 Nov 2022 10:40:09 +0000 Subject: [PATCH 59/63] new error modal structure --- src/components/reports/ReportForm.test.tsx | 8 ++-- src/components/reports/ReportForm.tsx | 46 +++++++++++----------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 52dc229..7f09cf3 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -166,9 +166,11 @@ describe("Report form", () => { }); // Assert - await waitFor(() => { - expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); - }); + // await waitFor(() => { + // expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); + // }); + const errorModal = await screen.findByText(/error/i, { selector: "h2" }); + expect(errorModal).toBeInTheDocument(); }); /** * Given the report form diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index de0e885..50c90c9 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -70,31 +70,29 @@ const ReportForm: FC = (props: Props) => { .then((response) => { const errors = getErrors(response, resourceList); if (errors.length > 0) { - const errorsTable = () => { - return ( - <> -
Code Resource Information
{error.errorCode}
- - - - - + const errorsTable = ( + <> +
CodeResourceInformation
+ + + + + + + + + {errors.map((error, i) => ( + + + + - - - {errors.map((error, i) => ( - - - - - - ))} - -
CodeResourceInformation
{error.errorCode}{error.resourceType}{error.diagnostics}
{error.errorCode}{error.resourceType}{error.diagnostics}
- - ); - }; - setModal({ message: errorsTable(), isError: true }); + ))} + + + + ); + setModal({ message: errorsTable, isError: true }); } }) .catch((error) => { From bab728bc101f02abd5f11af60647305c8920bf1d Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 9 Nov 2022 12:03:05 +0000 Subject: [PATCH 60/63] streamlining getErrors --- src/code_systems/types.ts | 18 ++++++++++++++++++ src/fhir/api.ts | 28 ++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index b0337b8..5e92208 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -22,6 +22,24 @@ export type BundleResponse = { ]; }; +export type ErrorResponse = { + entry: [ + { + response: { + status: string | number; + outcome: { + issue?: [ + { + diagnostics: string; + }, + ]; + }; + }; + count: number; + }, + ]; +}; + export type ErrorDetails = { errorCode: string; resourceType: string; diff --git a/src/fhir/api.ts b/src/fhir/api.ts index b624c76..476c1a7 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -16,7 +16,7 @@ import { } from "./resources"; import { VariantSchema } from "../components/reports/formDataValidation"; import { loincResources } from "../code_systems/loincCodes"; -import { ErrorDetails, RequiredCoding } from "../code_systems/types"; +import { BundleResponse, ErrorDetails, ErrorResponse, RequiredCoding } from "../code_systems/types"; /** * Create a report bundle @@ -129,26 +129,22 @@ const createEntry = (resource: Resource, identifier?: string) => { }; }; -export const getErrors = (r: any, resourceTypes?: string[]) => { - //should be result of response.json() +export const getErrors = (errorData: ErrorResponse, resourceTypes?: string[]) => { const errorArray: ErrorDetails[] = []; - const errorResponses = []; let count = 0; - for (const entry of r.entry) { - if (!entry.response.status.toString().startsWith("2")) { - entry.count = count; - errorResponses.push(entry); + + for (const error of errorData.entry) { + if (!error.response.status.toString().startsWith("2")) { + error.count = count; + const errorDetails: ErrorDetails = { + errorCode: error.response.status.toString(), + resourceType: resourceTypes?.[error.count] as string, + diagnostics: error.response.outcome.issue?.[0].diagnostics as string, + }; + errorArray.push(errorDetails); } count++; } - errorResponses.forEach((error) => { - const errorDetails: ErrorDetails = { - errorCode: error.response.status, - resourceType: resourceTypes?.[error.count] as string, - diagnostics: error.response.outcome.issue?.[0].diagnostics as string, - }; - errorArray.push(errorDetails); - }); return errorArray; }; From c5f8bec338c4df569011a57bff2ae78ec39487e3 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 9 Nov 2022 12:05:28 +0000 Subject: [PATCH 61/63] consolidating ErrorResponse into BundleResponse --- src/code_systems/types.ts | 19 +------------------ src/fhir/api.ts | 4 ++-- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/code_systems/types.ts b/src/code_systems/types.ts index 5e92208..d7863f2 100644 --- a/src/code_systems/types.ts +++ b/src/code_systems/types.ts @@ -18,24 +18,7 @@ export type BundleResponse = { ]; }; }; - }, - ]; -}; - -export type ErrorResponse = { - entry: [ - { - response: { - status: string | number; - outcome: { - issue?: [ - { - diagnostics: string; - }, - ]; - }; - }; - count: number; + count?: number; }, ]; }; diff --git a/src/fhir/api.ts b/src/fhir/api.ts index 476c1a7..8669249 100644 --- a/src/fhir/api.ts +++ b/src/fhir/api.ts @@ -16,7 +16,7 @@ import { } from "./resources"; import { VariantSchema } from "../components/reports/formDataValidation"; import { loincResources } from "../code_systems/loincCodes"; -import { BundleResponse, ErrorDetails, ErrorResponse, RequiredCoding } from "../code_systems/types"; +import { BundleResponse, ErrorDetails, RequiredCoding } from "../code_systems/types"; /** * Create a report bundle @@ -129,7 +129,7 @@ const createEntry = (resource: Resource, identifier?: string) => { }; }; -export const getErrors = (errorData: ErrorResponse, resourceTypes?: string[]) => { +export const getErrors = (errorData: BundleResponse, resourceTypes?: string[]) => { const errorArray: ErrorDetails[] = []; let count = 0; From 1b2cb7291256b6d0ba98339b8ec4664c60f8cbc2 Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 9 Nov 2022 12:11:35 +0000 Subject: [PATCH 62/63] going back to waitFor to see if CI is unhappy from that --- src/components/reports/ReportForm.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index 7f09cf3..dd368ee 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -166,11 +166,11 @@ describe("Report form", () => { }); // Assert - // await waitFor(() => { - // expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); - // }); - const errorModal = await screen.findByText(/error/i, { selector: "h2" }); - expect(errorModal).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/error/i, { selector: "h2" })).toBeInTheDocument(); + }); + // const errorModal = await screen.findByText(/error/i, { selector: "h2" }); + // expect(errorModal).toBeInTheDocument(); }); /** * Given the report form From 8adbca3c7f4d808c825ed99eb3ec0d905380269f Mon Sep 17 00:00:00 2001 From: Amanda Ho-Lyn Date: Wed, 9 Nov 2022 12:32:06 +0000 Subject: [PATCH 63/63] removing practitioner logs from test --- src/components/reports/ReportForm.test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/reports/ReportForm.test.tsx b/src/components/reports/ReportForm.test.tsx index dd368ee..fb3df01 100644 --- a/src/components/reports/ReportForm.test.tsx +++ b/src/components/reports/ReportForm.test.tsx @@ -149,10 +149,8 @@ describe("Report form", () => { const identifier = createIdentifier("always_the_same_report"); practitioner.identifier = [identifier]; - console.log("practitioners before:", await (await getResources("Practitioner")).total); await createPractitioner(practitioner); await createPractitioner(practitioner); - console.log("practitioners after:", await (await getResources("Practitioner")).total); // Act render();