<commit_before>/*global define, Candy */
/*jshint -W027*/

define([
		'intern!bdd'
	, 'intern/chai!expect'
	, 'intern/order!jquery'
	, 'intern/order!candy/libs.bundle.js'
	, 'intern/order!candy/src/candy.js'
	, 'intern/order!candy/src/core.js'
	, 'intern/order!candy/src/util.js'
], function (bdd, expect) {
	bdd.describe('Candy.Util', function () {
		bdd.describe('jidToId', function () {
			bdd.it('should MD5 hash a JID', function () {
				expect(Candy.Util.jidToId('foo@bar.com')).to.equal('f3ada405ce890b6f8204094deb12d8a8');
			});
		});

		bdd.describe('escapeJid', function () {
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("space cadet@example.com")).to.equal("space\\20cadet@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("call me \"ishmael\"@example.com")).to.equal("call\\20me\\20\\22ishmael\\22@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("at&t guy@example.com")).to.equal("at\\26t\\20guy@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("d'artagnan@example.com")).to.equal("d\\27artagnan@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("/.fanboy@example.com")).to.equal("\\2f.fanboy@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("::foo::@example.com")).to.equal("\\3a\\3afoo\\3a\\3a@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("<foo>@example.com")).to.equal("\\3cfoo\\3e@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				return true; // Skip this for now. See https://github.com/theintern/intern/pull/195
				expect(Candy.Util.escapeJid("user@host@example.com")).to.equal("user\\40host@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\net@example.com")).to.equal('c\\3a\\5cnet@example.com');
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\net@example.com")).to.equal("c\\3a\\5cnet@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\cool stuff@example.com")).to.equal("c\\3a\\5ccool\\20stuff@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\5commas@example.com")).to.equal("c\\3a\\5c5commas@example.com");
			});
		});

		bdd.describe('unescapeJid', function () {
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("space\\20cadet@example.com")).to.equal("space cadet@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("call\\20me\\20\\22ishmael\\22@example.com")).to.equal("call me \"ishmael\"@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("at\\26t\\20guy@example.com")).to.equal("at&t guy@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("d\\27artagnan@example.com")).to.equal("d'artagnan@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\2f.fanboy@example.com")).to.equal("/.fanboy@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\3a\\3afoo\\3a\\3a@example.com")).to.equal("::foo::@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\3cfoo\\3e@example.com")).to.equal("<foo>@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("user\\40host@example.com")).to.equal("user@host@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid('c\\3a\\5cnet@example.com')).to.equal("c:\\net@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5cnet@example.com")).to.equal("c:\\net@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5ccool\\20stuff@example.com")).to.equal("c:\\cool stuff@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5c5commas@example.com")).to.equal("c:\\5commas@example.com");
			});
		});

		bdd.describe('crop', function () {
			bdd.describe('with a string longer than the crop length', function () {
				bdd.it('crops the string to the specified length and replaces the end with elipses', function () {
					expect(Candy.Util.crop('FooBarBaz', 6)).to.equal('Foo...');
				});
			});

			bdd.describe('with a string the same length as the crop length', function () {
				bdd.it('does not modify the string', function () {
					expect(Candy.Util.crop('FooBar', 6)).to.equal('FooBar');
				});
			});

			bdd.describe('with a string shorter than the crop length', function () {
				bdd.it('does not modify the string', function () {
					expect(Candy.Util.crop('FooBar', 9)).to.equal('FooBar');
				});
			});
		});

		bdd.describe('Parser', function () {
			bdd.describe('jid', function () {
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("space cadet@example.com");
					expect(jid.node).to.equal("space cadet");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("call me \"ishmael\"@example.com");
					expect(jid.node).to.equal("call me \"ishmael\"");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("at&t guy@example.com");
					expect(jid.node).to.equal("at&t guy");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("d'artagnan@example.com");
					expect(jid.node).to.equal("d'artagnan");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("/.fanboy@example.com");
					expect(jid.node).to.equal("/.fanboy");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("::foo::@example.com");
					expect(jid.node).to.equal("::foo::");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("<foo>@example.com");
					expect(jid.node).to.equal("<foo>");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					return true; // Skip this for now. See https://github.com/theintern/intern/pull/195
					var jid = Candy.Util.Parser.jid("user@host@example.com");
					expect(jid.node).to.equal("user@host");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\net@example.com");
					expect(jid.node).to.equal('c:\\net');
					expect(jid.domain).to.equal('example.com');
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\net@example.com");
					expect(jid.node).to.equal("c:\\net");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\cool stuff@example.com");
					expect(jid.node).to.equal("c:\\cool stuff");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\5commas@example.com");
					expect(jid.node).to.equal("c:\\5commas");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
			});
		});
	});
});
<commit_msg>Skip tests in the nice way<commit_after>/*global define, Candy */
/*jshint -W027*/

