Wednesday, January 22, 2014

JavaScript Polymer SVG: Testing with Jasmine


OK tonight I go back to get SVG working with my JavaScript flavored <x-pizza> element. No more of the sweet, sweet nectar of Dart—I will eat my vegetables!

I kid, of course, I still love JavaScript. That love is not rewarded with a nice SVG API, however. In Dart, I could create the various elements that made up the pizza and its toppings with code like:
  _svgPepperoni() =>
    new CircleElement()..attributes = {'r': '10', 'fill': 'red'};
It seems that JavaScript lacks a constructor for circle SVG elements, leaving me to write much longer code like:
  _svgPepperoni: function() {
    var el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    el.setAttribute('r', '10');
    el.setAttribute('fill', 'red');
    return el;
  }
I make a bunch of changes along those lines (for other toppings and groups of toppings). I also have to manually convert a lot of Dart code into JS:
  • removing method cascades
  • changing innerHtml to the crazy innerHTML
  • add the this keyword absolutely everywhere
  • add the that variable where scope is an issue
  • Remove string interpolation in “favor” of plussing strings together.
It's a pain.

But it works:



I have been a little remiss in my testing, so I pick back up here with a Karma / Jasmine test. I have to update the list of files being tested and/or served to include not only my <x-pizza> elements in the elements directory, but I also need to be sure to grab the bower directory for Polymer:
...
    // list of files / patterns to load in the browser
    files: [
      'test/PolymerSetup.js',
      {pattern: 'elements/**', included: false, served: true},
      {pattern: 'bower_components/**', included: false, served: true},
      'test/**/*Spec.js'
    ],
...
My test setup is similar to what I have used in the past, updated only for new file names.

As for the test itself, I create a setup that adds <x-pizza> to the test page:
describe('<x-pizza>', function(){
  var container;

  beforeEach(function(){
    container = document.createElement("div");
    container.innerHTML = '<x-pizza></x-pizza>';
    document.body.appendChild(container);
    waits(0); // One event loop for elements to register in Polymer
  });

  afterEach(function(){
    document.body.removeChild(container);
  });

  // Tests here...
});
Then I can test the contents of the SVG element on the Polymer's shadow root:
  describe('defaults', function(){
    it('to a blank pizza', function() {
      var el = document.querySelector('x-pizza');
      var svg = el.shadowRoot.querySelector('svg');
      expect(svg.innerHTML).toContain('circle cx="150" cy="150" r="150" fill="tan"');
    });
  });
For now, I just verify that the SVG element is present and that it contains a dynamically generated <circle> element with all of the right attributes.

And it works:
INFO [watcher]: Changed file "/home/chris/repos/polymer-book/play/svg/js/test/XPizzaSpec.js".
Chrome 34.0.1797 (Linux): Executed 1 of 1 SUCCESS (0.701 secs / 0.403 secs)
Though it is better than nothing, that is a frail test. I ought to (and will before it is added to support a Patterns in Polymer chapter) query for the circle element and set expectations on it attributes rather than hoping that attributes retain their order. Still, I am happy to have gotten this converted over in relatively short order—better still to have actual tests to verify that it does what I think.


Day #1,004

No comments:

Post a Comment