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.

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