define([
		'intern!bdd'
	, 'intern/chai!expect'
	, 'intern/order!jquery'
	, 'intern/order!candy/libs.bundle.js'
	, 'intern/order!candy/src/candy.js'
	, 'intern/order!candy/src/core.js'
	, 'intern/order!candy/src/util.js'
], function (bdd, expect) {
	bdd.describe('Candy.Util', function () {
		bdd.describe('jidToId', function () {
			bdd.it('should MD5 hash a JID', function () {
				expect(Candy.Util.jidToId('foo@bar.com')).to.equal('f3ada405ce890b6f8204094deb12d8a8');
			});
		});

		bdd.describe('escapeJid', function () {
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("space cadet@example.com")).to.equal("space\\20cadet@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("call me \"ishmael\"@example.com")).to.equal("call\\20me\\20\\22ishmael\\22@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("at&t guy@example.com")).to.equal("at\\26t\\20guy@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("d'artagnan@example.com")).to.equal("d\\27artagnan@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("/.fanboy@example.com")).to.equal("\\2f.fanboy@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("::foo::@example.com")).to.equal("\\3a\\3afoo\\3a\\3a@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("<foo>@example.com")).to.equal("\\3cfoo\\3e@example.com");
			});
			// Skip this for now. See https://github.com/theintern/intern/pull/195
			bdd.skip('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("user@host@example.com")).to.equal("user\\40host@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\net@example.com")).to.equal('c\\3a\\5cnet@example.com');
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\net@example.com")).to.equal("c\\3a\\5cnet@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\cool stuff@example.com")).to.equal("c\\3a\\5ccool\\20stuff@example.com");
			});
			bdd.it('should escape JIDs per XEP-0106', function () {
				expect(Candy.Util.escapeJid("c:\\5commas@example.com")).to.equal("c\\3a\\5c5commas@example.com");
			});
		});

		bdd.describe('unescapeJid', function () {
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("space\\20cadet@example.com")).to.equal("space cadet@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("call\\20me\\20\\22ishmael\\22@example.com")).to.equal("call me \"ishmael\"@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("at\\26t\\20guy@example.com")).to.equal("at&t guy@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("d\\27artagnan@example.com")).to.equal("d'artagnan@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\2f.fanboy@example.com")).to.equal("/.fanboy@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\3a\\3afoo\\3a\\3a@example.com")).to.equal("::foo::@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("\\3cfoo\\3e@example.com")).to.equal("<foo>@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("user\\40host@example.com")).to.equal("user@host@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid('c\\3a\\5cnet@example.com')).to.equal("c:\\net@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5cnet@example.com")).to.equal("c:\\net@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5ccool\\20stuff@example.com")).to.equal("c:\\cool stuff@example.com");
			});
			bdd.it('should unescape JIDs per XEP-0106', function () {
				expect(Candy.Util.unescapeJid("c\\3a\\5c5commas@example.com")).to.equal("c:\\5commas@example.com");
			});
		});

		bdd.describe('crop', function () {
			bdd.describe('with a string longer than the crop length', function () {
				bdd.it('crops the string to the specified length and replaces the end with elipses', function () {
					expect(Candy.Util.crop('FooBarBaz', 6)).to.equal('Foo...');
				});
			});

			bdd.describe('with a string the same length as the crop length', function () {
				bdd.it('does not modify the string', function () {
					expect(Candy.Util.crop('FooBar', 6)).to.equal('FooBar');
				});
			});

			bdd.describe('with a string shorter than the crop length', function () {
				bdd.it('does not modify the string', function () {
					expect(Candy.Util.crop('FooBar', 9)).to.equal('FooBar');
				});
			});
		});

		bdd.describe('Parser', function () {
			bdd.describe('jid', function () {
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("space cadet@example.com");
					expect(jid.node).to.equal("space cadet");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("call me \"ishmael\"@example.com");
					expect(jid.node).to.equal("call me \"ishmael\"");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("at&t guy@example.com");
					expect(jid.node).to.equal("at&t guy");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("d'artagnan@example.com");
					expect(jid.node).to.equal("d'artagnan");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("/.fanboy@example.com");
					expect(jid.node).to.equal("/.fanboy");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("::foo::@example.com");
					expect(jid.node).to.equal("::foo::");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("<foo>@example.com");
					expect(jid.node).to.equal("<foo>");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				// Skip this for now. See https://github.com/theintern/intern/pull/195
				bdd.skip('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("user@host@example.com");
					expect(jid.node).to.equal("user@host");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\net@example.com");
					expect(jid.node).to.equal('c:\\net');
					expect(jid.domain).to.equal('example.com');
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\net@example.com");
					expect(jid.node).to.equal("c:\\net");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\cool stuff@example.com");
					expect(jid.node).to.equal("c:\\cool stuff");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
				bdd.it('should parse JIDs per RFC6122', function () {
					var jid = Candy.Util.Parser.jid("c:\\5commas@example.com");
					expect(jid.node).to.equal("c:\\5commas");
					expect(jid.domain).to.equal("example.com");
					expect(jid.resource).to.equal(undefined);
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>/**
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 *
 * Modified: 2015/09/16
 * @author softwarespot
 */
var loady = (function (document) { // jshint ignore:line
    // Constants

    var _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    var _head = document.head || document.getElementsByTagName('head')[0];

    var _reJsExtension = /\.js$/;

    // Store previously loaded source files
    var _storageFiles = [];

    // Store the state of the source file i.e. true or false
    var _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    var _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    var isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        var type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    // START: Loader class

    /**
     * ILoader class
     */
    function ILoader() {
        this.destroy();
    }

    /**
     * Loader prototype chain
     *
     * @type {object}
     */
    ILoader.prototype = {
        /**
         * Tidy up open resources, good housekeeping
         *
         * @return {undefined}
         */
        destroy: function () {
            // Callback function
            this._callback = null;

            // Currently loaded total count
            this._loaded = -1;

            // An array of loaded source file(s)
            this._called = null;

            // An array of source file(s)
            this._files = null;

            // Length of the source files
            this._length = 0;
        },

        /**
         * Load an array of source files
         *
         * @param {array} sourceFiles An array of source files. Note: .js is optional
         * @param {Function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load: function (sourceFiles, callback) {
            // Set the loaded count to -1, due to this.onCompleted incrementing by 1 and checking against this._length, which right now is 0
            this._loaded = -1;

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source files argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (var i = 0; i < this._length; i++) {
                var sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                var index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    console.log('%s is already loaded, Time: %i', sourceFile, +(new Date()));
                    this.onCompleted(_storageState[index] !== true);
                    return;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        },

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript: function (sourceFile) {
            var node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events. Note: Bind is used to 'bind' to the context of 'this' i.e. the class
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        },

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted: function (isSuccess) {
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        },

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad: function (event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            var type = event.type;
            var isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                var node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    var sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push the state of the source file
                    _storageState.push(true);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }
    };

    // END: Loader class

    // Public API

    return function (sourceFiles, callback) {
        // Create an instance of the internal loader class
        var loady = new ILoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };
})(this.document);
<commit_msg>Minor comment fixes<commit_after>/**
 * Loady module - Load external JavaScript file(s) and append it to the head of the current document
 * Note: This is NOT a replacement for module loaders available on the market
 *
 * Modified: 2015/09/16
 * @author softwarespot
 */
var loady = (function (document) { // jshint ignore:line
    // Constants

    var _dataAttributes = {
        SOURCE_FILE: 'data-loady-sourcefile'
    };

    // Store the first head node
    var _head = document.head || document.getElementsByTagName('head')[0];

    // Regular expression to strip the JS extension
    var _reJsExtension = /\.js$/;

    // Store previously loaded source file(s)
    var _storageFiles = [];

    // Store the state of the source file(s) i.e. true or false
    var _storageState = [];

    // Return strings of toString() found on the Object prototype
    // Based on the implementation by lodash inc. is* function as well
    const _objectStrings = {
        FUNCTION: '[object Function]',
        STRING: '[object String]'
    };

    // Store the toString method
    var _objectToString = Object.prototype.toString;

    /**
     * Check if a variable is an array datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an array datatype; otherwise, false
     */
    var isArray = Array.isArray;

    /**
     * Check if a variable is a function datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a function datatype; otherwise, false
     */
    function isFunction(value) {
        return isObject(value) && _objectToString.call(value) === _objectStrings.FUNCTION;
    }

    /**
     * Check if a variable is an object
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is an object; otherwise, false
     */
    function isObject(value) {
        // Store the typeof value
        var type = typeof value;

        // !!value is basically checking if value is not 'truthy' e.g. null or zero and then inverts that boolean value
        // So, !'Some test' is false and then inverting false is true. There if value contains 'something', continue
        return !!value && (type === 'object' || type === 'function');
    }

    /**
     * Check if a variable is a string datatype
     *
     * @param {mixed} value Value to check
     * @returns {boolean} True the value is a string datatype; otherwise, false
     */
    function isString(value) {
        return typeof value === 'string' || _objectToString.call(value) === _objectStrings.STRING;
    }

    // START: Loader class

    /**
     * ILoader class
     */
    function ILoader() {
        this.destroy();
    }

    /**
     * Loader prototype chain
     *
     * @type {object}
     */
    ILoader.prototype = {
        /**
         * Tidy up open resources, good housekeeping
         *
         * @return {undefined}
         */
        destroy: function () {
            // Final callback function
            this._callback = null;

            // Currently loaded total count.
            // Note: The loaded count is set to -1, due to this.onCompleted incrementing by 1 and checking against this._length,
            // which right now is set to 0
            this._loaded = -1;

            // An array of successfully loaded source file(s)
            this._called = null;

            // An array of source file(s) initially passed in
            this._files = null;

            // Length of the source file(s) initially passed in
            this._length = 0;
        },

        /**
         * Load an array of source file(s)
         *
         * @param {array} sourceFiles An array of source file(s). Note: .js is optional
         * @param {function} callback Callback function to invoke on successful completion.
         * The arguments passed to the callback is an array of loaded scripts and a success parameter of true or false
         * @return {undefined}
         */
        load: function (sourceFiles, callback) {
            // Destroy the previous contents
            this.destroy();

            // This is the only error thrown, due to a callback being required
            if (!isFunction(callback)) {
                throw new Error('Loady: The callback function argument is not a valid function type.');
            }

            // Coerce as an array if the source file is a string
            if (isString(sourceFiles)) {
                sourceFiles = [sourceFiles];
            }

            // Set the callback function property
            this._callback = callback;

            // Check if the source file(s) argument is not an array
            if (!isArray(sourceFiles)) {
                this.onCompleted(false);
                return;
            }

            // Check if any values exist in the array
            if (sourceFiles.length === 0) {
                this.onCompleted(false);
                return;
            }

            // Set to 0, as now all the important checks have passed, thankfully
            this._loaded = 0;
            this._called = [];
            this._files = sourceFiles;
            this._length = sourceFiles.length;

            for (var i = 0; i < this._length; i++) {
                var sourceFile = sourceFiles[i];
                // Strip and append .js to the source file
                sourceFile = sourceFile.replace(_reJsExtension, '') + '.js';

                var index = _storageFiles.indexOf(sourceFile);
                if (index !== -1) {
                    this.onCompleted(_storageState[index] !== true);
                    return;
                }

                // Load the script file and append to the current document
                this.loadScript(sourceFile);
            }
        },

        /**
         * Load a script and append to the first HEAD node in the DOM
         *
         * @param {string} sourceFile Script source location that can be absolute or relative
         * @return {undefined}
         */
        loadScript: function (sourceFile) {
            var node = document.createElement('script');
            node.src = sourceFile;
            // node.text = file;

            // node.type = 'text/javascript';
            // node.charset = 'utf-8';

            node.async = true;

            node.setAttribute(_dataAttributes.SOURCE_FILE, sourceFile);

            // Attach events. Note: Bind is used to 'bind' to the context of 'this' i.e. the class
            node.addEventListener('load', this.onLoad.bind(this), false);
            node.addEventListener('error', this.onLoad.bind(this), false);

            // Append to the HEAD node
            _head.appendChild(node);

            // Push to the internal storage
            _storageFiles.push(sourceFile);
        },

        /**
         * Increment the loaded scripts property and invoke the callback function on completion
         *
         * @param {boolean} isSuccess Whether the request was successful
         * @return {undefined}
         */
        onCompleted: function (isSuccess) {
            if (isSuccess !== true) {
                isSuccess = false;
            }

            // Increment the loaded total count
            this._loaded++;

            if (this._length === this._loaded) {
                this._callback.apply(this, [this._called, isSuccess]);
                this.destroy();
            }
        },

        /**
         * The 'load' or 'error' callback function for the event listeners
         *
         * @param {event} event Event object passed by the event listener
         * @return {undefined}
         */
        onLoad: function (event) {
            // Store the type of event and whether it was a 'load' or 'error' type event
            var type = event.type;
            var isLoaded = type === 'load';

            if (isLoaded || type === 'error') {
                var node = event.currentTarget || event.srcElement;
                if (!node) {
                    return;
                }

                // Remove assigned events
                node.removeEventListener('load', this.onLoad, false);
                node.removeEventListener('error', this.onLoad, false);

                // Display details about the inserted SCRIPT node and script
                if (isLoaded) {
                    // console.log('Loader.onLoad: Loaded/Error callback invoked, Time: %i', +(new Date()));
                    // console.log('Loader.onLoad: Attribute = ' + node.getAttribute(_dataAttributes.SOURCE_FILE));

                    // Get the source file directly from the data-* attribute
                    var sourceFile = node.getAttribute(_dataAttributes.SOURCE_FILE);

                    // Push the state of the source file
                    _storageState.push(true);

                    // Push to the successfully loaded scripts
                    this._called.push(sourceFile);
                }

                this.onCompleted(true);
            }
        }
    };

    // END: Loader class

    // Public API

    return function (sourceFiles, callback) {
        // Create an instance of the internal loader class
        var loady = new ILoader();

        // Load the source file(s)
        loady.load(sourceFiles, callback);
    };
})(this.document);
<|endoftext|>


<commit_before>require('../jspsych.js');
require('../plugins/jspsych-text.js');

describe('#addProperties', function(){
  test('should add data to all trials if called before experiment starts', function(){
    var timeline = [
      {type: 'text', text:'hello'}
    ];
    jsPsych.data.addProperties({'testprop': 1});
    jsPsych.init({timeline:timeline});
    // click through first trial
    document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 32}));
    document.dispatchEvent(new KeyboardEvent('keyup', {keyCode: 32}));
    // check if data contains testprop
    expect(jsPsych.data.getData().select('rt').count()).toBe(1);
    expect(jsPsych.data.getData().select('testprop').count()).toBe(1);
  });
})
<commit_msg>add test<commit_after>require('../jspsych.js');
require('../plugins/jspsych-text.js');

describe('Basic data recording', function(){
  test('should be able to get rt after running experiment', function(){
    var timeline = [
      {type: 'text', text:'hello'}
    ];
    jsPsych.init({timeline:timeline});
    // click through first trial
    document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 32}));
    document.dispatchEvent(new KeyboardEvent('keyup', {keyCode: 32}));
    // check if data contains rt
    expect(jsPsych.data.getData().select('rt').count()).toBe(1);
  })
})

describe('#addProperties', function(){
  test('should add data to all trials if called before experiment starts', function(){
    var timeline = [
      {type: 'text', text:'hello'}
    ];
    jsPsych.data.addProperties({'testprop': 1});
    jsPsych.init({timeline:timeline});
    // click through first trial
    document.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 32}));
    document.dispatchEvent(new KeyboardEvent('keyup', {keyCode: 32}));
    // check if data contains testprop
    expect(jsPsych.data.getData().select('testprop').count()).toBe(1);
  });
})
<|endoftext|>


<commit_before>// at the top of the test spec:
var browserLogs = require('protractor-browser-logs'),
 ToolBar = require('./../helper/toolBar'),
Container = require('./../helper/container');

describe('The Editor', function () {

    var toolBar = new ToolBar(),
        container = new Container();

    var logs;

    beforeEach(function () {
        logs = browserLogs(browser);
        logs.ignore(logs.DEBUG);
        logs.ignore(logs.INFO);
    });

    afterEach(function () {
        return logs.verify();
    });

    it('should loaded', function () {
        browser.driver.get('http://localhost:9001/index.html');
        browser.waitForAngular();

        var editor = element(by.className('sc-prose-editor'));
        expect(editor.isPresent()).toBe(true);
    });

    describe('container', function () {

        it('should display paragraph 1', function () {
            expect(container.getParagraphElement(1).isPresent()).toBe(true);
            expect(container.getContentOfParagraphElement(1).getText()).toEqual('Insert a new image using the image tool.');
        });

        it('should display paragraph 2', function () {
            expect(container.getParagraphElement(2).isPresent()).toBe(true);
            expect(container.getContentOfParagraphElement(2).getText()).toEqual('Please note that images are not actually uploaded in this example. You would need to provide a custom file client that talks to an image store. See FileClientStub which reveals the API you have to implement.');
        });
    });

    describe('save button', function () {

        it('should be present', function () {
            expect(toolBar.getSaveButton().isPresent()).toBe(true);
        });

        it('should switched off', function () {
             expect(toolBar.getSaveButton().isEnabled()).toBe(false);
        });

        it('should enable if text change', function () {
            container.getContentOfParagraphElement(2).click();
            browser.actions().sendKeys('a').perform();
            expect(toolBar.getSaveButton().isEnabled()).toBe(true);
        });

        it('should activate save handler', function () {
            toolBar.getSaveButton().click();

            logs.expect(/Save from Angular!/);
            //logs.verify();
        });
    });

});
<commit_msg>Make a test with sleep methode in tests<commit_after>// at the top of the test spec:
var browserLogs = require('protractor-browser-logs'),
 ToolBar = require('./../helper/toolBar'),
Container = require('./../helper/container');

describe('The Editor', function () {

    var toolBar = new ToolBar(),
        container = new Container();

    var logs;

    beforeEach(function () {
        logs = browserLogs(browser);
        logs.ignore(logs.DEBUG);
        logs.ignore(logs.INFO);
    });

    afterEach(function () {
        return logs.verify();
    });

    it('should loaded', function () {
        browser.driver.get('http://localhost:9001/index.html');
        browser.waitForAngular();

        var editor = element(by.className('sc-prose-editor'));
        expect(editor.isPresent()).toBe(true);
    });

    describe('container', function () {

        it('should display paragraph 1', function () {
            expect(container.getParagraphElement(1).isPresent()).toBe(true);
            expect(container.getContentOfParagraphElement(1).getText()).toEqual('Insert a new image using the image tool.');
        });

        it('should display paragraph 2', function () {
            expect(container.getParagraphElement(2).isPresent()).toBe(true);
            expect(container.getContentOfParagraphElement(2).getText()).toEqual('Please note that images are not actually uploaded in this example. You would need to provide a custom file client that talks to an image store. See FileClientStub which reveals the API you have to implement.');
        });
    });

    describe('save button', function () {

        it('should be present', function () {
            expect(toolBar.getSaveButton().isPresent()).toBe(true);
        });

        it('should switched off', function () {
             expect(toolBar.getSaveButton().isEnabled()).toBe(false);
        });

        it('should enable if text change', function () {
            container.getContentOfParagraphElement(2).click();
            browser.sleep(200);
            browser.actions().sendKeys('a').perform();
            browser.sleep(200);
            expect(toolBar.getSaveButton().isEnabled()).toBe(true);
        });

        it('should activate save handler', function () {
            toolBar.getSaveButton().click();
            logs.expect(/Save from Angular!/);
        });
    });

});
<|endoftext|>


<commit_before>/*global define*/
/*jshint loopfunc: true*/
define([
  'amd/describe',
  'amd/it',
  'amd/expect',
  'router'
], function(describe, it, expect, router) {
  'use strict';

  describe('Configuring the router', function() {
    router.config({
      routes: {
        route1: {path: '/example/path'},
        route2: {path: '/second/path'}
      }
    });

    it('should add a matchesUrl() method to every route', function() {
      for (var route in router.routes) {
        expect(router.routes[route].matchesUrl).toBeDefined();
      }
    });
  });

  describe('router.loadCurrentRoute()', function() {
    it('should call router.routeLoadedCallback() when it\'s done loading the route\'s module');
  });

  describe('router.currentRoute()', function() {
    it('should return the first route that matches the URL');
  });

  describe('router.urlChangeEventHandler()', function() {
    it('should call loadCurrentRoute()');
  });

  describe('router.currentUrl()', function() {
    it('should return window.location.href');
  });

  describe('router.urlPath(url)', function() {
    it('should return the path on a url without a hash or search', function() {
      var url = 'http://domain.com/example/path';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the path on a url with a search', function() {
      var url = 'http://domain.com/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the path on a url with a hash', function() {
      var url = 'http://domain.com/example/path#hash';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hash path if it exists', function() {
      var url = 'http://domain.com/#/example/path';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the query parameters when a hash path exists', function() {
      var url = 'http://domain.com/#/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hashbang path if it exists', function() {
      var url = 'http://domain.com/#!/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the query parameters when a hashbang path exists', function() {
      var url = 'http://domain.com/#!/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the hash and return the path if it\'s not a hash path', function() {
      var url = 'http://domain.com/example/path?queryParam2=false#notHashPath';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hash path when there is both a path and a hash path', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#/example/path?queryParam1=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hashbang path when there is both a path and a hashbang path', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should ignore an additional hash after a hashpath', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true#secondHash';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });
  });

  describe('router.testRoute(route)', function() {
    it('should return true on an exact match', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/example/path'});
      expect(result).toEqual(true);
    });

    it('should return true when matching with a wildcard', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/example/*'});
      expect(result).toEqual(true);
    });

    it('should return true when matching with a path argument', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/:patharg/path'});
      expect(result).toEqual(true);
    });

    it('should return true when matching on a combination of wildcards and path arguments', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/*/:patharg'});
      expect(result).toEqual(true);
    });

    it('should always return true when matching on "*"', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '*'});
      expect(result).toEqual(true);
    });

    it('should not match when one path has a trailing \'/\' but the other doesn\'t', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/example/route/'});
      expect(result).toEqual(false);
    });

    it('should return false if the route path does not have the same number of path segments as the URL path', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path?queryParam=true'; };
      var result = router.testRoute({path: '/example/route/longer'});
      expect(result).toEqual(false);
    });

    it('should ignore the real path and use the hash path if it exists', function() {
      router.currentUrl = function() { return 'http://domain.com/other/path?queryParam2=false#/example/path?queryParam1=true'; };
      var result = router.testRoute({path: '/other/route'});
      expect(result).toEqual(false);
    });

    it('should return true on a route with an optional path where the optional path doesn\'t exist', function() {
      router.currentUrl = function() { return 'http://domain.com/example'; };
      var result = router.testRoute({path: '/example(/path)'});
      expect(result).toEqual(true);
    });

    it('should return true on a route with an optional path where the full path exists', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path'; };
      var result = router.testRoute({path: '/example(/path)'});
      expect(result).toEqual(true);
    });

    it('should return true on a route with an optional path with a trailing slash where the optional path doesn\'t exist', function() {
      router.currentUrl = function() { return 'http://domain.com/example'; };
      var result = router.testRoute({path: '/example/(path)'});
      expect(result).toEqual(true);
    });

    it('should return true on a route with an optional path with a trailing slash where the full path exists', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path'; };
      var result = router.testRoute({path: '/example/(path)'});
      expect(result).toEqual(true);
    });

    it('should return true on a route with an optional path argument where the optional path doesn\'t exist', function() {
      router.currentUrl = function() { return 'http://domain.com/example'; };
      var result = router.testRoute({path: '/example(/:id)'});
      expect(result).toEqual(true);
    });

    it('should return true on a route with an optional path argument where the full path exists', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path'; };
      var result = router.testRoute({path: '/example(/:id)'});
      expect(result).toEqual(true);
    });

    it('should return true when matching on multiple optional paths', function() {
      router.currentUrl = function() { return 'http://domain.com/example/path'; };
      var result = router.testRoute({path: '/(example)(/:id)'});
      expect(result).toEqual(true);
    });
  });

  describe('router.routeArguments(route, url)', function() {
    it('should parse string query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=example%20string';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('example string');
    });

    it('should parse boolean query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse number query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=12.34';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(12.34);
    });

    it('should get the query parameter from the hash path if it exists', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=wrong#!/example/path?queryParam=correct';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('correct');
    });

    it('should correctly get a query param with an equals sign in the value', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=wrong#!/example/path?queryParam=some=text';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('some=text');
    });

    it('should get the query param if it\'s followed by a hash', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=true#hash';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse string path parameters', function() {
      var route = {path: '/person/:name'};
      var url = 'http://domain.com/person/jon?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.name).toEqual('jon');
    });

    it('should parse number path parameters', function() {
      var route = {path: '/customer/:id'};
      var url = 'http://domain.com/customer/123?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(123);
    });

    it('should parse complicated URLs', function() {
      var route = {path: '/customer/:id'};
      var url = 'http://domain.com/customer/123?queryParam=false#!/customer/456?queryParam=true&queryParam2=some%20string';
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(456);
      expect(result.queryParam).toEqual(true);
      expect(result.queryParam2).toEqual('some string');
    });

    it('should parse the query parameters if no route is specified', function() {
      var route = null;
      var url = 'http://domain.com/?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse the query parameters if no route path is specified', function() {
      var route = {};
      var url = 'http://domain.com/?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse the path arguments when an optional path exists', function() {
      var route = {path: '/example(/path)'};
      var url = 'http://domain.com/example?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse the path arguments when an optional path exists', function() {
      var route = {path: '/example/(path)'};
      var url = 'http://domain.com/example?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse the path arguments in an optional path', function() {
      var url = 'http://domain.com/example/123';
      var route = {path: '/example(/:id)'};
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(123);
    });

    it('should parse the path arguments in an optional path with a trailing slash', function() {
      var url = 'http://domain.com/example/123';
      var route = {path: '/example/(:id)'};
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(123);
    });

    it('should not populate the optional path argument if it doesn\'t exist', function() {
      var url = 'http://domain.com/example';
      var route = {path: '/example(/:id)'};
      var result = router.routeArguments(route, url);
      expect(result.id).toBeUndefined();
    });

    it('should parse arguments out of multiple optional paths', function() {
      router.currentUrl = function() { return 'http://domain.com/example/123'; };
      var result = router.testRoute({path: '/(example)(/:id)'});
      expect(result.id).toEqual(123);
    });
  });
});
<commit_msg>more tests<commit_after>/*global define*/
/*jshint loopfunc: true*/
define([
  'amd/describe',
  'amd/it',
  'amd/expect',
  'amd/spyOn',
  'router'
], function(describe, it, expect, spyOn, router) {
  'use strict';

  describe('router.config()', function() {
    // Arrange, Act
    router.config({
      routes: {
        route1: {path: '/example/path'},
        route2: {path: '/second/path'}
      }
    });

    it('should add a matchesUrl() method to every route', function() {
      // Assert
      for (var route in router.routes) {
        expect(router.routes[route].matchesUrl).toBeDefined();
      }
    });
  });

  describe('router.loadCurrentRoute()', function() {
    it('should call router.routeLoadedCallback(module, routeArguments) when it\'s done loading the route\'s module', function() {
      // Arrange
      var mockRoute = {path: '/example/path', module: 'example/exampleView'};
      var mockUrl = 'http://domain.com/example/path?queryParam=true';
      var mockRouteArguments = {queryParam: true};
      var MockModule = function() {};
      spyOn(router, 'currentRoute').and.returnValue(mockRoute);
      spyOn(router, 'currentUrl').and.returnValue(mockUrl);
      spyOn(router, 'routeArguments').and.returnValue(mockRouteArguments);
      spyOn(router, 'routeLoadedCallback');
      spyOn(window, 'require').and.callFake(function() {
        // This part of the test isn't precise since it's completely replacing the anonymouse require callback. There's no other
        // way to do this so this will have to do.
        router.routeLoadedCallback.call(router, MockModule, router.routeArguments(mockRoute, mockUrl));
      });

      // Act
      router.loadCurrentRoute();

      // Assert
      expect(router.currentRoute).toHaveBeenCalled();
      expect(router.currentUrl).toHaveBeenCalled();
      expect(window.require.calls.argsFor(0)[0]).toEqual(['example/exampleView']);
      expect(router.routeArguments.calls.argsFor(0)).toEqual([mockRoute, mockUrl]);
      expect(router.routeLoadedCallback.calls.argsFor(0)).toEqual([MockModule, mockRouteArguments]);
    });
  });

  describe('router.currentRoute()', function() {
    it('should return the first route that matches the URL', function() {
      // Arrange
      router.config({
        routes: {
          route1: {path: '/first/path'},
          route2: {path: '/second/path'},
          route3: {path: '/third/path'}
        }
      });
      spyOn(router, 'currentUrl').and.returnValue('http://domain.com/second/path?queryParam=true');

      // Act
      var actual = router.currentRoute();

      // Assert
      expect(actual).toEqual(router.routes.route2);
    });
  });

  describe('router.urlChangeEventHandler()', function() {
    it('should call loadCurrentRoute()', function() {
      // Arrange
      spyOn(router, 'loadCurrentRoute');

      // Act
      router.urlChangeEventHandler();

      // Assert
      expect(router.loadCurrentRoute).toHaveBeenCalled();
    });
  });

  describe('router.currentUrl()', function() {
    it('should return window.location.href', function() {
      // Act
      var actual = router.currentUrl();

      // Assert
      expect(actual).toEqual(window.location.href);
    });
  });

  describe('router.urlPath(url)', function() {
    it('should return the path on a url without a hash or search', function() {
      var url = 'http://domain.com/example/path';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the path on a url with a search', function() {
      var url = 'http://domain.com/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the path on a url with a hash', function() {
      var url = 'http://domain.com/example/path#hash';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hash path if it exists', function() {
      var url = 'http://domain.com/#/example/path';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the query parameters when a hash path exists', function() {
      var url = 'http://domain.com/#/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hashbang path if it exists', function() {
      var url = 'http://domain.com/#!/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the query parameters when a hashbang path exists', function() {
      var url = 'http://domain.com/#!/example/path?queryParam=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should correctly ignore the hash and return the path if it\'s not a hash path', function() {
      var url = 'http://domain.com/example/path?queryParam2=false#notHashPath';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hash path when there is both a path and a hash path', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#/example/path?queryParam1=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should return the hashbang path when there is both a path and a hashbang path', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });

    it('should ignore an additional hash after a hashpath', function() {
      var url = 'http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true#secondHash';
      var result = router.urlPath(url);
      expect(result).toEqual('/example/path');
    });
  });

  describe('router.testRoute(route)', function() {
    it('should return true on an exact match', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/example/path'});
      expect(result).toEqual(true);
    });

    it('should return true when matching with a wildcard', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/example/*'});
      expect(result).toEqual(true);
    });

    it('should return true when matching with a path argument', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/:patharg/path'});
      expect(result).toEqual(true);
    });

    it('should return true when matching on a combination of wildcards and path arguments', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/*/:patharg'});
      expect(result).toEqual(true);
    });

    it('should always return true when matching on "*"', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '*'});
      expect(result).toEqual(true);
    });

    it('should not match when one path has a trailing \'/\' but the other doesn\'t', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/example/route/'});
      expect(result).toEqual(false);
    });

    it('should return false if the route path does not have the same number of path segments as the URL path', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/example/route/longer'});
      expect(result).toEqual(false);
    });

    it('should ignore the real path and use the hash path if it exists', function() {
      spyOn(router, 'urlPath').and.returnValue('/example/path');
      var result = router.testRoute({path: '/other/route'});
      expect(result).toEqual(false);
    });

    // it('should return true on a route with an optional path where the optional path doesn\'t exist', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example'; };
    //   var result = router.testRoute({path: '/example(/path)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true on a route with an optional path where the full path exists', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example/path'; };
    //   var result = router.testRoute({path: '/example(/path)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true on a route with an optional path with a trailing slash where the optional path doesn\'t exist', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example'; };
    //   var result = router.testRoute({path: '/example/(path)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true on a route with an optional path with a trailing slash where the full path exists', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example/path'; };
    //   var result = router.testRoute({path: '/example/(path)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true on a route with an optional path argument where the optional path doesn\'t exist', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example'; };
    //   var result = router.testRoute({path: '/example(/:id)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true on a route with an optional path argument where the full path exists', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example/path'; };
    //   var result = router.testRoute({path: '/example(/:id)'});
    //   expect(result).toEqual(true);
    // });

    // it('should return true when matching on multiple optional paths', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example/path'; };
    //   var result = router.testRoute({path: '/(example)(/:id)'});
    //   expect(result).toEqual(true);
    // });
  });

  describe('router.routeArguments(route, url)', function() {
    it('should parse string query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=example%20string';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('example string');
    });

    it('should parse boolean query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse number query parameters', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/example/path?queryParam=12.34';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(12.34);
    });

    it('should get the query parameter from the hash path if it exists', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=wrong#!/example/path?queryParam=correct';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('correct');
    });

    it('should correctly get a query param with an equals sign in the value', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=wrong#!/example/path?queryParam=some=text';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual('some=text');
    });

    it('should get the query param if it\'s followed by a hash', function() {
      var route = {path: '/example/path'};
      var url = 'http://domain.com/other/path?queryParam=true#hash';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse string path parameters', function() {
      var route = {path: '/person/:name'};
      var url = 'http://domain.com/person/jon?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.name).toEqual('jon');
    });

    it('should parse number path parameters', function() {
      var route = {path: '/customer/:id'};
      var url = 'http://domain.com/customer/123?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(123);
    });

    it('should parse complicated URLs', function() {
      var route = {path: '/customer/:id'};
      var url = 'http://domain.com/customer/123?queryParam=false#!/customer/456?queryParam=true&queryParam2=some%20string';
      var result = router.routeArguments(route, url);
      expect(result.id).toEqual(456);
      expect(result.queryParam).toEqual(true);
      expect(result.queryParam2).toEqual('some string');
    });

    it('should parse the query parameters if no route is specified', function() {
      var route = null;
      var url = 'http://domain.com/?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    it('should parse the query parameters if no route path is specified', function() {
      var route = {};
      var url = 'http://domain.com/?queryParam=true';
      var result = router.routeArguments(route, url);
      expect(result.queryParam).toEqual(true);
    });

    // it('should parse the path arguments when an optional path exists', function() {
    //   var route = {path: '/example(/path)'};
    //   var url = 'http://domain.com/example?queryParam=true';
    //   var result = router.routeArguments(route, url);
    //   expect(result.queryParam).toEqual(true);
    // });

    // it('should parse the path arguments when an optional path exists', function() {
    //   var route = {path: '/example/(path)'};
    //   var url = 'http://domain.com/example?queryParam=true';
    //   var result = router.routeArguments(route, url);
    //   expect(result.queryParam).toEqual(true);
    // });

    // it('should parse the path arguments in an optional path', function() {
    //   var url = 'http://domain.com/example/123';
    //   var route = {path: '/example(/:id)'};
    //   var result = router.routeArguments(route, url);
    //   expect(result.id).toEqual(123);
    // });

    // it('should parse the path arguments in an optional path with a trailing slash', function() {
    //   var url = 'http://domain.com/example/123';
    //   var route = {path: '/example/(:id)'};
    //   var result = router.routeArguments(route, url);
    //   expect(result.id).toEqual(123);
    // });

    // it('should not populate the optional path argument if it doesn\'t exist', function() {
    //   var url = 'http://domain.com/example';
    //   var route = {path: '/example(/:id)'};
    //   var result = router.routeArguments(route, url);
    //   expect(result.id).toBeUndefined();
    // });

    // it('should parse arguments out of multiple optional paths', function() {
    //   router.currentUrl = function() { return 'http://domain.com/example/123'; };
    //   var result = router.testRoute({path: '/(example)(/:id)'});
    //   expect(result.id).toEqual(123);
    // });
  });
});
<|endoftext|>


