April 14, 2019

Test Lightning Web Components

Jest is a powerful tool with rich features for writing JavaScript tests. Use Jest to write unit tests for all of your Lightning web components. To run Jest tests, install lwc-jest, which sets up all the necessary Jest configurations for a Salesforce DX project.

Run Jest tests at the command line or (with some configuration) within your IDE. Jest tests don’t run in a browser or connect to an org, so they run fast. When run in “watch mode” they give you immediate feedback while you’re coding. Jest tests work only with Lightning web components, they don’t work with Aura components.

1. Download and install node.js and npm.

Node.js - https://nodejs.org/en/
npm - https://nodejs.org/en/

2. Open a Salesforce project in VS Code which has LWC component.

3. Go to Terminal tab.

4. Execute npm init command.


5. Execute npm install command.


6. Execute npm install @salesforce/lwc-jest --save-dev command. This will take sometime to complete.

7. Next, to identify your test script, add an entry in the scripts block of your project’s package.json file. The line must include a name and a command. You can choose the name. The command must be lwc-jest and can optionally include a supported flag like --watch or --debug.


8. Create __tests__ folder in the component folder.



9. 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.

**/__tests__/**


10. Create new js test file.


11. Use componentName.test.js naming convention.

12. Use npm run test:unit to run the test.


Sample Code:

Component:


  1. <template>  
  2.     <lightning-card title="Hello" icon-name="custom:custom14">  
  3.         <div class="slds-m-around_medium">  
  4.             Hello, {greeting}!  
  5.         </div>  
  6.     </lightning-card>  
  7. </template>  

JAVASCRIPT Controller:


  1. import { LightningElement } from 'lwc';  
  2.   
  3. export default class Hello extends LightningElement {  
  4.   
  5.     greeting = 'World';  
  6.   
  7. }  


Test class JAVASCRIPT Controller:
  1. import { createElement } from 'lwc';  
  2. import Hello from 'c/hello';  
  3.   
  4. describe('c-hello', () => {  
  5.     afterEach(() => {  
  6.         // The jsdom instance is shared across test cases in a single file so reset the DOM  
  7.         while (document.body.firstChild) {  
  8.             document.body.removeChild(document.body.firstChild);  
  9.         }  
  10.     });  
  11.   
  12.     it('displays greeting', () => {  
  13.         // Create element  
  14.         const element = createElement('c-hello', {  
  15.             is: Hello  
  16.         });  
  17.         document.body.appendChild(element);  
  18.   
  19.         // Verify displayed greeting  
  20.         const div = element.shadowRoot.querySelector('div');  
  21.         expect(div.textContent).toBe('Hello, World!');  
  22.     });  
  23. });  

Imports
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.
import { createElement } from 'lwc';
import Hello from 'c/hello';

describe block
A describe block defines a test suite. A test suite contains one or more tests that belong together from a functional point of view.
describe('c-hello', () => {
    ...
});
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.

Cleanup
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 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.
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);
    }
});
Jest also has other methods that you can use to perform setup and cleanup tasks. See jestjs.io/docs/en/setup-teardown.

it (or test) block
Note
NOTE 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.
it('displays greeting', () => {
    ...
});

Create the component under test
The test uses the imported createElement method to create an instance of the component to test, in this case, c-hello.
const element = createElement('c-hello', {
    is: Hello
});

Add the component to the DOM
The test then calls appendChild to add the component to the test’s version of document.
The document.body.appendChild() call attaches the Lightning web component to the DOM and renders it. Which also means that renderedCallback() lifecycle method gets called.
document.body.appendChild(element);
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 peak across the shadow boundary to inspect a component’s shadow tree. It’s the test equivalent of this.template.
const div = element.shadowRoot.querySelector('div');

Asserts
Finally, the expect statement is an assertion of the success condition: that the text of the element is “Hello, World!”
const div = element.shadowRoot.querySelector('div');
expect(div.textContent).toBe('Hello, World!');
Jest supports lots of matchers like toBe and toMatchObject that make it easy to check that a value meets a condition.

No comments:

Post a Comment