Search code examples
javascripttestingjestjsweb-component

Can I wait on connectedCallback finsh work in tests?


I am trying to test some code and I know it will work as expected, but I do not know how can I write tests in that case because my attribute is set always after test have finish?

In general, I have created an abstract WebComponent class which needs to be inherited by my custom web-components instead of HTMLElement. This whole abstract class have some common logic for all my web-components for example setting props if user passed any by constructor.

I have created a simple example to show what I want to achieve. In the example below I am creating a HelloWorld component this component has one observedAttributes which is heading-content (value which will be dispalyed inside <h1></h1> of HelloWorld component template). If users sets heading-content via constructor, then I am saving this value inside this.propsContent. Then after connectedCallback is triggered I am setting this props setContentFromProps which triggers attributeChangedCallback and this callback does the rest.

Is it possible to somehow wait until these actions end?

Example

HelloWorld component:

const template = `<h1 id="hello-world-content"></h1>`;

export class HelloWorld extends HTMLElement {
  static TAG = 'hello-world';
  static observedAttributes = ['heading-content'];

  constructor(props) {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = template;
    this.headingContent = null;
    this.propsContent = props;
    this.helloHeading = this.shadowRoot.querySelector('#hello-world-content');
  }

  connectedCallback() {
    this.setContentFromProps();
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'heading-content') {
      this.helloHeading.textContent = newValue;
      this.headingContent = newValue;
    }
  }

  setContentFromProps() {
    this.setAttribute('heading-content', this.propsContent);
  }
}

customElements.define(HelloWorld.TAG, HelloWorld);

HelloWorld unit tests:

import 'jest';
import { HelloWorld } from './HelloWorld';

describe(HelloWorld.name, () => {
  test('should set heading content to given value', () => {
    const helloWorld = new HelloWorld('dupa');
    expect(helloWorld.headingContent).toBe('dupa');
  });
});

Test result:

expect(received).toBe(expected) // Object.is equality

    Expected: "dupa"
    Received: null

Solution

  • Not without adding code; there is no allAttributesChangesDone callback. And its not possible to write unless you know upfront What needs to be changed.

    I see, so it is impossible. Anyway thank you for your answer

    If you wait till the Event Loop is done; you can be fairly sure all updates are done... unless there is async code doing updates...

    "What the heck is the Event Loop:" https://youtube.com/watch?v=8aGhZQkoFbQ&vl=en

    That's true but If I wait when EventLoop will become free than my tests can take much more time. Actually, now after I thought more about that my test is 'not working' (in my opinion a few hours ago) I can say I was mistaken and the test works correctly, and I should take care of the case when someone is trying to access the attribute before it is initialized.