<commit_before>describe('parseUrl(location, mode)', function() {
  var router = document.createElement('app-router');

  it('should parse a regular path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '',
      isHashPath: false
    });
  });

  it('should parse a regular path and search when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: false
    });
  });

  it('should use the regular path on a url with a hash not starting in #/ when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path#hash', 'auto')).toEqual({
      path: '/example/path',
      hash: '#hash',
      search: '',
      isHashPath: false
    });
  });

  it('should parse a hash path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/#/example/path', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should parse the search on a hash path', function() {
    expect(router.util.parseUrl('http://domain.com/#/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: true
    });
  });

  it('should parse a hashbang path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/#!/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: true
    });
  });

  it('should use the hash path and hash search when there is both a regular path and a hash path and mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/other/path?queryParam2=false#/example/path?queryParam1=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should return the hashbang path when there is both a path and a hashbang path', function() {
    expect(router.util.parseUrl('http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should use the real path when mode="pushstate"', function() {
    expect(router.util.parseUrl('http://domain.com/#/hash/path', 'pushstate')).toEqual({
      path: '/',
      hash: '#/hash/path',
      search: '',
      isHashPath: false
    });
    expect(router.util.parseUrl('http://domain.com/regular/path#/hash/path', 'pushstate')).toEqual({
      path: '/regular/path',
      hash: '#/hash/path',
      search: '',
      isHashPath: false
    });
  });

  it('should use the hash as the path when mode="hash" even if it doesn\'t start with #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path#hash/path', 'hash')).toEqual({
      path: 'hash/path',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should not use the regular path when mode="hash"', function() {
    expect(router.util.parseUrl('http://domain.com/test/', 'hash')).toEqual({
      path: '/',
      hash: '',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com/test/index.html', 'hash')).toEqual({
      path: '/',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should parse the hash when mode="pushstate"', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path?queryParam1=true#first', 'pushstate')).toEqual({
      path: '/regular/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: false
    });
  });

  it('should parse the hash when mode="auto" and the hash does not start with a #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path?queryParam1=true#first', 'auto')).toEqual({
      path: '/regular/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: false
    });
  });

  it('should parse the hash when mode="auto" and the hash starts with a #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/#/hash/path#first', 'auto')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com/#/hash/path?queryParam1=true#first', 'auto')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should parse the hash when mode="hash"', function() {
    expect(router.util.parseUrl('http://domain.com//#/hash/path#first', 'hash')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com//#/hash/path?queryParam1=true#first', 'hash')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });
});

