Monday, November 25, 2013

Dynamically Generating Polymer.dart Elements (revisited)


I have a little work ahead of me as I figure out how to run large amounts of acceptance tests against the code in Patterns in Polymer. The test suites that exist around Polymer and Polymer.dart are exquisite, but tend to be of the unit test variety. That's great for API tests, but I need to write tests from the perspective of a human reader, not a program context. Hence the need to nail down acceptance testing.

I think I have a better handle on this in Dart than I do in JavaScript. Although testing Polymer.dart has proven to be different than acceptance testing in projects and in Dart for Hipsters, there are enough similarities that I feel like I ought to be OK. But before switching back, I would like to push past the first two tests that I wrote last night. That means that I need to be able to add and remove Polymer elements per-test (or test group).

When I was first exploring Polymer.dart a while back, I found that I could dynamically create Polymer elements with createElement(). That method appears to have since been removed (it was marked as temporary at the time). Without it, I might try to create my <pricing-plan> element in a setup block like so:
  var _el;
  setUp((){
    _el = new Element.html('<pricing-plan>plan content</pricing-plan>');
    document.body.append(_el);
  });
That does not make it past Dart's built-in HTML sanitizer:
Removing disallowed element <PRICING-PLAN>
Removing disallowed element <PRICING-PLAN>
ERROR: [defaults] name is "Plan"
  Setup failed: Caught Bad state: No elements
The aforementioned createElement() was good for getting around this problem with registered, custom elements. In the meantime, the ability to dynamically create these registered, custom elements has moved into dart:html in the form of Element.tag():
  var _el;
  setUp((){
    _el = new Element.tag('pricing-plan')
      ..innerHtml = 'plan content';
    document.body.append(_el);
  });
As far as I can tell, there is no easy way to insert raw custom tag HTML, which itself might contain other custom Polymer elements. At least not without falling back to “null tree sanitizers” to skip Dart's HTML sanitization:
class NullTreeSanitizer implements NodeTreeSanitizer {
  void sanitizeTree(node) {}
}

main() {
  initPolymer();

  var _el;
  setUp((){
    _el = new Element.html(
      '<pricing-plan>plan content</pricing-plan>',
      treeSanitizer: new NullTreeSanitizer()
    );
    document.body.append(_el);
  });
  // Tests here...
}
While that works, I do not relish throwing around that treeSanitizer parameter in all of my setup. So instead I recreate the createElement() method of old, but only for use in my tests:
class NullTreeSanitizer implements NodeTreeSanitizer {
  void sanitizeTree(node) {}
}

createElement(String html) =>
  new Element.html(html, treeSanitizer: new NullTreeSanitizer());

main() {
  initPolymer();

  var _el;
  setUp((){
    _el = createElement('<pricing-plan>plan content</pricing-plan>');
    document.body.append(_el);
  });
  // Tests here...
}
I think I can live with that solution, at least for my tests. I suppose that, if I found myself dynamically generating large numbers of custom-element-containing HTML snippets from strings in actual application code that I could do something similar to this createElement(). Then again, that seems the very purpose of Polymer, so this may very well be a testing use-case only. Regardless, I think I have this sorted out well enough. Time for some writing...


Day #946

No comments:

Post a Comment