Examining the Scriptaculous Unit Testing Implementation
6: The "parse" Functions
Here they are again.
parseResultsURLQueryParameter: function() { return window.location.search.parseQuery()["resultsURL"]; }, parseTestsQueryParameter: function(){ if (window.location.search.parseQuery()["tests"]){ return window.location.search.parseQuery()["tests"].split(','); }; }
We know that the first uses toQueryParams
(for which parseQuery
serves as an alias) to get a hash of query key/value pairs. Then it returns the value for the key "resultsURL". Our previous examination of toQueryParams
informs us, now, that this value may be the undefined
value (if there is no key "resultsURL"), a string, or an array of strings. But the use of parseResultsURLQueryParameter
in the definition of Test.Unit.Runner
's initialize function does not seem to expect an array:
this.options.resultsURL = this.parseResultsURLQueryParameter();
Granted, I'm only going by the choice of the variable name, the single noun resultsURL
, but this is likely meaningful in source code that has been written with such care. We'll see how resultsURL
is used later, but my bet is that the Test.Unit.Runner
class expects the undefined
parseTestsQueryParameter
, on the other hand, is expected to return an array. Here's how it's used in the definition of initialize
:
this.options.tests = this.parseTestsQueryParameter();
Again, I'm taking a cue from the name of the lvalue: the plural noun tests. But it turns out a little examinaton of parseTestsQueryParameter
bears this out. The first line of the function checks the value of hash["tests"]
. I mentioned that the undefined
value may be treated as a boolean false. Well, here's an example of it. (window.location.search.parseQuery()["tests"])
resolves to false if its value is undefined
. This test also traps empty strings, which might be a possible value as well.
Then, a split function is applied to window.location.search.parseQuery()["tests"]
, a split on commas. So if window.location.search.parseQuery()["tests"]
is a string, split
will return an array. And if it were an array to start with? Well, split
is not part of the array prototype. You can type ["Harvey", "Peter"].split(',')
as a watch expression in the Firebug Script pane, and it will tell you
["Harvey", "Peter"].split
is not a function. Nor is there any addition of
split
into the Array class or the Enumerable mixin class by which Array
is extended in prototype.js. Again, I think it's just a convention that there won't be more than one tests
GET value. If there were, it appears that this code would halt. There's no trapping for an array, and there doesn't seem to be any exception handling either.
And, to complete the first stage of initialization, the initialize
function checks to see whether there is an element on the page that should receive log information about the tests:
if (this.options.testLog) { this.options.testLog = $(this.options.testLog) || null; }
If there is a value provided in the options object for testLog
, this.options.testLog
is assigned a reference to an HTML element with an id matching the existing value of this.options.testLog
. Or, if there is no such element, this.options.testLog
is set to the null value. That's what the $()
business is about: it's a shortcut for document.getElementById()
.
Since the first line of initialize creates an options object with a default value of 'testlog' for the member variable (or hash key, if you prefer, since hashes and objects behave the same way) testLog
, the default for Test.Unit.Runner
's initialize
function is to look for an HTML element, probably a DIV, with the id 'testlog'.