Skip to content

test: enable Azure AD with e2e tests #614

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

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 24 additions & 55 deletions .github/workflows/container-ecr-viewer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,20 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max

convert-data:
e2e-tests:
strategy:
fail-fast: false
matrix:
include:
- config: AWS_SQLSERVER_NON_INTEGRATED
- config: AWS_SQLSERVER_DUAL
azure_ad: true
schema: extended
- config: AZURE_PG_NON_INTEGRATED
- config: AZURE_PG_DUAL
azure_ad: false
schema: core
- config: AWS_INTEGRATED
azure_ad: false

runs-on: ubuntu-latest
timeout-minutes: 20
steps:
Expand Down Expand Up @@ -114,21 +119,16 @@ jobs:
run: |
echo "METADATA_DATABASE_SCHEMA=${{ matrix.schema }}" >> .env.local

- name: Run seed data conversion
run: npm run convert-seed-data
- name: Set up Azure AD
if: ${{ matrix.azure_ad }}
working-directory: ./containers/${{env.CONTAINER}}

e2e-tests:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{env.NODE_VERSION}}
run: |
sed -i 's/AUTH_PROVIDER=.*$/AUTH_PROVIDER=ad/' .env.local
sed -i 's/AUTH_CLIENT_ID=.*$/AUTH_CLIENT_ID=${{ secrets.AZURE_AD_CLIENT_ID }}/' .env.local
sed -i 's/AUTH_CLIENT_SECRET=.*$/AUTH_CLIENT_SECRET=${{ secrets.AZURE_AD_CLIENT_SECRET }}/' .env.local
sed -i 's/AUTH_ISSUER=.*$/AUTH_ISSUER=${{ secrets.AZURE_AD_ISSUER }}/' .env.local
echo "AZURE_AD_USER=${{ secrets.AZURE_AD_USER }}" >> .env.local
echo "AZURE_AD_PASSWORD=${{ secrets.AZURE_AD_PASSWORD }}" >> .env.local

- name: Install dependencies
working-directory: ./containers/${{env.CONTAINER}}
Expand All @@ -138,12 +138,6 @@ jobs:
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e:install

- name: Set up env vars
working-directory: ./containers/${{env.CONTAINER}}
run: |
npm run setup-local-env
../../setup-env.sh ../orchestration/.env ../orchestration/.env.sample

- name: Run local docker and wait for it to be ready
working-directory: ./containers/${{env.CONTAINER}}
run: npm run local-docker:silent && ./e2e/waitForUrl.sh localhost:3000/ecr-viewer/api/health-check localhost:8071/health/ready
Expand Down Expand Up @@ -174,68 +168,43 @@ jobs:
working-directory: ./containers/${{env.CONTAINER}}
run: npm run local-docker:silent && ./e2e/waitForUrl.sh localhost:3000/ecr-viewer/api/health-check localhost:8071/health/ready

- name: Run Playwright tests - Non-Integrated
- name: Run Playwright tests
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e

- name: Docker down
working-directory: ./containers/${{env.CONTAINER}}
run: docker compose --profile "*" down

- name: Upload playwright report - Non-Integrated
- name: Upload playwright report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
name: playwright-report-${{ matrix.config_name }}
path: containers/${{env.CONTAINER}}/playwright-report/
retention-days: 5

- name: Upload Lighthouse report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: lighthouse-report
name: lighthouse-report-${{ matrix.config_name }}
path: containers/${{env.CONTAINER}}/lighthouse/
retention-days: 5

- name: Set CONFIG_NAME to AWS_INTEGRATED
working-directory: ./containers/${{env.CONTAINER}}
run: |
sed -i 's/AWS_SQLSERVER_DUAL/AWS_INTEGRATED/' .env.local

- name: Run local docker and wait for it to be ready
working-directory: ./containers/${{env.CONTAINER}}
run: npm run local-docker:silent && ./e2e/waitForUrl.sh localhost:3000/ecr-viewer/api/health-check

- name: Run Playwright tests - Integrated
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e:integrated

- name: Docker down
working-directory: ./containers/${{env.CONTAINER}}
run: docker compose --profile "*" down

- name: Upload playwright report - integrated
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-integrated
path: containers/${{env.CONTAINER}}/playwright-report/
retention-days: 5

- name: Get docker logs
if: ${{ !cancelled() }}
if: ${{ always() }}
working-directory: ./containers/${{env.CONTAINER}}/e2e
shell: bash
run: |
echo "Saving $container logs"
docker compose --profile "*" logs --timestamps >& e2e-run.log

- name: Archive docker logs
if: ${{ !cancelled() }}
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: logs
name: logs-${{ matrix.config_name }}
path: ./containers/${{env.CONTAINER}}/e2e/e2e-run.log
retention-days: 5

Expand Down
76 changes: 15 additions & 61 deletions containers/ecr-viewer/e2e/dual/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import { test, expect } from "@playwright/test";

test.describe("keycloak", () => {
test("should require a login on main page and can log out", async ({
import { logIn, nbsAuthParam } from "../utils";

test.describe("auth", () => {
test("should require a login on main page and allow sign out", async ({
page,
}) => {
await page.goto("/ecr-viewer");
await page.waitForURL("ecr-viewer/signin?callbackUrl=%2Fecr-viewer%2F");

await page.getByRole("button").click();

await page
.getByRole("textbox", { name: "username" })
.fill("ecr-viewer-admin");
await page.getByRole("textbox", { name: "password" }).fill("pw");
await page.getByRole("button", { name: "Sign in" }).click();

await expect(page.getByText("eCR Library")).toBeVisible();

await logIn(page);
await expect(page.getByText("Sign Out")).toBeVisible();
await page.getByRole("button", { name: "Sign Out" }).click();

Expand All @@ -27,66 +17,30 @@ test.describe("keycloak", () => {
test("should require a login on main page even if valid auth token provided", async ({
page,
}) => {
await page.goto(
"/ecr-viewer?auth=eyJhbGciOiJSUzI1NiIsImlkIjoiYmxhaCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hXmX6wu9ThiSqNEl6Y3pBETppiIt0j4RKSVPO_AAYZJZsngSFiu8GuGDtA13kJ-texfUHshqcy4euoVwfmN-naDi2Ly6p6lPjY6xzmTuQ1DtiKLZDNBsDupjoLAuIJQ3K8uWRnCdRGG1ZlTkZa-SG8b4jfDLRrl1fPiJCWM62XV7_gIvqCvRAPdP9kMrOV1LtLEuXgoXZGifVNnPQhtT7fQ7kDmbM-HDG4MquZy89CIRy2q22xIclePOAoe0Ifz6q7-NG3I9CzKOAa_Vx6Oy5ZYBYphfV1n46gp4OC0Cb_w-wFLfRDuDPJZvcS5ed2HxdyZrU_GeD4WSN5IQpEn_45CZifBzmv9-jweEUD2or3sp1DReORLZG2CvBqtixC0p3gIeGnY4HROduafmDfyI0gcv7pDM-fcreMCBG-7uqUPkk9rqhCPw9n6fhWvNMSGrtW9tx6hAPNxjKJ2AsyTh7cJyR0teVpijhXZz0dGJOtYY1-nlR7_BnJH2lC9tLiIJcVl1JKfGRu18MV1bHs7y25Wp1HxVDUXllShXa7_oD7ljnE3stmpO5GPMbxvWC_RKO_bu_e2mAgJ3yiPImFpLVYZZgBqClctciZMQeV1lZTAy-7Xlzgdx-IvFc9VuigKw6hfk4on98BxMUENeh20KIgVv8cMr4ZjAGV3MjnFnHWw",
);
await page.waitForURL("ecr-viewer/signin?callbackUrl=%2Fecr-viewer%2F");

await page.getByRole("button").click();

await page
.getByRole("textbox", { name: "username" })
.fill("ecr-viewer-admin");
await page.getByRole("textbox", { name: "password" }).fill("pw");
await page.getByRole("button", { name: "Sign in" }).click();

expect(page.getByText("eCR Library"));
await logIn(page, `/ecr-viewer?${nbsAuthParam}`);
});

test("should require a login on view-data page", async ({ page }) => {
await page.goto(
await logIn(
page,
"/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703",
"Patient Name",
);
await page.waitForURL(
"ecr-viewer/signin?callbackUrl=%2Fecr-viewer%2Fview-data%3Fid%3Ddb734647-fc99-424c-a864-7e3cda82e703",
);

await page.getByRole("button").click();

await page
.getByRole("textbox", { name: "username" })
.fill("ecr-viewer-admin");
await page.getByRole("textbox", { name: "password" }).fill("pw");
await page.getByRole("button", { name: "Sign in" }).click();

await expect(page.getByText("Patient Name")).toHaveCount(2);

// via regular auth, should be able to navigate to library
await expect(page.getByText("Back to eCR Library")).toBeVisible();
await expect(page).toHaveURL(
"http://localhost:3000/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703",
);
});

test("should require a login on view-data page when invalid token provided", async ({
page,
}) => {
await page.goto("/ecr-viewer/view-data?id=1234&auth=hi");
await page.waitForURL(
"ecr-viewer/signin?callbackUrl=%2Fecr-viewer%2Fview-data%3Fid%3D1234",
);

await page.getByRole("button").click();

await page
.getByRole("textbox", { name: "username" })
.fill("ecr-viewer-admin");
await page.getByRole("textbox", { name: "password" }).fill("pw");
await page.getByRole("button", { name: "Sign in" }).click();

expect(
page.getByText(
"The eCR Viewer couldn't retrieve the associated eCR file",
),
await logIn(
page,
"/ecr-viewer/view-data?id=1234&auth=hi",
"The eCR Viewer couldn't retrieve the associated eCR file",
);
await expect(page).toHaveURL(
"http://localhost:3000/ecr-viewer/view-data?id=1234",
Expand All @@ -97,7 +51,7 @@ test.describe("keycloak", () => {
page,
}) => {
await page.goto(
"/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703&auth=eyJhbGciOiJSUzI1NiIsImlkIjoiYmxhaCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hXmX6wu9ThiSqNEl6Y3pBETppiIt0j4RKSVPO_AAYZJZsngSFiu8GuGDtA13kJ-texfUHshqcy4euoVwfmN-naDi2Ly6p6lPjY6xzmTuQ1DtiKLZDNBsDupjoLAuIJQ3K8uWRnCdRGG1ZlTkZa-SG8b4jfDLRrl1fPiJCWM62XV7_gIvqCvRAPdP9kMrOV1LtLEuXgoXZGifVNnPQhtT7fQ7kDmbM-HDG4MquZy89CIRy2q22xIclePOAoe0Ifz6q7-NG3I9CzKOAa_Vx6Oy5ZYBYphfV1n46gp4OC0Cb_w-wFLfRDuDPJZvcS5ed2HxdyZrU_GeD4WSN5IQpEn_45CZifBzmv9-jweEUD2or3sp1DReORLZG2CvBqtixC0p3gIeGnY4HROduafmDfyI0gcv7pDM-fcreMCBG-7uqUPkk9rqhCPw9n6fhWvNMSGrtW9tx6hAPNxjKJ2AsyTh7cJyR0teVpijhXZz0dGJOtYY1-nlR7_BnJH2lC9tLiIJcVl1JKfGRu18MV1bHs7y25Wp1HxVDUXllShXa7_oD7ljnE3stmpO5GPMbxvWC_RKO_bu_e2mAgJ3yiPImFpLVYZZgBqClctciZMQeV1lZTAy-7Xlzgdx-IvFc9VuigKw6hfk4on98BxMUENeh20KIgVv8cMr4ZjAGV3MjnFnHWw",
`/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703&${nbsAuthParam}`,
);
await page.getByText("Patient Name").first().waitFor();

Expand Down
4 changes: 2 additions & 2 deletions containers/ecr-viewer/e2e/dual/ecr-library.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import AxeBuilder from "@axe-core/playwright";
import { test, expect } from "@playwright/test";

import { logInToKeycloak } from "./utils";
import { logIn } from "../utils";

test.describe("ecr library page", () => {
test.beforeEach(logInToKeycloak);
test.beforeEach(({ page }) => logIn(page));

test.describe("eCR Library page", () => {
test("has title", async ({ page }) => {
Expand Down
20 changes: 8 additions & 12 deletions containers/ecr-viewer/e2e/dual/ecr-viewer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import AxeBuilder from "@axe-core/playwright";
import { test, expect } from "@playwright/test";

import { logInToKeycloak } from "./utils";
import { nbsAuthParam } from "../utils";

test.describe("viewer page", () => {
test.beforeEach(logInToKeycloak);

test("should not have any automatically detectable accessibility issues", async ({
page,
}) => {
// Set timetout to 2 minutes because the first call to local stack s3 can take ~1:30
test.setTimeout(120_000);

await page.goto(
"/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703",
`/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703&${nbsAuthParam}`,
);
await page.getByText("Patient Name").first().waitFor();

Expand All @@ -27,7 +25,7 @@ test.describe("viewer page", () => {
page,
}) => {
await page.goto(
"/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703",
`/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703&${nbsAuthParam}`,
);
await page.getByRole("button", { name: "Expand all labs" }).click();

Expand All @@ -44,7 +42,7 @@ test.describe("viewer page", () => {
test.describe("side nav", () => {
test.beforeEach(async ({ page }) => {
await page.goto(
"/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703",
`/ecr-viewer/view-data?id=db734647-fc99-424c-a864-7e3cda82e703&${nbsAuthParam}`,
);
await page.getByText("Patient Name").first().waitFor();
});
Expand All @@ -53,8 +51,8 @@ test.describe("viewer page", () => {
const nav = page.getByRole("navigation");
await expect(nav).toBeVisible();

const navLinks = await nav.getByRole("link").all();
expect(navLinks.length).toBe(22);
const navLinks = await nav.getByTestId("sidenav-link").all();
expect(navLinks.length).toBe(21);

// Make sure after collapsing and reopening, nav links still work
await page.getByText("Collapse all sections").click();
Expand All @@ -66,8 +64,6 @@ test.describe("viewer page", () => {
// make sure clicking each link scrolls the heading and highlights the corresponding
// side nav item
for (const navLink of navLinks) {
const linkText = await navLink.innerText();
if (linkText === "Back to eCR Library") continue;
await navLink.scrollIntoViewIfNeeded();
await navLink.click();
await expect(
Expand All @@ -86,9 +82,9 @@ test.describe("viewer page", () => {
const nav = page.getByRole("navigation");
await expect(nav).toBeVisible();

const navLinks = await nav.getByRole("link");
const navLinks = await nav.getByTestId("sidenav-link");
const numLinks = (await navLinks.all()).length;
let navIndex = 1; // skip "back to library" link
let navIndex = 0;
while (navIndex < numLinks) {
await page.mouse.wheel(0, 12);

Expand Down
4 changes: 2 additions & 2 deletions containers/ecr-viewer/e2e/dual/lighthouse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
playwrightLighthouseResult,
} from "playwright-lighthouse";

import { logInToKeycloak } from "./utils";
import { logIn } from "../utils";

const lighthouseTest = test.extend<
{},
Expand Down Expand Up @@ -80,7 +80,7 @@ const lighthouseTest = test.extend<
});

lighthouseTest.describe("lighthouse", async () => {
lighthouseTest.beforeEach(logInToKeycloak);
lighthouseTest.beforeEach(({ page }) => logIn(page));

lighthouseTest(
"home page",
Expand Down
21 changes: 0 additions & 21 deletions containers/ecr-viewer/e2e/dual/utils.ts

This file was deleted.

12 changes: 12 additions & 0 deletions containers/ecr-viewer/e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import fs from "fs";

/**
* Playwright has a bug with following symlinks. This hacks around it to make sure
* the viewer is tested in all modes.
*/
export default function gobalSetup() {
fs.copyFileSync(
"./e2e/dual/ecr-viewer.spec.ts",
"./e2e/integrated/ecr-viewer.spec.ts",
);
}
Loading
Loading