Write Jest Tests for Lightning Web Components
Write your component tests in local JavaScript files. Commit them to version control along with the component itself. Jest tests aren’t saved to Salesforce.
Jest tests are written, saved, and run differently than Jasmine or Mocha tests written for the Lightning Testing Service. Jest tests are local only, and are saved and run independently of Salesforce.
You can use the Salesforce CLI command sf force lightning lwc test create
to create a test directory and a boilerplate test file within the directory. The following command creates a test directory and file for testing the myButton
Lightning web component.
After you use the Salesforce CLI create
command, you see a folder named __tests__
at the top level of your component’s bundle directory, such as force-app/main/default/lwc/myButton/__tests__
. Otherwise, create the folder yourself. Save all tests for this component inside the __tests__
folder. Share tests with other team members or systems by committing the __tests__
folder to version control.
To ensure that the __tests__
folder and its contents are never saved to Salesforce, add this glob pattern to the .forceignore
file for each of your projects. The Salesforce CLI command sf force lightning lwc test setup
does this task for you.
This pattern ensures that Salesforce DX commands that push, pull, or transform code and metadata ignore the __tests__
folder and its contents.
Jest runs JavaScript files in the __tests__
directory. Test files must have names that end in .js
, and we recommend that tests end in .test.js
. You can have a single test file with all of your component tests, or you can have multiple files to organize related tests. Test files can be placed in sub folders.
To become an accomplished tester, learn how to use Jest. In particular, learn the syntax of the many matchers provided with Jest. We don’t cover general Jest usage here because the Jest documentation is excellent. We focus on the specifics of using Jest with Lightning web components.
Jest tests for a Lightning web component should test the behavior of a single component in isolation, with minimal dependencies on external components or services.
Let’s look at hello.test.js
, which is the test for the hello
Lightning web component in the lwc-recipes
repo.
Let’s walk through the code and learn about each section of the test file. All tests must use this structure.
First, the test imports the createElement
method. This method is available only in tests. The code must also import the component to test, which in this case is c/hello
. Use these imports later to create the component under test.
A describe
block defines a test suite. A test suite contains one or more tests that belong together from a functional point of view.
We recommend having a top level describe
block with a description matching the component name. Add more describe
blocks that group functionality only if necessary.
For hello.test.js
, a single describe
is sufficient. For more complex components, it may make sense to have several describe
blocks that group things into categories like error scenarios, empty input, wired data, regular data, and so on.
The Jest afterEach()
method resets the DOM at the end of the test.
Since a browser isn’t running when tests run, Jest uses jsdom
to provide an environment that behaves much like a browser’s DOM or document
. Jest has a dependency on jsdom
, which is a Node.js project, so jsdom
is downloaded during installation of the sfdx-lwc-jest
project the same way Jest itself is.
Each test file shares a single instance of jsdom
, and changes aren’t reset between tests inside the file. Therefore it’s a best practice to clean up between tests, so that a test’s output doesn’t affect any other test.
Jest also has other methods that you can use to perform setup and cleanup tasks. See jestjs.io/docs/en/setup-teardown
.
it
is an alias for test
. Use whichever word allows you to describe the expected behavior accurately.
An it
block describes a single test. A test represents a single functional unit that you want to test. Write the it
to describe the expected behavior of that function. For example, the hello
component displays “Hello, World!”, so the it
block tests that the hello component displays a greeting.
The test uses the imported createElement
method to create an instance of the component to test, in this case, c-hello
.
The test then calls appendChild
to add the component to the test’s version of document
.
The appendChild()
call inserts the component into the DOM and the lifecycle hooks connectedCallback()
and renderedCallback()
are called.
The next step is to use a standard DOM query method to search the DOM for the element. Use element.shadowRoot
as the parent for the query. It's a test-only API that lets you peek across the shadow boundary to inspect a component’s shadow tree. It’s the test equivalent of this.template
.
Finally, the expect
statement is an assertion of the success condition: that the text of the element is “Hello, World!”
Jest supports lots of matchers like toBe
and toMatchObject
that make it easy to check that a value meets a condition. See jestjs.io/docs/en/expect
.
To test a component that extends NavigationMixin(LightningElement)
, create a mock navigation plugin. The sfdx-lwc-jest
package includes a lightning/navigation
mock by default. To use the mock, you must provide a jest config.
Here's an example mock that's used by many navigation components in the lwc-recipes repo.
Use the mock with a jest.config.js
config file.
When the state of a Lightning web component changes, the DOM updates asynchronously. To ensure that your test waits for updates to complete before evaluating the result, return a resolved Promise. Chain the rest of your test code to the resolved Promise. Jest waits for the Promise chain to complete before ending the test. If the Promise ends in the rejected state, Jest fails the test.
The appendChild()
call inserts the component into the DOM and the lifecycle hooks connectedCallback()
and renderedCallback()
are called. The example then sets the element value after the appendChild()
call, which resembles cases where properties are set by another method or user interaction after the component is inserted into the DOM. In these cases, use a promise to wait for the asynchronous DOM update. For more information on the component lifecycle and rendering, see Lifecycle Flow.
In cases where the property is set before the appendChild()
call, the component is rendered synchronously. When the property is set before the appendChild()
call, you don’t need to wait for asynchronous updates or return a promise.
See Also
- Salesforce Developers Blog: Unit Test Lightning Web Components with Jest
- Jest: Get Started
- Jest: Expect Reference
- GitHub Repo: lwc-recipes
- Shadow DOM