Skip to main content
Skip table of contents

Unit tests

Last Updated: November 26, 2024

All new code that is added to vets-website should be unit tested and unit tests should cover at least 80% of code paths. Write unit tests as you build to make sure your form (or other component) is behaving as you expect and to help guard against future bugs. For example, you might create a unit test file for each page in a form and then test the following scenarios:

  • The correct number of inputs show up when you render the page.

  • The correct number of fields display validation errors if you submit without entering any information.

  • Any conditional logic on the page displays under the correct conditions.

For more detailed information about unit test best practices and an in-depth discussion of how they apply to vets-website, please view this recording of Front End Unit Tests on VA.gov - Best Practices/Q&A Brown Bag Training.

Overview

Unit test file format: file_name.unit.spec.js

Where: Any file_name.unit.spec.js file located in the /src folder. This file should be located in a unit test directory close to the code being tested.

When: Run the test locally through npm script commands, during the Github Actions build (Unit), and after merging to main.

The vets-website repo uses:

Enzyme has a legacy presence in the repo, but is no longer being maintained. Any unit tests still using Enzyme should be migrated to RTL to ensure long-term test stability.

  • Sinon for stubs and spies

Unit tests are collocated with the application folder in a test directory that matches the application directory structure:

CODE
- đź“‚ src
  - đź“‚ my-application
    - đź“‚ components
      - MyComponent.jsx
    - đź“‚ tests
      - đź“‚ components
        - MyComponent.unit.spec.jsx

Mocha runs any file_name.unit.spec.js file located in the /src folder. This file is usually located in a test directory close to the code being tested.

Unit test conventions

  • Use describe to organize tests by application and feature. Two levels should be adequate depending on the size of the application being tested. Try to avoid nesting deeper than two levels.

  • Use it to describe the unit test:

    • Use active voice.

    • Describe the behavior in terms specific to the unit.

    • Do not abstract the test description with business logic.

    • Recommended:

      • it('truncates the address property when it is longer than 15 characters')

      • it('renders an error when props.errors contains at least one item')

    • Not recommended:

      • it('shortens the address when the user has a long address')

      • it('shows an error when the user is not logged in')

  • It is not recommended to consolidate test specs for multiple components. If a single unit test spec file contains more than 30 it() blocks, consider separating the tests into multiple smaller specs.

    • “Kitchen sink” spec files risk running afoul of Mocha’s memory limitations. They may also complicate the identification of tests that are unintentionally creating memory leaks.

  • Testing components rendered within a shadow DOM may be best managed by converting any such tests to your product’s end-to-end (e2e) test specs.

    • RTL does have additional utilities available that attempt to circumvent the limitations presented by shadow DOM rendering, but VFS teams have not reported significant success with any one solution.

Testing components

Use React Testing Library's render function when testing components.

CODE
import { render, screen } from '@testing-library/react';
import MyComponent from '../../components/MyComponent';

describe('MyComponent', () => {
  it('renders without crashing', () => {
    render(<MyComponent />);
    expect(screen.getByText(/some expected text/i)).toBeInTheDocument();
  });
});

Other utilities

These utilities can be found in platform/testing/unit/helpers.js:

  • mockFetch() - A function to mock the global fetch function and return the value provided in returnVal

    • resetFetch() - Resets the mocked fetch set with mockFetch()

    • mockApiRequest() - Decorated mockFetch() that adds typical API headers to returnVal

    • mockMultipleApiRequests() - Decorated mockFetch() that mocks a fetch call for each response object in an array

CODE
mockFetch(
  new Error('fake error'), // returnVal
  false, // shouldResolve: false returns rejected promise. default is true
);

Note: This utility can be found in platform/utilities/storage/localstorage.js.

  • getLocalStorage() - convenient accessor for local storage and implements a fallback. Useful for stubbing localstorage.

Examples and guides

Libraries

  • mocha.js: Test framework.

  • chai.js: BDD/TDD assertion library.

  • chai-as-promised: Extends Chai with assertions about promises.

  • sinon.js: Standalone test spies, stubs, and mocks.

  • React Testing Library: React Testing Library is a branch of Testing Library that allows users to test their React components through actual DOM nodes instead of rendered instances.

  • react-dom: React DOM library needed for testing React components.

  • react-dom/test-utils: Test utilities for React DOM.

  • react-test-renderer: This package provides an experimental React renderer that can be used to render React components to pure JavaScript objects, without depending on the DOM or a native mobile environment.

  • jsdom: A JavaScript implementation of WHATWG DOM and HTML standards, for use with node.js.

  • choma: Random execution order for mocha suites.


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.