describe('testRoute(routePath, urlPath, trailingSlashOption, isRegExp)', function() {
  var router = document.createElement('app-router');

  it('should return true on an exact match', function() {
    expect(router.util.testRoute('/example/path', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true on an exact match of the root path', function() {
    expect(router.util.testRoute('/', '/', 'strict', false)).toEqual(true);
  });

  it('should return true when matching with a wildcard', function() {
    expect(router.util.testRoute('/example/*', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true when matching with a path argument', function() {
    expect(router.util.testRoute('/:patharg/path', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true when matching on a combination of wildcards and path arguments', function() {
    expect(router.util.testRoute('/*/:patharg', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should always return true when matching on "*"', function() {
    expect(router.util.testRoute('*', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should not match when one path has a trailing \'/\' but the other doesn\'t', function() {
    expect(router.util.testRoute('/example/route/', '/example/route', 'strict', false)).toEqual(false);
  });

  it('should return false if the route path does not have the same number of path segments as the URL path', function() {
    expect(router.util.testRoute('/example/route/longer', '/example/path', 'strict', false)).toEqual(false);
  });

  it('should ignore trailing slashes if `trailingSlash` is "ignore"', function() {
    expect(router.util.testRoute('/example/path', '/example/path/', 'ignore', false)).toEqual(true);
    expect(router.util.testRoute('/example/path/', '/example/path', 'ignore', false)).toEqual(true);
  });

  it('should enforce trailing slashes if `trailingSlash` is "strict" (the default)', function() {
    expect(router.util.testRoute('/example/path', '/example/path/', 'strict', false)).toEqual(false);
    expect(router.util.testRoute('/example/path/', '/example/path', 'strict', false)).toEqual(false);
  });

  it('should match when the route path is a matching regular expression', function() {
    expect(router.util.testRoute('/^\\/\\w+\\/\\d+$/', '/word/123', 'strict', true)).toEqual(true);
  });

  it('should not match when the route path is a matching regular expression', function() {
    expect(router.util.testRoute('/^\\/\\w+\\/\\d+$/i', '/word/non-number', 'strict', true)).toEqual(false);
  });
});

describe('routeArguments(routePath, urlPath, search, isRegExp, typecast)', function() {
  var router = document.createElement('app-router');

  it('should parse query parameters', function() {
    var args = router.util.routeArguments('*', '/example/path', '?stringQueryParam=example%20string&numQueryParam=12.34', false, true);
    expect(args).toEqual({
      stringQueryParam: 'example string',
      numQueryParam: 12.34
    });
  });

  it('should correctly get a query parameter with an equals sign in the value', function() {
    var args = router.util.routeArguments('*', '/example/path', '?queryParam=some=text&otherParam=123', false, true);
    expect(args.queryParam).toEqual('some=text');
  });

  it('should parse string path parameters', function() {
    var args = router.util.routeArguments('/person/:name', '/person/jon', '?queryParam=true', false, true);
    expect(args.name).toEqual('jon');
  });

  it('should parse number path parameters', function() {
    var args = router.util.routeArguments('/customer/:id', '/customer/123', '?queryParam=true', false, true);
    expect(args.id).toEqual(123);
  });

  it('should not add an empty string value when the search is empty', function() {
    var args = router.util.routeArguments('*', '/example/path', '', false, true);
    expect(args.hasOwnProperty('')).toBeFalsy();
    expect(args).toEqual({});
  });

  it('should still parse query parameters on regex paths', function() {
    var args = router.util.routeArguments('/^\\/\\w+\\/\\d+$/i', '/example/123', '?queryParam=correct', true, true);
    expect(args.queryParam).toEqual('correct');
  });

  it('should not typecast when typecast="string"', function() {
    var args = router.util.routeArguments('*', '/example/path', '?stringQueryParam=example%20string&numQueryParam=12.34', false, false);
    expect(args).toEqual({
      stringQueryParam: 'example%20string',
      numQueryParam: '12.34'
    });
  });
});

describe('typecast(value)', function() {
  var router = document.createElement('app-router');

  it('should leave unescaped strings alone', function() {
    expect(router.util.typecast('hello world!')).toEqual('hello world!');
  });

  it('should unescape (url decode) strings', function() {
    expect(router.util.typecast('example%20string')).toEqual('example string');
  });

  it('should convert "true" to `true`', function() {
    expect(router.util.typecast('true')).toEqual(true);
  });

  it('should convert "false" to `false`', function() {
    expect(router.util.typecast('false')).toEqual(false);
  });

  it('should convert integers', function() {
    expect(router.util.typecast('123')).toEqual(123);
  });

  it('should convert numbers with decimal points', function() {
    expect(router.util.typecast('123.456')).toEqual(123.456);
  });

  it('should not convert an empty string to zero', function() {
    expect(router.util.typecast('')).toEqual('');
  });

  it('should not convert a number with leading zeros to a number', function() {
    expect(router.util.typecast('00123')).toEqual('00123');
  });
});

describe('testRegExString(pattern, value)', function() {
  var router = document.createElement('app-router');

  it('should match a simple regular expression', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/', '/word/123')).toEqual(true);
  });

  it('should match a regular expression with the \'i\' option', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/i', '/Word/123')).toEqual(true);
  });

  it('should not match when the regular expressions shouldn\'t match', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/i', '/word/non-number')).toEqual(false);
  });

  it('should not match when the regular expression does not start with a slash', function() {
    expect(router.util.testRegExString('^\\/\\w+\\/\\d+$/i', '/word/123')).toEqual(false);
  });

  it('should not match when the regular expression does not end with a slash followed by zero or more options', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$', '/word/123')).toEqual(false);
  });
});
<commit_msg>initial globstar spec<commit_after>describe('parseUrl(location, mode)', function() {
  var router = document.createElement('app-router');

  it('should parse a regular path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '',
      isHashPath: false
    });
  });

  it('should parse a regular path and search when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: false
    });
  });

  it('should use the regular path on a url with a hash not starting in #/ when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/example/path#hash', 'auto')).toEqual({
      path: '/example/path',
      hash: '#hash',
      search: '',
      isHashPath: false
    });
  });

  it('should parse a hash path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/#/example/path', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should parse the search on a hash path', function() {
    expect(router.util.parseUrl('http://domain.com/#/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: true
    });
  });

  it('should parse a hashbang path when mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/#!/example/path?queryParam=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam=true',
      isHashPath: true
    });
  });

  it('should use the hash path and hash search when there is both a regular path and a hash path and mode="auto"', function() {
    expect(router.util.parseUrl('http://domain.com/other/path?queryParam2=false#/example/path?queryParam1=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should return the hashbang path when there is both a path and a hashbang path', function() {
    expect(router.util.parseUrl('http://domain.com/other/path?queryParam2=false#!/example/path?queryParam1=true', 'auto')).toEqual({
      path: '/example/path',
      hash: '',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should use the real path when mode="pushstate"', function() {
    expect(router.util.parseUrl('http://domain.com/#/hash/path', 'pushstate')).toEqual({
      path: '/',
      hash: '#/hash/path',
      search: '',
      isHashPath: false
    });
    expect(router.util.parseUrl('http://domain.com/regular/path#/hash/path', 'pushstate')).toEqual({
      path: '/regular/path',
      hash: '#/hash/path',
      search: '',
      isHashPath: false
    });
  });

  it('should use the hash as the path when mode="hash" even if it doesn\'t start with #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path#hash/path', 'hash')).toEqual({
      path: 'hash/path',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should not use the regular path when mode="hash"', function() {
    expect(router.util.parseUrl('http://domain.com/test/', 'hash')).toEqual({
      path: '/',
      hash: '',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com/test/index.html', 'hash')).toEqual({
      path: '/',
      hash: '',
      search: '',
      isHashPath: true
    });
  });

  it('should parse the hash when mode="pushstate"', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path?queryParam1=true#first', 'pushstate')).toEqual({
      path: '/regular/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: false
    });
  });

  it('should parse the hash when mode="auto" and the hash does not start with a #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/regular/path?queryParam1=true#first', 'auto')).toEqual({
      path: '/regular/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: false
    });
  });

  it('should parse the hash when mode="auto" and the hash starts with a #/ or #!/', function() {
    expect(router.util.parseUrl('http://domain.com/#/hash/path#first', 'auto')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com/#/hash/path?queryParam1=true#first', 'auto')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });

  it('should parse the hash when mode="hash"', function() {
    expect(router.util.parseUrl('http://domain.com//#/hash/path#first', 'hash')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '',
      isHashPath: true
    });
    expect(router.util.parseUrl('http://domain.com//#/hash/path?queryParam1=true#first', 'hash')).toEqual({
      path: '/hash/path',
      hash: '#first',
      search: '?queryParam1=true',
      isHashPath: true
    });
  });
});

