I now know the trick for dynamically generating Polymer definitions. I just don't know how to get that trick to work in Karma / Jasmine tests.
As I found last night, the trick to dynamically generate Polymer elements in regular web pages is to build the
<script> portions of the definition via document.createElement() rather than building the <script> tag via innerHTML assignments. Easy enough, I can live with that.But when I tried to do the same think in my Jasmine tests, I kept getting an error about
Polymer not being defined:Uncaught ReferenceError: Polymer is not definedBleary eyed, I was unable to figure out why this would be the case. With fresh eyes today, I realize that sample page and my tests are not quite the same. In my sample page, I have hard-coded the
<script> tag for the Polymer platform:<!doctype html>
<html>
<head>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="../bower_components/polymer/polymer.html">
<script>
var double_el = document.createElement('polymer-element');
double_el.setAttribute('name', 'x-double');
double_el.setAttribute('attributes', 'in out');
var script = document.createElement('script');
script.innerHTML = ' Polymer("x-double", { /* ... */ });';
double_el.appendChild(script);
document.getElementsByTagName("head")[0].appendChild(double_el);
</script>
</head>
<body>
<!-- ... -->
<x-double in="6"></x-double>
</body>
</html>In my tests, I have been dynamically adding those during test setup:var script = document.createElement("script");
script.src = "/base/bower_components/platform/platform.js";
document.getElementsByTagName("head")[0].appendChild(script);
var link = document.createElement("link");
link.rel = 'import';
link.href = "/base/bower_components/polymer/polymer.html";
document.getElementsByTagName("head")[0].appendChild(link);
And indeed, if switch my sample page to use those dynamically built <script> and <link> tags, then I see the same failure in my browser. I cannot hard-code those tags in Karma tests -- Karma decides which tags get added first and how. What ends up working is to assign an
onload function to the Polymer platform's <script> tag:var script = document.createElement("script");
script.src = "/base/bower_components/platform/platform.js";
script.onload = defineTestPolymerElements;
document.getElementsByTagName("head")[0].appendChild(script);
var link = document.createElement("link");
link.rel = 'import';
link.href = "/base/bower_components/polymer/polymer.html";
document.getElementsByTagName("head")[0].appendChild(link);
With that, my full test setup for a dynamically defined Polymer element looks like:var script = document.createElement("script");
script.src = "/base/bower_components/platform/platform.js";
script.onload = defineTestPolymerElements;
document.getElementsByTagName("head")[0].appendChild(script);
var link = document.createElement("link");
link.rel = 'import';
link.href = "/base/bower_components/polymer/polymer.html";
document.getElementsByTagName("head")[0].appendChild(link);
function defineTestPolymerElements() {
var double_el = document.createElement('polymer-element');
double_el.setAttribute('name', 'x-double');
double_el.setAttribute('attributes', 'in out');
var script = document.createElement('script');
script.innerHTML = ' Polymer("x-double", {\n'
+ ' publish: {\n'
+ ' out: {value: 0, reflect: true}\n'
+ ' },\n'
+ ' ready: function(){\n'
+ ' this.inChanged();\n'
+ ' },\n'
+ ' inChanged: function(){\n'
+ ' this.out = parseInt(this.in) * 2;\n'
+ ' }\n'
+ ' });\n';
double_el.appendChild(script);
document.getElementsByTagName("head")[0].appendChild(double_el);
}
// Delay Jasmine specs until polymer-ready
var POLYMER_READY = false;
beforeEach(function(done) {
window.addEventListener('polymer-ready', function(){
POLYMER_READY = true;
});
waitsFor(function(){return POLYMER_READY;});
});With that, I think I have finally answered all of the little questions that occurred to me while trying to test code that interacts with any Polymer elements. I did not strictly need to answer these questions to get my task done—testing AngularJS interaction in angular-bind-polymer. Even so, it is good to have a better understanding of all of this. Maybe tomorrow I can actually write the angular-bind-polymer test that I started on 7 days ago!Day #47
No comments:
Post a Comment