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

(test) O3-2428: E2E test for appointment scheduling #1664

Closed
wants to merge 24 commits into from

Conversation

Vijaykv5
Copy link
Contributor

@Vijaykv5 Vijaykv5 commented Feb 14, 2024

Requirements

  • This PR has a title that briefly describes the work done including the ticket number. If there is a ticket, make sure your PR title includes a conventional commit label. See existing PR titles for inspiration.
  • My work conforms to the OpenMRS 3.0 Styleguide and design documentation.
  • My work includes tests or is validated by existing tests.

Summary

This PR covers E2E test to test the appointment workflow.

The test involves adding an appointment for a patient, edit the added appointment, and cancel it.

Screenshots

appointments-test.mov

Related Issue

O3-2428

@Vijaykv5 Vijaykv5 marked this pull request as draft February 14, 2024 16:48
@Vijaykv5
Copy link
Contributor Author

@jayasanka-sack May you can look into this PR.
I'm failing to add this test case -

  • Then I should see the Schedule appointment workspace

@Vijaykv5 Vijaykv5 marked this pull request as ready for review February 17, 2024 12:30
@Vijaykv5
Copy link
Contributor Author

Vijaykv5 commented Feb 17, 2024

@jayasanka-sack @RandilaP May you can check this PR?
I've added the test video in description
Thanks

Copy link
Member

@jayasanka-sack jayasanka-sack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress, @Vijaykv5! 🎉 I've reviewed the changes and added some comments. Well done!

await test.step('When I click on appointment tab', async () => {
await appointmentsPage.goto(patient.uuid);
});
//test to add appointment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test steps are sufficiently descriptive; therefore, additional comments are unnecessary.

