1

I have a Lightning Web Component that represents a "wizard" and assists in animating the transitions between views. It has a <slot> tag which allows users to define whatever views they want by creating a series of <div> tags.

myWizard.html-------------------------------------------

<template>
    <slot class="wizard-view-container"></slot>
</template>


Sample usage of myWizard component ----------------------------

<c-my-wizard>
    <div data-view-id="first-view"> ... </div>
    <div data-view-id="second-view"> ... </div>
    <div data-view-id="first-view"> ... </div>
</c-my-wizard>

I want to write some Jest Test scripts for this component, but I can't seem to programmatically add children to the body slot

import { createElement } from 'lwc';
import MyWizard from 'c/MyWizard';

describe('myWizard', () => {
    afterEach(() => {
        while (document.body.firstChild) {
            document.body.removeChild(document.body.firstChild);
        }
    });

    it('sets the first view to have class curr-view by default and all other views to have next-view', () => {
        let testElement = createElement('c-my-wizard', { is: MyWizard });

        let divElement1 = document.createElement('div');
        let divElement2 = document.createElement('div');
        let divElement3 = document.createElement('div');

        testElement.appendChild(divElement1);
        testElement.appendChild(divElement2);
        testElement.appendChild(divElement3);

        document.body.appendChild(testElement);

        expect(divElement1.classList.contains('curr-view')).toBeTruthy();
        expect(divElement2.classList.contains('next-view')).toBeTruthy();
        expect(divElement3.classList.contains('next-view')).toBeTruthy();
    });
});

When I run this test, I get errors let the following

[LWC error]: appendChild is disallowed in Element unless lwc:dom="manual" directive is used in the template.

I tried putting lwc:dom="manual" to the <slot> tag, but that is not allowed. I can't seem to figure out where to go from here. Is testing for this type of component possible?

2
  • We are building the same component LOL, did you find a solution?, I think Sebastian provided a wrong answer, since the use case is to passed components declaratively and not programmatically. May 28, 2019 at 17:48
  • FYI, I ended up not creating any automated testing scripts for the Wizard LWC. But your answer below has me intrigued and i'll have to give it a go. Thanks for the suggestion.
    – Vincent Ip
    May 29, 2019 at 18:09

3 Answers 3

1

I don't know much about Jest but I can spot a potential problem.

You're creating a test element (let testElement = createElement('c-my-wizard', { is: MyWizard });) and later attempting to modify its DOM.

LWC only lets you manipulate an element's DOM if you decorate it with a lwc:dom="manual" in it's definition. The error gives you that hint.

The component you created gets rendered as <c-my-wizard></c-my-wizard> but it should get rendered as <c-my-wizard lwc:dom="manual"></c-my-wizard>

My lack of knowledge in Jest will preclude me from fixing your syntax, but if you can add that directive you'll be good to go

2
  • Yeah, I realized that and I tried to put the lwc:dom="manual" directive in the html portion of the component, but LWC doesn't allow that attribute on <slot> tags. I also tried to programmatically put the attribute in that testElement but using setAttribute(), but that didn't seem to work either. Thanks for trying to help.
    – Vincent Ip
    Mar 18, 2019 at 19:49
  • That wouldn't go on the slot tag, it'd go on the <c-my-wizard> declaration Mar 18, 2019 at 19:51
1

The solution I can think of to solve this problem is to create a demo component that wraps the wizard component and declaratively add the wizard steps components as children of wizard.

wizardTestDemo lwc

<template>
   <c-my-wizard>
     <c-my-wizard-step name="test1" label="Test 1">
     <c-my-wizard-step name="test2" label="Test 2">
     <c-my-wizard-step name="test3" label="Test 3">
   </c-my-wizard>
</template>
1
  • This is interesting. A component specifically for test only and then indirectly test the base component through Jest testing this component. I'll have to give this a try.
    – Vincent Ip
    May 29, 2019 at 18:06
0

Found this a long time later when trying to implement similar tests and functionality. I've solved this by creating a simple utility component to handle the query functionality for the parent component to "find" the child components :

export function getChildElements(template,selector) {
    return Array.from(template.querySelectorAll(selector));
}

and then wired this utility into the parent component :

const stepComponents = getChildElements(this.template,'c-child-component');

as opposed to :

this.template.querySelectorAll('c-child-component')

This will then allow you to mock the utility class in your LWC test :

jest.mock('c/slotUtils',() => {
    return {
        __esModule : true, 
        getChildElements : jest.fn()
    }
});

and use in your test class to 'bind' to your parent component :

const section = createElement('c-child-component', {
    is : ChildComponent
})

getChildElements.mockImplementation(() => [section]);
    
1
  • cool. i'll give this a try.
    – Vincent Ip
    Apr 25, 2022 at 13:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .