Skip to content

Commit

Permalink
add files for setup and basic home test
Browse files Browse the repository at this point in the history
  • Loading branch information
gmrabian committed Nov 15, 2024
1 parent 3e619fe commit 3887648
Show file tree
Hide file tree
Showing 17 changed files with 475 additions and 8 deletions.
8 changes: 8 additions & 0 deletions .env.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ CYPRESS_ADMIN_USER_EMAIL=op://mdct_devs/mcr_secrets/CYPRESS_ADMIN_USER_EMAIL
CYPRESS_ADMIN_USER_PASSWORD=op://mdct_devs/mcr_secrets/CYPRESS_ADMIN_USER_PASSWORD # pragma: allowlist secret
CYPRESS_STATE_USER_EMAIL=op://mdct_devs/mcr_secrets/CYPRESS_STATE_USER_EMAIL
CYPRESS_STATE_USER_PASSWORD=op://mdct_devs/mcr_secrets/CYPRESS_STATE_USER_PASSWORD # pragma: allowlist secret

# needed for playwright e2e tests
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ tests/cypress/downloads
.vscode/
*._S3rver_cors.xml
services/database/local_buckets
tests/test-results/
tests/playwright-report/
tests/playwright/.cache/
tests/playwright/.auth
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
},
"scripts": {
"test": "cd tests && npm test && cd -",
"test:ci": "cd tests && yarn run test:ci"
"test:ci": "cd tests && yarn run test:ci",
"test:e2e": "cd tests && yarn run test:e2e",
"test:e2e-ui": "cd tests && yarn run test:e2e-ui"
},
"repository": {
"type": "git",
Expand Down
6 changes: 5 additions & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@
"start": "cd ../ && ./run local && cd -",
"cypress": "cypress open",
"test": "concurrently --kill-others \"yarn start\" \"yarn cypress\"",
"test:ci": "cypress install && cypress run --browser chrome --headless"
"test:ci": "cypress install && cypress run --browser chrome --headless",
"test:e2e": "playwright test",
"test:e2e-ui": "playwright test --ui"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@axe-core/playwright": "^4.10.0",
"@cypress-audit/pa11y": "^1.3.1",
"@playwright/test": "^1.48.0",
"axe-core": "^4.6.3",
"concurrently": "^8.2.2",
"cypress": "^12.17.4",
Expand Down
59 changes: 59 additions & 0 deletions tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { defineConfig, devices } from "@playwright/test";
import dotenv from "dotenv";

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
dotenv.config({ path: "../.env" });

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "playwright",
testMatch: ["**/*.spec.js", "**/*.spec.ts"],
/* Run tests in files in parallel */
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: process.env.BASE_URL || "http://localhost:3000",

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",

/* Video recording configuration */
video: "retain-on-failure",
},

/* Configure projects for major browsers */
projects: [
{
name: "setup",
use: { ...devices["Desktop Chrome"] },
testMatch: /.*\.setup\.ts/,
},
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
dependencies: ["setup"],
},
],

/* Run your local dev server before starting the tests */
webServer: {
command: process.env.CI ? "" : "cd ../ && ./run local",
url: process.env.BASE_URL || "http://localhost:3000",
reuseExistingServer: !!process.env.CI,
stdout: "pipe",
},
});
52 changes: 52 additions & 0 deletions tests/playwright/pages/home.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { test, expect } from "../utils/fixtures/base";
import BasePage from "../utils/pageObjects/base.page";

test.describe("state user home page", () => {
test("Should see the correct home page as a state user", async ({
stateHomePage,
}) => {
await stateHomePage.goto();
await stateHomePage.isReady();
await expect(stateHomePage.wpButton).toBeVisible();
await expect(stateHomePage.sarButton).toBeVisible();
});

test("Is accessible on all device types for state user", async ({
stateHomePage,
}) => {
await stateHomePage.goto();
await stateHomePage.e2eA11y();
});
});

test.describe("admin user home page", () => {
test("Should see the correct home page as an admin user", async ({
adminHomePage,
}) => {
await adminHomePage.goto();
await adminHomePage.isReady();
await expect(adminHomePage.dropdown).toBeVisible();
});

test("Is accessible on all device types for admin user", async ({
adminHomePage,
}) => {
await adminHomePage.goto();
await adminHomePage.e2eA11y();
});
});

test.describe("not logged in home page", () => {
test("Is assessible when not logged in", async ({ browser }) => {
const userContext = await browser.newContext({
storageState: {
cookies: [],
origins: [],
},
});
const homePage = new BasePage(await userContext.newPage());
await homePage.goto();
await homePage.e2eA11y();
await userContext.close();
});
});
22 changes: 22 additions & 0 deletions tests/playwright/utils/a11y.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import AxeBuilder from "@axe-core/playwright";
import { expect, Page } from "@playwright/test";

// Note that this helper function actually calls expect
export async function e2eA11y(page: Page, url: string) {
const breakpoints = {
mobile: [560, 800],
tablet: [880, 1000],
desktop: [1200, 1200],
};

await page.goto(url);

for (const size of Object.values(breakpoints)) {
page.setViewportSize({ width: size[0], height: size[1] });
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa"])
.disableRules(["duplicate-id"])
.analyze();
expect(results.violations).toEqual([]);
}
}
43 changes: 43 additions & 0 deletions tests/playwright/utils/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { test as setup } from "@playwright/test";

