Friday, December 12, 2014

Delaying Intern for Polymer Tests


I started evaluating The Intern last night as an alternative to Karma for testing Polymer elements. Although I was not able to get it actually working, I can already see that there is much to like about Intern.

The biggest win so far is the ability to run acceptance tests against the same page on which I run my manual smoke tests. Configuration and setup does not seem much different than Karma. I also have yet to try my hand with Protractor for testing Polymer elements (another selenium driver based framework). So I cannot say that Intern is far and away the best, but it was relatively quick and easy to get my first test running.

Hopefully tonight I can actually get it passing.

I am still trying to test the <x-pizza> pizza building Polymer element. I am reasonably sure that last night's setup and configuration is solid. The problem lies in the test itself:
    '<x-pizza>': function () {
      return this.remote
        .get(require.toUrl('../index.html'))
        .setFindTimeout(5000)
        .findByXpath('//body[not(@unresolved)]')
        .findByTagName('x-pizza')
        .getProperty('shadowRoot')
        .then(function (doc) {
           console.log(doc);
           assert.isDefined(doc);
         });
    }
If I watch the test in the Sauce Labs viewer, everything looks good through finding the <body> tag without an unresolved attribute. From there, things are wonky.

The unresolved attribute is a Polymer convention for dealing with FOUC. Before Polymer loads and initializes the <body> content is not displayed. Once Polymer is ready, the unresolved attribute is removed from <body>, which starts a CSS transition to display contents.

And all of that works—even in the Sauce Labs viewer. The problem is finding the <x-pizza> element in the next step. It is in the original page:
  <body unresolved>
    <div class="container">
      <form action="test" method="post">
        <h1>Plain-old Form</h1>
        <x-pizza name="pizza_toppings"></x-pizza>
        <button>Order my pizza!</button>
      </form>
    </div>
  </body>
But before Polymer does its thing, it is an unresolved HTML element. After it is upgraded to a web component by Polymer, it should have a shadow root as the test attempts to assert (along with all kinds of pizza building behavior). But my test never even gets a chance to try that. It fails with a stale element error:
StaleElementReference: ... stale element reference: element is not attached to the page document
My guess here is that, even though Polymer is ready, it has not replaced the original, unresolved <x-pizza> element with the Polymer web component. That is, I believe that I need to wait a few milliseconds (possibly as little as a single event loop) before my test finds that element.

Unfortunately for me, this seems to be impossibly hard in Intern. Unless you read the documentation. I don't know how I missed that last night.

So I add pollUntil to my list of dependencies and use it:
define([
  'intern!object',
  'intern/chai!assert',
  'intern/node_modules/dojo/node!leadfoot/helpers/pollUntil',
  'require'
], function (registerSuite, assert, pollUntil, require) {
  registerSuite({
    name: 'index',

    '<x-pizza>': function () {
      return this.remote
        .get(require.toUrl('../index.html'))
        .setFindTimeout(5000)
        .findByXpath('//body[not(@unresolved)]')
        .then(pollUntil('return document.querySelector("x-pizza").shadowRoot;', 1000))
        .findByTagName('x-pizza')
        .getProperty('shadowRoot')
        .then(function (doc) {
           console.log(doc);
           assert.isDefined(doc);
         });
    }
  });
});
Only that has no effect whatsoever. I still get a stale element error.

In fact, if I try to get the element directly and run assertions against it, I find no shadow root even though I have just polled until it exists:
    '<x-pizza>': function () {
      return this.remote
        .get(require.toUrl('../index.html'))
        .setFindTimeout(5000)
        .findByXpath('//body[not(@unresolved)]')
        .then(pollUntil('return document.querySelector("x-pizza").shadowRoot;', 1000))
        .findByTagName('x-pizza')
        // .execute('return document.querySelector("x-pizza");')
        .then(function (el) {
           console.log(el);
           console.log(el.constructor);
           console.log(el.$);
           console.log(el.shadowRoot);
           assert.isDefined(el.shadowRoot);
         });
    }
The test always fails with shadowRoot being undefined. The properties logged are also undefined, except for the constructor, which is Element instead of Polymer.

At this point, I have to confess that I am at a loss for what to do next. No matter what I try, I get the original, unresolved <x-pizza> element. Even though the Polymer element is definitely in the document, I cannot gain access to it through Intern. Unless inspiration strikes, I am left to believe that Intern does not work with Polymer yet.


Day #22

No comments:

Post a Comment