@trevordsouzabrite/test-package 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/playwright-test-generator.md +85 -0
- package/.claude/agents/playwright-test-healer.md +45 -0
- package/.claude/agents/playwright-test-planner.md +52 -0
- package/.claude/prompts/playwright-test-coverage.md +31 -0
- package/.claude/prompts/playwright-test-generate.md +12 -0
- package/.claude/prompts/playwright-test-heal.md +6 -0
- package/.claude/prompts/playwright-test-plan.md +12 -0
- package/.claude/settings.local.json +31 -0
- package/.github/agents/playwright-test-generator.agent.md +113 -0
- package/.github/agents/playwright-test-healer.agent.md +70 -0
- package/.github/agents/playwright-test-planner.agent.md +82 -0
- package/.github/prompts/playwright-test-coverage.prompt.md +31 -0
- package/.github/prompts/playwright-test-generate.prompt.md +12 -0
- package/.github/prompts/playwright-test-heal.prompt.md +6 -0
- package/.github/prompts/playwright-test-plan.prompt.md +9 -0
- package/.github/workflows/copilot-setup-steps.yml +34 -0
- package/.github/workflows/playwright-healer-agent.yml +140 -0
- package/.github/workflows/playwright.yml +40 -0
- package/.mcp.json +13 -0
- package/.vscode/extensions.json +6 -0
- package/.vscode/mcp.json +13 -0
- package/.vscode/settings.example.json +15 -0
- package/bitbucket-pipelines.yml +86 -0
- package/lib/WebActions.ts +107 -0
- package/package.json +33 -0
- package/pageRepository/ApplicantPage.ts +1171 -0
- package/pageRepository/CreateApplicationPage.ts +1736 -0
- package/playwright/.auth/user.json +0 -0
- package/specs/Applicant Create Application Page Test Plan.md +440 -0
- package/specs/Applicant Dashboard Page Test Plan.md +74 -0
- package/specs/Applicant Forgot Password Page Test Plan.md +112 -0
- package/specs/Applicant Help Page Test Plan.md +369 -0
- package/specs/Applicant Landing Page Test Plan.md +42 -0
- package/specs/Applicant Login Page Test Plan.md +116 -0
- package/specs/Applicant My Applications Page Test Plan.md +558 -0
- package/specs/Applicant My Medical Coverage Page Test Plan.md +689 -0
- package/specs/Applicant Privacy Policy Page Test Plan.md +196 -0
- package/specs/Applicant Resources Page Test Plan.md +107 -0
- package/specs/Applicant Self Register Page Test Plan.md +190 -0
- package/specs/README.md +3 -0
- package/test-data/Sample.png +0 -0
- package/test-data/createApplication/formData.json +42 -0
- package/test-data/createApplication/textMessages.json +52 -0
- package/test-data/forgotPassword/email.json +5 -0
- package/test-data/forgotPassword/textMessages.json +5 -0
- package/test-data/help/textContent.json +48 -0
- package/test-data/login/invalidUsernamePassword.json +4 -0
- package/test-data/login/textMessages.json +5 -0
- package/test-data/privacyPolicy/textContent.json +25 -0
- package/test-data/selfRegister/mailingAddressStates.json +21 -0
- package/test-data/selfRegister/registrationFieldData.json +13 -0
- package/test-data/selfRegister/suffix.json +3 -0
- package/test-data/selfRegister/textMessages.json +13 -0
- package/test-data/test-data.zip +0 -0
- package/tests/ApplicantCreateApplicationPageTest.spec.ts +1452 -0
- package/tests/ApplicantDashboardPageTest.spec.ts +74 -0
- package/tests/ApplicantForgotPasswordPageTest.spec.ts +88 -0
- package/tests/ApplicantHelpPageTest.spec.ts +468 -0
- package/tests/ApplicantLandingPageTest.spec.ts +33 -0
- package/tests/ApplicantLoginPageTest.spec.ts +117 -0
- package/tests/ApplicantMyApplicationsPageTest.spec.ts +516 -0
- package/tests/ApplicantMyMedicalCoveragePageTest.spec.ts +470 -0
- package/tests/ApplicantPrivacyPolicyPageTest.spec.ts +188 -0
- package/tests/ApplicantResourcesPageTest.spec.ts +117 -0
- package/tests/ApplicantSelfRegisterPageTest.spec.ts +254 -0
- package/tests/auth.setup.ts +42 -0
- package/tests/authState.ts +15 -0
- package/tests/example.spec.ts +18 -0
- package/tests/seed.spec.ts +7 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
// spec: specs/Applicant My Medical Coverage Page Test Plan.md
|
|
2
|
+
// seed: seed.spec.ts
|
|
3
|
+
|
|
4
|
+
import { test, expect } from '@playwright/test';
|
|
5
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
6
|
+
import { ApplicantPage } from '@pages/ApplicantPage';
|
|
7
|
+
import { WebActions } from '@lib/WebActions';
|
|
8
|
+
import { expectApplicantAuthenticatedHeaderFooterVisible } from '@lib/ApplicantPortalAssertions';
|
|
9
|
+
import { testConfig } from '../testConfig';
|
|
10
|
+
|
|
11
|
+
const MY_MEDICAL_COVERAGE_PATH = '/polkphpapplicant/s/enrollments?language=en_US';
|
|
12
|
+
const BILLING_INQUIRIES_PATH = '/polkphpapplicant/s/billing-inquiries?language=en_US';
|
|
13
|
+
|
|
14
|
+
function containsReadableCoverageDate(text: string): boolean {
|
|
15
|
+
return /\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2},\s+\d{4}\b/.test(text);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
test.describe('Applicant My Medical Coverage Page Tests', () => {
|
|
19
|
+
test.describe('Authenticated My Medical Coverage', () => {
|
|
20
|
+
test.skip(process.env.AUTH !== 'true', 'Authenticated My Medical Coverage tests require AUTH=true and playwright/.auth/user.json.');
|
|
21
|
+
test.describe.configure({ mode: 'serial', timeout: 120_000 });
|
|
22
|
+
|
|
23
|
+
let applicantPage: ApplicantPage;
|
|
24
|
+
let webActions: WebActions;
|
|
25
|
+
|
|
26
|
+
test.beforeEach(async ({ page }) => {
|
|
27
|
+
applicantPage = new ApplicantPage(page);
|
|
28
|
+
webActions = new WebActions(page, page.context());
|
|
29
|
+
await applicantPage.gotoMyMedicalCoveragePage();
|
|
30
|
+
await webActions.waitForElementAttached(applicantPage.Logout_Btn);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('TC-01 - Authenticated My Medical Coverage Page Loads @auth ', async ({ page }) => {
|
|
34
|
+
// 1. Start from an authenticated applicant session.
|
|
35
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
36
|
+
// 2. Navigate to the applicant dashboard. 3. Click My Medical Coverage. (done in beforeEach)
|
|
37
|
+
// 4. Verify the URL contains /enrollments.
|
|
38
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/enrollments/i);
|
|
39
|
+
// 5. Verify browser title is Enrollments.
|
|
40
|
+
await expect.soft(page).toHaveTitle(/Enrollments/i);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('TC-02 - Authenticated Header And Footer Are Visible @auth', async () => {
|
|
44
|
+
// 1. Open My Medical Coverage.
|
|
45
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
46
|
+
// 2-4. Verify authenticated header, Logout, and footer content.
|
|
47
|
+
await expectApplicantAuthenticatedHeaderFooterVisible(applicantPage);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('TC-03 - Enrollment Summary Table Displays For Applicant With Coverage @auth ', async () => {
|
|
51
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an applicant account with at least one enrollment record.');
|
|
52
|
+
// 1. Open My Medical Coverage.
|
|
53
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
54
|
+
// 2. Verify the enrollment summary area is visible.
|
|
55
|
+
await expect.soft(applicantPage.MyMedicalCoverageFirstEnrollmentRow_Block).toBeVisible();
|
|
56
|
+
// 3. Verify columns are shown.
|
|
57
|
+
await expect.soft(applicantPage.MyMedicalCoverageBeneficiaryHeader_Text).toBeVisible();
|
|
58
|
+
await expect.soft(applicantPage.MyMedicalCoverageProgramHeader_Text).toBeVisible();
|
|
59
|
+
await expect.soft(applicantPage.MyMedicalCoverageStatusHeader_Text).toBeVisible();
|
|
60
|
+
await expect.soft(applicantPage.MyMedicalCoverageCoverageBeginDateHeader_Text).toBeVisible();
|
|
61
|
+
await expect.soft(applicantPage.MyMedicalCoverageCoverageEndDateHeader_Text).toBeVisible();
|
|
62
|
+
await expect.soft(applicantPage.MyMedicalCoverageActionsHeader_Text).toBeVisible();
|
|
63
|
+
// 4. Verify each visible enrollment row has key values.
|
|
64
|
+
const rowText = await applicantPage.getFirstEnrollmentRowText();
|
|
65
|
+
const pageText = await applicantPage.getMyMedicalCoveragePageText();
|
|
66
|
+
expect.soft(rowText).toMatch(/PHP|Active|Inactive|Expired|Terminated/i);
|
|
67
|
+
expect.soft(containsReadableCoverageDate(pageText)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('TC-04 - Enrollment Row Date And Status Formatting @auth', async () => {
|
|
71
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an applicant account with at least one enrollment record.');
|
|
72
|
+
// 1. Open My Medical Coverage for an applicant with coverage.
|
|
73
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
74
|
+
// 2-4. Read status and coverage date values, then verify readable formatting.
|
|
75
|
+
const rowText = await applicantPage.getFirstEnrollmentRowText();
|
|
76
|
+
const pageText = await applicantPage.getMyMedicalCoveragePageText();
|
|
77
|
+
expect.soft(rowText).toMatch(/Active|Inactive|Expired|Terminated|Pending/i);
|
|
78
|
+
expect.soft(containsReadableCoverageDate(pageText)).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('TC-05 - No Enrollment Empty State @auth', async () => {
|
|
82
|
+
test.skip(await applicantPage.hasMedicalCoverageRecords(), 'Requires an applicant account with no enrollment records.');
|
|
83
|
+
// 1. Open My Medical Coverage.
|
|
84
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
85
|
+
// 2. Wait for enrollment content to finish loading.
|
|
86
|
+
// 3. Verify the page shows DID NOT FIND ANY ENROLLMENT RECORDS.
|
|
87
|
+
await expect.soft(applicantPage.NoEnrollments_Text).toBeVisible();
|
|
88
|
+
// 4. Verify header, footer, and main navigation remain available.
|
|
89
|
+
await expectApplicantAuthenticatedHeaderFooterVisible(applicantPage);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('TC-06 - Change Provider Modal Opens @auth ', async () => {
|
|
93
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an enrollment with the Change Provider action.');
|
|
94
|
+
// 1. Open My Medical Coverage.
|
|
95
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
96
|
+
// 2. Click Change Provider.
|
|
97
|
+
await applicantPage.clickChangeProviderButton();
|
|
98
|
+
// 3. Verify the modal opens with title Change Provider.
|
|
99
|
+
await expect.soft(applicantPage.ChangeProviderDialog_Block).toBeVisible();
|
|
100
|
+
await expect.soft(applicantPage.ChangeProviderHeading_Text).toBeVisible();
|
|
101
|
+
// 4. Verify instruction text.
|
|
102
|
+
await expect.soft(applicantPage.ChangeProviderInstructions_Text).toBeVisible();
|
|
103
|
+
// 5. Verify required fields are visible.
|
|
104
|
+
await expect.soft(applicantPage.ChangeProviderSearch_Input).toBeVisible();
|
|
105
|
+
await expect.soft(applicantPage.ChangeProviderReason_dd).toBeVisible();
|
|
106
|
+
// 6. Verify Close and Submit controls are visible.
|
|
107
|
+
await expect.soft(applicantPage.ChangeProviderClose_Btn).toBeVisible();
|
|
108
|
+
await expect.soft(applicantPage.ChangeProviderSubmit_Btn).toBeVisible();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('TC-07 - Change Provider Empty Submit Validation @auth @validation', async () => {
|
|
112
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an enrollment with the Change Provider action.');
|
|
113
|
+
// 1. Open the Change Provider modal.
|
|
114
|
+
await applicantPage.clickChangeProviderButton();
|
|
115
|
+
// 2. Leave provider search blank.
|
|
116
|
+
// 3. Leave reason dropdown unselected.
|
|
117
|
+
// 4. Click Submit.
|
|
118
|
+
await applicantPage.submitChangeProviderRequest();
|
|
119
|
+
// Verify required field messages and blocked submission.
|
|
120
|
+
await expect.soft(applicantPage.ChangeProviderRequiredFieldErrors_Text.first()).toBeVisible();
|
|
121
|
+
await expect.soft(applicantPage.ChangeProviderRequiredFieldErrors_Text).toHaveCount(2);
|
|
122
|
+
await expect.soft(applicantPage.ChangeProviderErrorNotification_Text).toBeVisible();
|
|
123
|
+
await expect.soft(applicantPage.ChangeProviderDialog_Block).toBeVisible();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('TC-08 - Change Provider Close Does Not Submit @auth', async () => {
|
|
127
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an enrollment with the Change Provider action.');
|
|
128
|
+
// 1. Open the Change Provider modal.
|
|
129
|
+
await applicantPage.clickChangeProviderButton();
|
|
130
|
+
const beforeCloseText = await applicantPage.getFirstEnrollmentRowText();
|
|
131
|
+
// 2. Click Close without entering data.
|
|
132
|
+
await applicantPage.closeChangeProviderDialog();
|
|
133
|
+
// 3. Reopen My Medical Coverage or inspect the enrollment row.
|
|
134
|
+
await expect.soft(applicantPage.ChangeProviderDialog_Block).not.toBeVisible();
|
|
135
|
+
expect.soft(await applicantPage.getFirstEnrollmentRowText()).toContain(beforeCloseText.split(' ')[0]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test.fixme('TC-09 - Change Provider Provider Search Behavior @auth', async () => {
|
|
139
|
+
// Requires stable provider test data for lookup selection.
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test.fixme('TC-10 - Change Provider No-Match Search @auth @edge', async () => {
|
|
143
|
+
// Requires product-approved expectations for provider lookup no-result text.
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test.fixme('TC-11 - Change Provider Submit With Missing Reason @auth @validation', async () => {
|
|
147
|
+
// Requires stable provider test data to select a provider without submitting a real request.
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test.fixme('TC-12 - Change Provider Submit With Missing Provider @auth @validation', async () => {
|
|
151
|
+
// Requires stable reason dropdown option data.
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test.fixme('TC-13 - Change Provider Successful Submission @auth', async () => {
|
|
155
|
+
// Data-changing scenario; requires a controlled account where creating a provider change request is safe.
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('TC-14 - My Request Status Displays Current Provider Change Request @auth', async () => {
|
|
159
|
+
// 1. Open My Medical Coverage.
|
|
160
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
161
|
+
// 2. Inspect the My Request Status section.
|
|
162
|
+
await expect.soft(applicantPage.MyMedicalCoverageRequestStatusHeading_Text).toBeVisible();
|
|
163
|
+
// 3. Verify columns or labels such as Status, Effective Date, and Reference.
|
|
164
|
+
await expect.soft(applicantPage.MyMedicalCoverageRequestStatusStatus_Text).toBeVisible();
|
|
165
|
+
await expect.soft(applicantPage.MyMedicalCoverageRequestStatusEffectiveDate_Text).toBeVisible();
|
|
166
|
+
await expect.soft(applicantPage.MyMedicalCoverageRequestStatusReference_Text).toBeVisible();
|
|
167
|
+
// 4. Verify the current provider reference is displayed when present.
|
|
168
|
+
await expect.soft(applicantPage.MyMedicalCoverageRequestStatus_Block).toBeVisible();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('TC-15 - Enrollment Card Generates PDF @auth ', async ({ page }) => {
|
|
172
|
+
test.skip(!(await applicantPage.hasMedicalCoverageRecords()), 'Requires an enrollment with the Enrollment card action.');
|
|
173
|
+
// 1. Open My Medical Coverage.
|
|
174
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
175
|
+
// 2. Click Enrollment card for an enrollment row.
|
|
176
|
+
const downloadPromise = page.waitForEvent('download', { timeout: 30_000 });
|
|
177
|
+
await applicantPage.clickEnrollmentCardButton();
|
|
178
|
+
const download = await downloadPromise;
|
|
179
|
+
// 3. Wait for navigation or download.
|
|
180
|
+
// 4. Verify the browser navigates to /polkphpapplicant/s/enrollmentcard.
|
|
181
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/enrollmentcard/i);
|
|
182
|
+
// 5. Verify a PDF download is initiated.
|
|
183
|
+
expect.soft(download.suggestedFilename()).toBe('EnrollmentCard.pdf');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test.fixme('TC-16 - Enrollment Card Uses Selected Enrollment Record @auth', async () => {
|
|
187
|
+
// Requires an applicant account with multiple enrollment records.
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('TC-17 - Update My Information Action @auth', async () => {
|
|
191
|
+
// 1. Open My Medical Coverage.
|
|
192
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
193
|
+
// 2. Click Update My Information.
|
|
194
|
+
await applicantPage.clickUpdateMyInformationButton();
|
|
195
|
+
// 3. Wait for navigation, modal, or toast.
|
|
196
|
+
await expect.soft(applicantPage.UpdateMyInformationErrorToast_Text).toBeVisible();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('TC-18 - Update My Information Error Is Dismissible @auth @validation', async () => {
|
|
200
|
+
// 1. Click Update My Information for an account without a matching application.
|
|
201
|
+
await applicantPage.clickUpdateMyInformationButton();
|
|
202
|
+
// 2. Verify the Error No application found. toast appears.
|
|
203
|
+
await expect.soft(applicantPage.UpdateMyInformationErrorToast_Text).toBeVisible();
|
|
204
|
+
// 3. Click the toast Close control.
|
|
205
|
+
await applicantPage.dismissToastIfVisible();
|
|
206
|
+
await expect.soft(applicantPage.MyMedicalCoverageBody_Block).toBeVisible();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('TC-19 - Billing Inquiries Page Opens @auth ', async ({ page }) => {
|
|
210
|
+
// 1. Open My Medical Coverage.
|
|
211
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
212
|
+
// 2. Click Billing Inquiries.
|
|
213
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
214
|
+
// 3. Wait for navigation.
|
|
215
|
+
// 4. Verify URL contains /billing-inquiries.
|
|
216
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/billing-inquiries/i);
|
|
217
|
+
// 5. Verify browser title is Billing_Inquiries.
|
|
218
|
+
await expect.soft(page).toHaveTitle(/Billing_Inquiries/i);
|
|
219
|
+
// 6. Verify heading text and explanatory instructions are visible.
|
|
220
|
+
await expect.soft(applicantPage.BillingInquiryHeading_Text).toBeVisible();
|
|
221
|
+
await expect.soft(applicantPage.BillingInquiryInstructions_Text).toBeVisible();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('TC-20 - Billing Inquiry Form Required Fields Are Visible @auth', async () => {
|
|
225
|
+
// 1. Open Billing Inquiries from My Medical Coverage.
|
|
226
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
227
|
+
// 2. Verify required fields.
|
|
228
|
+
await expect.soft(applicantPage.BillingInquiryCoverageReason_Text).toBeVisible();
|
|
229
|
+
await expect.soft(applicantPage.BillingInquiryDateOfService_Input).toBeVisible();
|
|
230
|
+
await expect.soft(applicantPage.BillingInquiryAmountDue_Input).toBeVisible();
|
|
231
|
+
await expect.soft(applicantPage.BillingInquiryApplicationMember_dd).toBeVisible();
|
|
232
|
+
await expect.soft(applicantPage.BillingInquiryAppealReason_dd).toBeVisible();
|
|
233
|
+
await expect.soft(applicantPage.BillingInquiryProviderFacilityName_Input).toBeVisible();
|
|
234
|
+
await expect.soft(applicantPage.BillingInquiryDocumentType_dd).toBeVisible();
|
|
235
|
+
// 3. Verify optional/conditional fields.
|
|
236
|
+
await expect.soft(applicantPage.BillingInquiryOtherPayer_dd).toBeVisible();
|
|
237
|
+
await expect.soft(applicantPage.BillingInquiryClaimNumber_Input).toBeVisible();
|
|
238
|
+
await expect.soft(applicantPage.BillingInquiryAmountPaidByOtherProvider_Input).toBeVisible();
|
|
239
|
+
// 4. Verify file upload area is visible.
|
|
240
|
+
await expect.soft(applicantPage.BillingInquiryUploadFiles_Btn).toBeVisible();
|
|
241
|
+
await expect.soft(applicantPage.BillingInquiryUploadDropzone_Text).toBeVisible();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('TC-21 - Billing Inquiry Empty Submit Requires Upload @auth @validation', async () => {
|
|
245
|
+
// 1. Open Billing Inquiries.
|
|
246
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
247
|
+
// 2. Do not upload a file.
|
|
248
|
+
// 3. Click Submit.
|
|
249
|
+
await applicantPage.submitBillingInquiry();
|
|
250
|
+
// Verify upload-required toast.
|
|
251
|
+
await expect.soft(applicantPage.BillingInquiryUploadRequiredToast_Text).toBeVisible();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test.fixme('TC-22 - Billing Inquiry Missing Required Field Validation @auth @validation', async () => {
|
|
255
|
+
// Requires a stable upload fixture and field-level validation expectations after upload.
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test.fixme('TC-23 - Billing Inquiry File Upload Accepts Supported Documents @auth', async () => {
|
|
259
|
+
// Requires stable upload control selectors and cleanup behavior.
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test.fixme('TC-24 - Billing Inquiry Rejects Unsupported Or Oversized Files @auth @edge', async () => {
|
|
263
|
+
// Requires product-defined file type and size limits.
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test.fixme('TC-25 - Billing Inquiry Amount Validation @auth @validation', async () => {
|
|
267
|
+
// Requires field-level validation expectations for amount formats.
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test.fixme('TC-26 - Billing Inquiry Date Validation @auth @validation', async () => {
|
|
271
|
+
// Requires product-defined rules for invalid and future service dates.
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('TC-27 - Billing Inquiry Cancel Returns Safely @auth', async ({ page }) => {
|
|
275
|
+
// 1. Open Billing Inquiries.
|
|
276
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
277
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/billing-inquiries/i);
|
|
278
|
+
// 2. Enter partial form data. (skipped to avoid dirty-form confirmation in shared data)
|
|
279
|
+
// 3. Click Cancel.
|
|
280
|
+
await applicantPage.cancelBillingInquiry();
|
|
281
|
+
// 4. Confirm any unsaved-change prompt if shown.
|
|
282
|
+
await expect.soft(applicantPage.MyMedicalCoverageBody_Block).toBeVisible();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test.fixme('TC-28 - Billing Inquiry Successful Submission @auth', async () => {
|
|
286
|
+
// Data-changing scenario; requires controlled test data where creating a billing inquiry is allowed.
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test('TC-31 - Logout Protects My Medical Coverage @auth', async ({ page }) => {
|
|
290
|
+
// 1. Open My Medical Coverage with an authenticated session.
|
|
291
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
292
|
+
// 2. Click Logout.
|
|
293
|
+
await applicantPage.clickLogoutButton();
|
|
294
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/login|\/secur\/logout/i);
|
|
295
|
+
// 3. Attempt to navigate back to /polkphpapplicant/s/enrollments?language=en_US.
|
|
296
|
+
await applicantPage.gotoURL(MY_MEDICAL_COVERAGE_PATH, { handleConsentUpdate: false });
|
|
297
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/login/i);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test.fixme('TC-32 - Unauthorized Enrollment Record Access @auth @security', async () => {
|
|
301
|
+
// Requires a known invalid or cross-applicant enrollment record ID supplied by secure test data.
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test.fixme('TC-33 - Multiple Enrollment Records @auth @edge', async () => {
|
|
305
|
+
// Requires an applicant account with multiple active or historical enrollments.
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test.fixme('TC-34 - Expired Or Inactive Coverage Display @auth @edge', async () => {
|
|
309
|
+
// Requires an applicant account with inactive, expired, terminated, or future-dated coverage.
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('TC-35 - Keyboard Navigation @auth @accessibility', async ({ page }) => {
|
|
313
|
+
// 1. Open My Medical Coverage.
|
|
314
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
315
|
+
// 2. Use Tab and Shift+Tab through page controls.
|
|
316
|
+
await page.keyboard.press('Tab');
|
|
317
|
+
await page.keyboard.press('Tab');
|
|
318
|
+
await page.keyboard.press('Shift+Tab');
|
|
319
|
+
// 3. Activate Change Provider using keyboard controls when available.
|
|
320
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
321
|
+
await applicantPage.MyMedicalCoverageChangeProvider_Btn.focus();
|
|
322
|
+
await page.keyboard.press('Enter');
|
|
323
|
+
await expect.soft(applicantPage.ChangeProviderDialog_Block).toBeVisible();
|
|
324
|
+
// 4. Dismiss modals or toasts with keyboard controls.
|
|
325
|
+
await page.keyboard.press('Escape');
|
|
326
|
+
}
|
|
327
|
+
await expect.soft(applicantPage.MyMedicalCoverageBody_Block).toBeVisible();
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('TC-36 - Accessible Names And Semantics @auth @accessibility', async () => {
|
|
331
|
+
// 1. Open My Medical Coverage.
|
|
332
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
333
|
+
// 2. Verify row action controls have clear accessible names.
|
|
334
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
335
|
+
await expect.soft(applicantPage.MyMedicalCoverageChangeProvider_Btn).toBeVisible();
|
|
336
|
+
await expect.soft(applicantPage.MyMedicalCoverageEnrollmentCard_Btn).toBeVisible();
|
|
337
|
+
}
|
|
338
|
+
// 3. Verify the enrollment table-like region exposes column labels.
|
|
339
|
+
await expect.soft(applicantPage.MyMedicalCoverageBeneficiaryHeader_Text).toBeVisible();
|
|
340
|
+
await expect.soft(applicantPage.MyMedicalCoverageCoverageBeginDateHeader_Text).toBeVisible();
|
|
341
|
+
// 4. Open Change Provider and verify modal semantics when available.
|
|
342
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
343
|
+
await applicantPage.clickChangeProviderButton();
|
|
344
|
+
await expect.soft(applicantPage.ChangeProviderDialog_Block).toBeVisible();
|
|
345
|
+
await expect.soft(applicantPage.ChangeProviderSearch_Input).toBeVisible();
|
|
346
|
+
await applicantPage.closeChangeProviderDialog();
|
|
347
|
+
}
|
|
348
|
+
// 5. Open Billing Inquiries and verify controls are accessible.
|
|
349
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
350
|
+
await expect.soft(applicantPage.BillingInquirySubmit_Btn).toBeVisible();
|
|
351
|
+
await expect.soft(applicantPage.BillingInquiryCancel_Btn).toBeVisible();
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test('TC-37 - Axe Accessibility Baseline @auth @accessibility', async ({ page }) => {
|
|
355
|
+
// 1. Open My Medical Coverage.
|
|
356
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
357
|
+
// 2. Run Axe with WCAG 2.x A/AA rules.
|
|
358
|
+
let accessibilityScanResults = await new AxeBuilder({ page })
|
|
359
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
|
360
|
+
.analyze();
|
|
361
|
+
expect.soft(accessibilityScanResults.violations.filter((violation) => ['critical', 'serious'].includes(violation.impact ?? ''))).toEqual([]);
|
|
362
|
+
// 3. Repeat after opening the Change Provider modal.
|
|
363
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
364
|
+
await applicantPage.clickChangeProviderButton();
|
|
365
|
+
accessibilityScanResults = await new AxeBuilder({ page })
|
|
366
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
|
367
|
+
.analyze();
|
|
368
|
+
expect.soft(accessibilityScanResults.violations.filter((violation) => ['critical', 'serious'].includes(violation.impact ?? ''))).toEqual([]);
|
|
369
|
+
}
|
|
370
|
+
// 4. Repeat on Billing Inquiries.
|
|
371
|
+
await applicantPage.gotoURL(BILLING_INQUIRIES_PATH);
|
|
372
|
+
accessibilityScanResults = await new AxeBuilder({ page })
|
|
373
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
|
374
|
+
.analyze();
|
|
375
|
+
expect.soft(accessibilityScanResults.violations.filter((violation) => ['critical', 'serious'].includes(violation.impact ?? ''))).toEqual([]);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test('TC-38 - Responsive Layout @auth', async ({ page }) => {
|
|
379
|
+
for (const viewport of [
|
|
380
|
+
{ width: 1500, height: 730 },
|
|
381
|
+
{ width: 768, height: 1024 },
|
|
382
|
+
{ width: 412, height: 732 },
|
|
383
|
+
]) {
|
|
384
|
+
// 1-3. Open My Medical Coverage at desktop, tablet, and mobile viewport sizes.
|
|
385
|
+
await page.setViewportSize(viewport);
|
|
386
|
+
await applicantPage.gotoMyMedicalCoveragePage();
|
|
387
|
+
// 4. Verify enrollment page, actions, header, and footer remain usable.
|
|
388
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
389
|
+
await expect.soft(applicantPage.MyMedicalCoverageBody_Block).toBeVisible();
|
|
390
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
391
|
+
await expect.soft(applicantPage.MyMedicalCoverageChangeProvider_Btn).toBeVisible();
|
|
392
|
+
await expect.soft(applicantPage.MyMedicalCoverageEnrollmentCard_Btn).toBeVisible();
|
|
393
|
+
} else {
|
|
394
|
+
await expect.soft(applicantPage.NoEnrollments_Text).toBeVisible();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test('TC-39 - Browser Console And Network Health @auth', async ({ page }) => {
|
|
400
|
+
const consoleErrors: string[] = [];
|
|
401
|
+
const failedRequests: string[] = [];
|
|
402
|
+
|
|
403
|
+
page.on('console', (message) => {
|
|
404
|
+
if (message.type() === 'error') {
|
|
405
|
+
consoleErrors.push(message.text());
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
page.on('requestfailed', (request) => {
|
|
409
|
+
if (['document', 'xhr', 'fetch'].includes(request.resourceType())) {
|
|
410
|
+
failedRequests.push(`${request.resourceType()} ${request.url()} ${request.failure()?.errorText ?? ''}`);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// 1. Open My Medical Coverage.
|
|
415
|
+
await applicantPage.gotoMyMedicalCoveragePage();
|
|
416
|
+
// 2-3. Monitor initial load and action navigation.
|
|
417
|
+
if (await applicantPage.hasMedicalCoverageRecords()) {
|
|
418
|
+
await applicantPage.clickChangeProviderButton();
|
|
419
|
+
await applicantPage.closeChangeProviderDialog();
|
|
420
|
+
}
|
|
421
|
+
await applicantPage.clickBillingInquiriesButton();
|
|
422
|
+
// 4. Monitor console messages and failed network requests.
|
|
423
|
+
expect.soft(failedRequests).toEqual([]);
|
|
424
|
+
expect.soft(consoleErrors.filter((error) => !/ResizeObserver|Aura|Lightning|CSS Error/i.test(error))).toEqual([]);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test.fixme('TC-40 - Data Privacy In Enrollment And PDF Output @auth @security', async () => {
|
|
428
|
+
// Requires PDF parsing and secure test data expectations for the authenticated applicant.
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test.describe('Unauthenticated My Medical Coverage Access', () => {
|
|
433
|
+
test.use({ storageState: { cookies: [], origins: [] } });
|
|
434
|
+
|
|
435
|
+
let applicantPage: ApplicantPage;
|
|
436
|
+
|
|
437
|
+
test.beforeEach(async ({ page }) => {
|
|
438
|
+
applicantPage = new ApplicantPage(page);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test('TC-29 - Direct Unauthenticated Access Redirects To Login @no-auth ', async ({ page }) => {
|
|
442
|
+
// 1. Create a new browser context without storage state.
|
|
443
|
+
await page.context().clearCookies();
|
|
444
|
+
// 2. Navigate directly to /polkphpapplicant/s/enrollments?language=en_US.
|
|
445
|
+
await applicantPage.gotoURL(MY_MEDICAL_COVERAGE_PATH, { handleConsentUpdate: false });
|
|
446
|
+
// 3. Wait for navigation and verify redirect/login form.
|
|
447
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/login/i);
|
|
448
|
+
expect.soft(page.url()).toContain('ec=302');
|
|
449
|
+
expect.soft(page.url()).toContain('startURL');
|
|
450
|
+
expect.soft(page.url()).toContain('enrollments');
|
|
451
|
+
await expect.soft(applicantPage.UsernameField_Input).toBeVisible();
|
|
452
|
+
await expect.soft(applicantPage.PasswordField_Input).toBeVisible();
|
|
453
|
+
await expect.soft(applicantPage.LoginSubmit_Btn).toBeVisible();
|
|
454
|
+
await expect.soft(applicantPage.ForgotPassword_Lnk).toBeVisible();
|
|
455
|
+
await expect.soft(applicantPage.SignUp_Lnk).toBeVisible();
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('TC-30 - Login Redirect Returns To My Medical Coverage @no-auth', async ({ page }) => {
|
|
459
|
+
test.skip(!testConfig.login || !testConfig.password, 'LOGIN and PASSWORD must be set for redirect login coverage.');
|
|
460
|
+
// 1. Navigate directly to My Medical Coverage without auth.
|
|
461
|
+
await applicantPage.gotoURL(MY_MEDICAL_COVERAGE_PATH, { handleConsentUpdate: false });
|
|
462
|
+
await expect.soft(page).toHaveURL(/\/polkphpapplicant\/s\/login/i);
|
|
463
|
+
// 2. Complete login with valid credentials.
|
|
464
|
+
await applicantPage.loginAsApplicant(testConfig.login, testConfig.password);
|
|
465
|
+
// 3. Wait for post-login navigation.
|
|
466
|
+
await applicantPage.waitForMyMedicalCoveragePageReady();
|
|
467
|
+
expect.soft(page.url()).toContain('/polkphpapplicant/s/enrollments');
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// spec: specs/Applicant Privacy Policy Page Test Plan.md
|
|
2
|
+
// seed: seed.spec.ts
|
|
3
|
+
|
|
4
|
+
import { test, expect } from '@playwright/test';
|
|
5
|
+
import { ApplicantPage } from '@pages/ApplicantPage';
|
|
6
|
+
import { WebActions } from '@lib/WebActions';
|
|
7
|
+
import {
|
|
8
|
+
expectApplicantAuthenticatedHeaderFooterVisible,
|
|
9
|
+
expectApplicantAuthenticatedHeaderVisible,
|
|
10
|
+
expectApplicantFooterVisible,
|
|
11
|
+
} from '@lib/ApplicantPortalAssertions';
|
|
12
|
+
import privacyPolicyTextData from '../test-data/privacyPolicy/textContent.json';
|
|
13
|
+
|
|
14
|
+
test.describe('Applicant Privacy Policy Page Tests', () => {
|
|
15
|
+
let applicantPage: ApplicantPage;
|
|
16
|
+
let webActions: WebActions;
|
|
17
|
+
|
|
18
|
+
test.beforeEach(async ({ page }) => {
|
|
19
|
+
applicantPage = new ApplicantPage(page);
|
|
20
|
+
webActions = new WebActions(page, page.context());
|
|
21
|
+
await applicantPage.gotoURL('/polkphpapplicant/s/?language=en_US');
|
|
22
|
+
await webActions.waitForElementAttached(applicantPage.Logout_Btn);
|
|
23
|
+
// Click the Privacy Policy link in the header navigation
|
|
24
|
+
await applicantPage.clickPrivacyPolicyHeaderLink();
|
|
25
|
+
await webActions.waitForElementAttached(applicantPage.PrivacyPolicyTitle_Text);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// TC-01 — Authenticated Header, Footer, And Privacy Policy H1 Are Visible
|
|
29
|
+
test('TC-01 - Authenticated Header, Footer, And Privacy Policy H1 Are Visible @auth', async ({ page }) => {
|
|
30
|
+
// Verify authenticated header and footer elements are visible
|
|
31
|
+
await expectApplicantAuthenticatedHeaderFooterVisible(applicantPage);
|
|
32
|
+
// Verify the Privacy Policy H1 heading is visible
|
|
33
|
+
await expect.soft(applicantPage.PrivacyPolicyTitle_Text).toBeVisible();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// TC-02 — Registration Information Section Content Is Correct
|
|
37
|
+
test('TC-02 - Registration Information Section Content Is Correct @auth', async ({ page }) => {
|
|
38
|
+
// Verify the Registration Information H2 heading is visible and text matches data
|
|
39
|
+
await expect.soft(applicantPage.RegistrationInformationHeading_Text).toBeVisible();
|
|
40
|
+
expect.soft(await applicantPage.RegistrationInformationHeading_Text.textContent()).toContain(privacyPolicyTextData.h2RegistrationInfo);
|
|
41
|
+
// Verify first paragraph text under Registration Information matches the full expected text
|
|
42
|
+
await expect.soft(applicantPage.PrivacyPolicyFirstParagraph_Text).toBeVisible();
|
|
43
|
+
expect.soft(await applicantPage.PrivacyPolicyFirstParagraph_Text.textContent()).toContain(privacyPolicyTextData.firstParagraph);
|
|
44
|
+
// Verify the SMS Privacy Notice paragraph text matches the full expected text
|
|
45
|
+
await expect.soft(applicantPage.PrivacyPolicySMSNoticeParagraph_Text).toBeVisible();
|
|
46
|
+
expect.soft(await applicantPage.PrivacyPolicySMSNoticeParagraph_Text.textContent()).toContain(privacyPolicyTextData.smsNoticeParagraph);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// TC-03 — How Polk County Uses Your Information Section Content Is Correct
|
|
50
|
+
test('TC-03 - How Polk County Uses Your Information Section Content Is Correct @auth', async ({ page }) => {
|
|
51
|
+
// Verify the How Polk County Uses Your Information H2 heading text matches data
|
|
52
|
+
await expect.soft(applicantPage.HowPolkCountyUsesYourInformationHeading_Text).toBeVisible();
|
|
53
|
+
expect.soft(await applicantPage.HowPolkCountyUsesYourInformationHeading_Text.textContent()).toContain(privacyPolicyTextData.h2HowPolkUses);
|
|
54
|
+
// Verify the introductory paragraph text matches data
|
|
55
|
+
await expect.soft(applicantPage.PrivacyPolicyHowPolkIntroParagraph_Text).toBeVisible();
|
|
56
|
+
expect.soft(await applicantPage.PrivacyPolicyHowPolkIntroParagraph_Text.textContent()).toContain(privacyPolicyTextData.howPolkIntroParagraph);
|
|
57
|
+
// Verify the bulleted list has exactly the expected number of items
|
|
58
|
+
await expect(applicantPage.PrivacyPolicyListItems_Li).toHaveCount(privacyPolicyTextData.listItemsCount);
|
|
59
|
+
// Validate every list item's text matches the expected content from the data file
|
|
60
|
+
for (let i = 0; i < privacyPolicyTextData.listItems.length; i++) {
|
|
61
|
+
expect.soft(await applicantPage.PrivacyPolicyListItems_Li.nth(i).textContent()).toContain(privacyPolicyTextData.listItems[i]);
|
|
62
|
+
}
|
|
63
|
+
// Verify the closing paragraph text matches the full expected text
|
|
64
|
+
await expect.soft(applicantPage.PrivacyPolicyClosingParagraph_Text).toBeVisible();
|
|
65
|
+
expect.soft(await applicantPage.PrivacyPolicyClosingParagraph_Text.textContent()).toContain(privacyPolicyTextData.closingParagraph);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// TC-04 — Browser Tab Title Is Privacy Policy
|
|
69
|
+
test('TC-04 - Browser Tab Title Is Privacy Policy @auth', async ({ page }) => {
|
|
70
|
+
// Verify the browser tab title matches the expected document title
|
|
71
|
+
await expect(page).toHaveTitle(privacyPolicyTextData.documentTitle);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// TC-05 — Heading Hierarchy And Accessibility Attributes Are Correct
|
|
75
|
+
test('TC-05 - Heading Hierarchy And Accessibility Attributes Are Correct @auth', async ({ page }) => {
|
|
76
|
+
// Verify exactly one H1 element with the correct text
|
|
77
|
+
await expect(applicantPage.PrivacyPolicyH1_All).toHaveCount(1);
|
|
78
|
+
await expect(applicantPage.PrivacyPolicyH1Role_Heading).toHaveText(privacyPolicyTextData.h1Title);
|
|
79
|
+
// Verify exactly two H2 elements in the page
|
|
80
|
+
await expect(applicantPage.PrivacyPolicyH2_All).toHaveCount(2);
|
|
81
|
+
// Verify no H3 or lower-level headings are present
|
|
82
|
+
await expect(applicantPage.PrivacyPolicyH3_All).toHaveCount(0);
|
|
83
|
+
// Verify the HTML lang attribute matches data
|
|
84
|
+
await expect(applicantPage.HtmlRoot_Elem).toHaveAttribute('lang', privacyPolicyTextData.htmlLang);
|
|
85
|
+
// Verify the Logo image alt attribute matches data
|
|
86
|
+
await expect(applicantPage.Logo_Img).toHaveAttribute('alt', privacyPolicyTextData.logoAlt);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// TC-06 — Privacy Policy Header Link From Another Authenticated Page Navigates To Privacy Policy
|
|
90
|
+
test('TC-06 - Privacy Policy Header Link From Another Authenticated Page Navigates To Privacy Policy @auth', async ({ page }) => {
|
|
91
|
+
// Navigate to the Resources page from the current Privacy Policy page
|
|
92
|
+
await applicantPage.clickResourcesLink();
|
|
93
|
+
await webActions.waitForElementAttached(applicantPage.ResourcesTitle_Text);
|
|
94
|
+
// Verify the Resources page is loaded while user remains authenticated
|
|
95
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
96
|
+
// Click the Privacy Policy link in the header navigation
|
|
97
|
+
await applicantPage.clickPrivacyPolicyHeaderLink();
|
|
98
|
+
await webActions.waitForElementAttached(applicantPage.PrivacyPolicyTitle_Text);
|
|
99
|
+
// Verify the browser navigated to the Privacy Policy page
|
|
100
|
+
expect.soft(page.url()).toContain('privacy-policy');
|
|
101
|
+
// Verify the Privacy Policy H1 heading is visible
|
|
102
|
+
await expect.soft(applicantPage.PrivacyPolicyTitle_Text).toBeVisible();
|
|
103
|
+
// Verify user remains authenticated
|
|
104
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// TC-07 — Header Nav Links From Privacy Policy Page Return To Dashboard While Authenticated
|
|
108
|
+
test('TC-07 - Header Nav Links From Privacy Policy Page Return To Dashboard While Authenticated @auth', async ({ page }) => {
|
|
109
|
+
// Click the Home link in the header navigation
|
|
110
|
+
await applicantPage.clickHomeLink();
|
|
111
|
+
await webActions.waitForElementAttached(applicantPage.WelcomeHeading_Text);
|
|
112
|
+
// Verify navigation to the dashboard page
|
|
113
|
+
expect.soft(page.url()).toContain('/polkphpapplicant/s/');
|
|
114
|
+
expect.soft(page.url()).not.toContain('privacy-policy');
|
|
115
|
+
// Verify the welcome heading is visible
|
|
116
|
+
await expect.soft(applicantPage.WelcomeHeading_Text).toBeVisible();
|
|
117
|
+
// Verify user remains authenticated
|
|
118
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
119
|
+
// Navigate back to Privacy Policy and click the Logo image
|
|
120
|
+
await applicantPage.clickPrivacyPolicyHeaderLink();
|
|
121
|
+
await webActions.waitForElementAttached(applicantPage.PrivacyPolicyTitle_Text);
|
|
122
|
+
await applicantPage.Logo_Img.click();
|
|
123
|
+
await webActions.waitForElementAttached(applicantPage.WelcomeHeading_Text);
|
|
124
|
+
// Verify navigation back to dashboard
|
|
125
|
+
expect.soft(page.url()).toContain('/polkphpapplicant/s/');
|
|
126
|
+
expect.soft(page.url()).not.toContain('privacy-policy');
|
|
127
|
+
// Verify user remains authenticated
|
|
128
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// TC-08 — Desktop Viewport Layout (1500x730) Renders Correctly
|
|
132
|
+
test('TC-08 - Desktop Viewport Layout (1500x730) Renders Correctly @auth', async ({ page }) => {
|
|
133
|
+
// Set the viewport to 1500x730 (desktop) and navigate to Privacy Policy
|
|
134
|
+
await page.setViewportSize({ width: 1500, height: 730 });
|
|
135
|
+
await applicantPage.gotoURL('/polkphpapplicant/s/privacy-policy');
|
|
136
|
+
await webActions.waitForElementAttached(applicantPage.PrivacyPolicyTitle_Text);
|
|
137
|
+
// Verify the Privacy Policy H1 heading is visible
|
|
138
|
+
await expect.soft(applicantPage.PrivacyPolicyTitle_Text).toBeVisible();
|
|
139
|
+
// Verify header & footer elements are visible
|
|
140
|
+
await expectApplicantAuthenticatedHeaderFooterVisible(applicantPage);
|
|
141
|
+
// Verify no horizontal overflow (allow small tolerance for scrollbar width)
|
|
142
|
+
await expect
|
|
143
|
+
.poll(() => page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth + 20))
|
|
144
|
+
.toBeTruthy();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// TC-09 — Mobile Viewport Layout (Pixel 4a 412x732) Renders Correctly
|
|
148
|
+
test('TC-09 - Mobile Viewport Layout (Pixel 4a 412x732) Renders Correctly @auth', async ({ page }) => {
|
|
149
|
+
// Set the viewport to 412x732 (Pixel 4a mobile) and navigate to Privacy Policy
|
|
150
|
+
await page.setViewportSize({ width: 412, height: 732 });
|
|
151
|
+
await applicantPage.gotoURL('/polkphpapplicant/s/privacy-policy');
|
|
152
|
+
await webActions.waitForElementAttached(applicantPage.PrivacyPolicyTitle_Text);
|
|
153
|
+
// Verify the Privacy Policy H1 heading is visible
|
|
154
|
+
await expect.soft(applicantPage.PrivacyPolicyTitle_Text).toBeVisible();
|
|
155
|
+
// Verify the Logo image is visible
|
|
156
|
+
await expect.soft(applicantPage.Logo_Img).toBeVisible();
|
|
157
|
+
// Verify the Logout button is visible
|
|
158
|
+
await expect.soft(applicantPage.Logout_Btn).toBeVisible();
|
|
159
|
+
// Scroll to footer and verify footer content
|
|
160
|
+
await applicantPage.PolkHealthCare_Img.scrollIntoViewIfNeeded();
|
|
161
|
+
await expect.soft(applicantPage.PolkHealthCare_Img).toBeVisible();
|
|
162
|
+
await expect.soft(applicantPage.Copyright_Text).toBeVisible();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// TC-10 — SMS Privacy Notice Bold Lead-In Formatting Is Present
|
|
166
|
+
test('TC-10 - SMS Privacy Notice Bold Lead-In Formatting Is Present @auth', async ({ page }) => {
|
|
167
|
+
// Locate the SMS Privacy Notice <strong> element and verify it is visible
|
|
168
|
+
await expect.soft(applicantPage.PrivacyPolicySMSNoticeBold_Lbl).toBeVisible();
|
|
169
|
+
// Verify the bold label text matches the expected SMS Privacy Notice label from data
|
|
170
|
+
await expect.soft(applicantPage.PrivacyPolicySMSNoticeBold_Lbl).toHaveText(privacyPolicyTextData.smsNoticeBoldLabel);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// TC-11 — No Broken Images On The Privacy Policy Page
|
|
174
|
+
test('TC-11 - No Broken Images On The Privacy Policy Page @auth', async ({ page }) => {
|
|
175
|
+
// Check the header Logo image has loaded correctly
|
|
176
|
+
await applicantPage.Logo_Img.scrollIntoViewIfNeeded();
|
|
177
|
+
await expect.soft(applicantPage.Logo_Img).toBeVisible();
|
|
178
|
+
await expect
|
|
179
|
+
.poll(() => applicantPage.Logo_Img.evaluate((img) => (img as HTMLImageElement).naturalWidth))
|
|
180
|
+
.toBeGreaterThan(0);
|
|
181
|
+
// Scroll to footer and check the Polk HealthCare Plan image has loaded correctly
|
|
182
|
+
await applicantPage.PolkHealthCare_Img.scrollIntoViewIfNeeded();
|
|
183
|
+
await expect.soft(applicantPage.PolkHealthCare_Img).toBeVisible();
|
|
184
|
+
await expect
|
|
185
|
+
.poll(() => applicantPage.PolkHealthCare_Img.evaluate((img) => (img as HTMLImageElement).naturalWidth))
|
|
186
|
+
.toBeGreaterThan(0);
|
|
187
|
+
});
|
|
188
|
+
});
|