| | |

The Complete Guide to LWC Jest Testing: From Setup to Advanced Mocking


If you are a Salesforce developer, you know the drill: Apex requires 75% code coverage to deploy. But what about your Lightning Web Components (LWC)? While Salesforce doesn’t technically force you to test your front-end code, skipping it is a recipe for disaster.

In this deep dive we break down everything you need to know about Jest testing for LWC. From setting up your environment to mocking complex Apex wires, this is your roadmap to writing bulletproof components.

Why Write Jest Tests?

Unlike Apex tests which run on the Salesforce server, Jest tests run locally on your machine. This gives you instant feedback. The real value, however, is confidence. Good tests allow you to refactor your code freely without the fear of silently breaking existing functionality.

Part 1: The Setup

Before writing a single line of code, you need your environment ready.

  1. Node.js & NPM: Ensure you have Node.js installed.
  2. Salesforce Project: You typically use VS Code with a standard SFDX project structure (force-app/main/default).
  3. Install Jest: Run the following command in your project terminal to install the Salesforce Jest library: npm install @salesforce/sfdx-lwc-jest --save-dev
    Note: This updates your package.json with the necessary dev dependencies.

Part 2: The Anatomy of a Jest Test

Jest tests live in a __tests__ folder inside your component’s directory. A basic test file (myComponent.test.js) is built on three keywords:

  • describe: Defines a “suite” or group of tests.
  • it (or test): Defines an individual test case.
  • expect: The assertion. This is where you check if 2 + 2 actually equals 4.

The “Hello World” of LWC Testing

Testing a component is different from testing plain JavaScript because you have to render the HTML. Here is the standard boilerplate you will use for almost every test:

JavaScript

import { createElement } from 'lwc';
import MyComponent from 'c/myComponent';

describe('c-my-component', () => {
    // Cleanup after each test to prevent "bleeding" of data between tests
    afterEach(() => {
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
    });

    it('displays the correct text', () => {
        // 1. Create the component
        const element = createElement('c-my-component', {
            is: MyComponent
        });
        
        // 2. Add it to the (virtual) DOM
        document.body.appendChild(element);

        // 3. Select elements and assert
        const pTag = element.shadowRoot.querySelector('p');
        expect(pTag.textContent).toBe('Tacos are exciting');
    });
});

Part 3: Handling Asynchronous Events (The Promise Chain)

LWC is asynchronous. When you change a value or click a button, the DOM does not update instantly. You must wait for the framework to re-render.

To do this, use Promise.resolve().then().

Example: Testing a Button Click

If clicking a button should reveal a paragraph:

  1. Query the button and fire a click event.
  2. Use a Promise to wait for the DOM update.
  3. Assert the new element exists.

JavaScript

// ... setup element ...
const button = element.shadowRoot.querySelector('lightning-button');
button.click();

// Wait for any asynchronous DOM updates
return Promise.resolve().then(() => {
    const newParagraph = element.shadowRoot.querySelector('.new-paragraph');
    expect(newParagraph.textContent).toBe('Wow I love tacos');
});

Part 4: Mocking Data and Wire Services

This is where most developers get stuck. Since Jest runs locally, it cannot call your actual Salesforce org. You must “mock” (fake) the data.

1. Mocking the Wire Service (Apex)

If your component uses @wire to call an Apex method, you need to simulate the response.

The Setup:

First, create a JSON file (e.g., mockData/accounts.json) containing the dummy data you expect your Apex to return.

The Test:

Use the emit() function provided by the Jest test adapter to push this data into your component.

JavaScript

import getAccounts from '@salesforce/apex/AccountController.getAccounts';
// Import your mock data
const mockAccounts = require('./mockData/accounts.json');

// Mock the Apex module
jest.mock(
    '@salesforce/apex/AccountController.getAccounts',
    () => {
        const { createApexTestWireAdapter } = require('@salesforce/sfdx-lwc-jest');
        return {
            default: createApexTestWireAdapter(jest.fn())
        };
    },
    { virtual: true }
);

