Gotchas in writing PolymerJS 2.0 test

13 Sep 2017

I've been working on upgrading clusterfuzz.com from PolymerJS 1.0 to 2.0. It has been quite challenging because there are a bunch of breaking changes. Anyway, I've noticed that the “Test DOM mutations” section in Test your element is fairly light in detail, so I want to share how some gotchas in PolymerJS tests.

Accessing the Shadow DOM's assigned nodes (or, in other inaccurate words, “children”)

When we want to test slot, it becomes a little bit tricky. Let's see an example.

In ClusterFuzz, we have if-else to handle if-else condition (as opposed to using 2 dom-if, which is verbose). Here's the code:

<dom-module id="if-else"> <template> <!-- Need restamp according to https://github.com/Polymer/polymer/issues/2635#issuecomment-151672164 --> <template is="dom-if" if="[[condition]]" restamp> <slot name="true"></slot> </template> <template is="dom-if" if="[[!condition]]" restamp> <slot name="false"></slot> </template> </template> <script> Polymer({ is: 'if-else', properties: { condition: Boolean } }); </script> </dom-module>

and test:

<test-fixture id="panel"> <template> <if-else> <div slot="true" class="true">TRUE</div> <div slot="false" class="false">FALSE</div> </if-else> </template> </test-fixture>

In test, we cannot just invoke: fixture('panel').shadowRoot.querySelector('.true'). The query returns null because, within if-else, it only contains slot. We can see this by inspecting the element.

When inspecting the slot element on Chrome, we will also see that slot has a child with a reference to div class="true".

After searching around, I've found that the reference is called an assigned node. And we can get the list of assigned nodes with assignedNodes.

Here's the full statement: fixture('panel').shadowRoot.querySelector('slot').assignedNodes({flatten: true})[0].querySelector('div.true').

A case where we don't need to access to slot's assigned nodes

Mainly, because slot isn't used.

Here's an example:

<paper-dropdown-menu id="list"> <paper-listbox> <template is="dom-repeat" items="[[items]]"> <paper-item>[[item]]</paper-item> </template> </paper-listbox> </paper-dropdown-menu>

We can get all paper-items with: fixture('panel').shadowRoot.querySelectorAll('#list paper-item').

Test paper-spinner's visibilty within dom-if

Let's say you have paper-spinner inside dom-if. When dom-if is hidden, the property of paper-spinner is, surprisingly, not updated.

When a spinner appears and disappears, we cannot check expect(spinner.active).to.be.false. Because active is true, but the whole spinner disappears. We can use expect(spinner.offsetParent).to.be.null instead. Here are the full statements:

Checking for the spinner to appear:

expect(spinner.offsetParent).to.not.be.null; expect(spinner.active).to.be.true

Checking for the spinner to disappear:

expect(spinner.offsetParent).to.be.null;