6

I was trying to write unit tests for some of my LWC components, however the ones that use custom labels throw the following exception

[LWC error]: Invalid operation on Element [object:vm undefined (2)]. Elements created via a template should not be mutated using DOM APIs. Instead of attempting to update this element directly to change the value of attribute "title", you can update the state of the component, and let the engine to rehydrate the element accordingly.
<lightning-button>

From my understanding within Jest, the custom labels don't exist so I need some way to mock them out. From the documentation, it mentions to use a jest-transformer but doesn't show a working example of how to do it.

I've also used the latter example, which does not work as well. I copied the same format to mock out the specific label in my test file and I still received the same exception.

import myImport from '@salesforce/label/c.specialLabel';

jest.mock('@salesforce/label/c.specialLabel', () => {
    return { default: "value set in test" };
}, { virtual: true });

What is the proper way to mock out custom labels in LWC for a DX org?

1

This is a fair question and you're so close to the answer!

So, imagine you have the following Lightning Web Component named customLabelTest:

Markup (HTML):

<template>
   <lightning-card>
      <span class="slds-align_absolute-center">
        <div id="customlabel">{labels.labelDetails}</div>
      </span>
   </lightning-card>
</template>

Controller (JS):

import { LightningElement } from 'lwc';

// Custom Labels Imports
import labelDetails from '@salesforce/label/c.Details';

export default class CustomLabelTest extends LightningElement {

    labels = {
       labelDetails
    };
}

So, your Jest test would look somewhat like this:

    import { createElement } from 'lwc';
    import CustomLabelTest from 'c/customLabelTest';
    import labelDetails from '@salesforce/label/c.Details';

    let element;

    jest.mock("@salesforce/label/c.Details", () => {
        return { default: "Your mocked custom label here: Details" };
    }, { virtual: true });


    //This line of code is necessary to reset the DOM after each block of test code
    afterEach(() => {
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
    });

    beforeEach(() => {
        // Create initial element
        element = createElement('c-custom-label-test', {
            is: CustomLabelTest
        });
        document.body.appendChild(element);
    });

    describe('c-custom-label-test', () => {
        it('CUSTOM LABEL TEST: Custom label was mocked', () => {

            return Promise.resolve().then(() => {
                const divs = element.shadowRoot.querySelectorAll('div');
                expect(divs.length).toBe(1);
                expect(divs[0].textContent).toBe("Your mocked custom label here: Details");

            });
        });

    });

Note that I'm adding the custom label to a <div> but you could search for any other valid tag or id in your shadow DOM.

I hope that helps.

1
  • 1
    Thanks Matheus. The main difference I noticed was that you used Promise.resolve() in your test. I'll give this a try – Justin Jun 12 '20 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.