Comment on lines 13 to 14
const appointmentsPage = new AppointmentsPage(page);
await test.step('When I click on appointment tab', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const appointmentsPage = new AppointmentsPage(page);
await test.step('When I click on appointment tab', async () => {
const appointmentsPage = new AppointmentsPage(page);
await test.step('When I go to the appointment tab in the patient chart', async () => {

await page.click('button:has-text("Add")');
});

await test.step('When I select Mobile Clinic location', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await test.step('When I select Mobile Clinic location', async () => {
await test.step('And I select Mobile Clinic location', async () => {

});

await test.step('When I select Mobile Clinic location', async () => {
await page.locator('#location').selectOption('8d9045ad-50f0-45b8-93c8-3ed4bce19dbf');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to @ibacher 's comment on slack:

Always prefer grabbing the element by user-facing text (in this case the ARIA label) rather than technical details like id / class / tag as we want our tests to be robust to markup changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jayasanka-sack There's no element under options other than changing their values of location.
We have used the same here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we try with something akin to what's showcased in the Playwright documentation (link)?

await page.getByLabel('Choose a color').selectOption({ label: 'Blue' });

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies for other fields as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I missed that!
Fixed now :)
Thanks

await page.locator('#datePickerInput').fill('18/02/2024');
});

await test.step('And I set the “Duration”', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await test.step('And I set the “Duration”', async () => {
await test.step('And I set the “Duration” to 60', async () => {

await expect(page.getByText(/Appointment scheduled/i)).toBeVisible();
});
// test for editing the appointment
await test.step('And I choose the "Edit" option from the popup menu', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break this down to two steps:

  • When I click the options kebab menu in the appointment
  • And I choose the "Edit" option
    This applies to the deletion too.

Also add the following step

  • Then I should see the Edit an appointment workspace

await page.getByRole('menuitem', { name: 'Cancel' }).click();
});

await test.step('And I cancel the appointmen', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Then I should see a confirmation modal
  • When I click the "Cancel appointment" button to confirm

Copy link
Contributor

@RandilaP RandilaP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job @Vijaykv5

export class AppointmentsPage {
constructor(readonly page: Page) {}

readonly appointmentsTable = () => this.page.getByRole('table', { name: /appointments/i });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
readonly appointmentsTable = () => this.page.getByRole('table', { name: /appointments/i });
readonly appointmentsTable = () => this.page.getByRole('table', { name: /appointments/i });

I think it's best to Add a getByTestId to the table locator

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to avoid the use of ids, classes as much as possible. #1664 (comment)

});

await test.step('And I set the “Duration” to 60', async () => {
await page.locator('#duration').fill('60');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.locator('#duration').fill('60');
await page.locator('#duration').fill('60');

Use getById

});

await test.step('And I set the “Duration” of the appointment”', async () => {
await page.locator('#duration').fill('80');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.locator('#duration').fill('80');
await page.locator('#duration').fill('80');

Here as well

@Vijaykv5
Copy link
Contributor Author

Thanks for the Review @jayasanka-sack @RandilaP
I've made changes as per the suggestions.
I wonder why the Test fails in the PR? although it's working fine locally when I tried to test particular component

Copy link
Contributor

@RandilaP RandilaP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vijaykv5 Good to see your progress

Comment on lines 35 to 37
await test.step('And I set date for tomorrow', async () => {
await page.fill('input[placeholder="dd/mm/yyyy"]', '30/03/2024');
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await test.step('And I set date for tomorrow', async () => {
await page.fill('input[placeholder="dd/mm/yyyy"]', '30/03/2024');
});
await test.step('And I set date for tomorrow', async () => {
await page.fill('input[placeholder="dd/mm/yyyy"]', '30/03/2024');
});

Nice to see your progress in tests @Vijaykv5. I would like to highlight that we are using these E2E tests again and again when someone sends a PR. So after the date that u added in this test these tests will fail because this appointment is going to move to the past appointment section. I would like to suggest you if you are adding a date manually make sure add a previous date and in the test make sure to go through the past appointment section.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use Js to get tomorrow's date.

ex:

const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
await page.fill('input[placeholder="dd/mm/yyyy"]', tomorrow.toLocaleDateString('en-GB'));

btw, can't we use page.getByLabel().fill here?

Comment on lines 75 to 77
await test.step('And I change the date to Today', async () => {
await page.fill('input[placeholder="dd/mm/yyyy"]', '28/03/2024');
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but I think as @jayasanka-sack It would best way to make into today's date.

@RandilaP
Copy link
Contributor

@Vijaykv5 Make this PR a draft PR

@jayasanka-sack
Copy link
Member

Thanks for the Review @jayasanka-sack @RandilaP I've made changes as per the suggestions. I wonder why the Test fails in the PR? although it's working fine locally when I tried to test particular component

You can try to view the report and check what's going wrong: https://o3-docs.openmrs.org/docs/frontend-modules/testing#view-test-reports-from-github-actions--bamboo

@Vijaykv5 Vijaykv5 marked this pull request as draft February 28, 2024 16:52
@Vijaykv5 Vijaykv5 requested a review from RandilaP March 1, 2024 16:18
Copy link
Contributor

@RandilaP RandilaP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vijaykv5 Good job

});

await test.step('When I change to “Inpatient ward” location', async () => {
await page.getByLabel('Select location').selectOption('Inpatient Ward');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.getByLabel('Select location').selectOption('Inpatient Ward');
await page.getByLabel('Select location').selectOption('Inpatient Ward');

Can you check in other E2E tests how they select options in the tests. Test is failing because of it. Download the test report and check the video where it's failing.

Copy link
Member

@kdaud kdaud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @Vijaykv5! 👍

I've added a few comments to address.

let patient: Patient;

test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we start patient visit before recording the appointment, @Vijaykv5 what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I missed that out. Yes that right!
Thank you @kdaud
I've updated new changes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appointments should be able to be scheduled without requiring an active visit. That's a kind of basic feature of an appointment scheduling application.

patient = await generateRandomPatient(api);
});

test('Add appointment for a patient, edit the added appointment and cancel it', async ({ page, api }) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest we re-title the test to

Add, edit and cancel an appointment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest this be broken up into three tests, as it's three features:

  1. Add an appointment
  2. Edit an existing appointment
  3. Cancel an existing appointment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest this be broken up into three tests, as it's three features:

  1. Add an appointment
  2. Edit an existing appointment
  3. Cancel an existing appointment

@ibacher we are following this doc for the tests. So for adding tests for appointment section, is it better to do it as a whole test for appointment section?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest this be broken up into three tests, as it's three features:

@jayasanka-sack what do you think concerning Ian's idea?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested using a single flow to minimize API usage for the data population. But, after seeing how lengthy the test will be, I also think breaking it into three tests would simplify it.

Copy link
Member

@kdaud kdaud Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think breaking into three tests would make it much simpler.

@jayasanka-sack will this apply across all tests with the add, edit and delete workflows? cc: @denniskigen

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've got just a few that contains in single flow. Let's leave them as is for the time being and beef them up later when we can. Our priority is to expand our coverage. But, if you happen to have some extra time, feel free to tweak them too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's definitely a balance of concerns, but if the main concern is how much data is created during, it should be possible, for example, to create a single patient and run a suite of tests using that single patient (i.e., there's no reason here that the patient needs to be created in a beforeEach() rather than a beforeAll(), especially since we're fundamentally only working on data attached to the patient record rather than the patient record itself).

My concern here is related to this point in that doc: "We want business-level users to easily be able to see a report that reassures them about what functionality is covered". Specifically, if the "Add appointment for a patient, edit the added appointment and cancel it" test fails, then, as a business user, I'm stuck regarding that whole feature as broken, which is much more concerning than saying "We can currently add appointments, but something broke the cancellation flow", for example.

I also agree with @jayasanka-sack's point that the priority should be improving test coverage, not going back and revising everything to match some "gold standard" for how tests are written.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a ticket to monitor the proposed E2E test approach.

@kdaud
Copy link
Member

kdaud commented Mar 6, 2024

I would suggest to rename the spec file to 'appointments.spec.ts'. @Vijaykv5 let me know your thought?

@denniskigen denniskigen changed the title (test)O3-2428: E2E test for appointment scheduling (test) O3-2428: E2E test for appointment scheduling Mar 6, 2024
@kdaud
Copy link
Member

kdaud commented Mar 19, 2024

@Vijaykv5 as a result of O3-2891 we need to move the work on this PR to https://github.com/openmrs/openmrs-esm-patient-management/

@Vijaykv5
Copy link
Contributor Author

@Vijaykv5 as a result of O3-2891 we need to move the work on this PR to https://github.com/openmrs/openmrs-esm-patient-management/

Do I need to add the PR there?

@kdaud
Copy link
Member

kdaud commented Mar 19, 2024

yes

@denniskigen
Copy link
Member

I'm closing this in favour of a new PR in https://github.com/openmrs/openmrs-esm-patient-management following #1739. Let me know if you need any help setting that up, @Vijaykv5.

@Vijaykv5
Copy link
Contributor Author

@denniskigen I have made a New PR here
May you can check why it's failing there? It runs fine locally,I also have some issue regarding the commit history there.
Appreciate if you could help on that
Thanks!

@denniskigen
Copy link
Member

I've responded to your question in the other PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants