Manual:Writing testable JavaScript

From MediaWiki.org
Jump to: navigation, search

Return values[edit | edit source]

Functions should always have a return value. Not just "get"-like functions, but also (perhaps even more important) the "set"-like functions. Scripts may not use this return value in many cases (ie. it's out of their scope to do anything about it), but in more advanced structures or test suites, the return value of a "set" function is very important (ie. "don't load X if Y was not set", or "Did the function correctly refuse to do X in scenario Y").

Compare the following two functions

/**
 * Sets one or multiple key/value pairs.
 *
 * @param selection mixed String key or array of keys to set values for.
 * @param value mixed Value to set (optional, only in use when key is a string)
 */
Map.prototype.set = function( selection, value ) {
	if ( $.isPlainObject( selection ) ) {
		for ( var s in selection ) {
			this.values[s] = selection[s];
		}
	} else if ( typeof selection === 'string' && typeof value !== 'undefined' ) {
		this.values[selection] = value;
	}
};

Compared to:

/**
 * Sets one or multiple key/value pairs.
 *
 * @param selection mixed String key or array of keys to set values for.
 * @param value mixed Value to set (optional, only in use when key is a string)
 * @return bool This returns true on success, false on failure. */
Map.prototype.set = function( selection, value ) {
	if ( $.isPlainObject( selection ) ) {
		for ( var s in selection ) {
			this.values[s] = selection[s];
		}
		return true;	} else if ( typeof selection === 'string' && typeof value !== 'undefined' ) {
		this.values[selection] = value;
		return true;	}
	return false;};

The latter is much easier to verify. For example, in the above case, a key may not be a number (such as an array index key). So to test that it refuses to do so in QUnit:

assert.strictEqual( myMap.set( 12, 'Awesome' ), false, 'Map.set refuses to set value if key was a Number' );

See also[edit | edit source]