Skip to content

Latest commit

 

History

History
281 lines (200 loc) · 9.16 KB

README.md

File metadata and controls

281 lines (200 loc) · 9.16 KB

Getting started with ReportStream's React application

Run the React application

Our new React front-end is easy to get up and running on your machine. First, ensure the following dependencies installed:

  • node (see .nvmrc for version specification) via nvm
  • yarn package manager

Use the directions here to install nvm: https://github.com/nvm-sh/nvm#install--update-script Then:

nvm install 20.x.x # refer to nvmrc for exact current version
node -v # v20.x.x
npm -v # v10.2.x

npm install --global yarn

Serving

Now you have the tools necessary to run the front-end application. Navigate into the frontend-react folder and use yarn to serve it on localhost:3000

cd ../frontend-react
yarn
yarn run dev

Refreshing & stopping

The front-end application will run until you Ctrl + C to end the process in your terminal. Updates to the front-end render when a file's changes are saved, eliminating the need to rebuild and serve the project!

Ensure connection

If the window hasn't automatically opened, navigate to http://localhost:3000. You should be able to login and utilize the interface. To ensure the front-end is talking to the prime-router application, log in and access localhost:3000/daily-data. Observe your network calls through your browser's dev tools, checking for any error status codes.

Commands to know

yarn # Will install all dependencies in package.json

yarn run dev # Runs the React app use for localdev
yarn run build:staging # Builds the React app for staging
yarn run build:production # Builds the React app for production

yarn run storybook # Runs a local instance of Storybook showcase of all of the components within our .stories files

yarn run lint # Runs the front-end linter
yarn run lint:fix # Runs the front-end linter and fixes style errors

yarn run test:e2e-ui # Runs a local instance of Playwright UI where you can view and run the e2e tests
CI=true yarn run test:e2e-ui # Runs a local instance of Playwright UI that mimics Github integration

Static build info

This react app uses a static build approach and can be served from a static webserver (e.g. a storage bucket or CDN). This means there are no environment variables to load because there's no local environment. These variables must be "baked" into the html/javascript.

This is achieved using .env?.[ENVIRONMENT]?.local files.

This command loads the environment variables for develop (found in file '.env.development') and runs the [cmd]

cross-env NODE_ENV=development [cmd]

The build can then use variables like %VITE_TITLE% in the index.html template and import.meta.env.VITE_TITLE in the React code.

Testing Content-Security-Policy locally

CSP (Content-Security-Policy) is different from CORS (Cross-Origin Resource Sharing).
CSP

To use it:

  1. Build and run using yarn command preview:build:csp
  2. Open browser debugger and watch console for errors/warnings as you use the site.

Example error would look like this:

index.js:2 Refused to apply inline style because it violates the
 following Content Security Policy directive:
 "style-src 'self' https://global.oktacdn.com https://cdnjs.cloudflare.com".
 Either the 'unsafe-inline' keyword, a hash ('sha256-B7Q+2rCrkIRlD5/BjZIWIMJPSHYlTD1AOL+zDLDYQVg='),
 or a nonce ('nonce-...') is required to enable inline execution.
 Note that hashes do not apply to event handlers,
 style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present.

Chromatic and CI Autobuilds

Chromatic is a tool for hosting and publishing different versions of a given repository's Storybook. We use Chromatic to host an up-to-date version of all of our Storybook components (any file that ends with **.stories.tsx syntax) so that our non-technical folks can see all of our components on the web. All of our CI Autobuild Github workflows can be found in both .github/workflows/chromatic-master.yml and .github/workflows/chromatic-pr.yml.

.github/workflows/chromatic-master.yml triggers a Chromatic build anytime a PR gets merged into our master branch.

.github/workflows/chromatic-pr.yml triggers a Chromatic build anytime a file with // AutoUpdateFileChromatic comment on its FIRST LINE is checked in to a PR. The goal here is to automatically update our Chromatic anytime a file that has an associated Storybook is modified.

=======

Running the e2e tests

Playwright is the framework used to create and run our e2e tests.

To get started you will need to create three separate OKTA users. An admin, sender, and receiver.

  1. Assign the admin, sender, and receiver users to the Test Users Group
  2. Assign the sender user to the DHSender_ignore Group.
  3. Assign the receiver user to the DHak-phd Group and make sure that you have data locally to support that organization.
  4. Create a .env.test.local file within frontend-react and add the following properties along with the values created from step #1:
TEST_ADMIN_USERNAME=""
TEST_ADMIN_PASSWORD=""
TEST_ADMIN_TOTP_CODE=""

TEST_SENDER_USERNAME=""
TEST_SENDER_PASSWORD=""
TEST_SENDER_TOTP_CODE=""

TEST_RECEIVER_USERNAME=""
TEST_RECEIVER_PASSWORD=""
TEST_RECEIVER_TOTP_CODE=""

Check with an Okta administrator on the usage of the TOTP code

npx playwright install # Installs supported default browsers

npx playwright install-deps # Installs system dependencies

yarn run test:e2e-ui # Runs a local instance of Playwright UI where you can view and run the e2e tests

CI=true yarn run test:e2e-ui # Runs a local instance of Playwright UI that mimics Github integration

Currently, the tests are running each time a pull request is made and must pass before the pull request can be merged into master.

CSS Norms

For any new components we create, we have the pattern of Folder + Component + CSS + Storybook. If our component is called ExampleTable, then the structure should look like:

/ExampleTable/ExampleTable.tsx
/ExampleTable/ExampleTable.module.scss
/ExampleTable/ExampleTable.stories.tsx

Within ExampleTable.module.scss, the CSS structures should look as follows:

.ExampleTable {
  :global {

  }
}

Within the ExampleTable.tsx itself, the top-level element should use the CSS Module syntax:

import styles from "./ExampleTable.module.scss";

export const ExampleTable = () => {
  return (
    <div className={styles.ExampleTable}>
    </div>
  )
}

The idea here is that the top-level class of .ExampleTable will allow us to write simple, easy-to-read SASS in the component and stylesheet. No need for anymore CSS Module syntax as the :global {} allows us to write regular SASS within, which is protected by the name-spaced .ExampleTable CSS Module class. (If for some reason you need to revert to locally scoped variable within the :global {} block you can use :local {})

Now, there are two scenarios in which we're writing CSS for our components: 1, writing brand-new styles. 2, overwriting USWDS styles.

For your own custom styles, you should follow a BEM methodology while keeping your naming as semantic as possible, so if our code looks like this:

import styles from "./ExampleTable.module.scss";

export const ExampleTable = () => {
  return (
    <div className={styles.ExampleTable}>
      <div className="section">
        <div className="logo__container">
          <img className="logo__img" src="" />
          <p className="logo__text">Image</p>
        </div>
        <p className="content"></p>
        <p className="content content--alternate"></p>
      </div>
    </div>
  )
}

Then our CSS would look like:

.ExampleTable {
  :global {
    .section {
      padding: 1rem;
    }

    .logo {
      &__img {
        height: 12px;
        width: 12px;
      }

      &__text {
        font-size 8px;
      }
    }

    .content {
      font-size: 22px;
      line-height: 24px;
      color: black;

      &--alternate {
        color: blue;
      }
    }

  }
}

For overwriting USWDS styles, you'd just see look at the rendered DOM elements with Dev Tools, and find what selectors USWDS is using and then apply them like so:

.ExampleTable {
  :global {
    .usa-navbar {
      text-decoration: none;
    }
  }
}

These overwrites will ONLY be scoped to your particular component.

Documentation Table of Contents

General

Proposals