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:
Mocha for running unit tests
Chai for test assertions
React Testing Library (RTL) for mounting and inspecting React components
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:
- đź“‚ 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.
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 returnValresetFetch()
- Resets the mocked fetch set withmockFetch()
mockApiRequest()
- DecoratedmockFetch()
that adds typical API headers toreturnVal
mockMultipleApiRequests()
- DecoratedmockFetch()
that mocks a fetch call for each response object in an array
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 stubbinglocalstorage
.
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.
Help and feedback
Get help from the Platform Support Team in Slack.
Submit a feature idea to the Platform.