maidi
maidi

Reputation: 3489

Jest Test on Stencil Component does not apply changes in variables

I want to test a stencil component and configure a global variable in my test like this:

describe('my-component', () => {
  const myVarMock = 1;

  let page;
  let shadowRoot: ShadowRoot;

  beforeEach(async () => {
    page = await newSpecPage({
      components: [MyComponent],
      html: `<my-component></my-component>`,
      supportsShadowDom: true,
      autoApplyChanges: true
    });
    shadowRoot = page.root.shadowRoot;
  });


  it('should test', () => {
    page.rootInstance.myVar= myVarMock;
    page.rootInstance.componentWillLoad();
    page.rootInstance.render();

    console.log(shadowRoot.innerHTML.toString());
    const buttonElement = shadowRoot.querySelector('.my-button'); //is null because shadow root is empty
  });
});

My Component only renders something, when myVar is set. In the console.log of my test, shadowRoot is always empty, although I explicitly call render() in the test and when I go through the render function in debug-mode it has a value for myVar and renders everything. But why is shadowRoot then empty and my buttonElement is undefined?

Component:

@Component({
  tag: 'my-component',
  shadow: true,
})
export class MyComponent{

  public myVar;

  componentWillLoad() {
    ...
  }

    render() {
        return (
          <Host>
            {this.myVar? (
                 <div class="my-button"></div>
             ): null}
          </Host>
        )
    }
}

Upvotes: 3

Views: 2227

Answers (1)

Simon H&#228;nisch
Simon H&#228;nisch

Reputation: 4978

Calling those life-cycle hooks like componentWillLoad and render manually does not do what I think you're expecting it to do. The Stencil runtime calls render and uses the return value (JSX) to eventually render your component. Manually calling render does not render or re-render your component. In fact, it doesn't do anything except returning some JSX to you but you're not doing anything with the return value.

I think the main issue in your case is that myVar is not declared as a property with the @Prop() decorator. So even though you have marked your class member as public and are able to change it from the outside, Stencil will not wire up anything for you regarding that prop. See https://stenciljs.com/docs/properties.

Instead, you'll have to define it as:

@Prop() myVar?: number;

That way it will cause Stencil to re-render your component every time you update the prop's value.

Your test case should just look like

it('should test', () => {
    page.root.myVar = myVarMock;

    console.log(shadowRoot.innerHTML.toString());
    const buttonElement = shadowRoot.querySelector('.my-button');

    expect(buttonElement).not.toBeNull();
});

Upvotes: 2

Related Questions