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

JavaScript Date Object Chrome vs. Firefox

There is a very tiny yet important difference between how Chrome and Firefox treats “Date” object, when you are creating one from a String:

new Date("1980-03-14T00:00:00.0000000");

The difference is that Firefox (tested on v23.0.1) considers the passed string is on the local timezone so the output is:

new Date("1980-03-14T00:00:00.0000000").toString();
"Fri Mar 14 1980 00:00:00 GMT-0400 (Eastern Standard Time)"

While Chrome, considers the passed string in UTC/GMT timezone and then converts it to a local timezone:

new Date("1980-03-14T00:00:00.0000000").toString();
"Thu Mar 13 1980 20:00:00 GMT-0400 (Eastern Daylight Time)"

As you can see, that would be a potential for some Front-End Date/Time processing.

If you are using the Date object just for showing, using the UTC format would be very useful and would avoid any discrepancies.


var my_time =  new Date("1980-03-14T00:00:00.0000000");
my_time.getUTCFullYear();
my_time.getUTCMonth();
my_time.getUTCDate()

JavaScript, how life has changed

If you’ve been a web-developer/design for a while, you definitely remember this picture :

What a headache ! huh ? I remember whenever I wrote a JavaScript code or snippet, when I hit F5 to run it, I was praying all the time not to see this freaking error message again. It gave no clue what’s going wrong, where the error is, and it did everything other than helping you out to solve the problem. Oh God! How much stupid Internet Explorer was (or maybe still is). Back then it was the most commonly used web-browser that we had to made our works compatible to.

Now we can do all the stuff we want with JavaScript, getting an error message is not much a problem anymore and debugging, is kind of fun. None of are because any change in the language itself or that stupid browser (Internet Explorer).

It’s all because of the great browser “FireFox” which was flexible enough for other third-party addons to be added to and make it enormously strong and usefull for web-developers/designers. All the tools from FireBug , Web developer toolbar and all the JavaScript Consoles (including the one which comes built-in with FireBug) have made our lives much easier.

FireFox has sort of pushed the web-browsing boundaries and forced all other existing web-browsers and the ones coming in future to be standard, and developers friendly (I’m not talking about IE, which I’m pretty glad I abandoned it since version 7).

I was thinking about the way our lives as developers/designers have changed and how much more we’re enjoying our jobs with out the need to struggle with very basic and dull stuff.

P.S: No need to mention about the JavaScript Frameworks and such pain relievers they are (most of the times though).