Introduction
Testing is a crucial part of the software development process. It ensures that your code works as expected and helps prevent bugs from making it to production. In the world of Salesforce, Lightning Web Components (LWC) are a key part of the development process, and Jest is a popular testing framework that can help automate the testing of these components, In this blog we will see how we can Automating LWC Testing with Jest.
Step 1: Prerequisites
Before you begin, make sure you have the following installed and updated:
- Salesforce CLI
- Visual Studio Code
- Salesforce Extensions for Visual Studio Code
Step 2: Create a Salesforce DX Project
In Visual Studio Code, open the Command Palette by pressing Ctrl+Shift+P
(Windows) or Cmd+Shift+P
(macOS). Enter sfdx
. Select SFDX: Create Project
. Select Standard
. Enter test-lwc
as the project name. Press Enter
. Select a folder to store the project. Click Create Project
and wait for the new Visual Studio Code window to open.
Step 3: Install Node.js and npm
Jest is a Node module, so to use it you need to install Node.js and npm. Install Node.js from the official Node.js website. We recommend using the LTS (long-term support) version.
Confirm Node.js is installed by entering the following command in the terminal: node --version
. When you install Node.js, npm also installs automatically. In a terminal, enter the following command to confirm npm is installed: npm --version
.
Step 4: Install the @salesforce/sfdx-lwc-jest JavaScript module
This module is used to run Jest against Lightning web components in a Salesforce DX workspace environment. To install it, use the following command: yarn add -D @salesforce/sfdx-lwc-jest@winter22
or yarn add -D @salesforce/sfdx-lwc-jest@spring22
.
Step 5: Writing Your First Test
Now that you have Jest installed, you can start writing tests. Create a new file with a .test.js
extension. For example, if you’re testing a component called myComponent
, you would create a file called myComponent.test.js
.
Here’s an example of what a simple test might look like:
import { createElement } from 'lwc'; import MyComponent from 'c/myComponent'; describe('c-my-component', () => { afterEach(() => { // The jsdom instance is shared across test cases in a single file so reset the DOM while(document.body.firstChild) { document.body.removeChild(document.body.firstChild); } }); it('displays the correct label', () => { // Create element const element = createElement('c-my-component', { is: MyComponent }); document.body.appendChild(element); // Verify displayed greeting const div = element.shadowRoot.querySelector('div'); expect(div.textContent).toBe('Hello, World!'); }); });
In this test, we’re importing the myComponent
component, creating an instance of it, adding it to the DOM, and then checking that it displays the correct text.
let’s take a look at a more complex test case. This time, we’ll test a component that takes an input and updates its state accordingly.
import { createElement } from 'lwc'; import MyComponent from 'c/myComponent'; describe('c-my-component', () => { afterEach(() => { // The jsdom instance is shared across test cases in a single file so reset the DOM while(document.body.firstChild) { document.body.removeChild(document.body.firstChild); } }); it('updates the message when the input changes', () => { // Create element const element = createElement('c-my-component', { is: MyComponent }); document.body.appendChild(element); // Select input for simulating user input const inputElement = element.shadowRoot.querySelector('lightning-input'); // Simulate user input inputElement.value = 'Jest is great!'; inputElement.dispatchEvent(new CustomEvent('change')); // Return a promise to wait for any asynchronous DOM updates return Promise.resolve().then(() => { // Query for the paragraph element that displays the message const pElement = element.shadowRoot.querySelector('p'); // Verify that the input value is reflected in the paragraph element expect(pElement.textContent).toBe('Jest is great!'); }); }); });
Here’s what each part of the code does:
import { createElement } from 'lwc';
andimport MyComponent from 'c/myComponent';
: These lines import the necessary modules and the component that you want to test.describe('c-my-component', () => {...});
: This function defines a block of tests for themyComponent
component.afterEach(() => {...});
: This function runs after each test. It’s used here to clean up the DOM after each test.it('updates the message when the input changes', () => {...});
: This function defines an individual test. In this case, the test checks whether the component correctly updates its message when the input changes.const element = createElement('c-my-component', {is: MyComponent});
: This line creates a new instance of themyComponent
component.document.body.appendChild(element);
: This line adds the new component instance to the DOM.const inputElement = element.shadowRoot.querySelector('lightning-input');
: This line selects the input element within the component.inputElement.value = 'Jest is great!';
andinputElement.dispatchEvent(new CustomEvent('change'));
: These lines simulate a user typing ‘Jest is great!’ into the input element.return Promise.resolve().then(() => {...});
: This line returns a promise that resolves after all the asynchronous tasks in the test have completed.const pElement = element.shadowRoot.querySelector('p');
: This line selects the paragraph element that displays the message.expect(pElement.textContent).toBe('Jest is great!');
: This line checks that the paragraph element’s text content matches the input string.
Step 6: Running Your Tests
To run the test, you can use the Salesforce CLI by executing the following command: npm run test:unit
.
Conclusion
Automating your LWC tests with Jest can help you catch bugs early, make your code more robust, and speed up your development process. While this guide provides a basic introduction to using Jest with LWC, there’s a lot more to learn. Be sure to check out the official Jest documentation for more information.
Additional Resources: Test Lightning Web Components