describe('testRoute(routePath, urlPath, trailingSlashOption, isRegExp)', function() {
  var router = document.createElement('app-router');

  it('should return true on an exact match', function() {
    expect(router.util.testRoute('/example/path', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true on an exact match of the root path', function() {
    expect(router.util.testRoute('/', '/', 'strict', false)).toEqual(true);
  });

  it('should return true when matching with a wildcard', function() {
    expect(router.util.testRoute('/example/*', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true when matching with a path argument', function() {
    expect(router.util.testRoute('/:patharg/path', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should return true when matching on a combination of wildcards and path arguments', function() {
    expect(router.util.testRoute('/*/:patharg', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should always return true when matching on "*"', function() {
    expect(router.util.testRoute('*', '/example/path', 'strict', false)).toEqual(true);
  });

  it('should not match when one path has a trailing \'/\' but the other doesn\'t', function() {
    expect(router.util.testRoute('/example/route/', '/example/route', 'strict', false)).toEqual(false);
  });

  it('should return false if the route path does not have the same number of path segments as the URL path', function() {
    expect(router.util.testRoute('/example/route/longer', '/example/path', 'strict', false)).toEqual(false);
  });

  it('should ignore trailing slashes if `trailingSlash` is "ignore"', function() {
    expect(router.util.testRoute('/example/path', '/example/path/', 'ignore', false)).toEqual(true);
    expect(router.util.testRoute('/example/path/', '/example/path', 'ignore', false)).toEqual(true);
  });

  it('should enforce trailing slashes if `trailingSlash` is "strict" (the default)', function() {
    expect(router.util.testRoute('/example/path', '/example/path/', 'strict', false)).toEqual(false);
    expect(router.util.testRoute('/example/path/', '/example/path', 'strict', false)).toEqual(false);
  });

  it('should match when the route path is a matching regular expression', function() {
    expect(router.util.testRoute('/^\\/\\w+\\/\\d+$/', '/word/123', 'strict', true)).toEqual(true);
  });

  it('should not match when the route path is a matching regular expression', function() {
    expect(router.util.testRoute('/^\\/\\w+\\/\\d+$/i', '/word/non-number', 'strict', true)).toEqual(false);
  });

  it('should match globstars **', function() {
    expect(router.util.testRoute('/**/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/a/b/**', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/*/b/**/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/a/b/**/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
  });

  it('should match zero segment globstars **', function() {
    expect(router.util.testRoute('/**/a/b/**/c/d/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
  });

  it('should ignore trailing slash when using globstars ** in the last segment of the route', function() {
    expect(router.util.testRoute('/a/b/**', '/a/b', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/a/b/**', '/a/b/', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/a/b/**', '/a/b', 'ignore', false)).toEqual(true);
    expect(router.util.testRoute('/a/b/**', '/a/b/', 'ignore', false)).toEqual(true);
  });

  it('should not match invalid globstars **', function() {
    expect(router.util.testRoute('/a/b/**/c', '/a/b/c/d/e', 'strict', false)).toEqual(false);
    expect(router.util.testRoute('/**/a/b/e', '/a/b/c/d/e', 'strict', false)).toEqual(false);
    expect(router.util.testRoute('/a/b/e/**', '/a/b/c/d/e', 'strict', false)).toEqual(false);
    expect(router.util.testRoute('/a/b/**/c/e/**', '/a/b/c/d/e', 'strict', false)).toEqual(false);
  });

  it('should match relative routes when they match the end of the URL', function() {
    expect(router.util.testRoute('e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('b/c/d/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('a/b/c/d/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('a/**/e', '/a/b/c/d/e', 'strict', false)).toEqual(true);
    expect(router.util.testRoute('/b/c/d/e', '/a/b/c/d/e', 'strict', false)).toEqual(false);
  });
});

describe('routeArguments(routePath, urlPath, search, isRegExp, typecast)', function() {
  var router = document.createElement('app-router');

  it('should parse query parameters', function() {
    var args = router.util.routeArguments('*', '/example/path', '?stringQueryParam=example%20string&numQueryParam=12.34', false, true);
    expect(args).toEqual({
      stringQueryParam: 'example string',
      numQueryParam: 12.34
    });
  });

  it('should correctly get a query parameter with an equals sign in the value', function() {
    var args = router.util.routeArguments('*', '/example/path', '?queryParam=some=text&otherParam=123', false, true);
    expect(args.queryParam).toEqual('some=text');
  });

  it('should parse string path parameters', function() {
    var args = router.util.routeArguments('/person/:name', '/person/jon', '?queryParam=true', false, true);
    expect(args.name).toEqual('jon');
  });

  it('should parse number path parameters', function() {
    var args = router.util.routeArguments('/customer/:id', '/customer/123', '?queryParam=true', false, true);
    expect(args.id).toEqual(123);
  });

  it('should not add an empty string value when the search is empty', function() {
    var args = router.util.routeArguments('*', '/example/path', '', false, true);
    expect(args.hasOwnProperty('')).toBeFalsy();
    expect(args).toEqual({});
  });

  it('should still parse query parameters on regex paths', function() {
    var args = router.util.routeArguments('/^\\/\\w+\\/\\d+$/i', '/example/123', '?queryParam=correct', true, true);
    expect(args.queryParam).toEqual('correct');
  });

  it('should not typecast when typecast="string"', function() {
    var args = router.util.routeArguments('*', '/example/path', '?stringQueryParam=example%20string&numQueryParam=12.34', false, false);
    expect(args).toEqual({
      stringQueryParam: 'example%20string',
      numQueryParam: '12.34'
    });
  });
});

describe('typecast(value)', function() {
  var router = document.createElement('app-router');

  it('should leave unescaped strings alone', function() {
    expect(router.util.typecast('hello world!')).toEqual('hello world!');
  });

  it('should unescape (url decode) strings', function() {
    expect(router.util.typecast('example%20string')).toEqual('example string');
  });

  it('should convert "true" to `true`', function() {
    expect(router.util.typecast('true')).toEqual(true);
  });

  it('should convert "false" to `false`', function() {
    expect(router.util.typecast('false')).toEqual(false);
  });

  it('should convert integers', function() {
    expect(router.util.typecast('123')).toEqual(123);
  });

  it('should convert numbers with decimal points', function() {
    expect(router.util.typecast('123.456')).toEqual(123.456);
  });

  it('should not convert an empty string to zero', function() {
    expect(router.util.typecast('')).toEqual('');
  });

  it('should not convert a number with leading zeros to a number', function() {
    expect(router.util.typecast('00123')).toEqual('00123');
  });
});

describe('testRegExString(pattern, value)', function() {
  var router = document.createElement('app-router');

  it('should match a simple regular expression', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/', '/word/123')).toEqual(true);
  });

  it('should match a regular expression with the \'i\' option', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/i', '/Word/123')).toEqual(true);
  });

  it('should not match when the regular expressions shouldn\'t match', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$/i', '/word/non-number')).toEqual(false);
  });

  it('should not match when the regular expression does not start with a slash', function() {
    expect(router.util.testRegExString('^\\/\\w+\\/\\d+$/i', '/word/123')).toEqual(false);
  });

  it('should not match when the regular expression does not end with a slash followed by zero or more options', function() {
    expect(router.util.testRegExString('/^\\/\\w+\\/\\d+$', '/word/123')).toEqual(false);
  });
});
<|endoftext|>