-
Notifications
You must be signed in to change notification settings - Fork 242
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) O3-4040: Add delete ability to program enrollments #2133
base: main
Are you sure you want to change the base?
(feat) O3-4040: Add delete ability to program enrollments #2133
Conversation
…dit" and "delete" options for individual programs
…t button and the new delete button
…ved(clicking on the overflow menu) to get to the "edit" button
@vasharma05 @denniskigen can you please review this for me |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, @PiusKariuki ! The main thing is to clean up the user-facing text. We don't want to scare users by making them think they might be deleting a whole program, when they are in fact just deleting the patient's enrollment.
packages/esm-patient-programs-app/src/programs/program-actions-menu.scss
Outdated
Show resolved
Hide resolved
packages/esm-patient-programs-app/src/programs/delete-program.modal.tsx
Outdated
Show resolved
Hide resolved
packages/esm-patient-programs-app/src/programs/delete-program.modal.tsx
Outdated
Show resolved
Hide resolved
packages/esm-patient-programs-app/src/programs/delete-program.modal.tsx
Outdated
Show resolved
Hide resolved
packages/esm-patient-programs-app/src/programs/delete-program.modal.tsx
Outdated
Show resolved
Hide resolved
packages/esm-patient-programs-app/src/programs/delete-program.modal.tsx
Outdated
Show resolved
Hide resolved
@brandones I have made the necessary updates requested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @PiusKariuki ! Excellent work.
In the future, if you could work on figuring out how to add commits to your work in a way that makes it easy for reviewers to see what changed since last review, that would be really helpful. Right now it looks like you made like 14 new commits, which would be inconvenient to view one-by-one. Maybe check out git rebase --interactive
if you haven't.
Just a suggestion, nice work otherwise!
Oops, looks like the E2E test failure is related to this work. Please fix the E2E test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @PiusKariuki! Left a few nitpicks about the tests
})); | ||
|
||
const mockMutateEnrollments = jest.fn(); | ||
(useEnrollments as jest.Mock).mockImplementation(() => ({ mutateEnrollments: mockMutateEnrollments })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see the correct way to mock functions where we prefer to use jest.mocked
where possible - https://o3-docs.openmrs.org/docs/frontend-modules/unit-and-integration-testing#annotating-mocks-with-type-information
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to explicitly do this, since we have this specified by default in the jest.config
beforeEach(() => { | |
jest.clearAllMocks(); | |
}); |
jest.mock('@openmrs/esm-framework', () => ({ | ||
showSnackbar: jest.fn(), | ||
getCoreTranslation: jest.fn((key, defaultText) => defaultText), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see how to extend framework mocks - https://o3-docs.openmrs.org/docs/frontend-modules/unit-and-integration-testing#you-should-not-need-to-use-partial-mocks.
}); | ||
|
||
it('handles delete action successfully', async () => { | ||
(deleteProgramEnrollment as jest.Mock).mockResolvedValue({ ok: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
|
||
it('handles delete action error', async () => { | ||
const errorMessage = 'failed to delete'; | ||
(deleteProgramEnrollment as jest.Mock).mockRejectedValue(new Error(errorMessage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too
jest.mock('@openmrs/esm-framework', () => ({ | ||
showModal: jest.fn(), | ||
useLayoutType: jest.fn(() => 'desktop'), | ||
})); | ||
|
||
jest.mock('@openmrs/esm-patient-common-lib', () => ({ | ||
launchPatientWorkspace: jest.fn(), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for this test case about mocking patterns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine for @openmrs/esm-patient-common-lib
, @NethmiRodrigo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start, @PiusKariuki. I've left some feedback.
jest.mock('react-i18next', () => ({ | ||
useTranslation: () => ({ t: (key, defaultText) => defaultText }), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
describe('DeleteProgramModal', () => { | ||
const closeDeleteModalMock = jest.fn(); | ||
const programEnrollmentId = '123'; | ||
const patientUuid = 'abc'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add this import to the top:
import { mockPatient } from 'tools';
So that we can do:
const patientUuid = 'abc'; | |
const patientUuid = mockPatient.id |
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good pattern for setting up the test is doing something like:
const mockDeleteProgramEnrollment = jest.mocked(deleteProgramEnrollment);
const mockShowSnackbar = jest.mocked(showSnackbar);
const mockMutateEnrollments = jest.fn(() => Promise.resolve(undefined));
const mockUseEnrollments = jest.mocked(useEnrollments);
const mockCloseDeleteModal = jest.fn();
const testProps = {
closeDeleteModal: mockCloseDeleteModal,
patientUuid: mockPatient.id,
programEnrollmentId: '9b1deb4d-5b9f-4fec-a6ea-6b0c0f3a3d0f',
};
const renderDeleteProgramModal = () => {
render(
<DeleteProgramModal {...testProps} />,
);
};
So that in the tests we can just call:
it('renders something', () => {
renderDeleteProgramModal();
// assertions
})
render( | ||
<DeleteProgramModal | ||
closeDeleteModal={closeDeleteModalMock} | ||
programEnrollmentId={programEnrollmentId} | ||
patientUuid={patientUuid} | ||
/>, | ||
); | ||
expect(screen.getByText('Delete Program Enrollment')).toBeInTheDocument(); | ||
expect(screen.getByText('Are you sure you want to delete this program enrollment?')).toBeInTheDocument(); | ||
expect(screen.getByText('Cancel')).toBeInTheDocument(); | ||
expect(screen.getByText('Confirm')).toBeInTheDocument(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer using a11y roles wherever possible to make your tests more robust:
render( | |
<DeleteProgramModal | |
closeDeleteModal={closeDeleteModalMock} | |
programEnrollmentId={programEnrollmentId} | |
patientUuid={patientUuid} | |
/>, | |
); | |
expect(screen.getByText('Delete Program Enrollment')).toBeInTheDocument(); | |
expect(screen.getByText('Are you sure you want to delete this program enrollment?')).toBeInTheDocument(); | |
expect(screen.getByText('Cancel')).toBeInTheDocument(); | |
expect(screen.getByText('Confirm')).toBeInTheDocument(); | |
renderDeleteProgramModal(); | |
expect(screen.getByRole('heading', { name: /delete program enrollment/i })).toBeInTheDocument(); | |
expect(screen.getByText(/are you sure you want to delete this program enrollment?/i)).toBeInTheDocument(); | |
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument(); | |
expect(screen.getByRole('button', { name: /confirm/i })).toBeInTheDocument(); |
@@ -0,0 +1,100 @@ | |||
import React from 'react'; | |||
import { render, screen, fireEvent } from '@testing-library/react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer userEvent over fireEvent.
<div> | ||
<ModalHeader | ||
closeModal={closeDeleteModal} | ||
title={t('deletePatientProgramEnrollment', 'Delete Program Enrollment')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
title={t('deletePatientProgramEnrollment', 'Delete Program Enrollment')} | |
title={t('deletePatientProgramEnrollment', 'Delete program enrollment')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sentence case is preferable to title case for body text.
jest.mock('react-i18next', () => ({ | ||
useTranslation: () => ({ t: (key: string, defaultText: string) => defaultText }), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, we shouldn't mock this. A lot of the tips from the programs modal test can be applied here too.
jest.mock('@openmrs/esm-framework', () => ({ | ||
showModal: jest.fn(), | ||
useLayoutType: jest.fn(() => 'desktop'), | ||
})); | ||
|
||
jest.mock('@openmrs/esm-patient-common-lib', () => ({ | ||
launchPatientWorkspace: jest.fn(), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine for @openmrs/esm-patient-common-lib
, @NethmiRodrigo.
jest.mock('@openmrs/esm-framework', () => ({ | ||
showModal: jest.fn(), | ||
useLayoutType: jest.fn(() => 'desktop'), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jest.mock('@openmrs/esm-framework', () => ({ | |
showModal: jest.fn(), | |
useLayoutType: jest.fn(() => 'desktop'), | |
})); | |
const mockShowModal = jest.mocked(showModal); | |
const mockUseLayoutType = jest.mocked(useLayoutType); |
And then further below you could do this inside a beforeEach
block:
beforeEach(() => {
mockUseLayoutType.mockReturnValue('small-desktop'); // or 'large-desktop' or 'tablet'
})
To override the useLayoutType
implementation to suit your test.
@@ -160,8 +155,8 @@ const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = ({ patie | |||
{row.cells.map((cell) => ( | |||
<TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell> | |||
))} | |||
<TableCell className="cds--table-column-menu"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we still need this className...
The programs e2e test is failing because this button doesn't exist after moving it to the |
Thank you @denniskigen and @NethmiRodrigo . I am working on fixing these tests right now |
Requirements
Summary
This PR adds DELETE ability to program enrollments
Screenshots
Related Issue
https://openmrs.atlassian.net/browse/O3-4040
Other