Skip to content

Commit

Permalink
Implement Health Data (#60)
Browse files Browse the repository at this point in the history
* Add allergy intolerance groups

* Add ability to show json or table

* Handle errors and pending state

* Fix imports, minor refactor

* Minor refactor

* Use a ToggleButtonGroup rather than a Button

* Move toggle into a reusable component with Redux state, simplify Allergy Intolerances page further

* Initialize toggle state on mount, add getAllergyIntolerances request

* Initialize a default rather than using a side effect

* Add mui datagrid reference; add Connections page, Redux stuff and example of getConnections; add getAllergyIntolerances

* Fix dates in datagrid

* Rewrite Allergy Intolerance Groups to use DataGrid; remove Allergy Intolerances in order to re-implement it

* Remove Hello page, add withAuthCheck HOC, use server pagination in mui datagrid

* Add state persistence to local storage, logout feature, refactor out initializationSlice

* Minor bug fixes and refactors

* Fix SDK rehydration; add allergy intolerances; add bottom page margin

* Remove unused stuff

* Remove unused code

* Refactor to make more reusable components

* Remove getSdk's reliance on state; remove logging

* Fix tableOrJsonToggle

* Fix rehydration error message logic, no longer need to await getSdk

* Remove console logging, add Health Summary

* Add Conditions

* Adjust table

* Add spaces to menu

* Add columns to AllergyIntoleranceGroups

* Add source to condition groups

* Add Labs

* Add referenceRange to Labs

* Add Care Plans

* Add Encounters

* Add Immunizations

* Add Procedures

* Add Vital Signs; fix pagination

* Change dayMonthYear to monthDayYear

* Refactor to reduce duplicate code

* Clean up store directory

* Add Medications

* Add Medication Knowledge

* Add Lab Knowledge

* Turn off row selection message

* Display HTML as well as JSON for Knowledge

* Genericize toggle state and make it work better

* Add HTML-JSON toggle to DisplayKnowledge

* Remove console logging and unneeded default

* Remove tests, fix page frameworks

* Add test cases for Initialize

* Remove unused key

* Reset knowledge on page load

* Standardize connections

* Use reducers for request info

* Remove unused prop

* Add groupCode to requestInfoSlice

* Disable row selection for now

* Add groupCode support to HealthData pages

* Update README

* Hide Initialize page while rehydrating

* Fix weird login behavior

* Skip rehydration in brand-new session

* Add getRows support to HealthDataGrid

* Support client pagination for Connections screen

* Always await initialization

* Remove console log

* Refactor tests, fix broken tests, add 'Log Out' option to side menu

* Fix TypeScript errors so it's possible to build

* Update Readme and fix a bug on Medications

* Update .env.example

* Fix error messages in tests; expect network error when well-formed key has bad environment

* Move health reducers into a separate combineReducers call

* Remove key from .env.example

* Add TableOrJsonToggle to Connections
  • Loading branch information
kylewadebwell authored Jul 22, 2024
1 parent bd65c65 commit 6510bce
Show file tree
Hide file tree
Showing 70 changed files with 2,198 additions and 548 deletions.
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ test-results

.env

.yalc
.yalc

yalc.lock

dist

dist/*
6 changes: 5 additions & 1 deletion bwell-typescript-react/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
VITE_DEFAULT_KEY=""
VITE_DEFAULT_OAUTH_CREDS=""
VITE_DEFAULT_OAUTH_CREDS=""
VITE_BAD_KEY="blahblah"
VITE_BAD_OAUTH_CREDS="badoauthcreds"
VITE_WELL_FORMED_KEY_BAD_ENV=""
VITE_WELL_FORMED_KEY_GOOD_ENV=""
17 changes: 14 additions & 3 deletions bwell-typescript-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@

This is a sample TypeScript Web application meant to be used in testing the b.well TypeScript SDK.

It is built with react, vite, and material-ui.
It is built with react, redux + redux toolkit, vite, and material-ui.

## How to run it

1. `npm i` (if you haven't run it before)
2. `npm run dev`

## How to run run the tests
## How to run the tests

1. `npm run e2e`

A .env file will need to be present in this directory. See .env.example for the keys that will need to be supported.

### Docker Devcontainer

It is also recommended that you run tests in a container to ensure consistent execution across environments. If you are using VS Code, follow these steps:

1. Navigate into this folder (bwell-typescript-react)
2. Click the little green button in the lower-left corner of your screen
3. Select "Reopen in container"
4. You are now running in a Docker container. `npm run e2e` should run the tests, and a report will open in your web browser once the tests finish running.
4. You are now running in a Docker container. `npm run e2e` should run the tests, and a report will open in your web browser once the tests finish running.

See also: https://playwright.dev/docs/docker

## Notes

* On Health Data pages, clicking a row in a "Groups" grid will filter the rows shown in the second grid. For example, clicking "Cashew Nuts" under "Allergy Intolerance Groups" should filter the "Allergy Intolerances" grid to show only cashew-related incidents.
* On Lab and Medication pages, it should be possible to view "Knowlege" associated with a given detail row. Clicking on a row under "Labs" or "Medications" (not their corresponding Groups) will cause the "Knowledge" associated with that row to be retrieved and displayed, if available.
* Command-clicking on a selected row in one of the grids will deselect it.
* Global application state is automatically saved to local storage and rehydrated at the start of the session; this means the application will recall its state when you return to it, including page number and HTML/JSON toggle status for each grid.
25 changes: 25 additions & 0 deletions bwell-typescript-react/e2e/BasePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Page } from "@playwright/test";
import config from "./configTypes";

export class BasePage {
protected readonly page: Page;

public readonly mainMenuLocator = "#btnMainMenu";
public readonly menuItemSuffix = "MenuItem";

constructor(page: Page) {
this.page = page;
}

protected async clickMainMenu() {
await this.page.click(this.mainMenuLocator);
}

protected async navigate() {
await this.page.goto(config.TEST_APP_URL);
}

protected async clickMenuItem(menuItem: string) {
await this.page.click(menuItem);
}
}
44 changes: 0 additions & 44 deletions bwell-typescript-react/e2e/HelloPage.ts

This file was deleted.

29 changes: 6 additions & 23 deletions bwell-typescript-react/e2e/InitializePage.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
import { Page } from "@playwright/test";
import config from "./configTypes";
import { BasePage } from "./BasePage";

class InitializePage {
private readonly page: Page;

public readonly mainMenuLocator = "#btnMainMenu";
public readonly initializeMenuItemLocator = "#initializeMenuItem";
export class InitializePage extends BasePage {
public readonly txtKeyLocator = "#txtKey";
public readonly btnInitializeLocator = "#btnInitialize";
public readonly txtOauthCredsLocator = "#txtOauthCreds";
public readonly btnSubmitLocator = "#btnSubmit";
public readonly initializationErrorLocator = "#initializationError";
public readonly authenticationErrorLocator = "#authenticationError";

constructor(page: Page) {
this.page = page;
}
public readonly infoMessageLocator = "#authenticationInfo";
public readonly errorMessageLocator = "#authenticationError";

async navigate() {
await this.page.goto(config.TEST_APP_URL);
await super.navigate();
await this.clickMainMenu();
await this.clickInitializeMenuItem();
}

async clickMainMenu() {
await this.page.click(this.mainMenuLocator);
}

async clickInitializeMenuItem() {
await this.page.locator(this.initializeMenuItemLocator).click();
await this.clickMenuItem(`#initialize${this.menuItemSuffix}`);
}

async clickInitializeButton() {
Expand Down
50 changes: 0 additions & 50 deletions bwell-typescript-react/e2e/ShadowPage.ts

This file was deleted.

21 changes: 0 additions & 21 deletions bwell-typescript-react/e2e/hello.spec.ts

This file was deleted.

42 changes: 23 additions & 19 deletions bwell-typescript-react/e2e/initialize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const DEFAULT_OAUTH_CREDS = process.env.VITE_DEFAULT_OAUTH_CREDS ?? "";
const BAD_KEY = process.env.VITE_BAD_KEY ?? "";
const BAD_OAUTH_CREDS = process.env.VITE_BAD_OAUTH_CREDS ?? "";
const WELL_FORMED_KEY_BAD_ENV = process.env.VITE_WELL_FORMED_KEY_BAD_ENV ?? "";
const WELL_FORMED_KEY_GOOD_ENV = process.env.VITE_WELL_FORMED_KEY_GOOD_ENV ?? "";

const GENERIC_ERROR = "Error while authenticating";
const INVALID_KEY_ERROR = "It appears there is a problem with your Client Key. Contact b.well support for further assistance.";
const NETWORK_ERROR = "Network request failed";

test("Navigating to the Initialize page works", async ({ page }) => {
//arrange
Expand Down Expand Up @@ -65,9 +68,13 @@ test("Entering a valid key and valid oauth credential results in success", async
await initializePage.clickSubmitButton();

//assert: no error message should be displayed
expect(page.locator(initializePage.initializationErrorLocator)).toBe(null);
const infoElement = await page.waitForSelector(initializePage.infoMessageLocator);
const infoText = await infoElement.textContent();
expect(infoText).toBe("User successfully logged in.");
});



test("Entering an invalid client key results in an error", async ({ page }) => {
//arrange
const initializePage = new InitializePage(page);
Expand All @@ -78,10 +85,9 @@ test("Entering an invalid client key results in an error", async ({ page }) => {
await initializePage.clickInitializeButton();

//assert: error message should be displayed
const errorLocator = await page.waitForSelector(initializePage.initializationErrorLocator);
const errorText = await errorLocator.innerText();

expect(errorText).toBe("It appears there is a problem with your Client Key. Contact b.well support for further assistance.");
const errorElement = await page.waitForSelector(initializePage.errorMessageLocator);
const errorText = await errorElement.textContent();
expect(errorText).toBe(INVALID_KEY_ERROR);
});

test("Entering an invalid oauth credential results in an error", async ({ page }) => {
Expand All @@ -99,7 +105,7 @@ test("Entering an invalid oauth credential results in an error", async ({ page }
await initializePage.clickSubmitButton();
});

test("Entering a well-formed key with a bad env results in an error", async ({ page }) => {
test("Entering a well-formed valid client key with a bad environment results in the correct error", async ({ page }) => {
//arrange
const initializePage = new InitializePage(page);

Expand All @@ -108,25 +114,23 @@ test("Entering a well-formed key with a bad env results in an error", async ({ p
await initializePage.enterClientKey(WELL_FORMED_KEY_BAD_ENV);
await initializePage.clickInitializeButton();

//assert: error message should be displayed
const errorLocator = await page.waitForSelector(initializePage.initializationErrorLocator);
const errorText = await errorLocator.innerText();

expect(errorText).toBe("Network request failed");
//assert
const errorElement = await page.waitForSelector(initializePage.errorMessageLocator);
const errorText = await errorElement.textContent();
expect(errorText).toBe(NETWORK_ERROR);
});

test("Entering a well-formed key with a good env results in an error", async ({ page }) => {
test("Entering a bad client key and valid oauth credential results in an error", async ({ page }) => {
//arrange
const initializePage = new InitializePage(page);

//act
await initializePage.navigate();
await initializePage.enterClientKey(WELL_FORMED_KEY_GOOD_ENV);
await initializePage.enterClientKey(BAD_KEY);
await initializePage.clickInitializeButton();

//assert: error message should be displayed
const errorLocator = await page.waitForSelector(initializePage.initializationErrorLocator);
const errorText = await errorLocator.innerText();

expect(errorText).toContain("Internal Server Error");
//assert
const errorElement = await page.waitForSelector(initializePage.errorMessageLocator);
const errorText = await errorElement.textContent();
expect(errorText).toBe(INVALID_KEY_ERROR);
});
29 changes: 0 additions & 29 deletions bwell-typescript-react/e2e/shadow.spec.ts

This file was deleted.

Loading

0 comments on commit 6510bce

Please sign in to comment.