Testing a Google Polymer Project using InternJS

For the pas few days I had the opportunity to play with Google Polymer project and start implementing something very interesting.

But no project gets pretty fun until it is testable. And testing Polymer projects is not as easy as it is expected to be.

There are some existing tools to test including:

But we have had InternJS fully setup for our project and we’ve been happy with it [1]. So moving to yet another JS testing framework is the least we would want to do.

Getting InternJS up and running to test the Web-Components is not easy. I was lucky enough to stumble upon Chris Storm‘s blog posts (1, 2) around the same time I was looking in to this. Those posts helped me to get me on my foot. Although they are not fully functional.

The nature of problem is because of Shadow DOM. Each Web-Component is encapsulated in its own DOM and are completely independent from the rest and also the main DOM.
So even if you capture a reference to the element you want to test you suddenly face the following error from Intern:

stale element reference: element is not attached to the page document

Finally I was able to get a sample test running. It is pretty ugly but at least it could be a start.

The problem

Imagine we have a structure of Web-Components as follow:

<custom-element-one flex>
 <custom-nested-element id="someId">
 </custom-nested-element>
</custom-element-one>

What we want to test is to get the `id` of `custom-nested-element` and assert its value. So you are expecting the following would work:

return this.remote
.get(require.toUrl('http://localhost:8500/test.html'))
.then(pollUntil('return document.querySelector(&amp;quot;custom-element-one&amp;quot;).shadowRoot;', 20000))
.findByTagName('custom-element-one')
.getProperty('shadowRoot')
.then(function (doc) {
    doc.findByTagName('custom-nested-element')
        .getAttribute('id')
        .then(function (value) {
            assert.equal(value, 'someId');
        });
});

But unfortunately it won’t work.

The Solution

The problem is coming from WebDriver rather than Intern or Leadfoot. The issue is you can get a reference to the element, but WebDriver thinks that the reference is stale and is not attached to the document. As it only checks the DOM of the main document.

The solution is just a work around on WebDriver’s limitation. Here is a sample which could make it work, if you want to test lets say `id` attribute of that specific nested web-component element.

The same approach would work for result of exposed methods as well.

return this.remote
.get(require.toUrl('http://localhost:8500/test.html'))
.then(pollUntil(function () {
    if (document.querySelector('custom-element-one').shadowRoot) {
        return document.querySelector('custom-element-one').shadowRoot.querySelector('custom-nested-element').id;
    }
    return null;
}, [] , 20000))
.then(function (idValue) {
    assert.equal(idValue, 'someId');
});

At the core what we are doing is using `pollUntil` helper function to fetch the `shadowRoot` of the first web-component when it is ready and use that to fetch the second one.

Response of `pollUntil` is wrapped in a Promise, so having a `then` afterwards would receive the value of the returned `id`.


[1] If you are interested to know more about the architectural approach and tools we are using, I highly recommend reading Dominique’s detailed write up, JavaScript technology Stack.

Advertisements