From 07a05ff0beafc8f79e75f352091a0f7e53519bd7 Mon Sep 17 00:00:00 2001 From: Bangbay Siboliban Date: Fri, 6 Dec 2024 14:06:20 -0800 Subject: [PATCH] Add MCPAR dashboard Playwright tests (#11959) --- .env.tpl | 4 +- tests/playwright/pages/banner.spec.ts | 6 +- tests/playwright/pages/home.spec.ts | 9 ++- .../playwright/pages/mcpar/dashboard.spec.ts | 72 +++++++++++++++++ tests/playwright/pages/profile.spec.ts | 8 +- tests/playwright/utils/auth.setup.ts | 17 ++-- tests/playwright/utils/consts.ts | 7 +- tests/playwright/utils/fixtures/base.ts | 80 +++++++++++-------- tests/playwright/utils/index.ts | 3 +- .../utils/pageObjects/adminHome.page.ts | 32 ++++++++ tests/playwright/utils/pageObjects/index.ts | 13 +++ .../utils/pageObjects/mcpar/dashboard.page.ts | 67 ++++++++++++++++ .../pageObjects/mcpar/getStarted.page.ts | 17 ++++ .../utils/pageObjects/stateHome.page.ts | 11 +-- 14 files changed, 286 insertions(+), 60 deletions(-) create mode 100644 tests/playwright/pages/mcpar/dashboard.spec.ts create mode 100644 tests/playwright/utils/pageObjects/index.ts create mode 100644 tests/playwright/utils/pageObjects/mcpar/dashboard.page.ts create mode 100644 tests/playwright/utils/pageObjects/mcpar/getStarted.page.ts diff --git a/.env.tpl b/.env.tpl index b86c67798..106769d1d 100644 --- a/.env.tpl +++ b/.env.tpl @@ -46,5 +46,5 @@ TEST_ADMIN_USER_EMAIL=op://mdct_devs/mcr_secrets/CYPRESS_ADMIN_USER_EMAIL TEST_ADMIN_USER_PASSWORD=op://mdct_devs/mcr_secrets/CYPRESS_ADMIN_USER_PASSWORD # pragma: allowlist secret TEST_STATE_USER_EMAIL=op://mdct_devs/mcr_secrets/CYPRESS_STATE_USER_EMAIL TEST_STATE_USER_PASSWORD=op://mdct_devs/mcr_secrets/CYPRESS_STATE_USER_PASSWORD # pragma: allowlist secret -TEST_STATE=MN -TEST_STATE=Minnesota +TEST_STATE=DC +TEST_STATE_NAME="District of Columbia" diff --git a/tests/playwright/pages/banner.spec.ts b/tests/playwright/pages/banner.spec.ts index 92bfff922..0ae8d6368 100644 --- a/tests/playwright/pages/banner.spec.ts +++ b/tests/playwright/pages/banner.spec.ts @@ -1,5 +1,5 @@ -import { test, expect } from "../utils/fixtures/base"; -import BannerPage from "../utils/pageObjects/banner.page"; +import { expect, test } from "../utils/fixtures/base"; +import { BannerPage, stateUserAuth } from "../utils"; test.describe("admin user banner page", () => { test("Should see the correct banner page as an admin user", async ({ @@ -34,7 +34,7 @@ test.describe("admin user banner page", () => { profilePage, }) => { const userContext = await browser.newContext({ - storageState: ".auth/user.json", + storageState: stateUserAuth, }); await profilePage.goto(); const newBannerPage = new BannerPage(await userContext.newPage()); diff --git a/tests/playwright/pages/home.spec.ts b/tests/playwright/pages/home.spec.ts index 435dde011..381ee93cb 100644 --- a/tests/playwright/pages/home.spec.ts +++ b/tests/playwright/pages/home.spec.ts @@ -1,5 +1,5 @@ -import { test, expect } from "../utils/fixtures/base"; -import BasePage from "../utils/pageObjects/base.page"; +import { expect, test } from "../utils/fixtures/base"; +import { BasePage } from "../utils"; test.describe("state user home page", () => { test("Should see the correct home page as a state user", async ({ @@ -7,8 +7,9 @@ test.describe("state user home page", () => { }) => { await stateHomePage.goto(); await stateHomePage.isReady(); - await expect(stateHomePage.wpButton).toBeVisible(); - await expect(stateHomePage.sarButton).toBeVisible(); + await expect(stateHomePage.mcparButton).toBeVisible(); + await expect(stateHomePage.mlrButton).toBeVisible(); + await expect(stateHomePage.naaarButton).toBeVisible(); }); test("Is accessible on all device types for state user", async ({ diff --git a/tests/playwright/pages/mcpar/dashboard.spec.ts b/tests/playwright/pages/mcpar/dashboard.spec.ts new file mode 100644 index 000000000..59448d1d0 --- /dev/null +++ b/tests/playwright/pages/mcpar/dashboard.spec.ts @@ -0,0 +1,72 @@ +import { expect, test } from "../../utils/fixtures/base"; +import { stateName } from "../../utils"; + +let currentDate = ""; +let programName = ""; +let updatedProgramName = ""; + +test.beforeAll(async () => { + currentDate = new Date().toISOString(); + programName = `automated test - ${currentDate}`; + updatedProgramName = `Updated: ${programName}`; +}); + +test.describe( + "MCPAR Dashboard Page - Program Creation/Editing/Archiving", + () => { + test("State users can create and edit reports", async ({ + mcparDashboardPage, + mcparGetStartedPage, + stateHomePage, + }) => { + await stateHomePage.goto(); + await stateHomePage.isReady(); + + await stateHomePage.mcparButton.isVisible(); + await stateHomePage.mcparButton.click(); + await stateHomePage.redirectPage("/mcpar/get-started"); + + await mcparGetStartedPage.mcparButton.isVisible(); + await mcparGetStartedPage.mcparButton.click(); + await mcparGetStartedPage.redirectPage("/mcpar"); + + const originalRow = mcparDashboardPage.table.getByRole("row", { + name: programName, + }); + const updatedRow = mcparDashboardPage.table.getByRole("row", { + name: updatedProgramName, + }); + + // Create MCPAR + await mcparDashboardPage.create(programName); + await expect(originalRow).toBeVisible(); + await expect(updatedRow).toBeHidden(); + + // Update MCPAR + await mcparDashboardPage.update(programName, updatedProgramName); + await expect(originalRow).toBeHidden(); + await expect(updatedRow).toBeVisible(); + }); + + test("Admin users can archive/unarchive reports", async ({ + adminHomePage, + }) => { + await adminHomePage.archiveMCPAR(stateName, updatedProgramName); + await adminHomePage.unarchiveMCPAR(stateName, updatedProgramName); + }); + + test("State users can't see archived programs", async ({ + adminHomePage, + mcparDashboardPage, + }) => { + await adminHomePage.archiveMCPAR(stateName, updatedProgramName); + + await mcparDashboardPage.goto(); + await mcparDashboardPage.isReady(); + await mcparDashboardPage.table.isVisible(); + await expect( + mcparDashboardPage.table.getByRole("row", { name: updatedProgramName }) + ).toBeHidden(); + }); + } +); diff --git a/tests/playwright/pages/profile.spec.ts b/tests/playwright/pages/profile.spec.ts index ca53d2c40..db62155e2 100644 --- a/tests/playwright/pages/profile.spec.ts +++ b/tests/playwright/pages/profile.spec.ts @@ -1,6 +1,6 @@ -import { test, expect } from "../utils/fixtures/base"; +import { expect, test } from "../utils/fixtures/base"; import { BrowserContext, Page } from "@playwright/test"; -import ProfilePage from "../utils/pageObjects/profile.page"; +import { adminUserAuth, ProfilePage, stateUserAuth } from "../utils"; let adminPage: Page; let userPage: Page; @@ -9,12 +9,12 @@ let userContext: BrowserContext; test.beforeAll(async ({ browser }) => { adminContext = await browser.newContext({ - storageState: ".auth/admin.json", + storageState: adminUserAuth, }); adminPage = await adminContext.newPage(); userContext = await browser.newContext({ - storageState: ".auth/user.json", + storageState: stateUserAuth, }); userPage = await userContext.newPage(); }); diff --git a/tests/playwright/utils/auth.setup.ts b/tests/playwright/utils/auth.setup.ts index 8dcf84365..94e389a53 100644 --- a/tests/playwright/utils/auth.setup.ts +++ b/tests/playwright/utils/auth.setup.ts @@ -1,8 +1,13 @@ import { test as setup } from "@playwright/test"; -import { adminPassword, adminUser, statePassword, stateUser } from "./consts"; - -const adminFile = ".auth/admin.json"; +import { + adminPassword, + adminUser, + adminUserAuth, + statePassword, + stateUser, + stateUserAuth, +} from "./consts"; setup("authenticate as admin", async ({ page }) => { await page.goto("/"); @@ -19,11 +24,9 @@ setup("authenticate as admin", async ({ page }) => { }) .isVisible(); await page.waitForTimeout(1000); - await page.context().storageState({ path: adminFile }); + await page.context().storageState({ path: adminUserAuth }); }); -const userFile = ".auth/user.json"; - setup("authenticate as user", async ({ page }) => { await page.goto("/"); const emailInput = page.getByRole("textbox", { name: "email" }); @@ -39,5 +42,5 @@ setup("authenticate as user", async ({ page }) => { }) .isVisible(); await page.waitForTimeout(1000); - await page.context().storageState({ path: userFile }); + await page.context().storageState({ path: stateUserAuth }); }); diff --git a/tests/playwright/utils/consts.ts b/tests/playwright/utils/consts.ts index 367ceeb8c..11cfdfa18 100644 --- a/tests/playwright/utils/consts.ts +++ b/tests/playwright/utils/consts.ts @@ -3,7 +3,10 @@ export const adminPassword = process.env.TEST_ADMIN_USER_PASSWORD!; // pragma: a export const stateUser = process.env.TEST_STATE_USER_EMAIL!; export const statePassword = process.env.TEST_STATE_USER_PASSWORD!; // pragma: allowlist secret -export const stateAbbreviation = process.env.TEST_STATE || "MN"; -export const stateName = process.env.TEST_STATE_NAME || "Minnesota"; +export const stateAbbreviation = process.env.TEST_STATE || "DC"; +export const stateName = process.env.TEST_STATE_NAME || "District of Columbia"; export const currentYear: number = new Date().getFullYear(); + +export const stateUserAuth: string = ".auth/user.json"; +export const adminUserAuth: string = ".auth/admin.json"; diff --git a/tests/playwright/utils/fixtures/base.ts b/tests/playwright/utils/fixtures/base.ts index 88d6a39f7..2bfd969b6 100644 --- a/tests/playwright/utils/fixtures/base.ts +++ b/tests/playwright/utils/fixtures/base.ts @@ -1,48 +1,64 @@ -import { mergeTests, test as base } from "@playwright/test"; -import StateHomePage from "../pageObjects/stateHome.page"; -import AdminHomePage from "../pageObjects/adminHome.page"; -import BannerPage from "../pageObjects/banner.page"; -import ProfilePage from "../pageObjects/profile.page"; +import { Browser, mergeTests, test as base } from "@playwright/test"; +import { + AdminHomePage, + adminUserAuth, + BannerPage, + MCPARDashboardPage, + MCPARGetStartedPage, + ProfilePage, + StateHomePage, + stateUserAuth, +} from "../../utils"; type CustomFixtures = { - stateHomePage: StateHomePage; adminHomePage: AdminHomePage; bannerPage: BannerPage; profilePage: ProfilePage; + mcparGetStartedPage: MCPARGetStartedPage; + mcparDashboardPage: MCPARDashboardPage; + stateHomePage: StateHomePage; }; +async function addPageObject( + PageObject: any, + browser: Browser, + use: any, + storageState: string +) { + const context = await browser.newContext({ storageState }); + const page = new PageObject(await context.newPage()); + // Init page + await page.goto(); + await use(page); + await context.close(); +} + +async function adminPage(PageObject: any, browser: Browser, use: any) { + await addPageObject(PageObject, browser, use, adminUserAuth); +} + +async function statePage(PageObject: any, browser: Browser, use: any) { + await addPageObject(PageObject, browser, use, stateUserAuth); +} + export const baseTest = base.extend({ - stateHomePage: async ({ browser }, use) => { - const context = await browser.newContext({ - storageState: ".auth/user.json", - }); - const stateHomePage = new StateHomePage(await context.newPage()); - await use(stateHomePage); - await context.close(); - }, adminHomePage: async ({ browser }, use) => { - const context = await browser.newContext({ - storageState: ".auth/admin.json", - }); - const adminHomePage = new AdminHomePage(await context.newPage()); - await use(adminHomePage); - await context.close(); + await adminPage(AdminHomePage, browser, use); }, bannerPage: async ({ browser }, use) => { - const context = await browser.newContext({ - storageState: ".auth/admin.json", - }); - const bannerPage = new BannerPage(await context.newPage()); - await use(bannerPage); - await context.close(); + await adminPage(BannerPage, browser, use); + }, + mcparDashboardPage: async ({ browser }, use) => { + await statePage(MCPARDashboardPage, browser, use); + }, + mcparGetStartedPage: async ({ browser }, use) => { + await statePage(MCPARGetStartedPage, browser, use); }, profilePage: async ({ browser }, use) => { - const context = await browser.newContext({ - storageState: ".auth/user.json", - }); - const profilePage = new ProfilePage(await context.newPage()); - await use(profilePage); - await context.close(); + await statePage(ProfilePage, browser, use); + }, + stateHomePage: async ({ browser }, use) => { + await statePage(StateHomePage, browser, use); }, }); diff --git a/tests/playwright/utils/index.ts b/tests/playwright/utils/index.ts index 1b4506130..b42e6c82f 100644 --- a/tests/playwright/utils/index.ts +++ b/tests/playwright/utils/index.ts @@ -1,3 +1,4 @@ +export * from "./a11y"; export * from "./consts"; export * from "./login"; -export * from "./a11y"; +export * from "./pageObjects"; diff --git a/tests/playwright/utils/pageObjects/adminHome.page.ts b/tests/playwright/utils/pageObjects/adminHome.page.ts index 92678722e..da6d9e473 100644 --- a/tests/playwright/utils/pageObjects/adminHome.page.ts +++ b/tests/playwright/utils/pageObjects/adminHome.page.ts @@ -7,6 +7,7 @@ export default class AdminHomePage extends BasePage { readonly page: Page; readonly title: Locator; readonly dropdown: Locator; + readonly table: Locator; constructor(page: Page) { super(page); @@ -17,6 +18,7 @@ export default class AdminHomePage extends BasePage { this.dropdown = page.getByRole("combobox", { name: "List of states, including District of Columbia and Puerto Rico", }); + this.table = page.getByRole("table"); } public async selectMCPAR(state: string) { @@ -55,5 +57,35 @@ export default class AdminHomePage extends BasePage { name: "Go to Report Dashboard", }) .click(); + await this.page.waitForResponse((response) => response.status() == 200); + } + + public async getRowMCPAR(stateName: string, programName: string) { + await this.goto(); + await this.isReady(); + await this.selectMCPAR(stateName); + await this.table.isVisible(); + + return this.table.getByRole("row", { name: programName }); + } + + public async archiveMCPAR(stateName: string, programName: string) { + const row = await this.getRowMCPAR(stateName, programName); + const archiveButton = row.getByRole("button", { name: "Archive" }); + + await archiveButton.click(); + await this.page.waitForResponse((response) => response.status() == 200); + await archiveButton.isHidden(); + await row.getByRole("button", { name: "Unarchive" }).isVisible(); + } + + public async unarchiveMCPAR(stateName: string, programName: string) { + const row = await this.getRowMCPAR(stateName, programName); + const unarchiveButton = row.getByRole("button", { name: "Unarchive" }); + + await unarchiveButton.click(); + await this.page.waitForResponse((response) => response.status() == 200); + await row.getByRole("button", { name: "Archive" }).isVisible(); + await unarchiveButton.isHidden(); } } diff --git a/tests/playwright/utils/pageObjects/index.ts b/tests/playwright/utils/pageObjects/index.ts new file mode 100644 index 000000000..8b06e1a0a --- /dev/null +++ b/tests/playwright/utils/pageObjects/index.ts @@ -0,0 +1,13 @@ +export { default as BasePage } from "./base.page"; +export { default as BannerPage } from "./banner.page"; +export { default as ProfilePage } from "./profile.page"; + +// Admin User +export { default as AdminHomePage } from "./adminHome.page"; + +// State User +export { default as StateHomePage } from "./stateHome.page"; + +// MCPAR +export { default as MCPARDashboardPage } from "./mcpar/dashboard.page"; +export { default as MCPARGetStartedPage } from "./mcpar/getStarted.page"; diff --git a/tests/playwright/utils/pageObjects/mcpar/dashboard.page.ts b/tests/playwright/utils/pageObjects/mcpar/dashboard.page.ts new file mode 100644 index 000000000..df7050732 --- /dev/null +++ b/tests/playwright/utils/pageObjects/mcpar/dashboard.page.ts @@ -0,0 +1,67 @@ +import { Locator, Page } from "@playwright/test"; +import BasePage from "../base.page"; + +export default class MCPARDashboardPage extends BasePage { + public path = "/mcpar"; + + readonly page: Page; + readonly addCopyButton: Locator; + readonly table: Locator; + readonly modal: Locator; + readonly programNameInput: Locator; + readonly saveButton: Locator; + + constructor(page: Page) { + super(page); + this.page = page; + this.addCopyButton = page.getByRole("button", { + name: "Add / copy a MCPAR", + }); + this.table = page.getByRole("table"); + this.modal = page.getByRole("dialog"); + this.programNameInput = this.modal.getByLabel( + "Program name (for new MCPAR)" + ); + this.saveButton = this.modal.getByRole("button", { + name: "Save", + }); + } + + public async create(programName: string) { + await this.addCopyButton.isVisible(); + await this.addCopyButton.click(); + + await this.modal.isVisible(); + await this.modal + .getByRole("heading", { name: "Add / Copy a MCPAR" }) + .isVisible(); + await this.programNameInput.fill(programName); + await this.modal + .getByLabel("A.5a Reporting period (i.e. contract period) start date") + .fill("10/10/2024"); + await this.modal + .getByLabel("A.5b Reporting period (i.e. contract period) end date") + .fill("12/10/2024"); + await this.modal.getByLabel("Exclusion of CHIP from MCPAR").click(); + await this.modal.getByLabel("No").click(); + await this.saveButton.click(); + + await this.modal.isHidden(); + await this.table.isVisible(); + } + + public async update(programName: string, updatedProgramName: string) { + const row = this.page.getByRole("row", { name: programName }); + const editProgramButton = row.getByRole("button").first(); + await editProgramButton.isVisible(); + await editProgramButton.click(); + + await this.modal.isVisible(); + await this.modal.getByRole("heading", { name: "Edit Program" }).isVisible(); + await this.programNameInput.fill(updatedProgramName); + await this.saveButton.click(); + + await this.modal.isHidden(); + await this.table.isVisible(); + } +} diff --git a/tests/playwright/utils/pageObjects/mcpar/getStarted.page.ts b/tests/playwright/utils/pageObjects/mcpar/getStarted.page.ts new file mode 100644 index 000000000..3a73ba2f8 --- /dev/null +++ b/tests/playwright/utils/pageObjects/mcpar/getStarted.page.ts @@ -0,0 +1,17 @@ +import { Locator, Page } from "@playwright/test"; +import BasePage from "../base.page"; + +export default class MCPARGetStartedPage extends BasePage { + public path = "/mcpar/get-started"; + + readonly page: Page; + readonly mcparButton: Locator; + + constructor(page: Page) { + super(page); + this.page = page; + this.mcparButton = page.getByRole("button", { + name: "Enter MCPAR online", + }); + } +} diff --git a/tests/playwright/utils/pageObjects/stateHome.page.ts b/tests/playwright/utils/pageObjects/stateHome.page.ts index f452846d0..d39e404cd 100644 --- a/tests/playwright/utils/pageObjects/stateHome.page.ts +++ b/tests/playwright/utils/pageObjects/stateHome.page.ts @@ -6,8 +6,9 @@ export default class StateHomePage extends BasePage { readonly page: Page; readonly title: Locator; - readonly wpButton: Locator; - readonly sarButton: Locator; + readonly mcparButton: Locator; + readonly mlrButton: Locator; + readonly naaarButton: Locator; constructor(page: Page) { super(page); @@ -15,10 +16,10 @@ export default class StateHomePage extends BasePage { this.title = page.getByRole("heading", { name: "Managed Care Reporting Portal", }); - this.wpButton = page.getByRole("button", { + this.mcparButton = page.getByRole("button", { name: "Enter MCPAR online", }); - this.sarButton = page.getByRole("button", { name: "Enter MLR online" }); - this.sarButton = page.getByRole("button", { name: "Enter NAAAR online" }); + this.mlrButton = page.getByRole("button", { name: "Enter MLR online" }); + this.naaarButton = page.getByRole("button", { name: "Enter NAAAR online" }); } }