Testable Web UI V: Clicky!
Last time, I started diving into using a JSON service to pull statistics into an HTML widget. I stopped right after that point because I thought, at the time, that it was worth spending a moment to think about what the target design should be.
After spending a few minutes staring at the code, though, I think I’m okay: StatusWidget is fully complaint with the SRP, and whatever other rules I can think of. So, instead of pontificating on what separates a serviceable design from a superior design, I am instead going to code more things!
Let’s go back to the initial set of requirements:
I want to see my character’s picture, name, and statistics- I want to be able to pick some equipment for my character
- I want to see how my character’s equipment affects its statistics
The first one seems to work fine, so let’s move on to selecting equipment. Time to start coding some interactivity!
What I’ll be doing next is a sort of ‘drawer’ interface: A “Show Inventory” button that, when clicked, will toggle between displaying and hiding an inventory view (that we also have to code)
The current pattern I have been running with is to just dump markup into the test file, which is probably not sustainable (TODO: figure this out), but for now, it seems to be scaling pretty well. Let’s throw a menu in:
<ul class="main_menu">
<li class="equipment">Equipment</li>
</ul>
<ul class="inventory"><li>Filler</li></ul>
It doesn’t look like much, but we’ve just introduced another dependancy: we want the inventory to be hidden most of the time, so we need some CSS to do this:
.avatar > .inventory {
display: none;
}
There. Now we can’t see the filler.
That was fun. Now let’s make the button toggle the visibility.
testClickEquipmentExpandsInventory : function() {
YAHOO.util.UserAction.click(getNode("avatar-1", "equipment"));
Assert.areEqual(
'block',
getNode("avatar-1", "inventory").style["display"]
);
}
I spent almost an hour trying to figure out how to test whether the element was visible, and I have a feeling that even this is not quite airtight. (I will ask one of my HTML god friends about this later) Nevertheless, I get a red bar, so I am going to forge ahead!
Now to make my hard-earned test pass:
function StatusWidget() {
/* stuff we've already seen before */
var self = this;
this.__getChild("equipment").onclick = function() {
self.toggleInventoryDisplay();
};
}
/* ... */
StatusWidget.prototype = {
toggleInventoryDisplay : function() {
var n = this.__getChild("inventory");
if (n.style['display'] == 'block') {
n.style['display'] = 'none';
} else {
n.style['display'] = 'block';
}
},
/* stuff */
}
This test will consistently pass, but it suffers from a subtle, but very common problem that will wreck testing later. Identifying it is left as an exercise to the reader. (HINT: it has nothing to do with my terrible non-browser-compatible JS, or my pisspoor CSS. It is specifically a testability bug)
Tomorrow, I will fix it and (time permitting) populate the inventory list.