Writing an end-to-end test
Frontend engineers use end-to-end tests in vets-website
to validate multipage applications with client-side routing. They are primarily used to assert that:
Client applications render their inputs.
Client-side navigation occurs when the required fields are populated.
End-to-end testing overview
vets-website
uses Cypress to write end-to-end tests.
Some older end-to-end tests were written in Nightwatch before Cypress. All new tests should be written using Cypress. Nightwatch tests are being deprecated/migrated to Cypress.
End-to-end tests are collocated in the application folder with the application they test.
Cypress tests can be run using the command
yarn cy:run
(afteryarn watch
toyarn build
).
See Cypress Best Practices on the VA.gov Platform and Cypress Resources Reference Guide for detailed use cases and documented helpers/mocks.
End-to-end tests conventions
Use the name of the test spec to indicate the page under test.
Disable scrolling on the page.
Assert navigating the page is successful.
Use functions from the helper file to perform all actions on the page.
These are recommendations, not requirements, except when labeled as required.
Separate page navigation from form field input.
Use a main test file for navigation, assertions, and calls helpers.
Use a helper file for filling out forms.
Create separate, numbered, main test files to organize tests by their focus:
00-all-fields.cypress.spec.js
- required and optional fields.01-required.cypress.spec.js
- only required fields.02-accessibility.cypress.spec.js
- validates accessibility.03-auth.cypress.spec.js
- validates authentication.04-cross-cutting-feature.cypress.spec.js
- validates one feature used across several pages (Example: save in progress).
Group tests by pages and use a comment to indicate what page is being tested.
Mock all API responses before starting the test. See Mocking API responses below.
Use
waitForElementVisible
before interacting with any element on the page.Use
timeouts
constant for setting timeouts (platform/testing/e2e/timeouts.js
).Use helpers for filling in data and performing actions on the page.
Required: Perform
axeCheck
on the main body of the application on each page - see axeCheck.Assert that each navigation is successful.
Cypress uses
chai
to handle assertions.
Test dependencies
You generally don’t need to import any modules for helpers, timeouts, etc.
Test structure
Cypress uses Mocha's behavior-driven development (BDD) syntax, which is what we use for our unit tests.
Each spec file starts a new browser instance and runs the suite of tests according to the describe()
and it()
blocks.
Note that
it()
blocks are individual tests, so eachit()
block should be independent of others in the same test suite.Everything executed in the browser must be inside an
it()
block.
Visit the Cypress docs for more context.
Form tests
Applications that are built with the VA Forms Library should be tested with the Cypress form tester.
Visiting a page
When visiting a page, you don't need to specify the baseUrl
. The Cypress configuration file takes care of this. You can visit the page with a relative path:
cy.visit("health-care/apply/application");
Interacting with page elements
The most common interactions you'll probably use are clicking, selecting elements from dropdowns, and entering text inputs.
Below are examples of these interactions in Cypress:
Clicking
cy.get(".form-panel .usa-button-primary").click()
Selecting from dropdown
cy.findByLabelText(/country/i).select(testData.veteranAddress.country);
Entering data
cy.findByLabelText(/first name/i).type(testData.veteranFullName.first);
For more information about how Cypress interactions behave, visit the Cypress guide for interacting with elements.
For additional ways to interact with the DOM, we've also included the Cypress Testing Library as a dependency.
Active element
Checks if the given element is focused on the page.
// BDD assertion
cy.findByLabelText("First name").should("have.focus");
Disabled element
Checks if the given element is disabled on the page.
// BDD assertion
cy.findByRole("button", { name: "Submit" }).should("be.disabled");
Examples
Cypress test for the 21-526EZ form using the form tester
Mocking API responses
A mock server runs with the end-to-end tests to allow tests to make production-like calls.
See the Mocks section of Cypress Resources Reference Guide for detailed mock API examples currently used.
Below are some of the commonly used Cypress mocks (accessible from the link above).
mockFeatureToggles
mockConstants
createTestHistory
renderWithStoreAndRouter
mockAppointmentsGetApi
mockFacilityApi
Custom Cypress commands
Custom Cypress commands can be found in src/platform/testing/e2e/cypress/support/commands
.
Cypress supports extending its client API with custom commands.
Below are some of the commonly used custom Cypress commands.
axeCheck - Callback from accessibility check that logs axe violations to console output.
expandAccordions - Expands all accordions and AdditionalInfo components.
injectAxeThenAxeCheck - Combines two common, sequentially called functions.
login - Simulates a logged-in session.
upload - Workaround to support file upload functionality in tests, which is currently not officially implemented.
viewportPreset - Sets the viewport by preset name.
Helpers
The Cypress Resources Reference Guide contains a list of currently utilized Cypress & VAOS Helpers and Appointment Helpers.
Help and feedback
Get help from the Platform Support Team in Slack.
Submit a feature idea to the Platform.