Tonight, I break a rule. Sort of.
Normally in these chains, I think of a question to which I do not know the answer then do my best to answer it. During the course of exploring web-component-tester (WCT) last night, I was quite taken aback at the difficulty involved in upgrading a project from Polymer 0.5 to the new 0.8 (even with the very nice migration guide). I was able to get it working, but without much thought.
So tonight, I revert all of my code changes and start again:
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add/rmI can get rid of the Karma tests as I am likely switching to WCT one way or another, but I leave them for now since my CI build expects them...." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: code-js/polymer/elements/hello-you.html modified: code-js/polymer/elements/hello_you.js modified: code-js/polymer/index.html deleted: code-js/polymer/karma.conf.js deleted: code-js/polymer/test/HelloYouSpec.js deleted: code-js/polymer/test/PolymerSetup.js no changes added to commit (use "git add" and/or "git commit -a") $ git checkout . $ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean
I will do this work in a new
polymerjs-0_8
branch in the Patterns in Polymer book repository. After some thought (and discussion), I think it best for the book to target PolymerJS 0.5 for the time being. Targeting 0.8/0.9/1.0 can wait for the next edition. Still, I need to start playing with it, so let's try to repeat last night's success...First up, I remove the
"polymer": "<0.8"
constraint that I added earlier today to my project's bower.json
. In this branch, I will again target whatever the latest (semi-)stable version of Polymer is available:{ "name": "hello-you", // ... "dependencies": { "polymer": ">0.0" } }A Bower update and I am ready to roll:
bower update .... polymer#0.8.0 bower_components/polymer ├── core-component-page#0.5.5 └── webcomponentsjs#0.6.0 webcomponentsjs#0.6.0 bower_components/webcomponentsjsMy tests are failing, but before I even start with that, I update both my sample HTML page and my WCT test page to point to the new webcomponentjs:
<!-- 1. Load the polymer platform. -->
<script
src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<!-- 2. Load component(s) -->
<link rel="import" href="elements/hello-you.html">
My tests are still failing all the same, but this is the most obvious external change required, so it makes sense to start with that.Next, I start with making sure that my element compiles. I have a sanity test for just this sort of thing. In Polymer 0.5, I would check that my Polymer element had a shadow root element. In 0.8, I need to check for the existence of a "shady" root:
describe('element content', function(){
it('has a shady DOM', function(){
assert.isDefined(el.root);
});
});
It does not:chrome 41 ✖ index.html » <hello-you> » element content » has a shady DOM
expected undefined to not equal undefined
<unknown> at Context.<anonymous> at /polymer/test/index.js:10:0
If I look closer in a persistent WCT browser session, I find:Uncaught TypeError: undefined is not a function desugar polymer.html:37 window.Polymer polymer.html:21 (anonymous function) hello_you.js:2This is because I can no longer declare my elements in Polymer with the name of the element as the first argument to the
Polymer()
function:// 0.5 style: Polymer('hello-you', { // Element definition here... });Instead, the element name ("hello-you" in this case) goes in the definition as the
is
property:Polymer({ is: 'hello-you', // The rest of the element definition here... });With that, I have my sanity test passing:
✓ index.html » <hello-you> » element content » has a shady DOMOne hurdle cleared, but another of my tests is not even registering and the last, which tests clicks, is failing:
✖ index.html » <hello-you> » clicking » randomly changes the title's color Cannot read property 'querySelector' of null <unknown> at Context.<anonymous> at /polymer/test/index.js:44:0I start with the failing test because I can actually see it and, if last night's spike is any guide, the other test will magically reappear after this one is resolved. This is easy enough. I had been looking for child elements in my Polymer element's shadow DOM. There is no shadow DOM anymore (at least not by default), so I can query a little more directly in my tests now:
it('randomly changes the title\'s color', function(){
var button = el.querySelector('input[type=submit]');
var e = document.createEvent('MouseEvent');
e.initMouseEvent(
"click", true, true, window,
0, 0, 0, 80, 20,
false, false, false, false, 0, null
);
button.dispatchEvent(e);
var h2 = el.querySelector('h2');
assert.equal(h2.style.color, 'green');
});
My test still fails, but with a different message:✖ index.html » <hello-you> » clicking » randomly changes the title's color expected '' to equal 'green' <unknown> at Context.<anonymous> at /polymer/test/index.js:56:0I think I have a legitimate Polymer 0.8 test now, but it does not appear to be interacting with the randomizer button. Checking in the WCT persistent window, I find the following warning:
[input].[click]: event handler [{{feelingLucky}}] is null in scopeIt would be nice if warnings like that showed up in the WCT console output because this tells me exactly what the problem is: I can no longer bind methods with the double-curly braces like that. Instead, I have to update my randomizing button to point to the
feelingLucky()
method with no braces at all:<polymer-element name="hello-you"> <template> <h2>Hello {{your_name}}</h2> <p> <input value="{{your_name}}"> <input type=submit value="Fabulousize Me!" on-click="feelingLucky"> </p> <p class=help-block> <content></content> </p> </template> <script src="hello_you.js"></script> </polymer-element>After that my test still fails to pass, but that is a simple code fix—the
feelingLucky()
method was also pointing to the shadowRoot. After removing that reference, I have two passing tests and... the last test is still missing. I am unsure why that would be, but it seems like a bug in WCT. If I check the console in the WCT persistent browser, I see that I am again using shadowRoot
. After removing that from the test, I now get the failure that I desire:✖ index.html » <hello-you> » typing » says a friendly hello expected 'Hello {{your_name}}' to equal 'Hello Bob' <unknown> at Context.<anonymous> at /polymer/test/index.js:33:0Part of this is easy to solve. Bound variables now have to reside entirely inside of tag. So I update the Polymer template to place
{{your_name}}
inside a <span>
: <template>
<h2>Hello <span>{{your_name}}</span></h2>
<p>
<input value="{{your_name}}">
<input type=submit
value="Fabulousize Me!"
on-click="feelingLucky">
</p>
<p class=help-block>
<content></content>
</p>
</template>
The other thing that needs to change is the binding of the your_name
property inside the <input>
element—{{your_name}}
by itself will no longer work. In 0.8, I have to append the kind of event that triggers an update to the property. In this case, I want your_name
updated when an input
event occurs: <template>
<h2>Hello <span>{{your_name}}</span></h2>
<p>
<input value="{{your_name::input}}">
<input type=submit
value="Fabulousize Me!"
on-click="feelingLucky">
</p>
<p class=help-block>
<content></content>
</p>
</template>
With that, I have all three of my tests for this simple element passing:✓ index.html » <hello-you> » element content » has a shady DOM ✓ index.html » <hello-you> » typing » says a friendly hello ✓ index.html » <hello-you> » clicking » randomly changes the title's colorAnd, more importantly, the
<hello-you>
element again appears to be working:That was a lot saner than last night. The only thing that I did yesterday, but not today, was converting the
<polymer-element>
to <dom-element>
. I was under the impression that it was required, but it would seem not.Day #22
We ran into the issue of console errors not showing up in WCT and not causing any sort of failure either. We ended up writing a quick script that we load right after browser.js and polymer in every test HTML file. The script registers window.onerror handler that has a test("has no console errors", ...) and then assert.fail it with the error message. This causes our test suite to fail when a console error occurs before the rest of the suite starts running.
ReplyDeleteThis might be what's happening with your missing test. The script errors out before the test runner even begins running the test. We had the same problem and found 10 tests that weren't even running.
Hope this helps!
That's super helpful. I'm going to give that a try in a few days. Your explanation feels right based on what I was seeing. If so, this seems like something that ought to be baked into WCT.
DeleteThanks!