Skip to content
Rohit Macherla

Writing LWC tests when you haven't moved to SFDX repository structure

salesforce, lwc, testing2 min read

If you are yet to migrate to SFDX but still want to start using Lightning Web Components, then it’s possible to do it. However, one of the best reasons to start using LWC is that it’s testable. Jest tests to test the front-end bring a lot of advantages that the Aura framework doesn't have. Well, Aura has it but it's so tedious that it's as if it's non-existent.

As you are still using the pre-sfdx repository structure, your code is likely to be in this structure:

2|- src
3 |- aura
4 |- classes
5 ...
6 |- package.xml

Let’s say you started with your first helloWorld LWC component. That'd go into the src > lwc > directory and as you write your first Jest test, you'll place it in the __tests__ directory. Also, we have to make sure that we install the Jest library in the first place, which means we'll need the package.json file. Make sure you run the npm install command. The directory structure now looks like this:

2|- node_modules
3|- ...
4|- src
5 |- aura
6 |- classes
7 |- lwc
8 |- helloWorld
9 |- __tests__
10 |- helloWorld.test.js
11 |- helloWorld.html
12 |- helloWorld.js
13 |- helloWorld.js-meta.xml
14 ...
15 |- package.xml
17|- package.json

Now that it’s done, we can run the test. We do that using the command npm run test:unit as the test:unit script is already present in the package.json. Hold on, this doesn’t work.

1Error: Could not find sfdx-project.json. Make sure is run from project root

Alright, so we need to have an sfdx-project.json file even if we are not in an sfdx project structure.

Let's add one by copying an existing file that we can get from the lwc-recipes repo. It has some package and version references but we can remove them. Here's how it looks like when I pasted it in:

2 "packageDirectories": [
3 {
4 "path": "force-app",
5 "default": true
6 }
7 ],
8 "namespace": "",
9 "sfdcLoginUrl": "",
10 "sourceApiVersion": "51.0"

Hmmm, that path has force-app in it. That's not right - we don't use the sfdx project structure so we don't have the force-app directory at all! Let's see what happens when we re-run the tests.

1FAIL src/lwc/helloWorld/__tests__/helloWorld.test.js
3● Test suite failed to run
5Cannot find module 'c/helloWorld' from 'helloWorld.test.js'

So our test can’t find the module. Looks like it’s most likely because of the project structure.

Let’s change the sfdx-project.json so that it now points to src directory instead.

2 "packageDirectories": [
3 {
4 "path": "src",
5 "default": true
6 }
7 ],
8 "namespace": "",
9 "sfdcLoginUrl": "",
10 "sourceApiVersion": "51.0"

If we re-run the tests now, we get a nice success:

1PASS src/lwc/helloWorld/__tests__/helloWorld.test.js
2 c-hello-world
3 ✓ hello test (21ms)Test Suites: 1 passed, 1 total
4Tests: 1 passed, 1 total
5Snapshots: 0 total
6Time: 2.411s

That’s working now. Brilliant!

Let’s go ahead and deploy it using ant.

1All Component Failures:
21. lwc/helloWorld/__tests__/helloWorld.test.js (markup://c:helloWorld) -- Error: [Line: 1, Col: 9] LWC1518: Invalid LWC imported identifier *********** DEPLOYMENT FAILED ***********

Well hello! Looks like ant doesn't like some of our tests. 🤔

Actually, these tests are only in our repository and never saved to our salesforce org even if we use sfdx! That's why they are in the .forceignore file when the sfdx repository structure is used (sample here).

Anything in our src directory is deployed to our Org.

So, we'll have to keep our tests outside src. Let's create a tests directory at the same level as src instead, and move our tests there

2|- node_modules
3 |- ...
4|- src
5 |- aura
6 |- classes
7 |- lwc
8 |- helloWorld
9 |- helloWorld.html
10 |- helloWorld.js
11 |- helloWorld.js-meta.xml
12 ...
13 |- package.xml
14|- tests
15 |- helloWorld
16 |- helloWorld.test.js
18|- package.json

You can also see that we’ve included the helloWorld directory name within tests directory so that all tests are segregated. Let's run deployment this time.

2 [echo] SFDC Deployment [STARTED]
3 [sf:deploy] Request for a deploy submitted successfully.
4 [sf:deploy] Request ID for the current deploy task: 0Af0I00000ivEC6SAM
5 [sf:deploy] Waiting for server to finish processing the request...
6 [sf:deploy] Request Status: InProgress
7 [sf:deploy] Request Status: Succeeded
8 [sf:deploy] *********** DEPLOYMENT SUCCEEDED ***********
9 [sf:deploy] Finished request 0Af0I00000ivEC6SAM successfully.

Let’s run the tests to make sure that’s working too:

1(node:17928) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time
2 PASS tests/helloWorld/helloWorld.test.js
3 c-hello-world
4 ✓ hello test (21ms)Test Suites: 1 passed, 1 total
5Tests: 1 passed, 1 total
6Snapshots: 0 total
7Time: 2.489s
8Ran all test suites.

That’s it! 🎉

Conclusion - with all the steps

Here are all the steps required to write and run Jest tests in a non-sfdx repository structure:

  1. Create an sfdx-project.json file that refers to src instead of force-app.
  2. Also include the package.json file that has the unit test script and jest npm dependency. You can copy this from any standard sfdx repo.
  3. Create a tests directory as a sibling of src.
  4. Separate each tests by creating a directory with the same name as the component — helloWorld in our case.
  5. That’s it!
  6. Oh, and if you have a jest.config.js for any jest-mocks, you can put them in the same tests directory and update the jest.config.js to refer to it.