Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cerner): v1 #580

Merged
merged 3 commits into from
Feb 6, 2025
Merged

feat(cerner): v1 #580

merged 3 commits into from
Feb 6, 2025

Conversation

nckhell
Copy link
Contributor

@nckhell nckhell commented Feb 6, 2025

No description provided.

Copy link

github-actions bot commented Feb 6, 2025

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 5 🔵🔵🔵🔵🔵
🧪 PR contains tests
🔒 Security concerns

Sensitive information exposure:
The error handling logic in createPatient.ts logs the entire error response, which may include sensitive data. Ensure that sensitive information such as patient details or credentials is redacted before logging.

⚡ Recommended focus areas for review

Possible Issue

The birthDate field is being coerced to a date and formatted using toISOString().split('T')[0]. This could lead to unexpected behavior if the input is not properly validated or formatted beforehand.

...(!isEmpty(birthDate) && {
  birthDate: birthDate.toISOString().split('T')[0],
Error Handling

The error handling logic in the onError callback includes a JSON stringification of the error response. Ensure that sensitive information is not unintentionally exposed in logs.

message: `Status: ${String(err.response?.status)} (${String(
  err.response?.statusText,
)})\n${JSON.stringify(err.response?.data, null, 2)}`,
Field Validation

The assigningOrganizationId field is marked as required, but its validation schema only checks for a non-empty string. Consider adding stricter validation rules if applicable.

assigningOrganizationId: z.string().min(1),

Copy link

github-actions bot commented Feb 6, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Handle undefined appointment type codes

Ensure the appointmentTypeCode data point is set to a default value or explicitly
handled when the coding array is undefined or empty to avoid potential runtime
errors.

extensions/cerner/actions/getAppointment/getAppointment.ts [43]

-appointmentTypeCode: res.data?.appointmentType?.coding?.[0]?.code,
+appointmentTypeCode: res.data?.appointmentType?.coding?.[0]?.code ?? 'unknown',
Suggestion importance[1-10]: 9

__

Why: This suggestion ensures that the appointmentTypeCode data point is always set, even when the coding array is undefined or empty. It prevents potential runtime errors and improves the robustness of the code.

High
Add test for unexpected errors

Add a test case to verify the behavior when an unexpected error occurs in the
onEvent function to ensure robust error handling.

extensions/cerner/actions/getPatientEncounters/getPatientEncounters.test.ts [58-92]

-describe('When no encounter found', () => {
+describe('When an unexpected error occurs', () => {
   beforeEach(() => {
-    const mockSearchEncounter = jest
-      .fn()
-      .mockResolvedValue({ data: GetPatientEncountersNoResultsMockResponse })
+    const mockSearchEncounter = jest.fn().mockRejectedValue(new Error('Unexpected error'))
     const mockedCernerClient = jest.mocked(CernerR4APIClient)
 
     mockedCernerClient.mockImplementation(() => {
       return {
         searchEncounter: mockSearchEncounter,
       } as unknown as CernerR4APIClient
     })
   })
 
-  test('Should return an error', async () => {
+  test('Should handle unexpected errors gracefully', async () => {
     const res = extensionAction.onEvent({
       payload: {
         fields: {
           patientResourceId: 'something',
         },
         settings: {
           tenantId: 'some-tenant-id',
           clientId: 'some-client-id',
           clientSecret: 'some-secret',
         },
       } as any,
       onComplete,
       onError,
       helpers,
     })
 
-    await expect(res).rejects.toThrow('No encounters found')
+    await expect(res).rejects.toThrow('Unexpected error')
   })
 })
Suggestion importance[1-10]: 9

__

Why: Adding a test case for unexpected errors ensures that the error handling logic is robust and works as intended, which is critical for maintaining code quality and reliability.

High
Use meaningful time ranges for periods

Ensure that the period field in the DocumentReferenceInput.context object has a
valid and meaningful time range instead of using the same timestamp for both start
and end.

extensions/cerner/actions/createDocument/createDocument.ts [64-66]

 period: {
   start: new Date().toISOString(),
-  end: new Date().toISOString(),
+  end: new Date(new Date().getTime() + 60000).toISOString(), // Example: 1 minute later
 },
Suggestion importance[1-10]: 8

__

Why: The suggestion improves the accuracy and meaningfulness of the period field by ensuring the start and end times are not identical. This change enhances the data's validity and prevents potential issues with downstream systems that may require a valid time range.

Medium
Handle unexpected error statuses

Add a fallback error handling mechanism for cases where err.status is undefined to
avoid silent failures.

extensions/cerner/actions/getAppointment/getAppointment.ts [50-58]

-if (err.status === 404)
+if (err.status === 404) {
   await onError({
     events: [
       addActivityEventLog({
         message: 'Appointment not found',
       }),
     ],
   })
+} else {
+  await onError({
+    events: [
+      addActivityEventLog({
+        message: `Unexpected error: ${err.message}`,
+      }),
+    ],
+  })
+}
Suggestion importance[1-10]: 8

__

Why: Adding a fallback mechanism for undefined error statuses ensures that unexpected errors are logged and handled properly, reducing the risk of silent failures and improving error traceability.

Medium
Improve validation error messages

Add a more descriptive error message in the FieldsValidationSchema to help
developers identify the issue when the resourceId field is missing or invalid.

extensions/cerner/actions/getEncounter/config/fields.ts [15]

-resourceId: z.string().min(1),
+resourceId: z.string().min(1, { message: 'resourceId must be a non-empty string' }),
Suggestion importance[1-10]: 8

__

Why: Adding a descriptive error message enhances developer experience by providing clear feedback when validation fails, making debugging easier and more efficient.

Medium
Handle non-Axios errors consistently

Ensure the onError handler is called for non-Axios errors to maintain consistent
error handling.

extensions/cerner/actions/getPatientEncounters/getPatientEncounters.ts [59-60]

-// Throw all other errors
-throw error
+await onError({
+  events: [
+    addActivityEventLog({
+      message: `Unexpected error: ${error.message}`,
+    }),
+  ],
+});
+throw error;
Suggestion importance[1-10]: 8

__

Why: Ensuring consistent error handling for non-Axios errors improves the robustness and reliability of the application, making it a significant improvement.

Medium
Improve error message specificity

Add a specific error message for the case where multiple patients are found to
provide better debugging information.

extensions/cerner/actions/findPatientByMRN/findPatientByMRN.ts [38]

-throw new Error('Multiple patients found')
+throw new Error(`Multiple patients found for MRN: ${MRN}`)
Suggestion importance[1-10]: 7

__

Why: Adding the MRN to the error message provides more context, making debugging easier when multiple patients are found. This is a minor but valuable improvement to error handling.

Medium
Reset mock functions after tests

Ensure that the mocked getEncounter function is properly reset after each test to
avoid potential test contamination.

extensions/cerner/actions/getEncounter/getEncounter.test.ts [19-21]

 const mockGetEncounter = jest
   .fn()
   .mockResolvedValue({ data: GetEncounterMockResponse })
+afterEach(() => {
+  mockGetEncounter.mockReset()
+})
Suggestion importance[1-10]: 7

__

Why: Resetting mock functions after each test ensures test isolation and prevents contamination, which is a good practice for maintaining reliable and predictable test results.

Medium
Add logging for unexpected errors

Add a default error message or log for cases where the error is not an instance of
AxiosError to ensure all errors are properly handled or logged.

extensions/cerner/actions/getEncounter/getEncounter.ts [53-54]

-// Throw all other errors
-throw error
+// Log or handle other errors
+console.error('Unexpected error:', error);
+throw error;
Suggestion importance[1-10]: 7

__

Why: Adding logging for unexpected errors improves debugging and ensures that all errors are traceable, which enhances maintainability and robustness of the code.

Medium
Split mock data into smaller components

Limit the size of the mock response or split it into smaller, reusable components to
improve readability and maintainability.

extensions/cerner/actions/getEncounter/testdata/GetEncounter.mock.ts [3-9]

+export const GetEncounterMockResponseMeta = {
+  versionId: '108',
+  lastUpdated: '2025-01-06T12:40:46.000Z',
+}
 export const GetEncounterMockResponse = {
   resourceType: 'Encounter',
   id: '97939518',
-  meta: {
-    versionId: '108',
-    lastUpdated: '2025-01-06T12:40:46.000Z',
-  },
+  meta: GetEncounterMockResponseMeta,
   ...
 }
Suggestion importance[1-10]: 6

__

Why: Splitting the mock data into smaller, reusable components improves readability and maintainability. However, the suggestion does not address the entire mock structure, which limits its impact.

Low
Improve error message clarity

Include a more descriptive error message when throwing an error for no encounters
found to provide better debugging context.

extensions/cerner/actions/getPatientEncounters/getPatientEncounters.ts [35]

-throw new Error('No encounters found')
+throw new Error('No encounters found for the provided patient resource ID')
Suggestion importance[1-10]: 6

__

Why: The improved error message provides better context for debugging, making it clearer what caused the error, but it is a minor enhancement.

Low
Possible issue
Validate resourceId before processing

Add validation to ensure that the resourceId field in the payload is not null or
undefined before proceeding with the onEvent function to prevent runtime errors.

extensions/cerner/actions/getEncounter/getEncounter.test.ts [71-73]

 fields: {
   resourceId: '999',
-},
+} as any,
+if (!payload.fields.resourceId) {
+  throw new Error('resourceId is required')
+}
Suggestion importance[1-10]: 4

__

Why: Adding validation for resourceId can prevent runtime errors, but the suggestion is partially redundant as the FieldsValidationSchema already enforces this validation. The proposed code also introduces a runtime check which might not align with the existing validation approach.

Low

@nckhell nckhell enabled auto-merge (squash) February 6, 2025 11:57
@nckhell nckhell disabled auto-merge February 6, 2025 12:32
@nckhell nckhell merged commit 1a9a21f into main Feb 6, 2025
2 checks passed
@nckhell nckhell deleted the cerner_progress branch February 6, 2025 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant