-
Notifications
You must be signed in to change notification settings - Fork 1.1k
QA-187 | test: add Planned encounter status transition spec #16481
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
Open
nihal467
wants to merge
2
commits into
ohcnetwork:ENG-601-planned
Choose a base branch
from
nihal467:tests/ENG-601-planned-status-transition
base: ENG-601-planned
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+251
−49
Open
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
212 changes: 212 additions & 0 deletions
212
tests/facility/patient/encounter/encounterPlannedStatusTransition.spec.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| import { faker } from "@faker-js/faker"; | ||
| import { expect, test, type Page } from "@playwright/test"; | ||
| import { ENCOUNTER_CLASSES } from "tests/facility/patient/encounter/encounterClasses"; | ||
| import { getFacilityId } from "tests/support/facilityId"; | ||
| import { getPatientId } from "tests/support/patientId"; | ||
|
|
||
| test.use({ storageState: "tests/.auth/user.json" }); | ||
|
|
||
| const VALIDATION_ERROR_TEXT = | ||
| "period: Value error, Start Date cannot be greater than End Date"; | ||
|
|
||
| async function selectFutureDateInCalendar(page: Page) { | ||
| await page | ||
| .locator('[data-slot="form-item"]') | ||
| .filter({ hasText: "Date and Time" }) | ||
| .locator('[data-slot="popover-trigger"]') | ||
| .click(); | ||
|
|
||
| const nextMonthButton = page.getByRole("button", { | ||
| name: "Go to the Next Month", | ||
| }); | ||
| await expect(nextMonthButton).toBeEnabled(); | ||
| await nextMonthButton.click(); | ||
|
|
||
| const futureDayButton = page | ||
| .getByRole("gridcell") | ||
| .filter({ hasText: /^15$/ }) | ||
| .getByRole("button"); | ||
| await expect(futureDayButton).toBeEnabled(); | ||
| await futureDayButton.click(); | ||
| } | ||
|
|
||
| async function createPlannedEncounterWithFutureDate(page: Page) { | ||
| const facilityId = getFacilityId(); | ||
| const patientId = getPatientId(); | ||
|
|
||
| await page.goto(`/facility/${facilityId}/patient/${patientId}`); | ||
| await page.getByRole("link", { name: "Patient Home" }).click(); | ||
|
|
||
| await expect( | ||
| page.getByRole("button", { name: "Create Encounter" }), | ||
| ).toBeVisible(); | ||
| await page.getByRole("button", { name: "Create Encounter" }).click(); | ||
|
|
||
| const encounterClass = faker.helpers.arrayElement(ENCOUNTER_CLASSES); | ||
| await page.getByRole("button", { name: encounterClass }).click(); | ||
|
|
||
| await page.getByRole("combobox", { name: "Status" }).click(); | ||
| await page.getByRole("option", { name: "Planned", exact: true }).click(); | ||
|
|
||
| await selectFutureDateInCalendar(page); | ||
|
|
||
| const dialog = page.getByRole("dialog", { | ||
| name: "Initiate Patient Encounter", | ||
| }); | ||
| await dialog.getByRole("button", { name: /^Create Encounter/ }).click(); | ||
|
|
||
| // Submit navigates to the encounter detail page. | ||
| await page.waitForURL(/\/encounter\/[^/]+/); | ||
| await expect( | ||
| page.getByRole("button", { name: "Encounter Actions" }), | ||
| ).toBeVisible(); | ||
| } | ||
|
|
||
| // Update-encounter form uses a bare <Label> + <SelectTrigger> (no FormLabel/htmlFor), | ||
| // so the combobox has no programmatic accessible name. Anchor on the label and walk | ||
| // to its immediate parent (the space-y-2 wrapper that contains exactly one combobox). | ||
| function encounterStatusCombobox(page: Page) { | ||
| return page | ||
| .locator('label[data-slot="label"]') | ||
| .filter({ hasText: /^Encounter Status$/ }) | ||
| .locator("xpath=..") | ||
| .getByRole("combobox"); | ||
| } | ||
|
nihal467 marked this conversation as resolved.
|
||
|
|
||
| async function openEncounterUpdateForm(page: Page) { | ||
| await page.getByRole("tab", { name: "Details" }).click(); | ||
| await page.getByRole("link", { name: "Update Encounter" }).click(); | ||
| await expect(encounterStatusCombobox(page)).toBeVisible(); | ||
| } | ||
|
|
||
| async function changeStatus(page: Page, status: string) { | ||
| await encounterStatusCombobox(page).click(); | ||
| await page.getByRole("option", { name: status, exact: true }).click(); | ||
| } | ||
|
|
||
| async function submitQuestionnaire(page: Page) { | ||
| await page.getByRole("button", { name: "Submit", exact: true }).click(); | ||
| } | ||
|
|
||
| async function expectSubmissionSuccess(page: Page) { | ||
| await expect( | ||
| page.getByText("Questionnaire submitted successfully"), | ||
| ).toBeVisible(); | ||
| } | ||
|
|
||
| async function expectSubmissionBlockedByPeriodError(page: Page) { | ||
| await expect(page.getByText("Failed to submit questionnaire")).toBeVisible(); | ||
| await expect(page.getByText(VALIDATION_ERROR_TEXT)).toBeVisible(); | ||
| } | ||
|
|
||
| // Ensures the encounter ends in a terminal state so the patient's 5-live-encounter | ||
| // limit isn't reached across repeated runs. | ||
| async function cancelEncounterFromCurrentForm(page: Page) { | ||
| await changeStatus(page, "Cancelled"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionSuccess(page); | ||
| } | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
|
|
||
| test.describe("Planned Encounter Status Transition", () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await createPlannedEncounterWithFutureDate(page); | ||
| }); | ||
|
|
||
| test("allows transition from Planned to In Progress", async ({ page }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Transition Planned to In Progress", async () => { | ||
| await changeStatus(page, "In Progress"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionSuccess(page); | ||
| }); | ||
|
|
||
| await test.step("Cleanup: cancel encounter", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| await cancelEncounterFromCurrentForm(page); | ||
| }); | ||
| }); | ||
|
|
||
| test("allows transition from Planned to On Hold", async ({ page }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Transition Planned to On Hold", async () => { | ||
| await changeStatus(page, "On Hold"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionSuccess(page); | ||
| }); | ||
|
|
||
| await test.step("Cleanup: cancel encounter", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| await cancelEncounterFromCurrentForm(page); | ||
| }); | ||
| }); | ||
|
|
||
| test("allows transition from Planned to Cancelled", async ({ page }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Transition Planned to Cancelled", async () => { | ||
| await cancelEncounterFromCurrentForm(page); | ||
| }); | ||
| }); | ||
|
|
||
| test("allows transition from Planned to Entered in error", async ({ | ||
| page, | ||
| }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Transition Planned to Entered in error", async () => { | ||
| await changeStatus(page, "Entered in error"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionSuccess(page); | ||
| }); | ||
| }); | ||
|
|
||
| test("blocks transition from Planned to Completed with period error", async ({ | ||
| page, | ||
| }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Attempt Planned to Completed", async () => { | ||
| await changeStatus(page, "Completed"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionBlockedByPeriodError(page); | ||
| }); | ||
|
|
||
| await test.step("Cleanup: cancel encounter (still Planned on backend)", async () => { | ||
| // Backend rejected the transition, so the encounter is still Planned. | ||
| // Selecting Cancelled clears the auto-set end date (see EncounterQuestion | ||
| // useEffect handling for future-start Cancelled/EnteredInError), so this | ||
| // submit succeeds and moves the encounter to a terminal state. | ||
| await cancelEncounterFromCurrentForm(page); | ||
| }); | ||
| }); | ||
|
|
||
| test("blocks transition from Planned to Discontinued with period error", async ({ | ||
| page, | ||
| }) => { | ||
| await test.step("Open update form", async () => { | ||
| await openEncounterUpdateForm(page); | ||
| }); | ||
|
|
||
| await test.step("Attempt Planned to Discontinued", async () => { | ||
| await changeStatus(page, "Discontinued"); | ||
| await submitQuestionnaire(page); | ||
| await expectSubmissionBlockedByPeriodError(page); | ||
| }); | ||
|
|
||
| await test.step("Cleanup: cancel encounter (still Planned on backend)", async () => { | ||
| await cancelEncounterFromCurrentForm(page); | ||
| }); | ||
| }); | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.