import { adminPassword, adminUser, statePassword, stateUser } from "./consts";

const adminFile = "playwright/.auth/admin.json";

setup("authenticate as admin", async ({ page }) => {
await page.goto("/");
const emailInput = page.getByRole("textbox", { name: "email" });
const passwordInput = page.getByRole("textbox", { name: "password" });
const loginButton = page.getByRole("button", { name: "Log In with Cognito" });
await emailInput.fill(adminUser);
await passwordInput.fill(adminPassword);
await loginButton.click();
await page.waitForURL("/");
await page
.getByRole("heading", {
name: "View State/Territory Reports",
})
.isVisible();
await page.waitForTimeout(1000);
await page.context().storageState({ path: adminFile });
});

const userFile = "playwright/.auth/user.json";

setup("authenticate as user", async ({ page }) => {
await page.goto("/");
const emailInput = page.getByRole("textbox", { name: "email" });
const passwordInput = page.getByRole("textbox", { name: "password" });
const loginButton = page.getByRole("button", { name: "Log In with Cognito" });
await emailInput.fill(stateUser);
await passwordInput.fill(statePassword);
await loginButton.click();
await page.waitForURL("/");
await page
.getByRole("heading", {
name: "Managed Care Reporting Portal",
})
.isVisible();
await page.waitForTimeout(1000);
await page.context().storageState({ path: userFile });
});
9 changes: 9 additions & 0 deletions tests/playwright/utils/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const adminUser = process.env.TEST_ADMIN_USER_EMAIL!;
export const adminPassword = process.env.TEST_ADMIN_USER_PASSWORD!; // pragma: allowlist secret
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 currentYear: number = new Date().getFullYear();
31 changes: 31 additions & 0 deletions tests/playwright/utils/fixtures/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { mergeTests, test as base } from "@playwright/test";
import StateHomePage from "../pageObjects/stateHome.page";
import AdminHomePage from "../pageObjects/adminHome.page";

type CustomFixtures = {
stateHomePage: StateHomePage;
adminHomePage: AdminHomePage;
};

export const baseTest = base.extend<CustomFixtures>({
stateHomePage: async ({ browser }, use) => {
const context = await browser.newContext({
storageState: "playwright/.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: "playwright/.auth/admin.json",
});
const adminHomePage = new AdminHomePage(await context.newPage());
await use(adminHomePage);
await context.close();
},
});

export const test = mergeTests(baseTest);

export { expect } from "@playwright/test";
3 changes: 3 additions & 0 deletions tests/playwright/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./consts";
export * from "./login";
export * from "./a11y";
36 changes: 36 additions & 0 deletions tests/playwright/utils/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Page } from "@playwright/test";
import { adminPassword, adminUser, statePassword, stateUser } from "./consts";

export async function logInUser(page: Page, email: string, password: string) {
await page.goto("/");

const emailInput = page.getByRole("textbox", { name: "email" });
const passwordInput = page.getByRole("textbox", { name: "password" });
const loginButton = page.getByRole("button", { name: "Log In with Cognito" });

await emailInput.fill(email);
await passwordInput.fill(password);
await loginButton.click();
}

export async function logOutUser(page: Page) {
const menuButton = page.getByRole("button", { name: "My Account" });
const menu = page.getByTestId("header-menu-options-list");
const logoutButton = page.getByTestId("header-menu-option-log-out");

await menuButton.click();
await menu.isVisible();
await logoutButton.click();
await page.evaluate(() => window.localStorage.clear());
await page.goto("/");
}

export async function logInStateUser(page: Page) {
await logInUser(page, stateUser, statePassword);
await page.getByText("Managed Care Reporting Portal").isVisible();
}

export async function logInAdminUser(page: Page) {
await logInUser(page, adminUser, adminPassword);
await page.getByText("View State/Territory Reports").isVisible();
}
59 changes: 59 additions & 0 deletions tests/playwright/utils/pageObjects/adminHome.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Locator, Page } from "@playwright/test";
import BasePage from "./base.page";

export default class AdminHomePage extends BasePage {
public path = "/";

readonly page: Page;
readonly title: Locator;
readonly dropdown: Locator;

constructor(page: Page) {
super(page);
this.page = page;
this.title = page.getByRole("heading", {
name: "View State/Territory Reports",
});
this.dropdown = page.getByRole("combobox", {
name: "List of states, including District of Columbia and Puerto Rico",
});
}

public async selectMCPAR(state: string) {
await this.page
.getByRole("combobox", {
name: "List of states, including District of Columbia and Puerto Rico",
})
.selectOption(state);
await this.page
.getByRole("radio", {
name: "Managed Care Program Annual Report (MCPAR)",
})
.click();
await this.goToDashboard();
}

public async selectMLR() {
await this.page
.getByRole("radio", {
name: "Medicaid Medical Loss Ratio (MLR)",
})
.click();
}

public async selectNAAAR() {
await this.page
.getByRole("radio", {
name: "Network Adequacy and Access Assurances Report (NAAAR)",
})
.click();
}

public async goToDashboard() {
await this.page
.getByRole("button", {
name: "Go to Report Dashboard",
})
.click();
}
}
Loading

0 comments on commit 3887648

Please sign in to comment.