diff --git a/page-objects/patient/ProfilePage.ts b/page-objects/patient/ProfilePage.ts index 35ffcf3..50544b8 100644 --- a/page-objects/patient/ProfilePage.ts +++ b/page-objects/patient/ProfilePage.ts @@ -8,6 +8,11 @@ export class ProfilePage { private saveButton: Locator; + // Inline validation message shown for the diagnosis-date block (e.g. when the + // diagnosis date is earlier than the birth date). Anchored on the .PatientInfo-blocks + // container; the diagnosis date is the 3rd block. Update if the profile form changes. + readonly diagnosisDateError: Locator; + constructor(page: Page) { this.page = page; this.fieldLocators = { @@ -21,6 +26,10 @@ export class ProfilePage { }; this.saveButton = this.page.getByRole('button', { name: 'Save Changes' }); + + this.diagnosisDateError = this.page.locator( + '.PatientInfo-blocks > div:nth-child(3) > div > div', + ); } // Generic fill method for text fields @@ -97,6 +106,27 @@ export class ProfilePage { await this.saveButton.waitFor({ state: 'hidden', timeout: 10000 }); } + /** + * Wait for the core profile edit fields to be visible — confirms the form is in + * edit mode and rendered (used for a visual check after clicking Edit). + */ + async waitForEditFields(): Promise { + await this.fieldLocators.fullName.waitFor({ state: 'visible' }); + await this.fieldLocators.dateOfBirth.waitFor({ state: 'visible' }); + await this.fieldLocators.diagnosisDate.waitFor({ state: 'visible' }); + await this.saveButton.waitFor({ state: 'visible' }); + } + + /** + * Click "Save Changes" WITHOUT waiting for the form to close. Use this to trigger + * the form's on-submit validation when the data is expected to be invalid (the + * form stays open and surfaces inline errors, so `saveProfile()`'s wait-for-hidden + * would hang). + */ + async clickSave(): Promise { + await this.saveButton.click(); + } + /** * Checks if the edit button is displayed and validates against expected state * @param shouldBeVisible - Boolean indicating whether the edit button should be visible diff --git a/tests/claimed/API-Profile/Claimed-EditProfileDetailsAccessConfirm.spec.ts b/tests/claimed/API-Profile/Claimed-EditProfileDetailsAccessConfirm.spec.ts index c45f3f4..9d37ba2 100644 --- a/tests/claimed/API-Profile/Claimed-EditProfileDetailsAccessConfirm.spec.ts +++ b/tests/claimed/API-Profile/Claimed-EditProfileDetailsAccessConfirm.spec.ts @@ -1,4 +1,4 @@ -import { test } from '../../fixtures/base'; +import { expect, test } from '../../fixtures/base'; import { test as patientTest } from '../../fixtures/patient-helpers'; import { test as clinicTest } from '../../fixtures/clinic-helpers'; import { test as accountTest } from '../../fixtures/account-helpers'; @@ -79,21 +79,41 @@ test.describe('Comprehensive Profile Access Test: Edit as Claimed, View as Share // Initialize ProfilePage for steps 4 and 5 const profilePage = new ProfilePage(page); - // Step 5: Change profile fields (confirmed user access) + // Date values are computed once here so both the update step and the invalid-date + // check below share them. The diagnosis date is always birthYear + 20, so the + // "valid" data can never come out randomly earlier than the birth date. The + // invalid date is deliberately one year BEFORE birth for the negative check. + const testRunId = Math.floor(Math.random() * 10000); + const updatedName = `Claimed User Updated ${testRunId}`; + const birthYear = 1985 + (testRunId % 10); + const birthDate = `01/15/${birthYear}`; + const validDiagnosisDate = `01/15/${birthYear + 20}`; + const invalidDiagnosisDate = `01/15/${birthYear - 1}`; + + // Generate random 15-letter string for clinical notes + const randomString = Array.from({ length: 15 }, () => + String.fromCharCode(65 + Math.floor(Math.random() * 26)), + ).join(''); + + // Step 5: Visual check that the edit form is displayed after clicking Edit. await test.step( - 'And user updates profile fields', + 'Then the profile edit fields are displayed', async () => { - const testRunId = Math.floor(Math.random() * 10000); - const updatedName = `Claimed User Updated ${testRunId}`; - const birthYear = 1985 + (testRunId % 10); - const diagnosisYear = birthYear + 20; - const birthDate = `01/15/${birthYear}`; - - // Generate random 15-letter string for clinical notes - const randomString = Array.from({ length: 15 }, () => - String.fromCharCode(65 + Math.floor(Math.random() * 26)), - ).join(''); + await profilePage.waitForEditFields(); + }, + { + detail: + 'Confirm the editable profile fields (name, date of birth, diagnosis date, etc.) ' + + 'are shown after entering edit mode.', + }, + ); + // Step 6: Fill the fields with an INVALID diagnosis date (before birth) and submit. The + // validation error only appears on submit, so click Save without waiting for the form to + // close — it won't, because the data is invalid. + await test.step( + 'When user fills the profile fields with a diagnosis date earlier than the birth date', + async () => { // Get current diagnosis index and calculate next one (1-7, wrapping) const currentDiagnosisIndex = await profilePage.getCurrentDiagnosisIndex(); let nextDiagnosisIndex = currentDiagnosisIndex + 1; @@ -101,28 +121,60 @@ test.describe('Comprehensive Profile Access Test: Edit as Claimed, View as Share nextDiagnosisIndex = 1; } - // Update fields using ProfilePage methods + // Birth date is set before the diagnosis date so the form can validate one against + // the other; the diagnosis date here is deliberately earlier than the birth date. await profilePage.fillFullName(updatedName); await profilePage.fillDateOfBirth(birthDate); + await profilePage.fillDiagnosisDate(invalidDiagnosisDate); await profilePage.selectDiagnosisType(nextDiagnosisIndex); await profilePage.fillClinicalNotes(randomString); }, { detail: - 'Enter updated values for name, date of birth, diagnosis type, and clinical notes.', + 'Enter updated name, date of birth, a diagnosis date earlier than the birth date, ' + + 'diagnosis type, and clinical notes.', }, ); - // Step 6: Save profile edit await test.step( - 'And user saves profile changes', + 'And user clicks Save Changes', async () => { + await profilePage.clickSave(); + }, + { + detail: + 'Click Save Changes to submit the profile with an invalid diagnosis date (earlier than birth date).', + }, + ); + + // Step 7: Confirm the website rejects the invalid diagnosis date. + await test.step( + 'Then an inline validation error is shown for the diagnosis date', + async () => { + await expect(profilePage.diagnosisDateError).toHaveText(/\S/); + }, + { + detail: + 'Confirm the form shows an inline validation error because the diagnosis date is ' + + 'earlier than the birth date.', + }, + ); + + // Step 8: Correct the diagnosis date to a valid value (after birth) and save. + await test.step( + 'When user corrects the diagnosis date to a valid value and saves profile changes', + async () => { + await profilePage.fillDiagnosisDate(validDiagnosisDate); await profilePage.saveProfile(); }, - { detail: 'Click Save to submit the profile changes.' }, + { + detail: + 'Replace the invalid diagnosis date with a valid one (after the birth date) and ' + + 'click Save Changes to submit the profile.', + }, ); - // Step 7: GET response is validated and saved for comparison + // Step 9: GET response is validated and saved for comparison await (test as any).stepNoScreenshot( 'Then profile endpoint responds with GET request consistent with schema', async () => {