Shhhhh
Shhhhh

Reputation: 198

Shadow DOM and testing it via Jasmine

I have a webcomponent that creates a shadow DOM and adds some html to its shadowRoot.

class SomeThing extends HTMLElement {
  attachedCallback () {
    this.el = this.createShadowRoot();
    this.render();
  }

  render () {
    this.el.innerHTML = '<h1>Hello</h1>';
  }
}
export default SomeThing;

And I am compiling it with the help of webpack and its babel-core and babel-preset-es2015 plugins.

Also I am using Karma and Jasmine to write my Unit Test. This is what it looks like.

describe('some-thing', function () {
  var someElement;


  beforeEach(function () {
    someElement = document.createElement('some-thing');
  });


  it('created element should match string representation', function () {
    var expectedEl = '<some-thing></some-thing>';

    var wrapper = document.createElement('div');
    wrapper.appendChild(someElement);

    expect(wrapper.innerHTML).toBe(expectedEl);
  });

  it('created element should have shadow root', function () {

    var wrapper = document.createElement('div');
    wrapper.appendChild(someElement);

    expect(wrapper.querySelector('some-thing').shadowRoot).not.toBeNull();

  })
});

I want to see if there is something in the shadowRoot of my element, and want to write test cases for the HTML and events created inside the shadowRoot. But the second test is failing. It is not able to add shadowRoot to the some-element DOM.

If anyone can help me out, that would be helpful.

I am also uploading the full test working project on Github. You can access it via this link https://github.com/prateekjadhwani/unit-tests-for-shadow-dom-webcomponents

Thanks in advance

Upvotes: 4

Views: 7233

Answers (1)

Julian Correa
Julian Correa

Reputation: 81

I had a similar problem testing a web component but in my case I am using lit-element from polymer/lit-element. Lit-element provides life cycle hooks, template rendering using lit-html library (documentation).

So this is my problem and how I solved. I noticed that the component was added and the class executed constructor and I had access to public methods using:

const element = document.querySelector('my-component-name')
element.METHOD();
element.VARIABLE

But it never reached the hook firstUpdated, so I thought the problem was the speed the test executes vs the speed component is created. So I used the promised provided by lit-element API (updateComplete):

Note: I use mocha/chai instead of Jasmine

class MyComponent extends LitElement {
    render() {
        return html`<h1>Hello</h1>`
    }
}

customElements.define('my-component', TodoApp);
let element;

describe('main', () => {
    beforeEach(() => {
        element = document.createElement("my-component");
        document.querySelector('body').appendChild(element);
    });
    describe('test', () => {
        it('Checks that header tag was added to shadowRoot', (done) => {
            (async () => {
                const res = await element.updateComplete;
                const header = element.shadowRoot.querySelector('h1');
                assert.notEqual(header, null);
                done();
            })();
        });
    });
});

So, my advice is create a promise and resolve it when the render function is executed, use the promise to sync the creation of the component with tests. I am using this repository to test concepts https://github.com/correju/polymer-playground

Upvotes: 4

Related Questions