it('renders list of accounts from wire', () => {
    // ... create element ...
    
    // Emit the mock data into the wired property
    getAccounts.emit(mockAccounts);
    
    // Wait for the DOM to update
    return Promise.resolve().then(() => {
        const accountDivs = element.shadowRoot.querySelectorAll('.account-info');
        expect(accountDivs.length).toBe(3); // Assuming your JSON has 3 accounts
    });
});

2. Mocking Imperative Apex Calls

If you call Apex imperatively (e.g., inside a handle function or connectedCallback), the mocking strategy changes slightly. You use mockResolvedValue.

Crucial Tip: If you call Apex inside connectedCallback, you must mock the response before you append the element to the DOM.

JavaScript

import getCases from '@salesforce/apex/CaseController.getCases';

// Mock the module generally
jest.mock(
    '@salesforce/apex/CaseController.getCases',
    () => ({
        default: jest.fn() // Create a mock function
    }),
    { virtual: true }
);

it('loads cases on init', () => {
    // Define what the mock returns BEFORE adding to DOM
    getCases.mockResolvedValue(mockCasesJson);

    const element = createElement('c-case-list', { is: CaseList });
    document.body.appendChild(element);

    // Wait for the promise (microtask) queue
    return Promise.resolve().then(() => {
        const caseItems = element.shadowRoot.querySelectorAll('.case-item');
        expect(caseItems.length).toBe(1);
    });
});

Part 5: Testing Child Components

When your LWC contains another LWC (a child), you don’t need to test the child’s internal logic again. You only need to test that the parent is passing the correct data.

You can query the child component just like a standard HTML tag and check its public properties (@api).

JavaScript

const child = element.shadowRoot.querySelector('c-child-component');
expect(child.caseData).toEqual(mockCasesJson);

Summary Checklist

  • Install Node & Jest: Get your environment ready.
  • Boilerplate: Always use afterEach to clear the DOM.
  • DOM Updates: Always use Promise.resolve().then() after changing data or clicking buttons.
  • Mocking: Never rely on live data. Use JSON files and emit (for wire) or mockResolvedValue (for imperative calls).
  • Timing: If testing logic in connectedCallback, mock your data before document.body.appendChild.

For the full step-by-step coding session, watch the original video here: https://youtu.be/e3LWCIUBf2Q


Need help with your Salesforce Org?

If you need help with your Salesforce org, schedule an hour of consulting time with me! I’m one of only ~500 Salesforce Certified Technical Architect’s (CTA) worldwide and I’ve spent over 30,000 hours building Salesforce implementations over the last decade!

Schedule and hour of consulting with me here!


Do you want to be the next Salesforce Certified Technical Architect (CTA)?

If you need training to help you on your journey to complete your Salesforce CTA Board then why not sign up for the cheapest Salesforce CTA course out there, with someone who has training over a million Salesforce professionals worldwide! You can check out and enroll in the course below!

Sign up for the CTA course here!

Or if a course isn’t your thing, you can always sign up for an hour long CTA study session with me here:
Schedule 1-on-1 CTA Coaching Here!


Get Coding With The Force Merch!!

We now have a redbubble store setup so you can buy cool Coding With The Force merchandise! Please check it out! Every purchase goes to supporting the blog and YouTube channel.

Get Shirts Here!
Get Cups, Artwork, Coffee Cups, Bags, Masks and more here!


Check Out More Coding With The Force Stuff!

If you liked this post make sure to follow us on all our social media outlets to stay as up to date as possible with everything!

Youtube
Patreon
Github
Facebook
Twitter
Instagram


Salesforce Development Books I Recommend

Advanced Apex Programming
Salesforce Lightning Platform Enterprise Architecture
Mastering Salesforce DevOps

Good Non-SF Specific Development Books:

Clean Code
Clean Architecture


AI DISCLAIMER: Gemini assisted me in writing this blog post by analyzing and summarizing the contents on the YouTube video I created that is linked at the top of this post.

Similar Posts