Testing Lightning Web Components
At Vlocity, Matt Goldspink focuses on developing beautiful user interfaces using Salesforce’s Lightning technology, and with Salesforce's announcement of exciting changes to the platform, web development in general just got even more interesting.
For anyone with experience of Aura component development, they’ve probably faced the issue of how to test the things! They were so heavily tied to the platform that they couldn’t easily be tested in isolation.
Fortunately, Lightning Web Components has true TDD built in from the outset. It’s super simple to write tests and make assertions. Even better, if you’re used to writing tests with Jasmine, Mocha or Jest then you’ll be right at home.
Setting up your Project
If you don’t yet have an LWC project I’d suggest following my previous post. In this post we’ll take what we did in that project and evolve to add some simple unit tests that we can run right from the command line on your computer… no need to upload code to the org!
Firstly we’ll need to add a
project.json file to the root of our project. If you don’t have a
project.json, just run
npm init and follow the walkthrough – most options can be defaulted. After running this command you’ll need to add our test dependencies. On the command line run:
This will install Jest (a popular testing framework from Facebook used heavily on React) and Salesforce LWC Jest integrations, including the compiler and engine. Now open your
package.json and under the
"scripts" object add a
"test:unit" property who’s value is simply
The final step is to add a
jest.config.js file to the root of our project. The contents should simply look like:
With this setup you can run your tests on the command line by typing:
As you can see we don’t have any tests yet, so let’s go add one.
BUT WAIT! There’s a Simpler Way
We just saw a lot of configuration –
jest.config.js files and multiple
npm installs. I showed the above to reinforce that this is just standard Open Source Jest tooling – nothing Salesforce proprietary! However that doesn’t mean that the guys at Salesforce don’t want to make things easier, and they have! You can actually replace everything we just installed with one simple npm command:
This will install everything we installed last time but behind a
lwc-jest wrapper command. You can safely delete references to
@lwc/jest-preset @lwc/module-resolver @lwc/compiler @lwc/engine in your
Next you can delete your
jest.config.js and update your
package.json scripts to be:
Now when you run
npm run test:unit it will run the
lwc-jest cli command which in turn will call
jest with everything installed and configured for you!
Adding a Test to an LWC Component
Each component can contain it’s own suite of tests, navigate to your component, in my project I’ll be working with a very simple
helloComponent whose content is simply:
Add a folder called
__tests__. Now create a file called
Inside this file we’ll add our first test:
There’s a lot here so let me try describe it in chunks:
These first 2 lines import the
createElement function from the
lwc framework. This is the magic which knows how to take an LWC class and turn it into an HTML Element. We’ll use this further down. The second line is how we import our component that we want to test. The
c/ prefix is simply the namespace of it – in Salesforce orgs the default namespace is usually
Next we add our first
describe, this is essentially the wrapper around where our tests live. We also add an
afterEach hook. The code here will be run after every test and as stated in the comment it basically resets the DOM. In other words, it will remove any LWC elements we rendered after each test so that the next test has a clean slate.
Finally our test! We use the
createElement from the
lwc import earlier to turn our
HelloComponent into a real DOM element. Then we insert it into the body of our page. And finally we run our assertion – in this case I expect that there should be a tag whose text content is
Hello, World. If you re-run
npm run test:unit you’ll get a nice happy test!
Testing a Property Change
Whilst a passing test is nice, it’s not really covering all our logic. One thing we should do is verify that if we set the
person property to a different value, then that value is reflected in the DOM too. Let’s add a new test for that. After your existing test add the following:
This test is pretty much the same as before except we’re now changing the value of
person on the element to
Mattand we’re updating our expectation to verify it now says
Hello, Matt! instead. Let’s run it and see what happens:
Hurray – It works!
Testing a Property Change Part 2
Now I want to show something that will likely catch a lot of people out. Let’s take the same test as we just did, but we’re going to move one line:
I’ve shifted the
element.person = "Matt" line to be run after the element has been inserted into the DOM. If you run the tests now you should see:
Oh man! It fails!!! How can moving one line break a test?
The difference between the two versions of this test are that in the first version of the test we set the value of
person before we inserted the element into the DOM, therefore when the element is inserted it has the value of
Matt and renders it immediately. In the second version we set the value of
person after the element has been inserted. This means that the component needs to be re-rendered in order to update the DOM… and rendering is asynchronous. So when we do our expectation immediately after setting the new value, the DOM hasn’t been re-rendered and so we still see
So how do we fix this up? We need to run our expectations after then DOM has been updated. Fortunately there’s a nice easy way to do it… use a Promise. Let’s see what this updated test looks like:
The change above basically creates an immediately resolving Promise and then runs our assertions on the next tick of the browser. If you run the tests now you should see 2 passing tests:
All the code from this post is available as a github project for you to clone and run: bit.ly/2tcSHKq
There’s a lot more things we can do with our tests which I’ll cover in future posts including:
- Triggering, capturing and asserting events
- Mocking of Salesforce’s Lightning components
- Mocking of data sources
I’d highly recommend reading some of Salesforce’s own example tests like in the e-bikes app. Here’s some additional links for more information:
- Salesforce Developer Guide – Test Lightning Web Components
- Example Jest tests in Ebikes
- Jest Documentation