Skip to content
Frontend for
Branch: master
Clone or download
beeyayjay and ncksllvn VAGOV-2053: Update drupal breadcrumb template to use menu breadcrumbs. (

* VAGOV-2053: Update drupal breadcrumb template to use menu breadcrumbs.

* Trigger build.
Latest commit 5f29b13 Mar 23, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
jenkins add credentials for build (#9744) Mar 20, 2019
script Add Sentry logging to content preview server (#9793) Mar 22, 2019
src VAGOV-2053: Update drupal breadcrumb template to use menu breadcrumbs. ( Mar 23, 2019
.babelrc Update to Babel 7 (#9614) Feb 22, 2019
.eslintignore Ignore and remove assets (#9527) Feb 6, 2019
.eslintrc Add Sentry logging to content preview server (#9793) Mar 22, 2019
.nvmrc Update Node and Yarn (#7449) Mar 20, 2018
Dockerfile Upgrade yarn and add security check based on yarn audit (#9245) Dec 12, 2018
Jenkinsfile Update jenkins params (#9785) Mar 22, 2019
Jenkinsfile.content Fix git issues with content build (#9720) Mar 12, 2019
app.json heroku github auth (#8207) Aug 19, 2018
package.json Bump formation-react (#9792) Mar 22, 2019
yarn.lock Build Status

What is this?

This is the combined frontend repository for With this repository, it is possible to build all of the client-side (i.e., anything that gets downloaded to the browser) code for with the exception of some high sensitivity endpoints that require server side interaction such as login.

For backend, see vets-api repo.

As it is client side there are no secrets in this repository since, well, public secrets aren't very secret.

I want to...

I want to... Then you should...
clone the site and install dependencies git clone followed by cd vets-website, then follow the instructions below to install node, npm and yarn if needed. Next, clone the content repository into a sibling directory as described below. Finally, run yarn install to fetch all the dependencies. Run yarn install anytime package.json changes.
fetch all dependencies yarn install; run this any time package.json changes
Use the git hooks provided You can either copy the hooks as-is right now with cp script/hooks/* .git/hooks or make sure your git hooks by using a symbolic link to the hooks distributed with vets-website with rm -rf .git/hooks && ln -s ../script/hooks .git/hooks. On Linux, you may have to do ln -rs instead of just -s.
deploy the site merge to master for and Production deploys are executed by creating a release of vets-website via Jenkins.
update static content that is already on the site. Find the corresponding file in content/pages. Make your edit. Send a PR.
add new static content to the site. Create new files at the right location in content/pages. Send a PR.
build the site with dev features enabled. npm run build
build the production site (dev features disabled). npm run build -- --buildtype vagovprod Note the extra -- is required otherwise npm eats the buildtype argument instead of passing it on.
build the site with optimizitons (minification, chunking etc) on. Set NODE_ENV=production before running build.
reset local environment (clean out node modules and runs npm install) npm run reset:env
run the site for local development with automatic rebuilding of Javascript and sass without css sourcemaps npm run watch then visit http://localhost:3001/. You may also set buildtype and NODE_ENV though setting NODE_ENV to production will make incremental builds slow. CSS sourcemaps are off by default to avoid an issue that causes the default watch task to crash after rebuilding
run the site for local development with automatic rebuilding of Javascript and sass with css sourcemaps npm run watch:css-sourcemaps then visit http://localhost:3001/. You may also set buildtype and NODE_ENV though setting NODE_ENV to production will make incremental builds slow.
run the site for local development with automatic rebuilding of code and styles for specific apps npm run watch -- --entry disability-benefits,static-pages. Valid application names are in each app's manifest.json under entryName
run the site for local development with automatic rebuilding of code and styles for static content npm run watch:static. This is equivalent to running npm run watch -- --entry static-pages
run the site so that devices on your local network can access it npm run watch -- --host --public 198.162.x.x:3001 Note that we use CORS to limit what hosts can access different APIs, so accessing with a 192.168.x.x address may run into problems
run all tests npm run test
run only unit tests npm run test:unit
run all unit tests and watch npm run test:watch
run only unit tests for a subset of tests npm run test:unit -- path/to/my/test.unit.spec.jsx
npm run test:unit -- src/applications/disability-benefits/686/tests/**/*.unit.spec.js*
run only e2e tests Make sure the site is running locally (npm run watch) and run the tests with npm run test:e2e
run only e2e tests for a subset of tests Make sure the site is running locally (npm run watch) and run the desired tests with npm run test:e2e -- src/applications/edu-benefits/tests/1995/*.e2e.spec.js (provide file paths)
run e2e tests in headless mode npm run test:e2e:headless
run all linters npm run lint
run only javascript linter npm run lint:js
run only sass linter npm run lint:sass
run automated accessibility tests npm run build && npm run test:accessibility
run visual regression testing Start the site. Generate your baseline image set using npm run test:visual:baseline. Make your changes. Then run npm run test:visual.
test for broken links                   Build the site. Broken Link Checking is done via a Metalsmith plugin during build. Note that it only runs on build not watch.
add new npm modules yarn add my-module. Use the --dev flag for modules that are build or test related.
get the latest json schema yarn remove vets-json-schema; yarn add{latest commit hash}
check test coverage npm run test:coverage
run bundle analyzer on our production JS bundles npm run build-analyze
generate a stats file for analysis by bundle analyzer NODE_ENV=production npm run build -- -- buildtype=vagovprod --analyzer
load the analyzer tool on a stats file npm run analyze

Directory structure

Directory Description
build Output of the site build. A subdirectory is generated per buildtype so --buildtype=localhost appears in build/localhost. This directory is suitable for synchronizing into S3 for deployment
config Contains config files for the site.
logs Directory for log output from build tools. Currently only used by nightwatch and selenium for end-to-end testing.
node_modules install location of npm modules. Managed by npm.
script Scripts for building the repository. The most commonly used script is build.js which runs Metalsmith
src All of our application code, including styles and tests

Inside the src directory, we have two folders applications and platform. applications contains the individual applications used on, typically associated with a particular URL. platform contains the shared code used by those applications: the platform we build applications on top of.


Users with government furnished equipment may not have admin account access. These instructions might help.

The requirements for running this application are Node.js 8.10.0 and yarn 1.12.3

Once you have nvm installed you should now install node.js version 8.10.0 by running:

We use nvm to manage Node.js and other tools. Keeping your tools in sync with everyone else will reduce errors. To install please visit:

If you are on a mac and use homebrew, you can install nvm by typing in the Terminal:

brew update && brew install nvm

There will be some further instructions in the success message after install "finishes".

Once you have nvm installed, you should install Node.js:

nvm install 8.10.0

This will also install npm

Once you have node.js 8.10.0 you should set as the default version for nvm, you do that by running:

nvm alias default 8.10.0

Next install Yarn:

npm i -g yarn@1.12.3

Verify your local requirements are set

node --version // 8.10.0
yarn --version // 1.12.3

Once you use one of the correct commands above (like npm run watch), the site will be available locally by typing localhost:3001 into your browser. If you get weird errors, try yarn install as your first step.

Clone the content repository into a sibling directory

The content for is located in a separate repository and is required to build the website. The easiest way to do this is to clone that repository into a sibling directory to your clone of vets-website. For example -

git clone
git clone

The vets-website build will know to look for a sibling directory called vagov-content during its build. We also recommend regularly pulling latest for that repo just as with vets-website to ensure the two are always configured with one another correctly.

How it all works


The build is abstracted by the command npm run build which really just exectues scripts/build.js -- a simple Javscript program that configures Metalscript and Webpack based on things in config/, commandline flags, and the NODE_ENV environment variable.

WARNING: --buildtype and NODE_ENV are unrelated!

--buildtype changes what constants are defined which enables/disables features from the code.

NODE_ENV changes the optimizations applies such as disabling React PropType checks and enabling minification + javascript chunking.

(Note: The NODE_ENV env variable dependency is a questionable design choice. It should

Metalsmith -- Static content builds and top-level file watching.

The build.js script relies on Metalsmith's Javascript API as the main build script. Metalscript, at the core, is just a file watcher that runs a set of files through chain of plugins. Using the Javascript API for Metalscript allows removal of tools like Grunt while also enabling faster incremental builds because Metalsmith and Webpack can stay in memory.

Metalsmith's behavior is entirely defined by the plugins added, their configuration, and their ordering.

The primary responsibility of Metalsmith is to process all the pages in content/ and static assets under assets/ to produce output in build/.

With the exception of files under build/${BUILDTYPE}/generated/ that are handled by webpack, everything else is directly generated by metalsmith-plugins.

Refer to the (thorough) comments inside build.js for specifics.

Webpack -- Javascript and Sass processing. Outputs build/generated

Metalsmith invokes Webpack or Webpack Dev Server depending of it is in build or watch mode.

Webpack's configuration is stored in config/webpack.config.js and declares a set of loaders which are Webpack's version of plugins. The loaders are used to compile ES2015 to ES5 via Babel, and to process the sass into CSS.

Webpack is configured to create a bundle for each application, as defined in the manifest.json files found in src/applications. There are three "special" bundles: vendor, which contains dependencies shared across all bundles; styles, which has no JS and is used to create a common CSS file shared across applications, and static-pages, which is the bundle used by all static pages.

Sass and styles are loaded via Javascript. Each entry file typically imports an appropriate top-level sass file which the imports some shared variables and individual Sass files as needed. Webpack then generates a separate css bundle for each of these entrypoints allowing the site to have app-specific css.

Watch mode

File watching and incremental building is important for developer efficiency, but it's more complicated because, to be fast, each tool needs to keep its state between runs. This is actually the driving reason NOT to use grunt or gulp because, fundametnally, both those task runners would expect to restart either metalsmith or webpack on file changes.

In our setup, we use the metalsmith-watch plugin as well as the metalsmith-webpack-dev-server plugin to do file watching based on the separation of duties listed earlier. The Webpack Dev Server also serves as the actual web server endpoint that handles HTTP requests.

When a file chagnes in content/\* or asset/\*, whether and how it gets rebuilt is dependent on the metalsmith-watch configuration.

If a 404 is incorrectly handled, that's a configuration problem with Webpack Dev Server.

Similarly, everything in src/\* is dependent on the webpack configuration.


  • metalsmith-watch cannot do broken link detection during incrementals.
    • Webpack Dev Server uses an in-memory filesystem so nothing shows up in build/${}/generated
    • Visit http://localhost:3001/webpack-dev-server (no trailing slash!) to see the contents of generated files.

Overall, this runs pretty well.

Unit Test -- Mocha

All unit tests are named with the suffix .unit.spec.js and live in tests directories inside src/applications and src/platform. Keeping tests near application code keeps applications self contained and allows easier switching the files relevant to particular features on

Unit tests are done via mocha with the chai assertion library run directly via the mocha test runner in Node.

Unfortunately, it also means there is no true window or document provided which breaks ReactTestUtils's simulate calls. To remedy, a fake window and document are provided using jsdom and bootstrapped in src/platform/testing/unit/mocha-setup.js which is required via src/platform/testing/unit/mocha.opts.

If you need to polyfill additional browser functionality, mocha-setup.js is the place to do that globally. The mocha-setup.js file can be thought of as the init script for mocha tests.

Note that because mocha is running the test files directly, it needs to use babel-register (see compilers option in mocha.opts) to execute babel on the unittests. This is why babel configuration is kept in .babelrc, so it can be shared between build and test.

Static Webserver

The site comes bundled with a static webserver, which is used for serving the files of a certain build-type from the build directory. If there isn't already a server running on port 3001 as is the case with npm run watch, the static webserver will automatically be started during Nightwatch tests (E2E and Visual Regression) that will serve the files of the corresponding build.

Running the site in production

It is sometimes useful to ensure that a certain feature of the site will function correctly in a certain environment. For example, a common use case is to render a certain feature in all environments outside of production. In this case, it would be beneficial to ensure the production environment is not impacted. To locally run a production build of the website, follow these steps:

  1. NODE_ENV=production npm run build -- --buildtype=vagovprod
    • This will generate the complete static website in build/vagovprod.
    • NOTE: You will likely see files already in the build/development directory. This contains the generated content files from Metalsmith, but unless you recently executed a development build, it most likely does not contain the Webpack-compiled assets (JS/CSS) which are served from memory and not written to the file system during the watch-task.
  2. node src/platform/testing/e2e/test-server.js --buildtype=vagovprod
    • You should see console output indicating that a local webserver has started, which port it is running on, and for which build-type.

End-to-end Test -- nightwatch

All end-to-end tests are under test/\* and are named with the suffix .e2e.spec.js. All end-to-end tests are named with the suffix .e2e.spec.js and live in tests directories inside src/applications and src/platform.

Nightwatch is being used for browser-based testing. By default, Chrome is used as the browser for tests. On Jenkins, Headless Chrome is used.

Nightwatch is a wrapper on Selenium. It is configured in config/nightwatch.js. To run a nightwatch test, 3 things need to execute:

  1. A webserver with our site
  2. The selenium server (which will spawn browsers like PhanomJS)
  3. The nightwatch client that talks to the Selenium server

End-to-end tests do not need to be restricted exclusively to selenium style tests (eg, navigate to this url, click this button, etc). At its core, it just a system for starting up and controlling web browser. For mocha tests that we want to run on real browser, either because the tests is exercising browser quirks or because the test requries features that jsdom does not provide, putting them into a e2e.spec.js file is completely valid and good.

E2E Troubleshooting

Try running your selenium server manually:

$ java -jar <path to GitHub>/vets-website/node_modules/selenium-server/lib/runner/selenium-server-standalone-3.4.0.jar

and you should see:

04:35:15.862 INFO - Selenium Server is up and running
  • Selenium requires Java 8 to run

Executing Nightwatch Tests For a Certain Environment

A webserver is required for Nightwatch to execute. Locally, you will likely execute E2E tests while running the local development server via npm run watch, followed by npm run test:e2e.

However, it is sometimes useful to execute E2E tests for a certain build-type, which is done by first running a build for that build-type, then executing the tests with the build-type passed as an argument.

For example, to execute the E2E tests for Production:

  1. NODE_ENV=production npm run build -- --buildtype=vagovprod
  2. BUILDTYPE=vagovprod npm run test:e2e
    • The Nightwatch startup script will see that port 3001 is not blocked (as it would be by the watch-task), and will start a static webserver for the production build.

Visual Regression Testing

This is the second iteration of visual regression testing. It is useful to detect side effects or scope of visual changes.

VRT works by gathering the links for the site using the sitemap, then using Puppeteer to navigate throughout the site, capturing an image of each page that will either be used as the baseline for future comparisons or compared to the baseline. The developer must first create the baseline image set for comparisons (sometimes called the golden set), then after making their changes, run an additional task to execute the comparison. See the chart above for the commands.

There are some limitations, one of which is that VRG only tests the page on the initial load on a single viewport - it does not interact with the page or resize the window. This means that if there are dynamic elements they will not be covered. If this is functionality that interests you, you are welcome to join a discussion about the next phase of VRG.

To run visual regression testing start the server in one terminal and execute the following commands

  1. npm run test:visual:baseline - Create desktop baseline
  2. npm run test:visual - Compare to desktop baselines
  3. npm run test:visual:baseline -- --mobile - Create mobile baseline
  4. npm run test:visual -- --mobile - Compare to Mobile baselines

All screenshots are available at logs/visual-regression/[baseline | diff]/[mobile | desktop]

Automated Accessibility Testing -- aXe

All end-to-end tests should also run our accessibility checking tool, aXe. There's a Nightwatch command written for this, which should be run for any page that you test in an end-to-end tests. We also run aXe on all pages in the sitemap, to ensure 508 and WCAG compliance.

Continuous Integration

Continuous integration and deployment is done via Jenkins CI. All of the configuration is stored in Jenkinsfile. The build runs within docker, which is configured with the Dockerfile. You can run this container locally to debug any failed builds:

  docker build -t vets-website:local .
  docker run -it --rm vets-website:local /bin/bash
  cd /application && npm run build && npm run test

Builds are triggered for PRs for all build types. The special branch name content/wip/.*, will fail by default and not run any builds. This is to allow rapid iteration on WIP content team work before builds are tested.

Tests are run over the production buildtype for all PRs. Tests should not be tied to the build type. Instead, define a feature flag variable and test both the enabled and disabled states. While a build type will either enable or disable the feature in the UI, the tests will still run the feature's code path despite the environment. This ensures that your component will function in all builds regardless of the build type. The important distinction is that your feature is still active within the code base, but the UI is either enabled or disabled by the feature flag.

Supported Browsers

Browser Minimum version Note
Internet Explorer 11
Microsoft Edge 13
Safari / iOS Safari 9
Chrome / Android Web view 44 Latest version with >0.5% of traffic
Firefox 52 Latest version with >0.5% of traffic

More documentation

You can’t perform that action at this time.